diff --git a/src/carrot_core/output_set_finalization.cpp b/src/carrot_core/output_set_finalization.cpp index 64bcc3378..f9a051f5a 100644 --- a/src/carrot_core/output_set_finalization.cpp +++ b/src/carrot_core/output_set_finalization.cpp @@ -160,8 +160,8 @@ void get_output_enote_proposals(const std::vector &norm const crypto::key_image &tx_first_key_image, std::vector &output_enote_proposals_out, encrypted_payment_id_t &encrypted_payment_id_out, - std::vector> *payment_proposal_order_out, - size_t change_index_out) + size_t &change_index_out, + std::vector> *payment_proposal_order_out) { output_enote_proposals_out.clear(); encrypted_payment_id_out = {{0}}; diff --git a/src/carrot_core/output_set_finalization.h b/src/carrot_core/output_set_finalization.h index 1d8d65d8d..d9bb54d03 100644 --- a/src/carrot_core/output_set_finalization.h +++ b/src/carrot_core/output_set_finalization.h @@ -110,8 +110,8 @@ void get_output_enote_proposals(const std::vector &norm const crypto::key_image &tx_first_key_image, std::vector &output_enote_proposals_out, encrypted_payment_id_t &encrypted_payment_id_out, - std::vector> *payment_proposal_order_out = nullptr, - size_t change_index_out = 0); + size_t &change_index_out, + std::vector> *payment_proposal_order_out = nullptr); /** * brief: get_coinbase_output_enotes - convert a *finalized* set of payment proposals into coinbase output enotes * param: normal_payment_proposals - diff --git a/src/carrot_core/payment_proposal.cpp b/src/carrot_core/payment_proposal.cpp index 3092a0129..3f34a8ce8 100644 --- a/src/carrot_core/payment_proposal.cpp +++ b/src/carrot_core/payment_proposal.cpp @@ -332,6 +332,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal, // 6. save the amount and first key image output_enote_out.amount = proposal.amount; + output_enote_out.enote.asset_type = proposal.asset_type; output_enote_out.enote.tx_first_key_image = tx_first_key_image; } //------------------------------------------------------------------------------------------------------------------- @@ -399,6 +400,7 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo // 8. save the enote ephemeral pubkey, first tx key image, and amount output_enote_out.enote.enote_ephemeral_pubkey = enote_ephemeral_pubkey; output_enote_out.enote.tx_first_key_image = tx_first_key_image; + output_enote_out.enote.asset_type = "SAL1"; output_enote_out.amount = proposal.amount; } //------------------------------------------------------------------------------------------------------------------- @@ -526,6 +528,7 @@ void get_output_proposal_internal_v1(const CarrotPaymentProposalSelfSendV1 &prop // 9. save the enote ephemeral pubkey, first tx key image, and amount output_enote_out.enote.enote_ephemeral_pubkey = enote_ephemeral_pubkey; output_enote_out.enote.tx_first_key_image = tx_first_key_image; + output_enote_out.enote.asset_type = "SAL1"; output_enote_out.amount = proposal.amount; } //------------------------------------------------------------------------------------------------------------------- diff --git a/src/carrot_impl/format_utils.cpp b/src/carrot_impl/format_utils.cpp index f2276b808..091ef163d 100644 --- a/src/carrot_impl/format_utils.cpp +++ b/src/carrot_impl/format_utils.cpp @@ -35,6 +35,7 @@ #include "carrot_core/payment_proposal.h" #include "common/container_helpers.h" #include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_tx_utils.h" #include "cryptonote_config.h" //third party headers @@ -55,6 +56,9 @@ template static void store_carrot_ephemeral_pubkeys_to_extra(const EnoteContainer &enotes, std::vector &extra_inout) { const size_t nouts = enotes.size(); + if (nouts == 0) + return; + const bool use_shared_ephemeral_pubkey = nouts == 2 && 0 == memcmp( &enotes.front().enote_ephemeral_pubkey, &enotes.back().enote_ephemeral_pubkey, @@ -189,11 +193,13 @@ bool try_load_carrot_extra_v1( //------------------------------------------------------------------------------------------------------------------- cryptonote::transaction store_carrot_to_transaction_v1(const std::vector &enotes, const std::vector &key_images, + const std::vector &sources, const rct::xmr_amount fee, const encrypted_payment_id_t encrypted_payment_id) { const size_t nins = key_images.size(); const size_t nouts = enotes.size(); + CHECK_AND_ASSERT_THROW_MES(nins == sources.size(), "invalid inputs/sources size"); cryptonote::transaction tx; tx.pruned = true; @@ -208,13 +214,19 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector key_offsets; + for(const auto &out_entry: sources[i].outputs) + key_offsets.push_back(out_entry.first); + //L tx.vin.emplace_back(cryptonote::txin_to_key{ //@TODO: can save 2 bytes by using slim input type .amount = 0, - .key_offsets = {}, - .k_image = ki + .key_offsets = cryptonote::absolute_output_offsets_to_relative(key_offsets), + .k_image = key_images.at(i), + .asset_type = "SAL1" }); } @@ -225,7 +237,8 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector &enotes, const cryptonote::blobdata &extra_nonce, - const cryptonote::transaction_type &tx_type) + const cryptonote::transaction_type &tx_type, + const std::uint64_t block_index) { CARROT_CHECK_AND_THROW(tx_type == cryptonote::transaction_type::MINER || tx_type == cryptonote::transaction_type::PROTOCOL, invalid_tx_type, "invalid tx_type : is not MINER or PROTOCOL"); const size_t nouts = enotes.size(); - const std::uint64_t block_index = enotes.at(0).block_index; cryptonote::transaction tx; tx.type = tx_type; @@ -425,7 +438,7 @@ cryptonote::transaction make_single_enote_carrot_coinbase_transaction_v1(const C std::vector enotes(1); get_coinbase_output_proposal_v1(payment_proposal, block_index, enotes.front()); - return store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER); + return store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, block_index); } //------------------------------------------------------------------------------------------------------------------- bool try_load_carrot_coinbase_enote_from_transaction_v1(const cryptonote::transaction &tx, diff --git a/src/carrot_impl/format_utils.h b/src/carrot_impl/format_utils.h index e4bbf47c9..3d923ff4f 100644 --- a/src/carrot_impl/format_utils.h +++ b/src/carrot_impl/format_utils.h @@ -34,6 +34,7 @@ #include "cryptonote_basic/blobdatatype.h" #include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/tx_extra.h" +#include "cryptonote_core/cryptonote_tx_utils.h" //third party headers @@ -101,6 +102,7 @@ bool try_load_carrot_extra_v1( */ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector &enotes, const std::vector &key_images, + const std::vector &sources, const rct::xmr_amount fee, const encrypted_payment_id_t encrypted_payment_id); /** @@ -133,12 +135,14 @@ bool try_load_carrot_from_transaction_v1(const cryptonote::transaction &tx, * brief: store_carrot_to_coinbase_transaction_v1 - store coinbase Carrot info to a cryptonote::transaction * param: enotes - * param: extra_nonce - + * param: block_index - * return: a full coinbase transaction containing given Carrot information */ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( const std::vector &enotes, const cryptonote::blobdata &extra_nonce, - const cryptonote::transaction_type &tx_type); + const cryptonote::transaction_type &tx_type, + const std::uint64_t block_index); /** * brief: make_single_enote_carrot_coinbase_transaction_v1 - store one coinbase Carrot enote to a cryptonote::transaction * param: destination - diff --git a/src/carrot_impl/tx_builder_outputs.cpp b/src/carrot_impl/tx_builder_outputs.cpp index 52c957b54..e4b958906 100644 --- a/src/carrot_impl/tx_builder_outputs.cpp +++ b/src/carrot_impl/tx_builder_outputs.cpp @@ -59,6 +59,7 @@ void get_output_enote_proposals_from_proposal_v1(const CarrotTransactionProposal selfsend_payment_proposal_cores.push_back(selfsend_payment_proposal.proposal); // derive enote proposals + size_t change_index; get_output_enote_proposals(tx_proposal.normal_payment_proposals, selfsend_payment_proposal_cores, tx_proposal.dummy_encrypted_payment_id, @@ -67,6 +68,7 @@ void get_output_enote_proposals_from_proposal_v1(const CarrotTransactionProposal tx_proposal.key_images_sorted.at(0), output_enote_proposals_out, encrypted_payment_id_out, + change_index, payment_proposal_order_out); } //------------------------------------------------------------------------------------------------------------------- @@ -119,6 +121,7 @@ void make_pruned_transaction_from_proposal_v1(const CarrotTransactionProposalV1 // serialize tx pruned_tx_out = store_carrot_to_transaction_v1(enotes, tx_proposal.key_images_sorted, + tx_proposal.sources, tx_proposal.fee, encrypted_payment_id); diff --git a/src/carrot_impl/tx_proposal.h b/src/carrot_impl/tx_proposal.h index b59bcfe6b..1418dce15 100644 --- a/src/carrot_impl/tx_proposal.h +++ b/src/carrot_impl/tx_proposal.h @@ -31,6 +31,7 @@ //local headers #include "carrot_core/payment_proposal.h" #include "subaddress_index.h" +#include "cryptonote_core/cryptonote_tx_utils.h" //third party headers @@ -70,6 +71,8 @@ struct CarrotTransactionProposalV1 { /// Key images sorted in std::greater order std::vector key_images_sorted; + // sources in the same order as key_images_sorted. + std::vector sources; /// Payment proposals to be converted into output enotes std::vector normal_payment_proposals; diff --git a/src/carrot_impl/tx_proposal_utils.cpp b/src/carrot_impl/tx_proposal_utils.cpp index 9bd3f54c1..9415a8690 100644 --- a/src/carrot_impl/tx_proposal_utils.cpp +++ b/src/carrot_impl/tx_proposal_utils.cpp @@ -115,6 +115,7 @@ std::uint64_t get_carrot_default_tx_extra_size(const std::size_t n_outputs) void make_carrot_transaction_proposal_v1(const std::vector &normal_payment_proposals_in, const std::vector &selfsend_payment_proposals_in, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, select_inputs_func_t &&select_inputs, carve_fees_and_balance_func_t &&carve_fees_and_balance, @@ -172,13 +173,7 @@ void make_carrot_transaction_proposal_v1(const std::vector fee_per_input_count; for (size_t num_ins = CARROT_MIN_TX_INPUTS; num_ins <= CARROT_MAX_TX_INPUTS; ++num_ins) { - const uint64_t tx_weight = get_fcmppp_tx_weight(num_ins, num_outs, tx_extra_size); - CHECK_AND_ASSERT_THROW_MES(tx_weight != std::numeric_limits::max(), - "make_carrot_transaction_proposal_v1: invalid weight returned for ins=" << num_ins - << " outs=" << num_outs << " extra_size=" << tx_extra_size); - CHECK_AND_ASSERT_THROW_MES(std::numeric_limits::max() / tx_weight > fee_per_weight, - "make_carrot_transaction_proposal_v1: overflow in fee calculation"); - const rct::xmr_amount fee = tx_weight * fee_per_weight; + const rct::xmr_amount fee = estimate_fee_carrot(num_ins, 15, num_outs, tx_extra_size, true, true, true, true, fee_per_weight, fee_quantization_mask); fee_per_input_count.emplace(num_ins, fee); } @@ -237,6 +232,7 @@ void make_carrot_transaction_proposal_v1_transfer( const std::vector &normal_payment_proposals, const std::vector &selfsend_payment_proposals_in, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, select_inputs_func_t &&select_inputs, const crypto::public_key &change_address_spend_pubkey, @@ -387,6 +383,7 @@ void make_carrot_transaction_proposal_v1_transfer( make_carrot_transaction_proposal_v1(normal_payment_proposals, selfsend_payment_proposals, fee_per_weight, + fee_quantization_mask, extra, std::forward(select_inputs), std::move(carve_fees_and_balance), @@ -399,6 +396,7 @@ void make_carrot_transaction_proposal_v1_sweep( const std::vector &normal_payment_proposals, const std::vector &selfsend_payment_proposals, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, std::vector &&selected_inputs, const crypto::public_key &change_address_spend_pubkey, @@ -477,6 +475,7 @@ void make_carrot_transaction_proposal_v1_sweep( make_carrot_transaction_proposal_v1(normal_payment_proposals, selfsend_payment_proposals, fee_per_weight, + fee_quantization_mask, extra, std::move(select_inputs), std::move(carve_fees_and_balance), diff --git a/src/carrot_impl/tx_proposal_utils.h b/src/carrot_impl/tx_proposal_utils.h index 76382dfc4..72dbd155a 100644 --- a/src/carrot_impl/tx_proposal_utils.h +++ b/src/carrot_impl/tx_proposal_utils.h @@ -82,9 +82,110 @@ static inline std::size_t get_fcmppp_tx_weight(const std::size_t num_inputs, return 200 + num_inputs * 1000 + num_outputs * 100 + tx_extra_size; } +static size_t estimate_rct_tx_size_carrot(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags) +{ + size_t size = 0; + + // tx prefix + + // first few bytes + size += 1 + 6; + + // vin + size += n_inputs * (1+6+4+(mixin+1)*2+32); + + // vout + size += n_outputs * (3+4+16+32); + + // extra + size += extra_size; + + // rct signatures + + // type + size += 1; + + // rangeSigs + if (bulletproof || bulletproof_plus) + { + size_t log_padded_outputs = 0; + while ((1< 2) + { + const uint64_t bp_base = (32 * ((bulletproof_plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2) + size_t log_padded_outputs = 2; + while ((1< &normal_payment_proposals, const std::vector &selfsend_payment_proposals, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, select_inputs_func_t &&select_inputs, carve_fees_and_balance_func_t &&carve_fees_and_balance, @@ -96,6 +197,7 @@ void make_carrot_transaction_proposal_v1_transfer( const std::vector &normal_payment_proposals, const std::vector &selfsend_payment_proposals, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, select_inputs_func_t &&select_inputs, const crypto::public_key &change_address_spend_pubkey, @@ -108,6 +210,7 @@ void make_carrot_transaction_proposal_v1_sweep( const std::vector &normal_payment_proposals, const std::vector &selfsend_payment_proposals, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, std::vector &&selected_inputs, const crypto::public_key &change_address_spend_pubkey, diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 3d8db51ce..13ae5b19e 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -110,7 +110,11 @@ namespace cryptonote uint64_t get_transaction_weight_clawback(const transaction &tx, size_t n_padded_outputs) { const rct::rctSig &rv = tx.rct_signatures; - const bool plus = (rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs); + const bool plus = ( + rv.type == rct::RCTTypeBulletproofPlus || + rv.type == rct::RCTTypeFullProofs || + rv.type == rct::RCTTypeSalviumZero || + rv.type == rct::RCTTypeSalviumOne); const uint64_t bp_base = (32 * ((plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2) const size_t n_outputs = tx.vout.size(); if (n_padded_outputs <= 2) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 489c3fb36..1d26853c2 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3789,7 +3789,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr } } } - else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne) + else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumZero) { if (!tx.pruned) { @@ -3799,6 +3799,17 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr rv.p.CLSAGs[n].I = rct::ki2rct(boost::get(tx.vin[n]).k_image); } } + } + else if (rv.type == rct::RCTTypeSalviumOne) + { + if (!tx.pruned) + { + CHECK_AND_ASSERT_MES(rv.p.TCLSAGs.size() == tx.vin.size(), false, "Bad TCLSAGs size"); + for (size_t n = 0; n < tx.vin.size(); ++n) + { + rv.p.TCLSAGs[n].I = rct::ki2rct(boost::get(tx.vin[n]).k_image); + } + } } else { diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 1563616de..980facc3e 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -411,10 +411,12 @@ namespace cryptonote }; // Build the proposal - get_coinbase_output_proposal_v1(payment_proposal, height, enotes.back()); + carrot::CarrotCoinbaseEnoteV1 e; + get_coinbase_output_proposal_v1(payment_proposal, height, e); + enotes.push_back(e); } - - tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL); + + tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL, height); tx.amount_burnt = 0; tx.invalidate_hashes(); } diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 2becba67c..e782a4a45 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -90,11 +90,13 @@ namespace cryptonote uint64_t amount; //money bool rct; //true if the output is rct bool carrot; //true if the output is a carrot output + bool coinbase; //true if the output is a coinbase output rct::key mask; //ringct amount mask rct::multisig_kLRki multisig_kLRki; //multisig info std::string asset_type; crypto::key_image first_rct_key_image; crypto::public_key address_spend_pubkey; // the spend public key of the address that this source is for. + uint64_t block_index; origin_data origin_tx_data; void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); } diff --git a/src/cryptonote_core/tx_verification_utils.cpp b/src/cryptonote_core/tx_verification_utils.cpp index c6ccb9064..15c54b08e 100644 --- a/src/cryptonote_core/tx_verification_utils.cpp +++ b/src/cryptonote_core/tx_verification_utils.cpp @@ -59,7 +59,10 @@ static bool expand_tx_and_ver_rct_non_sem(transaction& tx, const rct::ctkeyM& mi VER_ASSERT(rv.mixRing == mix_ring, "Failed to check ringct signatures: mismatched pubkeys/mixRing"); // Check CLSAG/MLSAG size against transaction input - const size_t n_sigs = rct::is_rct_clsag(rv.type) ? rv.p.CLSAGs.size() : rv.p.MGs.size(); + const size_t n_sigs = rct::is_rct_tclsag(rv.type) ? rv.p.TCLSAGs.size() : + ( + rct::is_rct_clsag(rv.type) ? rv.p.CLSAGs.size() : rv.p.MGs.size() + ); VER_ASSERT(n_sigs == tx.vin.size(), "Failed to check ringct signatures: mismatched input sigs/vin sizes"); // For each input, check that the key images were copied into the expanded RCT sig correctly @@ -67,7 +70,12 @@ static bool expand_tx_and_ver_rct_non_sem(transaction& tx, const rct::ctkeyM& mi { const crypto::key_image& nth_vin_image = boost::get(tx.vin[n]).k_image; - if (rct::is_rct_clsag(rv.type)) + if (rct::is_rct_tclsag(rv.type)) + { + const bool ki_match = 0 == memcmp(&nth_vin_image, &rv.p.TCLSAGs[n].I, 32); + VER_ASSERT(ki_match, "Failed to check ringct signatures: mismatched TCLSAG key image"); + } + else if (rct::is_rct_clsag(rv.type)) { const bool ki_match = 0 == memcmp(&nth_vin_image, &rv.p.CLSAGs[n].I, 32); VER_ASSERT(ki_match, "Failed to check ringct signatures: mismatched CLSAG key image"); diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index b14b47e3b..866d8b80e 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -1507,26 +1507,26 @@ namespace rct { //RCT simple //for post-rct only - rctSig genRctSimpleCarrot( - const key &message, - const carrot_ctkeyV & inSk, - const keyV & destinations, - const cryptonote::transaction_type tx_type, - const std::string& in_asset_type, - const std::vector & destination_asset_types, - const std::vector & inamounts, - const std::vector & outamounts, - xmr_amount txnFee, - const ctkeyM & mixRing, - const std::vector & index, - const ctkeyV &outSk, - const RCTConfig &rct_config, - hw::device &hwdev, - const rct::salvium_data_t &salvium_data, - const key &x_change, - const key &y_change, - const size_t change_index - ) + void genRctSimpleCarrot( + const key &message, + const carrot_ctkeyV & inSk, + const keyV & destinations, + const cryptonote::transaction_type tx_type, + const std::string& in_asset_type, + const std::vector & destination_asset_types, + const std::vector & inamounts, + const std::vector & outamounts, + xmr_amount txnFee, + const ctkeyM & mixRing, + const std::vector & index, + const ctkeyV &outSk, + const RCTConfig &rct_config, + hw::device &hwdev, + const rct::salvium_data_t &salvium_data, + const key &x_change, + const key &y_change, + const size_t change_index, + rctSig &rv) { CHECK_AND_ASSERT_THROW_MES(rct_config.range_proof_type == RangeProofPaddedBulletproof, "Borromean range proofs no longer supported"); CHECK_AND_ASSERT_THROW_MES(destination_asset_types.size() == destinations.size(), "Different number of amount_keys/destinations"); @@ -1539,7 +1539,6 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing"); } - rctSig rv; switch (rct_config.bp_version) { case 0: @@ -1615,8 +1614,6 @@ namespace rct { else rv.p.TCLSAGs[i] = proveRctTCLSAGSimple(full_message, rv.mixRing[i], inSk[i].x, inSk[i].y, inSk[i].mask, a[i], pseudoOuts[i], index[i], hwdev); } - - return rv; } //RCT simple @@ -2126,7 +2123,7 @@ namespace rct { const keyV &pseudoOuts = bulletproof || bulletproof_plus ? rv.p.pseudoOuts : rv.pseudoOuts; const key message = get_pre_mlsag_hash(rv, hw::get_device("default")); - + results.clear(); results.resize(rv.mixRing.size()); for (size_t i = 0 ; i < rv.mixRing.size() ; i++) { diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index 930a58de8..81253f9bf 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -138,7 +138,7 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev); rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector & amounts, const keyV &amount_keys, const int mixin, const RCTConfig &rct_config, hw::device &hwdev); - rctSig genRctSimpleCarrot( + void genRctSimpleCarrot( const key &message, const carrot_ctkeyV & inSk, const keyV & destinations, @@ -156,7 +156,8 @@ namespace rct { const rct::salvium_data_t &salvium_data, const key &x_change, const key &y_change, - const size_t change_index + const size_t change_index, + rctSig &rv ); rctSig genRctSimple( const key & message, diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 314dd27b5..4d1fd043e 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -483,7 +483,7 @@ namespace rct { } ar.end_array(); FIELD(p_r) - if (type == RCTTypeSalviumZero) + if (type == RCTTypeSalviumZero || type == RCTTypeSalviumOne) { FIELD(salvium_data) } @@ -597,11 +597,11 @@ namespace rct { ar.end_array(); ar.tag("c1"); - FIELDS(CLSAGs[i].c1) + FIELDS(TCLSAGs[i].c1) // CLSAGs[i].I not saved, it can be reconstructed ar.tag("D"); - FIELDS(CLSAGs[i].D) + FIELDS(TCLSAGs[i].D) ar.end_object(); if (inputs - i > 1) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 8ef65f813..0bd631eeb 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -7326,8 +7326,8 @@ bool simple_wallet::transfer_main( float days = locked_blocks / 720.0f; prompt << boost::format(tr(".\nThis transaction (including %s change) will unlock in %llu blocks, approximately %s days (assuming 2 minutes per block)")) % cryptonote::print_money(change) % ((unsigned long long)unlock_block) % days; } - if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members())) - return false; + // if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members())) + // return false; bool default_ring_size = true; for (const auto &ptx: ptx_vector) { diff --git a/src/wallet/tx_builder.cpp b/src/wallet/tx_builder.cpp index 1aeb047be..dae128482 100644 --- a/src/wallet/tx_builder.cpp +++ b/src/wallet/tx_builder.cpp @@ -128,7 +128,8 @@ static bool build_payment_proposals(std::vector normal_payment_proposals_inout.push_back(carrot::CarrotPaymentProposalV1{ .destination = dest, .amount = tx_dest_entry.amount, - .randomness = carrot::gen_janus_anchor() + .randomness = carrot::gen_janus_anchor(), + .asset_type = tx_dest_entry.asset_type }); } @@ -293,20 +294,120 @@ carrot::select_inputs_func_t make_wallet2_single_transfer_input_selector( }; } //------------------------------------------------------------------------------------------------------------------- -std::vector make_carrot_transaction_proposals_wallet2_transfer( +std::vector get_sources( const wallet2::transfer_container &transfers, - const std::unordered_map &subaddress_map, + const std::vector &selected_transfers, + const std::string &source_asset, + wallet2 &w +) { + // get decoys + const size_t fake_outputs_count = 15; + std::vector> outs; + std::unordered_set valid_public_keys_cache; + w.get_outs(outs, selected_transfers, fake_outputs_count, true, valid_public_keys_cache); // may throw + + LOG_PRINT_L2("preparing outputs"); + size_t i = 0, out_index = 0; + std::vector sources; + for(size_t idx: selected_transfers) + { + sources.resize(sources.size()+1); + cryptonote::tx_source_entry& src = sources.back(); + const wallet2::transfer_details& td = transfers[idx]; + + // Sanity check the asset_type for this TD is correct + THROW_WALLET_EXCEPTION_IF(td.asset_type != source_asset, error::wallet_internal_error, "Input has wrong asset_type - expected " + source_asset + " but found " + td.asset_type); + + src.amount = td.amount(); + src.rct = td.is_rct(); + src.carrot = td.is_carrot(); + src.coinbase = td.m_tx.vin[0].type() == typeid(cryptonote::txin_gen); + src.block_index = td.m_block_height; + src.asset_type = td.asset_type; + + // Create the origin TX data + if (td.m_td_origin_idx != (uint64_t)-1) { + THROW_WALLET_EXCEPTION_IF(td.m_td_origin_idx >= w.get_num_transfer_details(), error::wallet_internal_error, "cannot locate return_payment origin index in m_transfers"); + const wallet2::transfer_details& td_origin = w.get_transfer_details(td.m_td_origin_idx); + src.origin_tx_data.tx_type = td_origin.m_tx.type; + src.origin_tx_data.tx_pub_key = cryptonote::get_tx_pub_key_from_extra(td_origin.m_tx); + src.origin_tx_data.output_index = td_origin.m_internal_output_index; + } + + //paste mixin transaction + + THROW_WALLET_EXCEPTION_IF(outs.size() < out_index + 1 , error::wallet_internal_error, "outs.size() < out_index + 1"); + THROW_WALLET_EXCEPTION_IF(outs[out_index].size() < fake_outputs_count , error::wallet_internal_error, "fake_outputs_count > random outputs found"); + + typedef cryptonote::tx_source_entry::output_entry tx_output_entry; + for (size_t n = 0; n < fake_outputs_count + 1; ++n) + { + tx_output_entry oe; + oe.first = std::get<0>(outs[out_index][n]); + oe.second.dest = rct::pk2rct(std::get<1>(outs[out_index][n])); + oe.second.mask = std::get<2>(outs[out_index][n]); + src.outputs.push_back(oe); + } + ++i; + + //paste real transaction to the random index + auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) + { + // HERE BE DRAGONS!!! + // SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING + //return a.first == td.m_global_output_index; + return a.first == td.m_asset_type_output_index; + // LAND AHOY!!! + }); + THROW_WALLET_EXCEPTION_IF(it_to_replace == src.outputs.end(), error::wallet_internal_error, + "real output not found"); + + tx_output_entry real_oe; + // HERE BE DRAGONS!!! + // SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING + //real_oe.first = td.m_global_output_index; + real_oe.first = td.m_asset_type_output_index; + // LAND AHOY!!! + real_oe.second.dest = rct::pk2rct(td.get_public_key()); + real_oe.second.mask = rct::commit(td.amount(), td.m_mask); + *it_to_replace = real_oe; + src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index); + src.real_out_additional_tx_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); + src.real_output = it_to_replace - src.outputs.begin(); + src.real_output_in_tx_index = td.m_internal_output_index; + src.mask = td.m_mask; + src.address_spend_pubkey = td.m_recovered_spend_pubkey; + if (td.m_tx.vin[0].type() == typeid(cryptonote::txin_to_key)) { + src.first_rct_key_image = boost::get(td.m_tx.vin[0]).k_image; + } + + if (false) // w.m_multisig // TODO: + // note: multisig_kLRki is a legacy struct, currently only used as a key image shuttle into the multisig tx builder + src.multisig_kLRki = {.k = {}, .L = {}, .R = {}, .ki = rct::ki2rct(td.m_key_image)}; + else + src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()}); + detail::print_source_entry(src); + ++out_index; + } + LOG_PRINT_L2("outputs prepared"); + + return sources; +} +//------------------------------------------------------------------------------------------------------------------- +std::vector make_carrot_transaction_proposals_wallet2_transfer( + wallet2 &w, std::vector dsts, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, - const std::uint32_t subaddr_account, + const uint32_t subaddr_account, const std::set &subaddr_indices, - const rct::xmr_amount ignore_above, - const rct::xmr_amount ignore_below, wallet2::unique_index_container subtract_fee_from_outputs, const std::uint64_t top_block_index) { - wallet2::transfer_container unused_transfers(transfers); + wallet2::transfer_container unused_transfers; + w.get_transfers(unused_transfers); + const auto subaddress_map = w.get_subaddress_map_ref(); std::vector tx_proposals; tx_proposals.reserve(dsts.size() / (FCMP_PLUS_PLUS_MAX_OUTPUTS - 1) + 1); @@ -346,8 +447,8 @@ std::vector make_carrot_transaction_proposa unused_transfers, subaddr_account, subaddr_indices, - ignore_above, - ignore_below, + w.ignore_outputs_above(), + w.ignore_outputs_below(), top_block_index, /*allow_carrot_external_inputs_in_normal_transfers=*/true, /*allow_pre_carrot_inputs_in_normal_transfers=*/true, @@ -359,6 +460,7 @@ std::vector make_carrot_transaction_proposa normal_payment_proposals, selfsend_payment_proposals, fee_per_weight, + fee_quantization_mask, extra, std::move(select_inputs), change_address_spend_pubkey, @@ -366,6 +468,13 @@ std::vector make_carrot_transaction_proposa subtractable_normal_payment_proposals, subtractable_selfsend_payment_proposals, tx_proposal); + + // populate the sources + std::vector selected_transfer_indices_sorted; + for (const auto &ki: tx_proposal.key_images_sorted) { + selected_transfer_indices_sorted.push_back(w.get_transfer_details(ki)); + } + tx_proposal.sources = get_sources(unused_transfers, selected_transfer_indices_sorted, "SAL1", w); // update `unused_transfers` for next proposal by removing selected transfers tools::for_all_in_vector_erase_no_preserve_order_if(unused_transfers, @@ -400,6 +509,9 @@ std::vector make_carrot_transaction_proposa const rct::xmr_amount fee_per_weight = w.get_base_fee(priority); MDEBUG("fee_per_weight = " << fee_per_weight << ", from priority = " << priority); + + const rct::xmr_amount fee_quantization_mask = w.get_fee_quantization_mask(); + MDEBUG("fee_quantization_mask = " << fee_quantization_mask << ", from priority = " << priority); const std::uint64_t current_chain_height = w.get_blockchain_current_height(); CHECK_AND_ASSERT_THROW_MES(current_chain_height > 0, @@ -407,15 +519,13 @@ std::vector make_carrot_transaction_proposa const std::uint64_t top_block_index = current_chain_height - 1; return make_carrot_transaction_proposals_wallet2_transfer( - transfers, - w.get_subaddress_map_ref(), + w, dsts, fee_per_weight, + fee_quantization_mask, extra, subaddr_account, subaddr_indices, - w.ignore_outputs_above(), - w.ignore_outputs_below(), subtract_fee_from_outputs, top_block_index); } @@ -428,6 +538,7 @@ std::vector make_carrot_transaction_proposa const bool is_subaddress, const size_t n_dests_per_tx, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, const std::uint64_t top_block_index) { @@ -498,6 +609,7 @@ std::vector make_carrot_transaction_proposa carrot::make_carrot_transaction_proposal_v1_sweep(normal_payment_proposals, selfsend_payment_proposals, fee_per_weight, + fee_quantization_mask, extra, std::move(selected_inputs), change_address_spend_pubkey, @@ -524,6 +636,7 @@ std::vector make_carrot_transaction_proposa w.get_transfers(transfers); const rct::xmr_amount fee_per_weight = w.get_base_fee(priority); + const rct::xmr_amount fee_quantization_mask = w.get_fee_quantization_mask(); const std::uint64_t current_chain_height = w.get_blockchain_current_height(); CHECK_AND_ASSERT_THROW_MES(current_chain_height > 0, @@ -538,6 +651,7 @@ std::vector make_carrot_transaction_proposa is_subaddress, n_dests_per_tx, fee_per_weight, + fee_quantization_mask, extra, top_block_index); } @@ -550,6 +664,7 @@ std::vector make_carrot_transaction_proposa const bool is_subaddress, const size_t n_dests_per_tx, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, const std::uint32_t subaddr_account, const std::set &subaddr_indices, @@ -591,6 +706,7 @@ std::vector make_carrot_transaction_proposa is_subaddress, n_dests_per_tx, fee_per_weight, + fee_quantization_mask, extra, top_block_index); } @@ -610,6 +726,7 @@ std::vector make_carrot_transaction_proposa w.get_transfers(transfers); const rct::xmr_amount fee_per_weight = w.get_base_fee(priority); + const rct::xmr_amount fee_quantization_mask = w.get_fee_quantization_mask(); const std::uint64_t current_chain_height = w.get_blockchain_current_height(); CHECK_AND_ASSERT_THROW_MES(current_chain_height > 0, @@ -624,110 +741,15 @@ std::vector make_carrot_transaction_proposa is_subaddress, n_dests_per_tx, fee_per_weight, + fee_quantization_mask, extra, subaddr_account, subaddr_indices, top_block_index); } -std::vector get_sources( - const wallet2::transfer_container &transfers, - const std::vector &selected_transfers, - const std::string &source_asset, - const wallet2 &w -) { - // get decoys - const size_t fake_outputs_count = 15; - std::vector> outs; - std::unordered_set valid_public_keys_cache; - wallet2 &w2 = const_cast(w); - w2.get_outs(outs, selected_transfers, fake_outputs_count, true, valid_public_keys_cache); // may throw - - LOG_PRINT_L2("preparing outputs"); - size_t i = 0, out_index = 0; - std::vector sources; - for(size_t idx: selected_transfers) - { - sources.resize(sources.size()+1); - cryptonote::tx_source_entry& src = sources.back(); - const wallet2::transfer_details& td = transfers[idx]; - - // Sanity check the asset_type for this TD is correct - THROW_WALLET_EXCEPTION_IF(td.asset_type != source_asset, error::wallet_internal_error, "Input has wrong asset_type - expected " + source_asset + " but found " + td.asset_type); - - src.amount = td.amount(); - src.rct = td.is_rct(); - src.carrot = td.is_carrot(); - src.asset_type = td.asset_type; - - // Create the origin TX data - if (td.m_td_origin_idx != (uint64_t)-1) { - THROW_WALLET_EXCEPTION_IF(td.m_td_origin_idx >= w.get_num_transfer_details(), error::wallet_internal_error, "cannot locate return_payment origin index in m_transfers"); - const wallet2::transfer_details& td_origin = w.get_transfer_details(td.m_td_origin_idx); - src.origin_tx_data.tx_type = td_origin.m_tx.type; - src.origin_tx_data.tx_pub_key = cryptonote::get_tx_pub_key_from_extra(td_origin.m_tx); - src.origin_tx_data.output_index = td_origin.m_internal_output_index; - } - - //paste mixin transaction - - THROW_WALLET_EXCEPTION_IF(outs.size() < out_index + 1 , error::wallet_internal_error, "outs.size() < out_index + 1"); - THROW_WALLET_EXCEPTION_IF(outs[out_index].size() < fake_outputs_count , error::wallet_internal_error, "fake_outputs_count > random outputs found"); - - typedef cryptonote::tx_source_entry::output_entry tx_output_entry; - for (size_t n = 0; n < fake_outputs_count + 1; ++n) - { - tx_output_entry oe; - oe.first = std::get<0>(outs[out_index][n]); - oe.second.dest = rct::pk2rct(std::get<1>(outs[out_index][n])); - oe.second.mask = std::get<2>(outs[out_index][n]); - src.outputs.push_back(oe); - } - ++i; - - //paste real transaction to the random index - auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) - { - // HERE BE DRAGONS!!! - // SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING - //return a.first == td.m_global_output_index; - return a.first == td.m_asset_type_output_index; - // LAND AHOY!!! - }); - THROW_WALLET_EXCEPTION_IF(it_to_replace == src.outputs.end(), error::wallet_internal_error, - "real output not found"); - - tx_output_entry real_oe; - // HERE BE DRAGONS!!! - // SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING - //real_oe.first = td.m_global_output_index; - real_oe.first = td.m_asset_type_output_index; - // LAND AHOY!!! - real_oe.second.dest = rct::pk2rct(td.get_public_key()); - real_oe.second.mask = rct::commit(td.amount(), td.m_mask); - *it_to_replace = real_oe; - src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index); - src.real_out_additional_tx_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); - src.real_output = it_to_replace - src.outputs.begin(); - src.real_output_in_tx_index = td.m_internal_output_index; - src.first_rct_key_image = boost::get(td.m_tx.vin[0]).k_image; - src.mask = td.m_mask; - src.address_spend_pubkey = td.m_recovered_spend_pubkey; - if (false) // w.m_multisig // TODO: - // note: multisig_kLRki is a legacy struct, currently only used as a key image shuttle into the multisig tx builder - src.multisig_kLRki = {.k = {}, .L = {}, .R = {}, .ki = rct::ki2rct(td.m_key_image)}; - else - src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()}); - detail::print_source_entry(src); - ++out_index; - } - LOG_PRINT_L2("outputs prepared"); - - return sources; -} //------------------------------------------------------------------------------------------------------------------- cryptonote::transaction finalize_all_proofs_from_transfer_details( const carrot::CarrotTransactionProposalV1 &tx_proposal, - const std::vector &selected_transfers, const cryptonote::transaction_type tx_type, const wallet2 &w) { @@ -765,13 +787,13 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( carrot::get_output_enote_proposals(tx_proposal.normal_payment_proposals, selfsend_payment_proposal_cores, tx_proposal.dummy_encrypted_payment_id, - &w.get_carrot_account().s_view_balance_dev, + nullptr, &addr_dev, tx_proposal.key_images_sorted.at(0), output_enote_proposals, encrypted_payment_id, - nullptr, - change_index); + change_index, + nullptr); CHECK_AND_ASSERT_THROW_MES(output_enote_proposals.size() == n_outputs, "finalize_all_proofs_from_transfer_details: unexpected number of output enote proposals"); @@ -797,13 +819,17 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( // serialize transaction cryptonote::transaction tx = carrot::store_carrot_to_transaction_v1(enotes, tx_proposal.key_images_sorted, + tx_proposal.sources, tx_proposal.fee, encrypted_payment_id); + tx.source_asset_type = "SAL1"; + tx.destination_asset_type = "SAL1"; + tx.type = tx_type; - // collect input key images and amounts + // aliases hw::device &hwdev = acc_keys.get_device(); - std::vector sources = get_sources(transfers, selected_transfers, "SAL1", w); - + const auto &sources = tx_proposal.sources; + // inputs uint64_t amount_in = 0; rct::carrot_ctkeyV inSk; @@ -857,7 +883,12 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( const size_t ephemeral_pubkey_index = shared_ephemeral_pubkey ? 0 : sources[i].real_output_in_tx_index; // input_context - const carrot::input_context_t input_context = carrot::make_carrot_input_context(sources[i].first_rct_key_image); + carrot::input_context_t input_context; + if (sources[i].coinbase) { + input_context = carrot::make_carrot_input_context_coinbase(sources[i].block_index); + } else { + input_context = carrot::make_carrot_input_context(sources[i].first_rct_key_image); + } // s^ctx_sr = H_32(s_sr, D_e, input_context) make_carrot_sender_receiver_secret(s_sender_receiver_unctx.data, @@ -992,15 +1023,17 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( // fee uint64_t fee = amount_in - amount_out - tx.amount_burnt; - rct::BulletproofPlus bpp; - bpp = rct::bulletproof_plus_PROVE(outamounts, output_amount_blinding_factors); + // bpp + tx.rct_signatures.p.bulletproofs_plus.push_back( + rct::bulletproof_plus_PROVE(outamounts, output_amount_blinding_factors) + ); // store proofs crypto::hash tx_prefix_hash; get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev); rct::salvium_data_t salvium_data; salvium_data.salvium_data_type = rct::SalviumOne; - tx.rct_signatures = rct::genRctSimpleCarrot( + rct::genRctSimpleCarrot( rct::hash2rct(tx_prefix_hash), inSk, destinations, @@ -1021,7 +1054,8 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( salvium_data, rct::sk2rct(change_x), rct::sk2rct(change_y), - change_index + change_index, + tx.rct_signatures ); tx.pruned = false; @@ -1170,7 +1204,6 @@ wallet2::pending_tx finalize_all_proofs_from_transfer_details_as_pending_tx( ptx.tx = finalize_all_proofs_from_transfer_details( tx_proposal, - ptx.selected_transfers, cryptonote::transaction_type::TRANSFER, // TODO:take this as a parameter w ); diff --git a/src/wallet/tx_builder.h b/src/wallet/tx_builder.h index 8ea5c95fe..711dee821 100644 --- a/src/wallet/tx_builder.h +++ b/src/wallet/tx_builder.h @@ -58,15 +58,13 @@ carrot::select_inputs_func_t make_wallet2_single_transfer_input_selector( std::set &selected_transfer_indices_out); std::vector make_carrot_transaction_proposals_wallet2_transfer( - const wallet2::transfer_container &transfers, - const std::unordered_map &subaddress_map, + wallet2 &w, std::vector dsts, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, const uint32_t subaddr_account, const std::set &subaddr_indices, - const rct::xmr_amount ignore_above, - const rct::xmr_amount ignore_below, wallet2::unique_index_container subtract_fee_from_outputs, const std::uint64_t top_block_index); std::vector make_carrot_transaction_proposals_wallet2_transfer( @@ -86,6 +84,7 @@ std::vector make_carrot_transaction_proposa const bool is_subaddress, const size_t n_dests_per_tx, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, const std::uint64_t top_block_index); std::vector make_carrot_transaction_proposals_wallet2_sweep( @@ -105,6 +104,7 @@ std::vector make_carrot_transaction_proposa const bool is_subaddress, const size_t n_dests_per_tx, const rct::xmr_amount fee_per_weight, + const rct::xmr_amount fee_quantization_mask, const std::vector &extra, const std::uint32_t subaddr_account, const std::set &subaddr_indices, @@ -126,7 +126,6 @@ wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionPropos cryptonote::transaction finalize_all_proofs_from_transfer_details( const carrot::CarrotTransactionProposalV1 &tx_proposal, - const std::vector &selected_transfers, const cryptonote::transaction_type tx_type, const wallet2 &w); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 22ce8b35d..f8f66e7c6 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -2035,6 +2035,7 @@ private: public: void get_outs(std::vector> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, bool rct, std::unordered_set &valid_public_keys_cache); void get_outs(std::vector> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, std::vector &rct_offsets, std::unordered_set &valid_public_keys_cache, uint64_t &num_spendable_global_outs, uint64_t &num_outs); + size_t get_transfer_details(const crypto::key_image &ki) const; private: bool tx_add_fake_output(std::vector> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked, std::unordered_set &valid_public_keys_cache) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector &unused_transfers_indices, const std::vector &unused_dust_indices) const; @@ -2054,7 +2055,6 @@ private: const crypto::chacha_key get_cache_key(); void verify_password_with_cached_key(const epee::wipeable_string &password); void verify_password_with_cached_key(const crypto::chacha_key &key); - size_t get_transfer_details(const crypto::key_image &ki) const; tx_entry_data get_tx_entries(const std::unordered_set &txids); void sort_scan_tx_entries(std::vector &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 &tx_hashes_to_reprocess, detached_blockchain_data &dbd); diff --git a/tests/unit_tests/carrot_core.cpp b/tests/unit_tests/carrot_core.cpp index 4c67aa01f..019304379 100644 --- a/tests/unit_tests/carrot_core.cpp +++ b/tests/unit_tests/carrot_core.cpp @@ -710,6 +710,7 @@ static void subtest_2out_transfer_get_output_enote_proposals_completeness(const // turn payment proposals into enotes, passing dummy pid_enc if bob isn't integrated std::vector enote_proposals; encrypted_payment_id_t encrypted_payment_id; + size_t change_index; get_output_enote_proposals({bob_payment_proposal}, {alice_payment_proposal}, dummy_encrypted_pid, @@ -717,7 +718,8 @@ static void subtest_2out_transfer_get_output_enote_proposals_completeness(const &alice.k_view_incoming_dev, tx_first_key_image, enote_proposals, - encrypted_payment_id); + encrypted_payment_id, + change_index); ASSERT_EQ(2, enote_proposals.size()); // 2-out tx diff --git a/tests/unit_tests/carrot_fcmp.cpp b/tests/unit_tests/carrot_fcmp.cpp index 00646aee5..c8f264dae 100644 --- a/tests/unit_tests/carrot_fcmp.cpp +++ b/tests/unit_tests/carrot_fcmp.cpp @@ -374,6 +374,7 @@ TEST(carrot_fcmp, receive_scan_spend_and_verify_serialized_carrot_tx) LOG_PRINT_L1("Deriving enotes"); std::vector output_enote_proposals; encrypted_payment_id_t encrypted_payment_id; + size_t change_index; get_output_enote_proposals(tx_proposal.normal_payment_proposals, selfsend_payment_proposal_cores, tx_proposal.dummy_encrypted_payment_id, @@ -382,7 +383,8 @@ TEST(carrot_fcmp, receive_scan_spend_and_verify_serialized_carrot_tx) alice.carrot_account_spend_pubkey, tx_proposal.key_images_sorted.at(0), output_enote_proposals, - encrypted_payment_id); + encrypted_payment_id, + change_index); // Collect balance info and enotes std::vector input_onetime_addresses; @@ -409,6 +411,7 @@ TEST(carrot_fcmp, receive_scan_spend_and_verify_serialized_carrot_tx) LOG_PRINT_L1("Storing carrot to transaction"); cryptonote::transaction tx = store_carrot_to_transaction_v1(output_enotes, tx_proposal.key_images_sorted, + tx_proposal.sources, tx_proposal.fee, encrypted_payment_id); diff --git a/tests/unit_tests/carrot_impl.cpp b/tests/unit_tests/carrot_impl.cpp index 4c9b5db9e..6318a51f0 100644 --- a/tests/unit_tests/carrot_impl.cpp +++ b/tests/unit_tests/carrot_impl.cpp @@ -203,6 +203,7 @@ static void subtest_multi_account_transfer_over_transaction(const unittest_trans // can be passed to a hardware device for deterministic verification of the signable tx hash std::vector rederived_output_enote_proposals; encrypted_payment_id_t rederived_encrypted_payment_id; + size_t change_index; get_output_enote_proposals(tx_proposal.normal_payment_proposals, modified_selfsend_payment_proposals, *parsed_encrypted_payment_id, @@ -210,7 +211,8 @@ static void subtest_multi_account_transfer_over_transaction(const unittest_trans &ss_keys.k_view_incoming_dev, parsed_key_images.at(0), rederived_output_enote_proposals, - rederived_encrypted_payment_id); + rederived_encrypted_payment_id, + change_index); EXPECT_EQ(*parsed_encrypted_payment_id, rederived_encrypted_payment_id); ASSERT_EQ(parsed_enotes.size(), rederived_output_enote_proposals.size()); for (size_t enote_idx = 0; enote_idx < parsed_enotes.size(); ++enote_idx) diff --git a/tests/unit_tests/carrot_legacy.cpp b/tests/unit_tests/carrot_legacy.cpp index 61a29a677..a9387d5a3 100644 --- a/tests/unit_tests/carrot_legacy.cpp +++ b/tests/unit_tests/carrot_legacy.cpp @@ -187,6 +187,7 @@ static void subtest_legacy_2out_transfer_get_output_enote_proposals_completeness // turn payment proposals into enotes, always pass dummy pid std::vector enote_proposals; encrypted_payment_id_t encrypted_payment_id; + size_t change_index; get_output_enote_proposals({bob_payment_proposal}, {alice_payment_proposal}, gen_encrypted_payment_id(), @@ -194,7 +195,8 @@ static void subtest_legacy_2out_transfer_get_output_enote_proposals_completeness &alive_k_v_dev, tx_first_key_image, enote_proposals, - encrypted_payment_id); + encrypted_payment_id, + change_index); ASSERT_EQ(2, enote_proposals.size()); // 2-out tx diff --git a/tests/unit_tests/tx_construction_helpers.cpp b/tests/unit_tests/tx_construction_helpers.cpp index 8c08f945a..8a9d73fe3 100644 --- a/tests/unit_tests/tx_construction_helpers.cpp +++ b/tests/unit_tests/tx_construction_helpers.cpp @@ -75,7 +75,7 @@ bool construct_miner_tx_fake_reward_1out(const size_t height, height, coinbase_enotes); - tx = carrot::store_carrot_to_coinbase_transaction_v1(coinbase_enotes, "", cryptonote::transaction_type::MINER); + tx = carrot::store_carrot_to_coinbase_transaction_v1(coinbase_enotes, "", cryptonote::transaction_type::MINER, height); } else // !is_carrot {