diff options
author | j-berman <justinberman@protonmail.com> | 2022-09-09 20:34:18 -0600 |
---|---|---|
committer | j-berman <justinberman@protonmail.com> | 2023-06-15 02:21:29 -0700 |
commit | e6b86af931f16291ef0b7083d55816b38be1d3b6 (patch) | |
tree | c98bfdbcbadab6d83401e8f2b12d423028f4abb2 /src/wallet/wallet2.h | |
parent | Merge pull request #8842 (diff) | |
download | monero-e6b86af931f16291ef0b7083d55816b38be1d3b6.tar.xz |
wallet2: fix rescanning tx via scan_tx
- Detach & re-process txs >= lowest scan height
- ensures that if a user calls scan_tx(tx1) after scanning tx2,
the wallet correctly processes tx1 and tx2
- if a user provides a tx with a height higher than the wallet's
last scanned height, the wallet will scan starting from that tx's
height
- scan_tx requires trusted daemon iff need to re-process existing
txs: in addition to querying a daemon for txids, if a user
provides a txid of a tx with height *lower* than any *already*
scanned txs in the wallet, then the wallet will also query the
daemon for all the *higher* txs as well. This is likely
unexpected behavior to a caller, and so to protect a caller from
revealing txid's to an untrusted daemon in an unexpected way,
require the daemon be trusted.
Diffstat (limited to 'src/wallet/wallet2.h')
-rw-r--r-- | src/wallet/wallet2.h | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 5e922494b..554a766bf 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -810,6 +810,30 @@ private: bool empty() const { return tx_extra_fields.empty() && primary.empty() && additional.empty(); } }; + struct detached_blockchain_data + { + hashchain detached_blockchain; + size_t original_chain_size; + std::unordered_set<crypto::hash> detached_tx_hashes; + std::unordered_map<crypto::hash, std::vector<cryptonote::tx_destination_entry>> detached_confirmed_txs_dests; + }; + + struct process_tx_entry_t + { + cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry tx_entry; + cryptonote::transaction tx; + crypto::hash tx_hash; + }; + + struct tx_entry_data + { + std::vector<process_tx_entry_t> tx_entries; + uint64_t lowest_height; + uint64_t highest_height; + + tx_entry_data(): lowest_height((uint64_t)-1), highest_height(0) {} + }; + /*! * \brief Generates a wallet or restores one. Assumes the multisig setup * has already completed for the provided multisig info. @@ -1360,7 +1384,7 @@ private: std::string get_spend_proof(const crypto::hash &txid, const std::string &message); bool check_spend_proof(const crypto::hash &txid, const std::string &message, const std::string &sig_str); - void scan_tx(const std::vector<crypto::hash> &txids); + void scan_tx(const std::unordered_set<crypto::hash> &txids); /*! * \brief Generates a proof that proves the reserve of unspent funds @@ -1644,10 +1668,11 @@ private: */ bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password); bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password, boost::optional<crypto::chacha_key>& keys_to_encrypt); - void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); + void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL, bool ignore_callbacks = false); bool should_skip_block(const cryptonote::block &b, uint64_t height) const; void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); - void detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); + detached_blockchain_data detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); + void handle_reorg(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const; bool clear(); void clear_soft(bool keep_key_images=false); @@ -1703,6 +1728,9 @@ private: crypto::chacha_key get_ringdb_key(); void setup_keys(const epee::wipeable_string &password); size_t get_transfer_details(const crypto::key_image &ki) const; + tx_entry_data get_tx_entries(const std::unordered_set<crypto::hash> &txids); + void sort_scan_tx_entries(std::vector<process_tx_entry_t> &unsorted_tx_entries); + void process_scan_txs(const tx_entry_data &txs_to_scan, const tx_entry_data &txs_to_reprocess, const std::unordered_set<crypto::hash> &tx_hashes_to_reprocess, detached_blockchain_data &dbd); void register_devices(); hw::device& lookup_device(const std::string & device_descriptor); @@ -1793,6 +1821,9 @@ private: // m_refresh_from_block_height was defaulted to zero.*/ bool m_explicit_refresh_from_block_height; uint64_t m_pool_info_query_time; + uint64_t m_skip_to_height; + // m_skip_to_height is useful when we don't want to modify the wallet's restore height. + // m_refresh_from_block_height is also a wallet's restore height which should remain constant unless explicitly modified by the user. bool m_confirm_non_default_ring_size; AskPasswordType m_ask_password; uint64_t m_max_reorg_depth; |