diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 4b153d51..6b9abed1 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -603,6 +603,14 @@ POP_GCC_WARNINGS s = *(t_pod_type*)bin_buff.data(); return true; } + //---------------------------------------------------------------------------- + template + t_pod_type hex_to_pod(const std::string& hex_str) + { + t_pod_type p = AUTO_VAL_INIT(p); + hex_to_pod(hex_str, p); + return p; + } //---------------------------------------------------------------------------- inline std::string get_extension(const std::string& str) { diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 74f5c824..876155ea 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -51,6 +51,8 @@ namespace currency const static crypto::signature null_sig = AUTO_VAL_INIT(null_sig); const static crypto::key_derivation null_derivation = AUTO_VAL_INIT(null_derivation); + const static crypto::hash gdefault_genesis = epee::string_tools::hex_to_pod("CC608F59F8080E2FBFE3C8C80EB6E6A953D47CF2D6AEBD345BADA3A1CAB99852"); + typedef std::string payment_id_t; diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 7be149de..c9991207 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -233,6 +233,7 @@ #endif + static_assert(CURRENCY_MINER_TX_MAX_OUTS <= CURRENCY_TX_MAX_ALLOWED_OUTS, "Miner tx must obey normal tx max outs limit"); static_assert(PREMINE_AMOUNT / WALLET_MAX_ALLOWED_OUTPUT_AMOUNT < CURRENCY_MINER_TX_MAX_OUTS, "Premine can't be divided into reasonable number of outs"); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index dce7b77f..dbf724a0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1091,8 +1091,7 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre { WLT_LOG_L3( "Skipped block by timestamp, height: " << height << ", block time " << b.timestamp << ", account time " << m_account.get_createtime()); } - push_new_block_id(bl_id, height); //m_blockchain.push_back(bl_id); - m_local_bc_size = height + 1; + m_chain.push_new_block_id(bl_id, height); //m_blockchain.push_back(bl_id); m_last_bc_timestamp = b.timestamp; if (!is_pos_block(b)) m_last_pow_block_h = height; @@ -1178,7 +1177,7 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop) r = string_tools::parse_tpod_from_hex_string(gbd_res.blocks.back().id, new_genesis_id); THROW_IF_TRUE_WALLET_EX(!r, error::no_connection_to_daemon, "get_blocks_details"); reset_all(); - m_genesis = new_genesis_id; + m_chain.set_genesis(new_genesis_id); WLT_LOG_MAGENTA("New genesis set for wallet: " << new_genesis_id, LOG_LEVEL_0); get_short_chain_history(req.block_ids); //req.block_ids.push_back(new_genesis_id); @@ -1812,7 +1811,6 @@ void wallet2::detach_blockchain(uint64_t height) } size_t blocks_detached = detach_from_block_ids(height); - m_local_bc_size -= height+1; //rollback spends // do not clear spent flag in spent transfers as corresponding txs are most likely in the pool @@ -4116,25 +4114,24 @@ void wallet2::process_genesis_if_needed(const currency::block& genesis) THROW_IF_TRUE_WALLET_EX(get_blockchain_current_size() > 1, error::wallet_internal_error, "Can't change wallet genesis block once the blockchain has been populated"); crypto::hash genesis_hash = get_block_hash(genesis); - if (get_blockchain_current_size() == 1 && m_genesis != genesis_hash) - WLT_LOG_L0("Changing genesis block for wallet " << m_account.get_public_address_str() << ":" << ENDL << " " << m_genesis << " -> " << genesis_hash); + if (get_blockchain_current_size() == 1 && m_chain.get_genesis() != genesis_hash) + WLT_LOG_L0("Changing genesis block for wallet " << m_account.get_public_address_str() << ":" << ENDL << " " << m_chain.get_genesis() << " -> " << genesis_hash); //m_blockchain.clear(); //m_blockchain.push_back(genesis_hash); - m_genesis = genesis_hash; - m_local_bc_size = 1; + m_chain.set_genesis(genesis_hash); m_last_bc_timestamp = genesis.timestamp; WLT_LOG_L2("Processing genesis block: " << genesis_hash); process_new_transaction(genesis.miner_tx, 0, genesis); } - +//---------------------------------------------------------------------------------------------------- void wallet2::set_genesis(const crypto::hash& genesis_hash) { THROW_IF_TRUE_WALLET_EX(get_blockchain_current_size() != 1, error::wallet_internal_error, "Can't change wallet genesis hash once the blockchain has been populated"); - WLT_LOG_L0("Changing genesis hash for wallet " << m_account.get_public_address_str() << ":" << ENDL << " " << m_genesis << " -> " << genesis_hash); - m_genesis = genesis_hash; + WLT_LOG_L0("Changing genesis hash for wallet " << m_account.get_public_address_str() << ":" << ENDL << " " << m_chain.get_genesis() << " -> " << genesis_hash); + m_chain.set_genesis(genesis_hash); } //---------------------------------------------------------------------------------------------------- void wallet2::print_tx_sent_message(const currency::transaction& tx, const std::string& description, uint64_t fee /* = UINT64_MAX */) diff --git a/src/wallet/wallet_chain_shortener.cpp b/src/wallet/wallet_chain_shortener.cpp index 84d0c05f..71300974 100644 --- a/src/wallet/wallet_chain_shortener.cpp +++ b/src/wallet/wallet_chain_shortener.cpp @@ -5,18 +5,24 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "wallet_chain_shortener.h" +#include "wallet_errors.h" -#define WALLET_EVERYBLOCK_SIZE 10 +#define WALLET_EVERYBLOCK_SIZE 20 #define WALLET_EVERY_10_BLOCKS_SIZE 144 #define WALLET_EVERY_100_BLOCKS_SIZE 144 #define WALLET_EVERY_1000_BLOCKS_SIZE 144 +void exception_handler(){} +wallet_chain_shortener::wallet_chain_shortener(): m_genesis(currency::gdefault_genesis) +{ + m_local_bc_size = 1; +} void wallet_chain_shortener::clear() { m_local_bc_size = 1; - m_last_10_blocks.clear(); + m_last_20_blocks.clear(); m_last_144_blocks_every_10.clear(); m_last_144_blocks_every_100.clear(); m_last_144_blocks_every_1000.clear(); @@ -33,19 +39,32 @@ uint64_t wallet_chain_shortener::get_top_block_height() const return m_local_bc_size - 1; } //---------------------------------------------------------------------------------------------------- +void wallet_chain_shortener::set_genesis(const crypto::hash& id) +{ + m_genesis = id; + m_local_bc_size = 1; +} +//---------------------------------------------------------------------------------------------------- +const crypto::hash& wallet_chain_shortener::get_genesis() +{ + return m_genesis; +} +//---------------------------------------------------------------------------------------------------- void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t height) { + //primary 10 //self check - if (!m_last_10_blocks.empty()) + if (!m_last_20_blocks.empty()) { THROW_IF_FALSE_WALLET_INT_ERR_EX(get_blockchain_current_size() == height, "Inernal error: get_blockchain_current_height(){" << get_blockchain_current_size() << "} == height{" << height << "} is not equal"); } - m_last_10_blocks[height] = id; - if (m_last_10_blocks.size() > WALLET_EVERYBLOCK_SIZE) + m_local_bc_size++; + m_last_20_blocks[height] = id; + if (m_last_20_blocks.size() > WALLET_EVERYBLOCK_SIZE) { - m_last_10_blocks.erase(m_last_10_blocks.begin()); + m_last_20_blocks.erase(m_last_20_blocks.begin()); } //every 10-th @@ -57,6 +76,10 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_144_blocks_every_10.end())->first + 10 == height, "Inernal error: (--m_last_144_blocks_every_10.end())->first + 10{" << (--m_last_144_blocks_every_10.end())->first + 10 << "} == height{" << height << "} is not equal"); } m_last_144_blocks_every_10[height] = id; + if (m_last_144_blocks_every_10.size() > WALLET_EVERY_10_BLOCKS_SIZE) + { + m_last_144_blocks_every_10.erase(m_last_144_blocks_every_10.begin()); + } } //every 100-th if (height % 100 == 0) @@ -67,6 +90,10 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_144_blocks_every_100.end())->first + 100 == height, "Inernal error: (--m_last_144_blocks_every_100.end())->first + 100{" << (--m_last_144_blocks_every_100.end())->first + 100 << "} == height{" << height << "} is not equal"); } m_last_144_blocks_every_100[height] = id; + if (m_last_144_blocks_every_100.size() > WALLET_EVERY_100_BLOCKS_SIZE) + { + m_last_144_blocks_every_100.erase(m_last_144_blocks_every_100.begin()); + } } //every 1000-th //every 100-th @@ -78,7 +105,14 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_144_blocks_every_1000.end())->first + 1000 == height, "Inernal error: (--m_last_144_blocks_every_1000.end())->first + 1000{" << (--m_last_144_blocks_every_1000.end())->first + 1000 << "} == height{" << height << "} is not equal"); } m_last_144_blocks_every_1000[height] = id; + if (m_last_144_blocks_every_1000.size() > WALLET_EVERY_1000_BLOCKS_SIZE) + { + m_last_144_blocks_every_1000.erase(m_last_144_blocks_every_1000.begin()); + } + } + + } //---------------------------------------------------------------------------------------------------- void wallet_chain_shortener::get_short_chain_history(std::list& ids)const @@ -90,18 +124,19 @@ void wallet_chain_shortener::get_short_chain_history(std::list& id return; //first put last 10 - for (auto it = m_last_10_blocks.rbegin(); it != m_last_10_blocks.rend(); it++) + uint64_t count = 0; + for (auto it = m_last_20_blocks.rbegin(); it != m_last_20_blocks.rend() && count != 10; it++) { ids.push_back(it->second); i = it->first; + count++; } - uint64_t current_back_offset = m_last_10_blocks.size(); + uint64_t current_back_offset = ids.size()+1; //self check - THROW_IF_FALSE_WALLET_INT_ERR_EX(current_back_offset == sz - i, "Inernal error: current_back_offset{" << current_back_offset << "} == sz-i{" << sz << " - " << i << "} is not equal"); + THROW_IF_FALSE_WALLET_INT_ERR_EX(current_back_offset == sz - i + 1, "Inernal error: current_back_offset{" << current_back_offset << "} == sz-i{" << sz << " - " << i << "} is not equal"); - uint64_t current_offset_distance = 10; - current_back_offset += 10; + uint64_t current_offset_distance = 1; while (current_back_offset < sz) { uint64_t get_item_around = sz - current_back_offset; @@ -123,18 +158,23 @@ bool wallet_chain_shortener::lookup_item_around(uint64_t i, std::pair* pcontainer; - if (m_last_144_blocks_every_10.size() && i < m_last_144_blocks_every_10.begin()->first) + const std::map* pcontainer; + if (m_last_20_blocks.size() && i >= m_last_20_blocks.begin()->first) + { + devider = 1; + pcontainer = &m_last_20_blocks; + } + else if (m_last_144_blocks_every_10.size() && i >= m_last_144_blocks_every_10.begin()->first) { devider = 10; pcontainer = &m_last_144_blocks_every_10; } - else if (m_last_144_blocks_every_100.size() && i < m_last_144_blocks_every_100.begin()->first) + else if (m_last_144_blocks_every_100.size() && i >= m_last_144_blocks_every_100.begin()->first) { devider = 100; pcontainer = &m_last_144_blocks_every_100; } - else if (m_last_144_blocks_every_1000.size() && i < m_last_144_blocks_every_1000.begin()->first) + else if (m_last_144_blocks_every_1000.size() && i >= m_last_144_blocks_every_1000.begin()->first) { devider = 1000; pcontainer = &m_last_144_blocks_every_1000; @@ -155,18 +195,18 @@ bool wallet_chain_shortener::lookup_item_around(uint64_t i, std::pair m_last_10_blocks.begin()->first) + if (!m_last_20_blocks.empty() && i > m_last_20_blocks.begin()->first) { - //must be in short sequence (m_last_10_blocks) + //must be in short sequence (m_last_20_blocks) //self check - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_10_blocks.end())->first >= i, - "Inernal error: index " << i << " is not located in expected range of m_last_10_blocks={" - << m_last_10_blocks.begin()->first << ":" << (--m_last_10_blocks.end())->first << "}"); + THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_20_blocks.end())->first >= i, + "Inernal error: index " << i << " is not located in expected range of m_last_20_blocks={" + << m_last_20_blocks.begin()->first << ":" << (--m_last_20_blocks.end())->first << "}"); - auto it = m_last_10_blocks.find(i); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_last_10_blocks.end(), - "Inernal error: filde to find index " << i << " in m_last_10_blocks={" - << m_last_10_blocks.begin()->first << ":" << (--m_last_10_blocks.end())->first << "}"); + auto it = m_last_20_blocks.find(i); + THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_last_20_blocks.end(), + "Inernal error: filde to find index " << i << " in m_last_20_blocks={" + << m_last_20_blocks.begin()->first << ":" << (--m_last_20_blocks.end())->first << "}"); block_found = true; if (id == it->second) @@ -181,7 +221,7 @@ void wallet_chain_shortener::check_if_block_matched(uint64_t i, const crypto::ha bool r = lookup_item_around(i, result); if (!r) { - WLT_LOG_L0("Wallet is getting fully resynced due to unmatched block " << id << " at " << i); + LOG_PRINT_L0("Wallet is getting fully resynced due to unmatched block " << id << " at " << i); block_matched = block_found = false; full_reset_needed = true; return; @@ -216,10 +256,12 @@ void clean_map_from_items_above(std::map& container, uin container.erase(--container.end()); } } +//---------------------------------------------------------------------------------------------------- void wallet_chain_shortener::detach(uint64_t height) { - clean_map_from_items_above(m_last_10_blocks, height); + clean_map_from_items_above(m_last_20_blocks, height); clean_map_from_items_above(m_last_144_blocks_every_10, height); clean_map_from_items_above(m_last_144_blocks_every_100, height); clean_map_from_items_above(m_last_144_blocks_every_1000, height); + m_local_bc_size = height + 1; } \ No newline at end of file diff --git a/src/wallet/wallet_chain_shortener.h b/src/wallet/wallet_chain_shortener.h index 44d0180d..29387c00 100644 --- a/src/wallet/wallet_chain_shortener.h +++ b/src/wallet/wallet_chain_shortener.h @@ -14,6 +14,8 @@ #include #include +#include "crypto/crypto.h" + #include "include_base_utils.h" #include "crypto/crypto.h" @@ -21,6 +23,7 @@ class wallet_chain_shortener { public: + wallet_chain_shortener(); void push_new_block_id(const crypto::hash& id, uint64_t height); uint64_t get_top_block_height() const; uint64_t get_blockchain_current_size() const; @@ -29,20 +32,25 @@ public: void check_if_block_matched(uint64_t i, const crypto::hash& id, bool& block_found, bool& block_matched, bool& full_reset_needed) const; void detach(uint64_t height); void clear(); + void set_genesis(const crypto::hash& id); + const crypto::hash& get_genesis(); template inline void serialize(t_archive &a, const unsigned int ver) { a & m_local_bc_size; a & m_genesis; - a & m_last_10_blocks; + a & m_last_20_blocks; a & m_last_144_blocks_every_10; a & m_last_144_blocks_every_100; a & m_last_144_blocks_every_1000; } + + //debug functions + private: std::atomic m_local_bc_size; //temporary workaround crypto::hash m_genesis; - std::map m_last_10_blocks; + std::map m_last_20_blocks; std::map m_last_144_blocks_every_10; //1 day std::map m_last_144_blocks_every_100; //10 days std::map m_last_144_blocks_every_1000; //100 days diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 657f433f..1430b35d 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -696,22 +696,3 @@ if (cond) LOG_ERROR(" (" << #cond << ") is FALSE. THROW EXCEPTION: wallet_common_error"); \ tools::error::throw_wallet_ex(std::string(__FILE__ ":" STRINGIZE(__LINE__)), ss.str()); \ } - - -// wallet-specific logging functions -#define WLT_LOG_L0(msg) LOG_PRINT_L0("[W:" << m_log_prefix << "] " << msg) -#define WLT_LOG_L1(msg) LOG_PRINT_L1("[W:" << m_log_prefix << "] " << msg) -#define WLT_LOG_L2(msg) LOG_PRINT_L2("[W:" << m_log_prefix << "] " << msg) -#define WLT_LOG_L3(msg) LOG_PRINT_L3("[W:" << m_log_prefix << "] " << msg) -#define WLT_LOG_L4(msg) LOG_PRINT_L4("[W:" << m_log_prefix << "] " << msg) -#define WLT_LOG_ERROR(msg) LOG_ERROR("[W:" << m_log_prefix << "] " << msg) -#define WLT_LOG_BLUE(msg, log_level) LOG_PRINT_BLUE("[W:" << m_log_prefix << "] " << msg, log_level) -#define WLT_LOG_CYAN(msg, log_level) LOG_PRINT_CYAN("[W:" << m_log_prefix << "] " << msg, log_level) -#define WLT_LOG_GREEN(msg, log_level) LOG_PRINT_GREEN("[W:" << m_log_prefix << "] " << msg, log_level) -#define WLT_LOG_MAGENTA(msg, log_level) LOG_PRINT_MAGENTA("[W:" << m_log_prefix << "] " << msg, log_level) -#define WLT_LOG_RED(msg, log_level) LOG_PRINT_RED("[W:" << m_log_prefix << "] " << msg, log_level) -#define WLT_LOG_YELLOW(msg, log_level) LOG_PRINT_YELLOW("[W:" << m_log_prefix << "] " << msg, log_level) -#define WLT_CHECK_AND_ASSERT_MES(expr, ret, msg) CHECK_AND_ASSERT_MES(expr, ret, "[W:" << m_log_prefix << "] " << msg) -#define WLT_CHECK_AND_ASSERT_MES_NO_RET(expr, msg) CHECK_AND_ASSERT_MES_NO_RET(expr, "[W:" << m_log_prefix << "] " << msg) -#define WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, "[W:" << m_log_prefix << "] " << msg) -#define WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, "[W:" << m_log_prefix << "] " << msg) diff --git a/tests/unit_tests/wallet_chain_shortener_test.cpp b/tests/unit_tests/wallet_chain_shortener_test.cpp new file mode 100644 index 00000000..0a228579 --- /dev/null +++ b/tests/unit_tests/wallet_chain_shortener_test.cpp @@ -0,0 +1,31 @@ +// Copyright (c) 2019 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include + +#include "gtest/gtest.h" +#include "wallet/wallet_chain_shortener.h" + +TEST(wallet_chain_shortener, wallet_chain_shortener) +{ + uint64_t counter = 0; + wallet_chain_shortener ws; + + for (counter = 1; counter != 1000000; counter++) + { + crypto::hash id_ = AUTO_VAL_INIT(id_); + *((uint64_t*)&id_) = counter; + + ws.push_new_block_id(id_, counter); + } + + std::list short_chain; + ws.get_short_chain_history(short_chain); + for(auto& id: short_chain) + { + LOG_PRINT_L0("{" << *((uint64_t*)&id) << "}{" << counter - *((uint64_t*)&id) << "}" << ENDL); + } + LOG_PRINT_L0("Finished"); + +} +