From 18ec1c331ba22daccc467db4e7011cc33229dbc8 Mon Sep 17 00:00:00 2001 From: akildemir Date: Wed, 14 May 2025 16:02:35 +0300 Subject: [PATCH] make scanning pre-carrot and carrot coinbase txs work --- src/carrot_core/carrot_enote_types.h | 4 ++++ src/carrot_core/payment_proposal.cpp | 3 ++- src/carrot_core/payment_proposal.h | 2 ++ src/carrot_impl/format_utils.cpp | 6 ++++++ src/cryptonote_basic/cryptonote_format_utils.cpp | 6 +++++- src/cryptonote_core/blockchain.cpp | 5 +++-- src/cryptonote_core/cryptonote_tx_utils.cpp | 4 +++- src/hardforks/hardforks.cpp | 3 +++ src/wallet/scanning_tools.cpp | 7 +++++++ src/wallet/scanning_tools.h | 3 +++ src/wallet/wallet2.cpp | 3 +++ 11 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/carrot_core/carrot_enote_types.h b/src/carrot_core/carrot_enote_types.h index 6cfc99b9e..0288cae04 100644 --- a/src/carrot_core/carrot_enote_types.h +++ b/src/carrot_core/carrot_enote_types.h @@ -61,6 +61,8 @@ struct CarrotEnoteV1 final crypto::public_key onetime_address; /// C_a rct::key amount_commitment; + /// asset type + std::string asset_type; /// a_enc encrypted_amount_t amount_enc; /// anchor_enc @@ -92,6 +94,8 @@ struct CarrotCoinbaseEnoteV1 final crypto::public_key onetime_address; /// a rct::xmr_amount amount; + /// asset type + std::string asset_type; /// anchor_enc encrypted_janus_anchor_t anchor_enc; /// view_tag diff --git a/src/carrot_core/payment_proposal.cpp b/src/carrot_core/payment_proposal.cpp index 3bc525709..c30415105 100644 --- a/src/carrot_core/payment_proposal.cpp +++ b/src/carrot_core/payment_proposal.cpp @@ -282,8 +282,9 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal, s_sender_receiver, output_enote_out.onetime_address); - // 6. save the amount and block index + // 6. save the amount and block index and asset type output_enote_out.amount = proposal.amount; + output_enote_out.asset_type = proposal.asset_type; output_enote_out.block_index = block_index; } //------------------------------------------------------------------------------------------------------------------- diff --git a/src/carrot_core/payment_proposal.h b/src/carrot_core/payment_proposal.h index 9bc3afbae..c210b0267 100644 --- a/src/carrot_core/payment_proposal.h +++ b/src/carrot_core/payment_proposal.h @@ -59,6 +59,8 @@ struct CarrotPaymentProposalV1 final CarrotDestinationV1 destination; /// b rct::xmr_amount amount; + /// asset type + std::string asset_type; /// anchor_norm: secret 16-byte randomness for Janus anchor janus_anchor_t randomness; }; diff --git a/src/carrot_impl/format_utils.cpp b/src/carrot_impl/format_utils.cpp index 126ad2479..4abe944aa 100644 --- a/src/carrot_impl/format_utils.cpp +++ b/src/carrot_impl/format_utils.cpp @@ -360,6 +360,7 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( const std::uint64_t block_index = enotes.at(0).block_index; cryptonote::transaction tx; + tx.type = cryptonote::transaction_type::MINER; tx.pruned = false; tx.version = 2; tx.unlock_time = block_index + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; @@ -379,6 +380,7 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( cryptonote::txout_to_carrot_v1{ .key = enote.onetime_address, .view_tag = enote.view_tag, + .asset_type = enote.asset_type, .encrypted_janus_anchor = enote.anchor_enc } }); @@ -411,6 +413,7 @@ cryptonote::transaction make_single_enote_carrot_coinbase_transaction_v1(const C const CarrotPaymentProposalV1 payment_proposal{ .destination = destination, .amount = block_reward, + .asset_type = "SAL1", .randomness = gen_janus_anchor() }; @@ -443,6 +446,9 @@ bool try_load_carrot_coinbase_enote_from_transaction_v1(const cryptonote::transa const cryptonote::txout_to_carrot_v1 * const c = boost::strict_get(&o.target); CHECK_AND_ASSERT_MES(c, false, "try_load_carrot_coinbase_enote_from_transaction_v1: wrong output type"); + // asset type + enote_out.asset_type = c->asset_type; + //K_o enote_out.onetime_address = c->key; diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 3a5ff091b..8f194190f 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1308,6 +1308,8 @@ namespace cryptonote output_asset_type = boost::get< txout_to_key>(out.target).asset_type; else if (out.target.type() == typeid(txout_to_tagged_key)) output_asset_type = boost::get< txout_to_tagged_key >(out.target).asset_type; + else if (out.target.type() == typeid(txout_to_carrot_v1)) + output_asset_type = boost::get(out.target).asset_type; else { LOG_ERROR("Unexpected output target type found: " << out.target.type().name() << " - cannot retrieve output_asset_type"); @@ -1325,6 +1327,8 @@ namespace cryptonote output_unlock_time = boost::get< txout_to_key>(out.target).unlock_time; else if (out.target.type() == typeid(txout_to_tagged_key)) output_unlock_time = boost::get< txout_to_tagged_key >(out.target).unlock_time; + else if (out.target.type() == typeid(txout_to_carrot_v1)) + output_unlock_time = boost::get(out.target).unlock_time; else { LOG_ERROR("Unexpected output target type found: " << out.target.type().name() << " - cannot retrieve output_unlock_time"); @@ -1375,7 +1379,7 @@ namespace cryptonote { if (hf_version >= HF_VERSION_CARROT) { - // from v18, require outputs be carrot outputs + // from v11, require outputs be carrot outputs CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: " << o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx)); } else { diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 2f272130d..4f00e20f4 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1370,7 +1370,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, CHECK_AND_ASSERT_MES(check_output_types(b.miner_tx, hf_version), false, "miner transaction has invalid output type(s) in block " << get_block_hash(b)); - // from carrot or v18, require output pubkeys be sorted in strictly increasing lexicographical order + // from carrot or v11, require output pubkeys be sorted in strictly increasing lexicographical order const bool tx_is_carrot = !b.miner_tx.vout.empty() && b.miner_tx.vout.at(0).target.type() == typeid(txout_to_carrot_v1); const bool should_enforce_sorted_outputs = hf_version > HF_VERSION_CARROT || tx_is_carrot; if (should_enforce_sorted_outputs) { @@ -1504,6 +1504,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl case HF_VERSION_AUDIT2: case HF_VERSION_AUDIT2_PAUSE: case HF_VERSION_TREASURY_SAL1_MINT: + case HF_VERSION_CARROT: if (b.miner_tx.amount_burnt > 0) { CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt"); money_in_use += b.miner_tx.amount_burnt; @@ -3698,7 +3699,7 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio return false; } - // from carrot or v18, require output pubkeys be sorted in strictly increasing lexicographical order + // from carrot or v11, require output pubkeys be sorted in strictly increasing lexicographical order const bool tx_is_carrot = !tx.vout.empty() && tx.vout.at(0).target.type() == typeid(txout_to_carrot_v1); const bool should_enforce_sorted_outputs = hf_version > HF_VERSION_CARROT || tx_is_carrot; if (should_enforce_sorted_outputs) { diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 5eb9c9a4c..c6f8e8720 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -450,7 +450,9 @@ namespace cryptonote miner_address.m_view_public_key, destination); - tx = carrot::make_single_enote_carrot_coinbase_transaction_v1(destination, block_reward, height, extra_nonce); + uint64_t stake_reward = block_reward / 5; + tx = carrot::make_single_enote_carrot_coinbase_transaction_v1(destination, block_reward - stake_reward, height, extra_nonce); + tx.amount_burnt = stake_reward; tx.invalidate_hashes(); } catch (const std::exception &e) diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp index 6b9a57806..c4a7bd33f 100644 --- a/src/hardforks/hardforks.cpp +++ b/src/hardforks/hardforks.cpp @@ -92,6 +92,9 @@ const hardfork_t testnet_hard_forks[] = { // version 10 treasury mint starts from block 1100 {10, 1100, 0, 1739780005 }, + + // version 11 carrot starts from block 1500 + {11, 1500, 0, 1739780010 }, }; const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1); diff --git a/src/wallet/scanning_tools.cpp b/src/wallet/scanning_tools.cpp index 775a9d48b..b8c4bd298 100644 --- a/src/wallet/scanning_tools.cpp +++ b/src/wallet/scanning_tools.cpp @@ -102,6 +102,9 @@ static bool try_load_pre_carrot_enote(const bool is_coinbase, CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(o, enote_out.onetime_address), false, "make_pre_carrot_enote: missing output public key"); + CHECK_AND_ASSERT_MES(cryptonote::get_output_asset_type(o, enote_out.asset_type), + false, + "make_pre_carrot_enote: missing output asset type"); enote_out.view_tag = cryptonote::get_output_view_tag(o); enote_out.local_output_index = local_output_index; @@ -240,6 +243,7 @@ static std::optional view_incoming_scan_pre_car .payment_id = payment_id, .subaddr_index = subaddr_index, .amount = amount, + .asset_type = enote.asset_type, .amount_blinding_factor = amount_blinding_factor, .main_tx_pubkey_index = main_deriv_idx }; @@ -264,6 +268,7 @@ static std::optional view_incoming_scan_carrot_ res.payment_id = crypto::null_hash; res.subaddr_index = carrot::subaddress_index_extended{{0, 0}}; res.amount = enote.amount; + res.asset_type = enote.asset_type; res.amount_blinding_factor = rct::I; res.main_tx_pubkey_index = 0; @@ -309,6 +314,7 @@ static std::optional view_incoming_scan_carrot_ res.subaddr_index.reset(); res.amount_blinding_factor = rct::sk2rct(amount_blinding_factor_sk); res.main_tx_pubkey_index = 0; + res.asset_type = enote.asset_type; return res; } @@ -358,6 +364,7 @@ static std::optional view_incoming_scan_carrot_ res.subaddr_index = subaddr_index; res.amount_blinding_factor = rct::sk2rct(amount_blinding_factor_sk); res.main_tx_pubkey_index = 0; + res.asset_type = enote.asset_type; return res; } diff --git a/src/wallet/scanning_tools.h b/src/wallet/scanning_tools.h index f9066f869..85f36a2c5 100644 --- a/src/wallet/scanning_tools.h +++ b/src/wallet/scanning_tools.h @@ -81,6 +81,9 @@ struct PreCarrotEnote crypto::public_key onetime_address; boost::optional view_tag; + // asset type + std::string asset_type; + std::size_t local_output_index; bool encrypted_amount; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3f6ec43c6..69541af84 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2630,6 +2630,9 @@ void wallet2::process_new_scanned_transaction( output_tracker_cache[std::make_pair(tx.vout.at(td.m_internal_output_index).amount, td.m_global_output_index)] = m_transfers.size() - 1; + // update m_transfer_indices + m_transfers_indices[enote_scan_info->asset_type].insert(m_transfers.size()-1); + // update multisig info if (m_multisig) {