move reconcile() utils from monero_utils to gen_utils

This commit is contained in:
woodser
2019-10-02 18:54:06 -04:00
parent f76b604807
commit ef95dc390d
6 changed files with 279 additions and 161 deletions
+1
View File
@@ -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
+57 -56
View File
@@ -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<monero_block_header>& self, const shared_ptr<monero_block_header>& 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");
}
}
+55
View File
@@ -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;
+151
View File
@@ -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 <class T, typename std::enable_if<std::is_same<T, string>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> 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 <class T, typename std::enable_if<std::is_same<T, string>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& err_msg = "") {
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
}
template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> 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 <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& err_msg = "") {
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
}
template <class T, typename std::enable_if<std::is_same<T, bool>::value, T>::type>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> 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 <class T, typename std::enable_if<std::is_same<T, bool>::value, T>::type>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& err_msg = "") {
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
}
template <class T>
vector<T> reconcile(const vector<T>& v1, const vector<T>& 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 */
-91
View File
@@ -92,7 +92,6 @@ namespace monero_utils
*/
shared_ptr<monero_block> 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<uint8_t>& nums);
boost::property_tree::ptree to_property_tree(const vector<uint32_t>& nums);
boost::property_tree::ptree to_property_tree(const vector<uint64_t>& nums);
// ------------------------- VALUE RECONCILATION- ---------------------------
// TODO: refactor common template code
template <class T, typename std::enable_if<std::is_same<T, string>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> 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 <class T, typename std::enable_if<std::is_same<T, string>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& err_msg = "") {
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
}
template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> 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 <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& err_msg = "") {
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
}
template <class T, typename std::enable_if<std::is_same<T, bool>::value, T>::type>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> 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 <class T, typename std::enable_if<std::is_same<T, bool>::value, T>::type>
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& err_msg = "") {
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
}
template <class T>
vector<T> reconcile(const vector<T>& v1, const vector<T>& 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 <class T>
// boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2) {
// return reconcile(val1, val2, boost::none, boost::none, boost::none);
// }
}
#endif /* monero_utils_h */
+15 -14
View File
@@ -52,6 +52,7 @@
#include "monero_wallet.h"
#include "utils/gen_utils.h"
#include "utils/monero_utils.h"
#include <stdio.h>
#include <iostream>
@@ -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<monero_incoming_transfer>& self, const shared_ptr<monero_incoming_transfer>& 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<monero_outgoing_transfer>& self, const shared_ptr<monero_outgoing_transfer>& 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 ---------------------------