post-carrot tx scanning bug fixes

This commit is contained in:
akildemir
2025-06-20 11:40:46 +03:00
parent e235199ff3
commit ae02dcbe9a
6 changed files with 63 additions and 31 deletions

View File

@@ -308,12 +308,18 @@ crypto::secret_key carrot_and_legacy_account::generate(
}
//----------------------------------------------------------------------------------------------------------------------
void carrot_and_legacy_account::set_carrot_keys()
{
{
// top level keys
m_keys.s_master = m_keys.m_spend_secret_key;
make_carrot_provespend_key(m_keys.s_master, m_keys.k_prove_spend);
make_carrot_viewbalance_secret(m_keys.s_master, m_keys.s_view_balance);
// view balance keys
make_carrot_viewincoming_key(m_keys.s_view_balance, m_keys.k_view_incoming);
make_carrot_generateimage_key(m_keys.s_view_balance, m_keys.k_generate_image);
make_carrot_generateaddress_secret(m_keys.s_view_balance, m_keys.s_generate_address);
// carrot account address
make_carrot_spend_pubkey(m_keys.k_generate_image, m_keys.k_prove_spend, m_keys.m_carrot_account_address.m_spend_public_key);
k_view_incoming_dev.view_key_scalar_mult_ed25519(
m_keys.m_carrot_account_address.m_spend_public_key,

View File

@@ -53,7 +53,7 @@ namespace carrot
std::unordered_map<crypto::public_key, subaddress_index_extended> subaddress_map;
AddressDeriveType default_derive_type;
carrot_and_legacy_account(): k_view_incoming_dev(get_keys().m_view_secret_key),
carrot_and_legacy_account(): k_view_incoming_dev(get_keys().k_view_incoming),
s_view_balance_dev(get_keys().s_view_balance),
s_generate_address_dev(get_keys().s_generate_address)
{}

View File

@@ -59,10 +59,10 @@ static void store_carrot_ephemeral_pubkeys_to_extra(const EnoteContainer &enotes
if (nouts == 0)
return;
const bool use_shared_ephemeral_pubkey = nouts == 2 && 0 == memcmp(
const bool use_shared_ephemeral_pubkey = nouts == 1 || (nouts == 2 && 0 == memcmp(
&enotes.front().enote_ephemeral_pubkey,
&enotes.back().enote_ephemeral_pubkey,
sizeof(mx25519_pubkey));
sizeof(mx25519_pubkey)));
bool success = true;
if (use_shared_ephemeral_pubkey)
{

View File

@@ -57,6 +57,7 @@ namespace cryptonote
crypto::secret_key s_master;
crypto::secret_key k_prove_spend;
crypto::secret_key s_view_balance;
crypto::secret_key k_view_incoming;
crypto::secret_key k_generate_image;
crypto::secret_key s_generate_address;

View File

@@ -727,7 +727,7 @@ void view_incoming_scan_transaction(
//! @TODO: HW device
const bool is_carrot = carrot::is_carrot_transaction_v1(tx);
carrot::view_incoming_key_ram_borrowed_device k_view_dev(
is_carrot ? acc.s_view_balance : acc.m_view_secret_key
is_carrot ? acc.k_view_incoming : acc.m_view_secret_key
);
// do view-incoming scan for each output enotes
@@ -775,7 +775,7 @@ void view_incoming_scan_transaction(
const bool is_carrot = carrot::is_carrot_transaction_v1(tx);
perform_ecdh_derivations(epee::to_span(main_tx_ephemeral_pubkeys),
epee::to_span(additional_tx_ephemeral_pubkeys),
is_carrot ? acc.s_view_balance : acc.m_view_secret_key,
is_carrot ? acc.k_view_incoming : acc.m_view_secret_key,
acc.get_device(),
is_carrot,
main_derivations,
@@ -799,8 +799,13 @@ std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_t
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
tools::keystore &subaddress_keystore)
{
std::vector<std::optional<enote_view_incoming_scan_info_t>> res(tx.vout.size());
view_incoming_scan_transaction(tx, acc, subaddress_keystore, epee::to_mut_span(res));
const auto n_outputs = tx.vout.size();
std::vector<std::optional<enote_view_incoming_scan_info_t>> res(n_outputs);
if (n_outputs > 0)
{
view_incoming_scan_transaction(tx, acc, subaddress_keystore, epee::to_mut_span(res));
}
return res;
}
//-------------------------------------------------------------------------------------------------------------------

View File

@@ -3480,12 +3480,19 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const std::vect
auto tx_scan_job = [this, &enote_scan_infos, &output_key_images, &password_failure, &keystore]
(const cryptonote::transaction &tx, size_t tx_output_idx)
{
if (tx.vout.empty())
{
MWARNING("Skipping tx without any outputs: " << get_transaction_hash(tx) << ", height: " << m_blockchain.size());
return;
}
const size_t output_span_end = tx_output_idx + tx.vout.size();
if (output_span_end > enote_scan_infos.size() || output_span_end > output_key_images.size())
{
LOG_ERROR("BUG: tx scan worker output index out of bounds, skipping...");
return;
}
wallet::view_incoming_scan_transaction(tx,
this->m_account.get_keys(),
keystore,
@@ -3505,31 +3512,44 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const std::vect
size_t i = 0;
size_t tx_output_idx = 0;
while (i < blocks.size()) {
tools::threadpool::waiter scan_blocks_waiter(tpool);
for (size_t j = 0; j < 10; ++j)
const parsed_block &par_blk = parsed_blocks.at(i);
const std::uint64_t height = start_height + i;
const bool skip_scan_for_this_block = should_skip_block(par_blk.block, height);
if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
tx_scan_job(par_blk.block.miner_tx, tx_output_idx);
tx_output_idx += par_blk.block.miner_tx.vout.size();
if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
tx_scan_job(par_blk.block.protocol_tx, tx_output_idx);
tx_output_idx += par_blk.block.protocol_tx.vout.size();
for (const cryptonote::transaction &tx : par_blk.txes)
{
const parsed_block &par_blk = parsed_blocks.at(i);
const std::uint64_t height = start_height + i;
const bool skip_scan_for_this_block = should_skip_block(par_blk.block, height);
if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(par_blk.block.miner_tx), tx_output_idx));
tx_output_idx += par_blk.block.miner_tx.vout.size();
if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(par_blk.block.protocol_tx), tx_output_idx));
tx_output_idx += par_blk.block.protocol_tx.vout.size();
for (const cryptonote::transaction &tx : par_blk.txes)
{
if (!skip_scan_for_this_block)
tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(tx), tx_output_idx));
tx_output_idx += tx.vout.size();
}
if (++i >= blocks.size()) break;
}
if (!scan_blocks_waiter.wait())
{
THROW_WALLET_EXCEPTION_IF(password_failure, error::password_needed);
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Unrecognized exception in enote scanning threadpool");
if (!skip_scan_for_this_block)
tx_scan_job(tx, tx_output_idx);
tx_output_idx += tx.vout.size();
}
// tools::threadpool::waiter scan_blocks_waiter(tpool);
// for (size_t j = 0; j < 10; ++j)
// {
// if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
// tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(par_blk.block.miner_tx), tx_output_idx));
// tx_output_idx += par_blk.block.miner_tx.vout.size();
// if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
// tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(par_blk.block.protocol_tx), tx_output_idx));
// tx_output_idx += par_blk.block.protocol_tx.vout.size();
// for (const cryptonote::transaction &tx : par_blk.txes)
// {
// if (!skip_scan_for_this_block)
// tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(tx), tx_output_idx));
// tx_output_idx += tx.vout.size();
// }
// if (++i >= blocks.size()) break;
// }
// if (!scan_blocks_waiter.wait())
// {
// THROW_WALLET_EXCEPTION_IF(password_failure, error::password_needed);
// THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Unrecognized exception in enote scanning threadpool");
// }
i++;
}
// Start processing blockchain entries with scanned outputs