diff --git a/CMakeLists.txt b/CMakeLists.txt index 020c032..fe8804e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,6 +228,7 @@ set_target_properties(version PROPERTIES IMPORTED_LOCATION set( LIBRARY_SRC_FILES + src/utils/gen_utils.cpp src/utils/monero_utils.cpp src/daemon/monero_daemon_model.cpp src/daemon/monero_daemon.cpp diff --git a/src/daemon/monero_daemon_model.cpp b/src/daemon/monero_daemon_model.cpp index e89d0d4..5ccc271 100644 --- a/src/daemon/monero_daemon_model.cpp +++ b/src/daemon/monero_daemon_model.cpp @@ -52,6 +52,7 @@ #include "monero_daemon_model.h" +#include "utils/gen_utils.h" #include "utils/monero_utils.h" #include "include_base_utils.h" #include "common/util.h" @@ -111,24 +112,24 @@ namespace monero { void monero_block_header::merge(const shared_ptr& self, const shared_ptr& other) { if (this != self.get()) throw runtime_error("this != self"); if (self == other) return; - m_id = monero_utils::reconcile(m_id, other->m_id); - m_height = monero_utils::reconcile(m_height, other->m_height, boost::none, boost::none, true, "block height"); // height can increase - m_timestamp = monero_utils::reconcile(m_timestamp, other->m_timestamp, boost::none, boost::none, true, "block header timestamp"); // timestamp can increase - m_size = monero_utils::reconcile(m_size, other->m_size, "block header size"); - m_weight = monero_utils::reconcile(m_weight, other->m_weight, "block header weight"); - m_long_term_weight = monero_utils::reconcile(m_long_term_weight, other->m_long_term_weight, "block header long term weight"); - m_depth = monero_utils::reconcile(m_depth, other->m_depth, "block header depth"); - m_difficulty = monero_utils::reconcile(m_difficulty, other->m_difficulty, "difficulty"); - m_cumulative_difficulty = monero_utils::reconcile(m_cumulative_difficulty, other->m_cumulative_difficulty, "m_cumulative_difficulty"); - m_major_version = monero_utils::reconcile(m_major_version, other->m_major_version, "m_major_version"); - m_minor_version = monero_utils::reconcile(m_minor_version, other->m_minor_version, "m_minor_version"); - m_nonce = monero_utils::reconcile(m_nonce, other->m_nonce, "m_nonce"); - m_miner_tx_id = monero_utils::reconcile(m_miner_tx_id, other->m_miner_tx_id); - m_num_txs = monero_utils::reconcile(m_num_txs, other->m_num_txs, "block header m_num_txs"); - m_orphan_status = monero_utils::reconcile(m_orphan_status, other->m_orphan_status); - m_prev_id = monero_utils::reconcile(m_prev_id, other->m_prev_id); - m_reward = monero_utils::reconcile(m_reward, other->m_reward, "block header m_reward"); - m_pow_hash = monero_utils::reconcile(m_pow_hash, other->m_pow_hash); + m_id = gen_utils::reconcile(m_id, other->m_id); + m_height = gen_utils::reconcile(m_height, other->m_height, boost::none, boost::none, true, "block height"); // height can increase + m_timestamp = gen_utils::reconcile(m_timestamp, other->m_timestamp, boost::none, boost::none, true, "block header timestamp"); // timestamp can increase + m_size = gen_utils::reconcile(m_size, other->m_size, "block header size"); + m_weight = gen_utils::reconcile(m_weight, other->m_weight, "block header weight"); + m_long_term_weight = gen_utils::reconcile(m_long_term_weight, other->m_long_term_weight, "block header long term weight"); + m_depth = gen_utils::reconcile(m_depth, other->m_depth, "block header depth"); + m_difficulty = gen_utils::reconcile(m_difficulty, other->m_difficulty, "difficulty"); + m_cumulative_difficulty = gen_utils::reconcile(m_cumulative_difficulty, other->m_cumulative_difficulty, "m_cumulative_difficulty"); + m_major_version = gen_utils::reconcile(m_major_version, other->m_major_version, "m_major_version"); + m_minor_version = gen_utils::reconcile(m_minor_version, other->m_minor_version, "m_minor_version"); + m_nonce = gen_utils::reconcile(m_nonce, other->m_nonce, "m_nonce"); + m_miner_tx_id = gen_utils::reconcile(m_miner_tx_id, other->m_miner_tx_id); + m_num_txs = gen_utils::reconcile(m_num_txs, other->m_num_txs, "block header m_num_txs"); + m_orphan_status = gen_utils::reconcile(m_orphan_status, other->m_orphan_status); + m_prev_id = gen_utils::reconcile(m_prev_id, other->m_prev_id); + m_reward = gen_utils::reconcile(m_reward, other->m_reward, "block header m_reward"); + m_pow_hash = gen_utils::reconcile(m_pow_hash, other->m_pow_hash); } // ----------------------------- MONERO BLOCK ------------------------------- @@ -154,8 +155,8 @@ namespace monero { monero_block_header::merge(self, other); // merge reconcilable block extensions - m_hex = monero_utils::reconcile(m_hex, other->m_hex); - m_tx_ids = monero_utils::reconcile(m_tx_ids, other->m_tx_ids); + m_hex = gen_utils::reconcile(m_hex, other->m_hex); + m_tx_ids = gen_utils::reconcile(m_tx_ids, other->m_tx_ids); // merge miner tx if (m_miner_tx == boost::none) m_miner_tx = other->m_miner_tx; @@ -299,37 +300,37 @@ namespace monero { } // otherwise merge tx fields - m_id = monero_utils::reconcile(m_id, other->m_id); - m_version = monero_utils::reconcile(m_version, other->m_version); - m_payment_id = monero_utils::reconcile(m_payment_id, other->m_payment_id); - m_fee = monero_utils::reconcile(m_fee, other->m_fee, "tx fee"); - m_mixin = monero_utils::reconcile(m_mixin, other->m_mixin, "tx m_mixin"); - m_is_confirmed = monero_utils::reconcile(m_is_confirmed, other->m_is_confirmed); - m_do_not_relay = monero_utils::reconcile(m_do_not_relay, other->m_do_not_relay); - m_is_relayed = monero_utils::reconcile(m_is_relayed, other->m_is_relayed); - m_is_double_spend_seen = monero_utils::reconcile(m_is_double_spend_seen, other->m_is_double_spend_seen); - m_key = monero_utils::reconcile(m_key, other->m_key); - m_full_hex = monero_utils::reconcile(m_full_hex, other->m_full_hex); - m_pruned_hex = monero_utils::reconcile(m_pruned_hex, other->m_pruned_hex); - m_prunable_hex = monero_utils::reconcile(m_prunable_hex, other->m_prunable_hex); - m_prunable_hash = monero_utils::reconcile(m_prunable_hash, other->m_prunable_hash); - m_size = monero_utils::reconcile(m_size, other->m_size, "tx size"); - m_weight = monero_utils::reconcile(m_weight, other->m_weight, "tx weight"); - //m_output_indices = monero_utils::reconcile(m_output_indices, other->m_output_indices); // TODO - m_metadata = monero_utils::reconcile(m_metadata, other->m_metadata); - m_common_tx_sets = monero_utils::reconcile(m_common_tx_sets, other->m_common_tx_sets); - //m_extra = monero_utils::reconcile(m_extra, other->m_extra); // TODO - m_rct_signatures = monero_utils::reconcile(m_rct_signatures, other->m_rct_signatures); - m_rct_sig_prunable = monero_utils::reconcile(m_rct_sig_prunable, other->m_rct_sig_prunable); - m_is_kept_by_block = monero_utils::reconcile(m_is_kept_by_block, other->m_is_kept_by_block); - m_is_failed = monero_utils::reconcile(m_is_failed, other->m_is_failed); - m_last_failed_height = monero_utils::reconcile(m_last_failed_height, other->m_last_failed_height, "m_last_failed_height"); - m_last_failed_id = monero_utils::reconcile(m_last_failed_id, other->m_last_failed_id); - m_max_used_block_height = monero_utils::reconcile(m_max_used_block_height, other->m_max_used_block_height, "max_used_block_height"); - m_max_used_block_id = monero_utils::reconcile(m_max_used_block_id, other->m_max_used_block_id); - //m_signatures = monero_utils::reconcile(m_signatures, other->m_signatures); // TODO - m_unlock_time = monero_utils::reconcile(m_unlock_time, other->m_unlock_time, "m_unlock_time"); - m_num_confirmations = monero_utils::reconcile(m_num_confirmations, other->m_num_confirmations, "m_num_confirmations"); + m_id = gen_utils::reconcile(m_id, other->m_id); + m_version = gen_utils::reconcile(m_version, other->m_version); + m_payment_id = gen_utils::reconcile(m_payment_id, other->m_payment_id); + m_fee = gen_utils::reconcile(m_fee, other->m_fee, "tx fee"); + m_mixin = gen_utils::reconcile(m_mixin, other->m_mixin, "tx m_mixin"); + m_is_confirmed = gen_utils::reconcile(m_is_confirmed, other->m_is_confirmed); + m_do_not_relay = gen_utils::reconcile(m_do_not_relay, other->m_do_not_relay); + m_is_relayed = gen_utils::reconcile(m_is_relayed, other->m_is_relayed); + m_is_double_spend_seen = gen_utils::reconcile(m_is_double_spend_seen, other->m_is_double_spend_seen); + m_key = gen_utils::reconcile(m_key, other->m_key); + m_full_hex = gen_utils::reconcile(m_full_hex, other->m_full_hex); + m_pruned_hex = gen_utils::reconcile(m_pruned_hex, other->m_pruned_hex); + m_prunable_hex = gen_utils::reconcile(m_prunable_hex, other->m_prunable_hex); + m_prunable_hash = gen_utils::reconcile(m_prunable_hash, other->m_prunable_hash); + m_size = gen_utils::reconcile(m_size, other->m_size, "tx size"); + m_weight = gen_utils::reconcile(m_weight, other->m_weight, "tx weight"); + //m_output_indices = gen_utils::reconcile(m_output_indices, other->m_output_indices); // TODO + m_metadata = gen_utils::reconcile(m_metadata, other->m_metadata); + m_common_tx_sets = gen_utils::reconcile(m_common_tx_sets, other->m_common_tx_sets); + //m_extra = gen_utils::reconcile(m_extra, other->m_extra); // TODO + m_rct_signatures = gen_utils::reconcile(m_rct_signatures, other->m_rct_signatures); + m_rct_sig_prunable = gen_utils::reconcile(m_rct_sig_prunable, other->m_rct_sig_prunable); + m_is_kept_by_block = gen_utils::reconcile(m_is_kept_by_block, other->m_is_kept_by_block); + m_is_failed = gen_utils::reconcile(m_is_failed, other->m_is_failed); + m_last_failed_height = gen_utils::reconcile(m_last_failed_height, other->m_last_failed_height, "m_last_failed_height"); + m_last_failed_id = gen_utils::reconcile(m_last_failed_id, other->m_last_failed_id); + m_max_used_block_height = gen_utils::reconcile(m_max_used_block_height, other->m_max_used_block_height, "max_used_block_height"); + m_max_used_block_id = gen_utils::reconcile(m_max_used_block_id, other->m_max_used_block_id); + //m_signatures = gen_utils::reconcile(m_signatures, other->m_signatures); // TODO + m_unlock_time = gen_utils::reconcile(m_unlock_time, other->m_unlock_time, "m_unlock_time"); + m_num_confirmations = gen_utils::reconcile(m_num_confirmations, other->m_num_confirmations, "m_num_confirmations"); // merge vins if (!other->m_vins.empty()) { @@ -426,9 +427,9 @@ namespace monero { m_received_timestamp = boost::none; m_last_relayed_timestamp = boost::none; } else { - m_in_tx_pool = monero_utils::reconcile(m_in_tx_pool, other->m_in_tx_pool, boost::none, true, boost::none); // unrelayed -> tx pool - m_received_timestamp = monero_utils::reconcile(m_received_timestamp, other->m_received_timestamp, boost::none, boost::none, false, "m_received_timestamp"); // take earliest receive time - m_last_relayed_timestamp = monero_utils::reconcile(m_last_relayed_timestamp, other->m_last_relayed_timestamp, boost::none, boost::none, true, "m_last_relayed_timestamp"); // take latest relay time + m_in_tx_pool = gen_utils::reconcile(m_in_tx_pool, other->m_in_tx_pool, boost::none, true, boost::none); // unrelayed -> tx pool + m_received_timestamp = gen_utils::reconcile(m_received_timestamp, other->m_received_timestamp, boost::none, boost::none, false, "m_received_timestamp"); // take earliest receive time + m_last_relayed_timestamp = gen_utils::reconcile(m_last_relayed_timestamp, other->m_last_relayed_timestamp, boost::none, boost::none, true, "m_last_relayed_timestamp"); // take latest relay time } } @@ -488,7 +489,7 @@ namespace monero { // otherwise merge output fields if (m_key_image == boost::none) m_key_image = other->m_key_image; else if (other->m_key_image != boost::none) m_key_image.get()->merge(m_key_image.get(), other->m_key_image.get()); - m_amount = monero_utils::reconcile(m_amount, other->m_amount, "output amount"); - m_index = monero_utils::reconcile(m_index, other->m_index, "output index"); + m_amount = gen_utils::reconcile(m_amount, other->m_amount, "output amount"); + m_index = gen_utils::reconcile(m_index, other->m_index, "output index"); } } diff --git a/src/utils/gen_utils.cpp b/src/utils/gen_utils.cpp new file mode 100644 index 0000000..437a897 --- /dev/null +++ b/src/utils/gen_utils.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2017-2019 woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Parts of this file are originally copyright (c) 2014-2019, The Monero Project + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + */ + +#include "gen_utils.h" + +using namespace std; diff --git a/src/utils/gen_utils.h b/src/utils/gen_utils.h new file mode 100644 index 0000000..c7fa8f8 --- /dev/null +++ b/src/utils/gen_utils.h @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2017-2019 woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Parts of this file are originally copyright (c) 2014-2019, The Monero Project + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + */ +#pragma once + +#ifndef gen_utils_h +#define gen_utils_h + +#include "wallet/monero_wallet.h" + +/** + * Collection of utilities for working with Monero's binary portable storage format. + */ +namespace gen_utils +{ + using namespace std; + + // ------------------------- VALUE RECONCILATION- --------------------------- + + // TODO: refactor common template code + template ::value, T>::type* = nullptr> + boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, boost::optional resolve_defined, boost::optional resolve_true, boost::optional resolve_max, const string& err_msg = "") { + + // check for equality + if (val1 == val2) return val1; + + // resolve one value none + if (val1 == boost::none || val2 == boost::none) { + if (resolve_defined != boost::none && *resolve_defined == false) return boost::none; + else return val1 == boost::none ? val2 : val1; + } + + throw runtime_error(string("Cannot reconcile strings: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!err_msg.empty() ? string(". ") + err_msg : string(""))); + } + template ::value, T>::type* = nullptr> + boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, const string& err_msg = "") { + return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); + } + + template ::value, T>::type* = nullptr> + boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, boost::optional resolve_defined, boost::optional resolve_true, boost::optional resolve_max, const string& err_msg = "") { + + // check for equality + if (val1 == val2) return val1; + + // resolve one value none + if (val1 == boost::none || val2 == boost::none) { + if (resolve_defined != boost::none && *resolve_defined == false) return boost::none; + else return val1 == boost::none ? val2 : val1; + } + + // resolve different numbers + if (resolve_max != boost::none) { + return *resolve_max ? max(*val1, *val2) : min(*val1, *val2); + } + + // throw runtime_error("Cannot reconcile values " + val1 + " and " + val2 + " with config: [" + resolve_defined + ", " + resolve_true + ", " + resolve_max + "]", val1, val2); + throw runtime_error(string("Cannot reconcile integrals: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!err_msg.empty() ? string(". ") + err_msg : string(""))); + } + template ::value, T>::type* = nullptr> + boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, const string& err_msg = "") { + return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); + } + + template ::value, T>::type> + boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, boost::optional resolve_defined, boost::optional resolve_true, boost::optional resolve_max, const string& err_msg = "") { + + // check for equality + if (val1 == val2) return val1; + + // resolve one value none + if (val1 == boost::none || val2 == boost::none) { + if (resolve_defined != boost::none && *resolve_defined == false) return boost::none; + else return val1 == boost::none ? val2 : val1; + } + + // resolve different booleans + if (resolve_true != boost::none) { + return val1 == resolve_true ? val1 : val2; // if resolve true, return true, else return false + } else { + throw runtime_error(string("Cannot reconcile booleans: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!err_msg.empty() ? string(". ") + err_msg : string(""))); + } + } + template ::value, T>::type> + boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, const string& err_msg = "") { + return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); + } + + template + vector reconcile(const vector& v1, const vector& v2, const string& err_msg = "") { + + // check for equality + if (v1 == v2) return v1; + + // resolve one vector empty + if (v1.empty()) return v2; + if (v2.empty()) return v1; + + // otherwise cannot reconcile + throw runtime_error("Cannot reconcile vectors" + (!err_msg.empty() ? string(". ") + err_msg : string(""))); + } +} +#endif /* gen_utils_h */ diff --git a/src/utils/monero_utils.h b/src/utils/monero_utils.h index 6a45557..31b41aa 100644 --- a/src/utils/monero_utils.h +++ b/src/utils/monero_utils.h @@ -92,7 +92,6 @@ namespace monero_utils */ shared_ptr cn_block_to_block(const cryptonote::block& cn_block); - /** * Convert a Monero Core crpytonote::transaction to a transaction in this library's * native model. @@ -140,95 +139,5 @@ namespace monero_utils boost::property_tree::ptree to_property_tree(const vector& nums); boost::property_tree::ptree to_property_tree(const vector& nums); boost::property_tree::ptree to_property_tree(const vector& nums); - - // ------------------------- VALUE RECONCILATION- --------------------------- - - // TODO: refactor common template code - template ::value, T>::type* = nullptr> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, boost::optional resolve_defined, boost::optional resolve_true, boost::optional resolve_max, const string& err_msg = "") { - - // check for equality - if (val1 == val2) return val1; - - // resolve one value none - if (val1 == boost::none || val2 == boost::none) { - if (resolve_defined != boost::none && *resolve_defined == false) return boost::none; - else return val1 == boost::none ? val2 : val1; - } - - throw runtime_error(string("Cannot reconcile strings: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!err_msg.empty() ? string(". ") + err_msg : string(""))); - } - template ::value, T>::type* = nullptr> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, const string& err_msg = "") { - return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); - } - - template ::value, T>::type* = nullptr> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, boost::optional resolve_defined, boost::optional resolve_true, boost::optional resolve_max, const string& err_msg = "") { - - // check for equality - if (val1 == val2) return val1; - - // resolve one value none - if (val1 == boost::none || val2 == boost::none) { - if (resolve_defined != boost::none && *resolve_defined == false) return boost::none; - else return val1 == boost::none ? val2 : val1; - } - - // resolve different numbers - if (resolve_max != boost::none) { - return *resolve_max ? max(*val1, *val2) : min(*val1, *val2); - } - - // throw runtime_error("Cannot reconcile values " + val1 + " and " + val2 + " with config: [" + resolve_defined + ", " + resolve_true + ", " + resolve_max + "]", val1, val2); - throw runtime_error(string("Cannot reconcile integrals: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!err_msg.empty() ? string(". ") + err_msg : string(""))); - } - template ::value, T>::type* = nullptr> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, const string& err_msg = "") { - return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); - } - - template ::value, T>::type> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, boost::optional resolve_defined, boost::optional resolve_true, boost::optional resolve_max, const string& err_msg = "") { - - // check for equality - if (val1 == val2) return val1; - - // resolve one value none - if (val1 == boost::none || val2 == boost::none) { - if (resolve_defined != boost::none && *resolve_defined == false) return boost::none; - else return val1 == boost::none ? val2 : val1; - } - - // resolve different booleans - if (resolve_true != boost::none) { - return val1 == resolve_true ? val1 : val2; // if resolve true, return true, else return false - } else { - throw runtime_error(string("Cannot reconcile booleans: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!err_msg.empty() ? string(". ") + err_msg : string(""))); - } - } - template ::value, T>::type> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, const string& err_msg = "") { - return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); - } - - template - vector reconcile(const vector& v1, const vector& v2, const string& err_msg = "") { - - // check for equality - if (v1 == v2) return v1; - - // resolve one vector empty - if (v1.empty()) return v2; - if (v2.empty()) return v1; - - // otherwise cannot reconcile - throw runtime_error("Cannot reconcile vectors" + (!err_msg.empty() ? string(". ") + err_msg : string(""))); - } - -// template -// boost::optional reconcile(const boost::optional& val1, const boost::optional& val2) { -// return reconcile(val1, val2, boost::none, boost::none, boost::none); -// } } #endif /* monero_utils_h */ diff --git a/src/wallet/monero_wallet_model.cpp b/src/wallet/monero_wallet_model.cpp index 1604e86..31f669a 100644 --- a/src/wallet/monero_wallet_model.cpp +++ b/src/wallet/monero_wallet_model.cpp @@ -52,6 +52,7 @@ #include "monero_wallet.h" +#include "utils/gen_utils.h" #include "utils/monero_utils.h" #include #include @@ -164,7 +165,7 @@ namespace monero { monero_tx::merge(self, other); // merge wallet extensions - m_note = monero_utils::reconcile(m_note, other->m_note); + m_note = gen_utils::reconcile(m_note, other->m_note); // merge incoming transfers if (!other->m_incoming_transfers.empty()) { @@ -352,16 +353,16 @@ namespace monero { } // otherwise merge transfer fields - m_account_index = monero_utils::reconcile(m_account_index, other->m_account_index, "acountIndex"); + m_account_index = gen_utils::reconcile(m_account_index, other->m_account_index, "acountIndex"); // TODO monero core: failed m_tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount/m_num_suggested_confirmations of 0 if (m_amount != boost::none && other->m_amount != boost::none && *m_amount != *other->m_amount && (*m_amount == 0 || *other->m_amount == 0)) { - m_account_index = monero_utils::reconcile(m_account_index, other->m_account_index, boost::none, boost::none, true, "acountIndex"); - m_num_suggested_confirmations = monero_utils::reconcile(m_num_suggested_confirmations, other->m_num_suggested_confirmations, boost::none, boost::none, true, "m_num_suggested_confirmations"); + m_account_index = gen_utils::reconcile(m_account_index, other->m_account_index, boost::none, boost::none, true, "acountIndex"); + m_num_suggested_confirmations = gen_utils::reconcile(m_num_suggested_confirmations, other->m_num_suggested_confirmations, boost::none, boost::none, true, "m_num_suggested_confirmations"); MWARNING("WARNING: failed tx in pool causes non-originating wallets to return duplicate incoming transfers but with one amount/m_num_suggested_confirmations of 0"); } else { - m_amount = monero_utils::reconcile(m_amount, other->m_amount, "transfer amount"); - m_num_suggested_confirmations = monero_utils::reconcile(m_num_suggested_confirmations, other->m_num_suggested_confirmations, boost::none, boost::none, false, "m_num_suggested_confirmations"); + m_amount = gen_utils::reconcile(m_amount, other->m_amount, "transfer amount"); + m_num_suggested_confirmations = gen_utils::reconcile(m_num_suggested_confirmations, other->m_num_suggested_confirmations, boost::none, boost::none, false, "m_num_suggested_confirmations"); } } @@ -391,8 +392,8 @@ namespace monero { void monero_incoming_transfer::merge(const shared_ptr& self, const shared_ptr& other) { if (self == other) return; monero_transfer::merge(self, other); - m_subaddress_index = monero_utils::reconcile(m_subaddress_index, other->m_subaddress_index, "incoming transfer m_subaddress_index"); - m_address = monero_utils::reconcile(m_address, other->m_address); + m_subaddress_index = gen_utils::reconcile(m_subaddress_index, other->m_subaddress_index, "incoming transfer m_subaddress_index"); + m_address = gen_utils::reconcile(m_address, other->m_address); } // ----------------------- MONERO OUTGOING TRANSFER ------------------------- @@ -422,9 +423,9 @@ namespace monero { void monero_outgoing_transfer::merge(const shared_ptr& self, const shared_ptr& other) { if (self == other) return; monero_transfer::merge(self, other); - m_subaddress_indices = monero_utils::reconcile(m_subaddress_indices, other->m_subaddress_indices); - m_addresses = monero_utils::reconcile(m_addresses, other->m_addresses); - m_destinations = monero_utils::reconcile(m_destinations, other->m_destinations); + m_subaddress_indices = gen_utils::reconcile(m_subaddress_indices, other->m_subaddress_indices); + m_addresses = gen_utils::reconcile(m_addresses, other->m_addresses); + m_destinations = gen_utils::reconcile(m_destinations, other->m_destinations); } // ----------------------- MONERO TRANSFER REQUEST -------------------------- @@ -588,9 +589,9 @@ namespace monero { monero_output::merge(self, other); // merge output wallet extensions - m_account_index = monero_utils::reconcile(m_account_index, other->m_account_index); - m_subaddress_index = monero_utils::reconcile(m_subaddress_index, other->m_subaddress_index); - m_is_spent = monero_utils::reconcile(m_is_spent, other->m_is_spent); + m_account_index = gen_utils::reconcile(m_account_index, other->m_account_index); + m_subaddress_index = gen_utils::reconcile(m_subaddress_index, other->m_subaddress_index); + m_is_spent = gen_utils::reconcile(m_is_spent, other->m_is_spent); } // ------------------------ MONERO OUTPUT REQUEST ---------------------------