mirror of
https://github.com/monero-project/monero.git
synced 2026-07-30 23:50:24 -07:00
Merge pull request #4889
f42263eb wallet: adds rescan_bc option with preserving key images (Dusan Klinec)
This commit is contained in:
+89
-17
@@ -3222,6 +3222,26 @@ bool wallet2::clear()
|
||||
m_device_last_key_image_sync = 0;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::clear_soft(bool keep_key_images)
|
||||
{
|
||||
m_blockchain.clear();
|
||||
m_transfers.clear();
|
||||
if (!keep_key_images)
|
||||
m_key_images.clear();
|
||||
m_pub_keys.clear();
|
||||
m_unconfirmed_txs.clear();
|
||||
m_payments.clear();
|
||||
m_confirmed_txs.clear();
|
||||
m_unconfirmed_payments.clear();
|
||||
m_scanned_pool_txs[0].clear();
|
||||
m_scanned_pool_txs[1].clear();
|
||||
|
||||
cryptonote::block b;
|
||||
generate_genesis(b);
|
||||
m_blockchain.push_back(get_block_hash(b));
|
||||
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Stores wallet information to wallet file.
|
||||
@@ -5468,8 +5488,12 @@ void wallet2::rescan_spent()
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::rescan_blockchain(bool hard, bool refresh)
|
||||
void wallet2::rescan_blockchain(bool hard, bool refresh, bool keep_key_images)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(!hard || !keep_key_images, "Cannot preserve key images on hard rescan");
|
||||
const size_t transfers_cnt = m_transfers.size();
|
||||
crypto::hash transfers_hash{};
|
||||
|
||||
if(hard)
|
||||
{
|
||||
clear();
|
||||
@@ -5477,25 +5501,16 @@ void wallet2::rescan_blockchain(bool hard, bool refresh)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_blockchain.clear();
|
||||
m_transfers.clear();
|
||||
m_key_images.clear();
|
||||
m_pub_keys.clear();
|
||||
m_unconfirmed_txs.clear();
|
||||
m_payments.clear();
|
||||
m_confirmed_txs.clear();
|
||||
m_unconfirmed_payments.clear();
|
||||
m_scanned_pool_txs[0].clear();
|
||||
m_scanned_pool_txs[1].clear();
|
||||
|
||||
cryptonote::block b;
|
||||
generate_genesis(b);
|
||||
m_blockchain.push_back(get_block_hash(b));
|
||||
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
|
||||
if (keep_key_images && refresh)
|
||||
hash_m_transfers((int64_t) transfers_cnt, transfers_hash);
|
||||
clear_soft(keep_key_images);
|
||||
}
|
||||
|
||||
if (refresh)
|
||||
this->refresh(false);
|
||||
|
||||
if (refresh && keep_key_images)
|
||||
finish_rescan_bc_keep_key_images(transfers_cnt, transfers_hash);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_unlocked(const transfer_details& td) const
|
||||
@@ -11392,6 +11407,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||
auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
|
||||
if (it != m_key_images.end())
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(it->second >= m_transfers.size(), error::wallet_internal_error, std::string("Key images cache contains illegal transfer offset: ") + std::to_string(it->second) + std::string(" m_transfers.size() = ") + std::to_string(m_transfers.size()));
|
||||
const transfer_details& td = m_transfers[it->second];
|
||||
uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
|
||||
if (amount > 0)
|
||||
@@ -12490,5 +12506,61 @@ void wallet2::throw_on_rpc_response_error(const boost::optional<std::string> &st
|
||||
THROW_WALLET_EXCEPTION_IF(*status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, method);
|
||||
THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, m_trusted_daemon ? *status : "daemon error");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const
|
||||
{
|
||||
KECCAK_CTX state;
|
||||
keccak_init(&state);
|
||||
keccak_update(&state, (const uint8_t *) transfer.m_txid.data, sizeof(transfer.m_txid.data));
|
||||
keccak_update(&state, (const uint8_t *) transfer.m_internal_output_index, sizeof(transfer.m_internal_output_index));
|
||||
keccak_update(&state, (const uint8_t *) transfer.m_global_output_index, sizeof(transfer.m_global_output_index));
|
||||
keccak_update(&state, (const uint8_t *) transfer.m_amount, sizeof(transfer.m_amount));
|
||||
keccak_finish(&state, (uint8_t *) hash.data);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(transfer_height > (int64_t)m_transfers.size(), "Hash height is greater than number of transfers");
|
||||
|
||||
KECCAK_CTX state;
|
||||
crypto::hash tmp_hash{};
|
||||
uint64_t current_height = 0;
|
||||
|
||||
keccak_init(&state);
|
||||
for(const transfer_details & transfer : m_transfers){
|
||||
if (transfer_height >= 0 && current_height >= (uint64_t)transfer_height){
|
||||
break;
|
||||
}
|
||||
|
||||
hash_m_transfer(transfer, tmp_hash);
|
||||
keccak_update(&state, (const uint8_t *) transfer.m_block_height, sizeof(transfer.m_block_height));
|
||||
keccak_update(&state, (const uint8_t *) tmp_hash.data, sizeof(tmp_hash.data));
|
||||
current_height += 1;
|
||||
}
|
||||
|
||||
keccak_finish(&state, (uint8_t *) hash.data);
|
||||
return current_height;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash)
|
||||
{
|
||||
// Compute hash of m_transfers, if differs there had to be BC reorg.
|
||||
crypto::hash new_transfers_hash{};
|
||||
hash_m_transfers((int64_t) transfer_height, new_transfers_hash);
|
||||
|
||||
if (new_transfers_hash != hash)
|
||||
{
|
||||
// Soft-Reset to avoid inconsistency in case of BC reorg.
|
||||
clear_soft(false); // keep_key_images works only with soft reset.
|
||||
THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Transfers changed during rescan, soft or hard rescan is needed");
|
||||
}
|
||||
|
||||
// Restore key images in m_transfers from m_key_images
|
||||
for(auto it = m_key_images.begin(); it != m_key_images.end(); it++)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(it->second >= m_transfers.size(), error::wallet_internal_error, "Key images cache contains illegal transfer offset");
|
||||
m_transfers[it->second].m_key_image = it->first;
|
||||
m_transfers[it->second].m_key_image_known = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user