|
|
|
@ -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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|