From 4825b7c01262b65007bf111ae386fe6090eb29b9 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 24 Apr 2020 01:05:36 +0200 Subject: [PATCH] initial code for upgrading walle sync protocol --- src/currency_core/currency_config.h | 3 +- src/wallet/wallet2.cpp | 85 +++++++++++++++++++++++------ src/wallet/wallet2.h | 34 +++++++++++- 3 files changed, 100 insertions(+), 22 deletions(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 8de1ee32..0fb51938 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -215,7 +215,8 @@ #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+65) +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+66) + #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 5aaf395f..a418be65 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1070,8 +1070,8 @@ void wallet2::process_unconfirmed(const currency::transaction& tx, std::vectoron_new_block(height, b); } //---------------------------------------------------------------------------------------------------- +void wallet2::push_new_block_id(const crypto::hash& id, uint64_t height) +{ + //primary 10 + //self check + if (!m_last_10_blocks.empty()) + { + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(get_blockchain_current_height() == height, "Inernal error: get_blockchain_current_height(){" << get_blockchain_current_height() << "} == height{" << height << "} is not equal"); + } + + m_last_10_blocks[height] = id; + if (m_last_10_blocks.size() > WALLET_EVERYBLOCK_SIZE) + { + m_last_10_blocks.erase(m_last_10_blocks.begin()); + } + + //every 10-th + if (height % 10 == 0) + { + //self check + if (!m_last_144_blocks_every_10.empty()) + { + WLT_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; + } + //every 100-th + if (height % 100 == 0) + { + //self check + if (!m_last_144_blocks_every_100.empty()) + { + WLT_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; + } + //every 1000-th + //every 100-th + if (height % 1000 == 0) + { + //self check + if (!m_last_144_blocks_every_1000.empty()) + { + WLT_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; + } + +} +//---------------------------------------------------------------------------------------------------- void wallet2::get_short_chain_history(std::list& ids) { ids.clear(); size_t i = 0; size_t current_multiplier = 1; - size_t sz = m_blockchain.size(); + size_t sz = get_blockchain_current_height(); if(!sz) return; size_t current_back_offset = 1; @@ -1168,9 +1217,9 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop) return; } THROW_IF_TRUE_WALLET_EX(res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, res.status); - THROW_IF_TRUE_WALLET_EX(m_blockchain.size() && m_blockchain.size() <= res.start_height, error::wallet_internal_error, + THROW_IF_TRUE_WALLET_EX(get_blockchain_current_height() && get_blockchain_current_height() <= res.start_height, error::wallet_internal_error, "wrong daemon response: m_start_height=" + std::to_string(res.start_height) + - " not less than local blockchain size=" + std::to_string(m_blockchain.size())); + " not less than local blockchain size=" + std::to_string(get_blockchain_current_height())); handle_pulled_blocks(blocks_added, stop, res); } @@ -1180,7 +1229,7 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop { size_t current_index = res.start_height; - if (res.start_height == 0 && m_blockchain.size() == 1 && !res.blocks.empty()) + if (res.start_height == 0 && get_blockchain_current_height() == 1 && !res.blocks.empty()) { const currency::block& genesis = res.blocks.front().block_ptr->bl; THROW_IF_TRUE_WALLET_EX(get_block_height(genesis) != 0, error::wallet_internal_error, "first block expected to be genesis"); @@ -1199,7 +1248,7 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop //TODO: get_block_hash is slow crypto::hash bl_id = get_block_hash(bl); - if (current_index >= m_blockchain.size()) + if (current_index >= get_blockchain_current_height()) { process_new_blockchain_entry(bl, bl_entry, bl_id, current_index); ++blocks_added; @@ -1233,7 +1282,7 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop } } - WLT_LOG_L1("[PULL BLOCKS] " << res.start_height << " --> " << m_blockchain.size()); + WLT_LOG_L1("[PULL BLOCKS] " << res.start_height << " --> " << get_blockchain_current_height()); } //---------------------------------------------------------------------------------------------------- uint64_t wallet2::get_sync_progress() @@ -1610,7 +1659,7 @@ void wallet2::refresh(size_t & blocks_fetched, bool& received_money, std::atomic size_t added_blocks = 0; size_t try_count = 0; crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash(m_transfers.back().m_ptx_wallet_info->m_tx) : null_hash; - m_height_of_start_sync = m_blockchain.size(); + m_height_of_start_sync = get_blockchain_current_height(); m_last_sync_percent = 0; while (!stop.load(std::memory_order_relaxed)) { @@ -2075,7 +2124,7 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) { reset_history(); } - m_local_bc_height = m_blockchain.size(); + m_local_bc_height = get_blockchain_current_height(); THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file)); WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str()); @@ -2623,7 +2672,7 @@ bool wallet2::is_transfer_okay_for_pos(const transfer_details& tr, uint64_t& sta return false; //prevent staking of after-last-pow-coins - if (m_blockchain.size() - tr.m_ptx_wallet_info->m_block_height <= m_core_runtime_config.min_coinstake_age) + if (get_blockchain_current_height() - tr.m_ptx_wallet_info->m_block_height <= m_core_runtime_config.min_coinstake_age) return false; if (tr.m_ptx_wallet_info->m_block_height > m_last_pow_block_h) @@ -2945,20 +2994,20 @@ bool wallet2::is_transfer_unlocked(const transfer_details& td, bool for_pos_mini if (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_BLOCKED) return false; - if (td.m_ptx_wallet_info->m_block_height + WALLET_DEFAULT_TX_SPENDABLE_AGE > m_blockchain.size()) + if (td.m_ptx_wallet_info->m_block_height + WALLET_DEFAULT_TX_SPENDABLE_AGE > get_blockchain_current_height()) return false; uint64_t unlock_time = get_tx_unlock_time(td.m_ptx_wallet_info->m_tx, td.m_internal_output_index); - if (for_pos_mining && m_blockchain.size() > m_core_runtime_config.hard_fork1_starts_after_height) + if (for_pos_mining && get_blockchain_current_height() > m_core_runtime_config.hard_fork1_starts_after_height) { //allowed of staking locked coins with stake_lock_time = unlock_time; } else { - if (!currency::is_tx_spendtime_unlocked(unlock_time, m_blockchain.size(), m_core_runtime_config.get_core_time())) + if (!currency::is_tx_spendtime_unlocked(unlock_time, get_blockchain_current_height(), m_core_runtime_config.get_core_time())) return false; } return true; @@ -4047,10 +4096,10 @@ void wallet2::process_genesis_if_needed(const currency::block& genesis) if (!m_transfers.empty() || !m_key_images.empty()) return; - THROW_IF_TRUE_WALLET_EX(m_blockchain.size() > 1, error::wallet_internal_error, "Can't change wallet genesis block once the blockchain has been populated"); + THROW_IF_TRUE_WALLET_EX(get_blockchain_current_height() > 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 (m_blockchain.size() == 1 && m_blockchain[0] != genesis_hash) + if (get_blockchain_current_height() == 1 && m_blockchain[0] != genesis_hash) WLT_LOG_L0("Changing genesis block for wallet " << m_account.get_public_address_str() << ":" << ENDL << " " << m_blockchain[0] << " -> " << genesis_hash); m_blockchain.clear(); @@ -4065,7 +4114,7 @@ void wallet2::process_genesis_if_needed(const currency::block& genesis) void wallet2::set_genesis(const crypto::hash& genesis_hash) { - THROW_IF_TRUE_WALLET_EX(m_blockchain.size() != 1, error::wallet_internal_error, "Can't change wallet genesis hash once the blockchain has been populated"); + THROW_IF_TRUE_WALLET_EX(get_blockchain_current_height() != 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_blockchain[0] << " -> " << genesis_hash); m_blockchain[0] = genesis_hash; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index aa866008..00ff344a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -44,6 +44,12 @@ #define WALLET_DEFAULT_POS_MINT_PACKING_SIZE 100 +#define WALLET_EVERYBLOCK_SIZE 10 +#define WALLET_EVERY_10_BLOCKS_SIZE 144 +#define WALLET_EVERY_100_BLOCKS_SIZE 144 +#define WALLET_EVERY_1000_BLOCKS_SIZE 144 + + #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "wallet" @@ -632,7 +638,9 @@ namespace tools uint64_t fee, size_t& outs_total, uint64_t& amount_total, size_t& outs_swept, currency::transaction* p_result_tx = nullptr, std::string* p_filename_or_unsigned_tx_blob_str = nullptr); bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id); - uint64_t get_blockchain_current_height() const { return m_blockchain.size(); } + uint64_t get_blockchain_current_height() const { + return m_last_10_blocks.empty() ? 0 : (--m_last_10_blocks.end())->first + 1; + } template inline void serialize(t_archive &a, const unsigned int ver) @@ -665,8 +673,21 @@ namespace tools return; } } + //convert from old version + if (ver < CURRENCY_FORMATION_VERSION + 65) + { + //TODO: a & m_blockchain; + } + else + { + a & m_genesis; + a & m_last_10_blocks; + a & m_last_144_blocks_every_10; + a & m_last_144_blocks_every_100; + a & m_last_144_blocks_every_1000; + } + - a & m_blockchain; a & m_transfers; a & m_multisig_transfers; a & m_key_images; @@ -870,6 +891,7 @@ private: bool generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number); bool store_unsigned_tx_to_file_and_reserve_transfers(const finalize_tx_param& ftp, const std::string& filename, std::string* p_unsigned_tx_blob_str = nullptr); void check_and_throw_if_self_directed_tx_with_payment_id_requested(const construct_tx_param& ctp); + void push_new_block_id(const crypto::hash& id, uint64_t height); currency::account_base m_account; bool m_watch_only; @@ -877,7 +899,13 @@ private: std::wstring m_wallet_file; std::wstring m_pending_ki_file; std::string m_password; - std::vector m_blockchain; + //std::vector m_blockchain; + crypto::hash m_genesis; + std::map m_last_10_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 + std::atomic m_local_bc_height; //temporary workaround std::atomic m_last_bc_timestamp; bool m_do_rise_transfer;