From b70222c774e7a3713901704bf0d4d7b5b3b4c47a Mon Sep 17 00:00:00 2001 From: jeffro256 Date: Mon, 2 Dec 2024 14:47:35 -0600 Subject: [PATCH] get_output_enote_proposals now supports external selfsends --- src/carrot_core/output_set_finalization.cpp | 32 ++++++++-- src/carrot_core/output_set_finalization.h | 18 +++++- src/carrot_core/payment_proposal.cpp | 4 +- src/carrot_core/payment_proposal.h | 6 +- tests/unit_tests/carrot_core.cpp | 71 ++++++++++++++++----- 5 files changed, 101 insertions(+), 30 deletions(-) diff --git a/src/carrot_core/output_set_finalization.cpp b/src/carrot_core/output_set_finalization.cpp index e05654492..558096681 100644 --- a/src/carrot_core/output_set_finalization.cpp +++ b/src/carrot_core/output_set_finalization.cpp @@ -146,7 +146,9 @@ tools::optional_variant &&normal_payment_proposals, std::vector &&selfsend_payment_proposals, - const view_balance_secret_device &s_view_balance_dev, + const view_balance_secret_device *s_view_balance_dev, + const view_incoming_key_device *k_view_dev, + const crypto::public_key &account_spend_pubkey, const crypto::key_image &tx_first_key_image, std::vector &output_enote_proposals_out, encrypted_payment_id_t &encrypted_payment_id_out) @@ -208,18 +210,34 @@ void get_output_enote_proposals(std::vector &&normal_pa encrypted_payment_id_out = encrypted_payment_id; } - // in the case that the pid is ambiguous, set it to random bytes + // in the case that the pid target is ambiguous, set it to random bytes const bool ambiguous_pid_destination = num_integrated == 0 && normal_payment_proposals.size() > 1; if (ambiguous_pid_destination) encrypted_payment_id_out = gen_payment_id(); - // construct selfsend enotes + // construct selfsend enotes, preferring internal enotes over special enotes when possible for (const CarrotPaymentProposalSelfSendV1 &selfsend_payment_proposal : selfsend_payment_proposals) { - get_output_proposal_internal_v1(selfsend_payment_proposal, - s_view_balance_dev, - tx_first_key_image, - tools::add_element(output_enote_proposals_out)); + if (s_view_balance_dev != nullptr) + { + get_output_proposal_internal_v1(selfsend_payment_proposal, + *s_view_balance_dev, + tx_first_key_image, + tools::add_element(output_enote_proposals_out)); + } + else if (k_view_dev != nullptr) + { + get_output_proposal_special_v1(selfsend_payment_proposal, + *k_view_dev, + account_spend_pubkey, + tx_first_key_image, + tools::add_element(output_enote_proposals_out)); + } + else // neither k_v nor s_vb device passed + { + ASSERT_MES_AND_THROW( + "get output enote proposals: neither a view-balance nor view-incoming device was provided"); + } } // sort enotes by D_e and assert uniqueness properties of D_e diff --git a/src/carrot_core/output_set_finalization.h b/src/carrot_core/output_set_finalization.h index 90da62f75..94b5ea8d0 100644 --- a/src/carrot_core/output_set_finalization.h +++ b/src/carrot_core/output_set_finalization.h @@ -87,11 +87,25 @@ tools::optional_variant &&normal_payment_proposals, std::vector &&selfsend_payment_proposals, - const view_balance_secret_device &s_view_balance_dev, + const view_balance_secret_device *s_view_balance_dev, + const view_incoming_key_device *k_view_dev, + const crypto::public_key &account_spend_pubkey, const crypto::key_image &tx_first_key_image, std::vector &output_enote_proposals_out, encrypted_payment_id_t &encrypted_payment_id_out); diff --git a/src/carrot_core/payment_proposal.cpp b/src/carrot_core/payment_proposal.cpp index e09f65f4b..2d6f25bbf 100644 --- a/src/carrot_core/payment_proposal.cpp +++ b/src/carrot_core/payment_proposal.cpp @@ -321,7 +321,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal, //------------------------------------------------------------------------------------------------------------------- void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &proposal, const view_incoming_key_device &k_view_dev, - const crypto::public_key &primary_address_spend_pubkey, + const crypto::public_key &account_spend_pubkey, const crypto::key_image &tx_first_key_image, RCTOutputEnoteProposal &output_enote_out) { @@ -362,7 +362,7 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo k_view_dev.make_janus_anchor_special(proposal.enote_ephemeral_pubkey, input_context, output_enote_out.enote.onetime_address, - primary_address_spend_pubkey, + account_spend_pubkey, janus_anchor_special); // 6. encrypt special anchor: anchor_enc = anchor XOR m_anchor diff --git a/src/carrot_core/payment_proposal.h b/src/carrot_core/payment_proposal.h index 04fa0bcdb..51fcb850b 100644 --- a/src/carrot_core/payment_proposal.h +++ b/src/carrot_core/payment_proposal.h @@ -129,20 +129,20 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal, * brief: get_output_proposal_v1 - convert the carrot proposal to an output proposal (external selfsend) * param: proposal - * param: k_view_dev - -* param: primary_address_spend_pubkey - +* param: account_spend_pubkey - * param: tx_first_key_image - * outparam: output_enote_out - */ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &proposal, const view_incoming_key_device &k_view_dev, - const crypto::public_key &primary_address_spend_pubkey, + const crypto::public_key &account_spend_pubkey, const crypto::key_image &tx_first_key_image, RCTOutputEnoteProposal &output_enote_out); /** * brief: get_output_proposal_internal_v1 - convert the carrot proposal to an output proposal (internal) * param: proposal - * param: s_view_balance_dev - -* param: primary_address_spend_pubkey - +* param: account_spend_pubkey - * param: tx_first_key_image - * outparam: output_enote_out - * outparam: partial_memo_out - diff --git a/tests/unit_tests/carrot_core.cpp b/tests/unit_tests/carrot_core.cpp index f2f0f9736..057f677c0 100644 --- a/tests/unit_tests/carrot_core.cpp +++ b/tests/unit_tests/carrot_core.cpp @@ -893,10 +893,11 @@ TEST(carrot_core, main_address_coinbase_scan_completeness) enote.onetime_address)); } //---------------------------------------------------------------------------------------------------------------------- -static void subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(const bool alice_subaddress, +static void subtest_2out_transfer_get_output_enote_proposals_completeness(const bool alice_subaddress, const bool bob_subaddress, const bool bob_integrated, - const CarrotEnoteType alice_selfsend_type) + const CarrotEnoteType alice_selfsend_type, + const bool alice_internal_selfsends) { // generate alice keys and address const mock_carrot_keys alice = mock_carrot_keys::generate(); @@ -972,11 +973,13 @@ static void subtest_2out_transfer_get_enote_output_proposals_internal_ss_complet encrypted_payment_id_t encrypted_payment_id; get_output_enote_proposals({bob_payment_proposal}, {alice_payment_proposal}, - alice.s_view_balance_dev, + alice_internal_selfsends ? &alice.s_view_balance_dev : nullptr, + &alice.k_view_dev, + alice.account_spend_pubkey, tx_first_key_image, enote_proposals, encrypted_payment_id); - + ASSERT_EQ(2, enote_proposals.size()); // 2-out tx // collect enotes @@ -1061,37 +1064,73 @@ static void subtest_2out_transfer_get_enote_output_proposals_internal_ss_complet //---------------------------------------------------------------------------------------------------------------------- TEST(carrot_core, get_enote_output_proposals_internal_ss_main2main_completeness) { - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, false, CarrotEnoteType::PAYMENT); - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, false, CarrotEnoteType::CHANGE); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::PAYMENT, true); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::CHANGE, true); } //---------------------------------------------------------------------------------------------------------------------- TEST(carrot_core, get_enote_output_proposals_internal_ss_main2sub_completeness) { - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, true, false, CarrotEnoteType::PAYMENT); - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, true, false, CarrotEnoteType::CHANGE); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::PAYMENT, true); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::CHANGE, true); } //---------------------------------------------------------------------------------------------------------------------- TEST(carrot_core, get_enote_output_proposals_internal_ss_main2integ_completeness) { - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, true, CarrotEnoteType::PAYMENT); - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(false, false, true, CarrotEnoteType::CHANGE); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::PAYMENT, true); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::CHANGE, true); } //---------------------------------------------------------------------------------------------------------------------- TEST(carrot_core, get_enote_output_proposals_internal_ss_sub2main_completeness) { - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, false, CarrotEnoteType::PAYMENT); - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, false, CarrotEnoteType::CHANGE); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::PAYMENT, true); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::CHANGE, true); } //---------------------------------------------------------------------------------------------------------------------- TEST(carrot_core, get_enote_output_proposals_internal_ss_sub2sub_completeness) { - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, true, false, CarrotEnoteType::PAYMENT); - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, true, false, CarrotEnoteType::CHANGE); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::PAYMENT, true); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::CHANGE, true); } //---------------------------------------------------------------------------------------------------------------------- TEST(carrot_core, get_enote_output_proposals_internal_ss_sub2integ_completeness) { - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, true, CarrotEnoteType::PAYMENT); - subtest_2out_transfer_get_enote_output_proposals_internal_ss_completeness(true, false, true, CarrotEnoteType::CHANGE); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::PAYMENT, true); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::CHANGE, true); +} +//---------------------------------------------------------------------------------------------------------------------- +TEST(carrot_core, get_enote_output_proposals_external_ss_main2main_completeness) +{ + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::PAYMENT, false); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, false, CarrotEnoteType::CHANGE, false); +} +//---------------------------------------------------------------------------------------------------------------------- +TEST(carrot_core, get_enote_output_proposals_external_ss_main2sub_completeness) +{ + subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::PAYMENT, false); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, true, false, CarrotEnoteType::CHANGE, false); +} +//---------------------------------------------------------------------------------------------------------------------- +TEST(carrot_core, get_enote_output_proposals_external_ss_main2integ_completeness) +{ + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::PAYMENT, false); + subtest_2out_transfer_get_output_enote_proposals_completeness(false, false, true, CarrotEnoteType::CHANGE, false); +} +//---------------------------------------------------------------------------------------------------------------------- +TEST(carrot_core, get_enote_output_proposals_external_ss_sub2main_completeness) +{ + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::PAYMENT, false); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, false, CarrotEnoteType::CHANGE, false); +} +//---------------------------------------------------------------------------------------------------------------------- +TEST(carrot_core, get_enote_output_proposals_external_ss_sub2sub_completeness) +{ + subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::PAYMENT, false); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, true, false, CarrotEnoteType::CHANGE, false); +} +//---------------------------------------------------------------------------------------------------------------------- +TEST(carrot_core, get_enote_output_proposals_external_ss_sub2integ_completeness) +{ + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::PAYMENT, false); + subtest_2out_transfer_get_output_enote_proposals_completeness(true, false, true, CarrotEnoteType::CHANGE, false); } //----------------------------------------------------------------------------------------------------------------------