Skip to content

Commit 31a9113

Browse files
committed
carrot+fcmp: misc refactors of tx_builder b4 hot/cold support
* info fetchers for `tx_reconstruct_variant_t` * expose `collect_non_burned_transfers_by_onetime_address()` * add `collect_selected_transfer_indices()` * document and cleanup `sign_carrot_transaction_proposal()` * finalize proofs in `finalize_all_proofs_from_transfer_details()` with transfer details * `make_pending_carrot_tx()` without transfers list or `hw::device` needed * rename `finalize_all_proofs_from_transfer_details()` * document all functions in `tx_builder.h`
1 parent 90ce152 commit 31a9113

File tree

6 files changed

+637
-293
lines changed

6 files changed

+637
-293
lines changed

src/wallet/tx_builder.cpp

Lines changed: 467 additions & 259 deletions
Large diffs are not rendered by default.

src/wallet/tx_builder.h

Lines changed: 164 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#pragma once
3030

3131
//local headers
32+
#include "carrot_impl/address_device.h"
3233
#include "carrot_impl/input_selection.h"
3334
#include "fee_priority.h"
3435
#include "fcmp_pp/tree_cache.h"
@@ -85,6 +86,36 @@ struct PreCarrotTransactionProposal
8586
uint8_t construction_flags;
8687
};
8788

89+
/**
90+
* brief: data to reconstruct any Monero transaction's "signable transaction hash" or "pre-MLSAG hash"
91+
*/
92+
using tx_reconstruct_variant_t = std::variant<
93+
PreCarrotTransactionProposal,
94+
carrot::CarrotTransactionProposalV1
95+
>;
96+
/// destinations for finalized enote (AKA split and w/ change) [requires view-incoming key]
97+
std::vector<cryptonote::tx_destination_entry> finalized_destinations_ref(const tx_reconstruct_variant_t&,
98+
const carrot::view_incoming_key_device &k_view_dev);
99+
/// change destination [requires view-incoming key]
100+
cryptonote::tx_destination_entry change_destination_ref(const tx_reconstruct_variant_t&,
101+
const carrot::view_incoming_key_device &k_view_dev);
102+
/// fee
103+
rct::xmr_amount fee_ref(const tx_reconstruct_variant_t&);
104+
/// short payment ID (8 bytes, pre-encryption)
105+
std::optional<crypto::hash8> short_payment_id_ref(const tx_reconstruct_variant_t&);
106+
/// long payment ID (32 bytes)
107+
std::optional<crypto::hash> long_payment_id_ref(const tx_reconstruct_variant_t&);
108+
/// "true-spend" one-time addresses in inputs (in proposal order, not final tx order)
109+
std::vector<crypto::public_key> spent_onetime_addresses_ref(const tx_reconstruct_variant_t&);
110+
/// sum total of input amounts
111+
boost::multiprecision::uint128_t input_amount_total_ref(const tx_reconstruct_variant_t&);
112+
/// ring sizes (in proposal order, not final tx order)
113+
std::vector<std::uint64_t> ring_sizes_ref(const tx_reconstruct_variant_t&);
114+
/// unlock time
115+
std::uint64_t unlock_time_ref(const tx_reconstruct_variant_t&);
116+
/// extra tx fields (includes PIDs and enote ephemeral pubkeys in pre-Carrot ONLY)
117+
const std::vector<std::uint8_t> &extra_ref(const tx_reconstruct_variant_t&);
118+
88119
// The convention for destinations is:
89120
// dests does not include change
90121
// splitted_dsts (in construction_data) does
@@ -104,15 +135,17 @@ struct pending_tx
104135
uint32_t subaddr_account; // subaddress account of your wallet to be used in this transfer
105136
std::set<uint32_t> subaddr_indices; // set of address indices used as inputs in this transfer
106137

107-
using tx_reconstruct_variant_t = std::variant<
108-
PreCarrotTransactionProposal,
109-
carrot::CarrotTransactionProposalV1
110-
>;
111138
tx_reconstruct_variant_t construction_data;
112139
};
113140

114141
/**
115-
* brief: collect_carrot_input_candidate_list - filter and convert wallet2 transfer contain into carrot input candidates
142+
* brief: index transfers by OTA, including a burning bug filter
143+
* param: transfers -
144+
*/
145+
std::unordered_map<crypto::public_key, size_t> collect_non_burned_transfers_by_onetime_address(
146+
const wallet2_basic::transfer_container &transfers);
147+
/**
148+
* brief: filter and convert wallet2 transfer contain into carrot input candidates
116149
* param: transfers - wallet2 incoming transfers list
117150
* param: from_subaddr_account - ignore transfers not addressed to this major account index
118151
* param: from_subaddr_indices - ignore transfers not addressed to one of these minor account indices, empty means all
@@ -128,7 +161,23 @@ std::vector<carrot::InputCandidate> collect_carrot_input_candidate_list(
128161
const rct::xmr_amount ignore_above,
129162
const rct::xmr_amount ignore_below,
130163
const std::uint64_t top_block_index);
131-
164+
/**
165+
* brief: create "transfer" style Carrot/FCMP++ transaction proposals
166+
* param: transfers - transfers list to perform input selection from
167+
* param: subaddress_map -
168+
* param: dsts - list of (address, amount) payment outlays to fulfill
169+
* param: fee_per_weight - ratio of pXMR / vB to set fee at
170+
* param: extra - truly "extra" fields to be included in tx_extra, doesn't include ephemeral tx pubkeys or PIDs
171+
* param: subaddr_account - the only account (AKA major) index for which input selection should pull inputs from
172+
* param: subaddr_indices - if non-empty, the only minor indices for which input selection should pull inputs from
173+
* param: ignore_above - if the enote's amount is greater than this amount, exclude it from input selection
174+
* param: ignore_below - if the enote's amount is less than this amount, exclude it from input selection
175+
* param: subtract_fee_from_outputs - indices into `dsts` which are "fee-subtractable"
176+
* param: top_block_index - the block index of the current top block inside the blockchain
177+
* return: list of carrot transaction proposals
178+
*
179+
* Transfer-style means that transactions are added until all payment outlays are fulfilled.
180+
*/
132181
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_transfer(
133182
const wallet2_basic::transfer_container &transfers,
134183
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
@@ -141,7 +190,21 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
141190
const rct::xmr_amount ignore_below,
142191
std::set<std::uint32_t> subtract_fee_from_outputs,
143192
const std::uint64_t top_block_index);
144-
193+
/**
194+
* brief: create "sweep-multiple" style Carrot/FCMP++ transaction proposals
195+
* param: transfers - transfers list to perform input selection from
196+
* param: subaddress_map -
197+
* param: input_key_images - key images of inputs to spend
198+
* param: address - public address for all destinations in txs
199+
* param: is_subaddress - true iff `address` refers to a subaddress
200+
* param: n_dests_per_tx - the min num of outputs to make per tx (if `address` isn't ours, a change output is included)
201+
* param: fee_per_weight - ratio of pXMR / vB to set fee at
202+
* param: extra - truly "extra" fields to be included in tx_extra, doesn't include ephemeral tx pubkeys or PIDs
203+
* param: top_block_index - the block index of the current top block inside the blockchain
204+
* return: list of carrot transaction proposals
205+
*
206+
* Sweep-multiple-style means that transactions are added until all inputs specified by index are spent.
207+
*/
145208
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep(
146209
const wallet2_basic::transfer_container &transfers,
147210
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
@@ -152,7 +215,23 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
152215
const rct::xmr_amount fee_per_weight,
153216
std::vector<uint8_t> extra,
154217
const std::uint64_t top_block_index);
155-
218+
/**
219+
* brief: create "sweep-all" style Carrot/FCMP++ transaction proposals
220+
* param: transfers - transfers list to perform input selection from
221+
* param: subaddress_map -
222+
* param: only_below - if the enote's amount is greater than this amount, exclude it from input selection (unless 0)
223+
* param: address - public address for all destinations in txs
224+
* param: is_subaddress - true iff `address` refers to a subaddress
225+
* param: n_dests_per_tx - the min num of outputs to make per tx (if `address` isn't ours, a change output is included)
226+
* param: fee_per_weight - ratio of pXMR / vB to set fee at
227+
* param: extra - truly "extra" fields to be included in tx_extra, doesn't include ephemeral tx pubkeys or PIDs
228+
* param: subaddr_account - the only account (AKA major) index for which input selection should pull inputs from
229+
* param: subaddr_indices - if non-empty, the only minor indices for which input selection should pull inputs from
230+
* param: top_block_index - the block index of the current top block inside the blockchain
231+
* return: list of carrot transaction proposals
232+
*
233+
* Sweep-all-style means that transactions are added until all inputs <= amount `only_below` are spent.
234+
*/
156235
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep_all(
157236
const wallet2_basic::transfer_container &transfers,
158237
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
@@ -165,34 +244,93 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
165244
const std::uint32_t subaddr_account,
166245
const std::set<uint32_t> &subaddr_indices,
167246
const std::uint64_t top_block_index);
168-
247+
/**
248+
* brief: convert a `wallet2_basic::transfer_details` into a output opening hint
249+
* param: td -
250+
* return: output opening hint
251+
*/
169252
carrot::OutputOpeningHintVariant make_sal_opening_hint_from_transfer_details(const wallet2_basic::transfer_details &td);
170-
171-
std::unordered_map<crypto::key_image, fcmp_pp::FcmpPpSalProof> sign_carrot_transaction_proposal_from_transfer_details(
253+
/**
254+
* brief: get index into transfers list of spent enotes in a potential transaction
255+
* param: tx_construction_data -
256+
* param: transfers -
257+
* return: list of spent input enotes indices in construction-specified order, not necessarily final transaction order
258+
*
259+
* WARNING: The indices returned assumes the best case scenario for burning bugs for pre-Carrot
260+
* transactions. If the transfers list contains multiple pre-Carrot enotes with the same onetime
261+
* address, this function returns the index of the best of the duplicates. If you do not trust the
262+
* originating source of this construction data, then this is not safe. Validating the amounts
263+
* actually line up with the best case, instead of trusting, would require tx_reconstruct_variant_t
264+
* to store openings for the pseudo output amount commitments. This isn't an issue w/ spending
265+
* Carrot enotes since Carrot mitigates the burning bug statelessly.
266+
*/
267+
std::vector<std::size_t> collect_selected_transfer_indices(const tx_reconstruct_variant_t &tx_construction_data,
268+
const wallet2_basic::transfer_container &transfers);
269+
/**
270+
* brief: sign all Carrot transaction proposal inputs given rerandomized outputs
271+
* param: tx_proposal -
272+
* param: rerandomized_outputs - rerandomized outputs in order of input proposals in `tx_proposal`
273+
* param: addr_dev -
274+
* param: k_spend - k_s
275+
* return: valid SA/L proofs by key image
276+
*/
277+
std::unordered_map<crypto::key_image, fcmp_pp::FcmpPpSalProof> sign_carrot_transaction_proposal(
172278
const carrot::CarrotTransactionProposalV1 &tx_proposal,
173279
const std::vector<FcmpRerandomizedOutputCompressed> &rerandomized_outputs,
174-
const wallet2_basic::transfer_container &transfers,
175-
const cryptonote::account_keys &acc_keys);
176-
177-
//! @TODO: accept already-calculated rerandomized outputs and their blinds
178-
cryptonote::transaction finalize_all_proofs_from_transfer_details(
280+
const carrot::cryptonote_hierarchy_address_device &addr_dev,
281+
const crypto::secret_key &k_spend);
282+
/**
283+
* brief: finalize FCMPs and BP+ range proofs for output amounts for Carrot/FCMP++ txs
284+
* param: sorted_input_key_images - key images in input order
285+
* param: sorted_rerandomized_outputs - rerandomized outputs in key image order
286+
* param: sorted_sal_proofs - SA/L proofs in key image order
287+
* param: encrypted_payment_id - pid_enc
288+
* param: fee -
289+
* param: tree_cache - FCMP tree cache to draw enote paths from
290+
* param: curve_trees -
291+
*/
292+
cryptonote::transaction finalize_fcmps_and_range_proofs(
293+
const std::vector<crypto::key_image> &sorted_input_key_images,
294+
const std::vector<FcmpRerandomizedOutputCompressed> &sorted_rerandomized_outputs,
295+
const std::vector<fcmp_pp::FcmpPpSalProof> &sorted_sal_proofs,
296+
const std::vector<carrot::RCTOutputEnoteProposal> &output_enote_proposals,
297+
const carrot::encrypted_payment_id_t &encrypted_payment_id,
298+
const rct::xmr_amount fee,
299+
const fcmp_pp::curve_trees::TreeCacheV1 &tree_cache,
300+
const fcmp_pp::curve_trees::CurveTreesV1 &curve_trees);
301+
/**
302+
* brief: finalize FCMPs, BP+ range proofs for outputs amounts, and SA/L proofs for Carrot/FCMP++ txs
303+
* param: tx_proposal -
304+
* param: tree_cache - FCMP tree cache to draw enote paths from
305+
* param: curve_trees -
306+
* param: acc_keys -
307+
* return: a fully proved FCMP++ transaction corresponding to the transaction proposal
308+
*/
309+
cryptonote::transaction finalize_all_fcmp_pp_proofs(
179310
const carrot::CarrotTransactionProposalV1 &tx_proposal,
180-
const wallet2_basic::transfer_container &transfers,
181311
const fcmp_pp::curve_trees::TreeCacheV1 &tree_cache,
182312
const fcmp_pp::curve_trees::CurveTreesV1 &curve_trees,
183313
const cryptonote::account_keys &acc_keys);
184-
314+
/**
315+
* brief: fill out a `pending_tx` from a Carrot transaction proposal, excluding the transaction itself
316+
* param: tx_proposal -
317+
* param: sorted_input_key_images - key images in input order
318+
* param: k_view_incoming_dev - k_v
319+
* return: `pending_tx` representing the Carrot transaction proposal
320+
*/
185321
pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionProposalV1 &tx_proposal,
186322
const std::vector<crypto::key_image> &sorted_input_key_images,
187-
const wallet2_basic::transfer_container &transfers,
188-
const crypto::secret_key &k_view,
189-
hw::device &hwdev);
190-
191-
crypto::hash8 get_pending_tx_payment_id(const pending_tx &ptx);
192-
193-
pending_tx finalize_all_proofs_from_transfer_details_as_pending_tx(
323+
const carrot::view_incoming_key_device &k_view_incoming_dev);
324+
/**
325+
* brief: finalize FCMPs, BP+ range proofs, and SA/Ls, proofs for Carrot/FCMP++ txs into a `pending_tx`
326+
* param: tx_proposal -
327+
* param: tree_cache - FCMP tree cache to draw enote paths from
328+
* param: curve_trees -
329+
* param: acc_keys -
330+
* return: `pending_tx` representing the Carrot transaction proposal, including a fully proved FCMP++ transaction
331+
*/
332+
pending_tx finalize_all_fcmp_pp_proofs_as_pending_tx(
194333
const carrot::CarrotTransactionProposalV1 &tx_proposal,
195-
const wallet2_basic::transfer_container &transfers,
196334
const fcmp_pp::curve_trees::TreeCacheV1 &tree_cache,
197335
const fcmp_pp::curve_trees::CurveTreesV1 &curve_trees,
198336
const cryptonote::account_keys &acc_keys);

src/wallet/wallet2.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -937,12 +937,13 @@ static tools::wallet::pending_tx finalize_all_proofs_from_transfer_details_as_pe
937937
const carrot::CarrotTransactionProposalV1 &tx_proposal,
938938
const tools::wallet2 &w)
939939
{
940-
return tools::wallet::finalize_all_proofs_from_transfer_details_as_pending_tx(
940+
tools::wallet::pending_tx ptx = tools::wallet::finalize_all_fcmp_pp_proofs_as_pending_tx(
941941
tx_proposal,
942-
get_transfers(w),
943942
w.get_tree_cache_ref(),
944943
w.get_curve_trees_ref(),
945944
w.get_account().get_keys());
945+
ptx.selected_transfers = tools::wallet::collect_selected_transfer_indices(ptx.construction_data, get_transfers(w));
946+
return ptx;
946947
}
947948

948949
static const tools::wallet2::tx_construction_data &get_construction_data(const tools::wallet2::pending_tx &ptx)
@@ -7634,7 +7635,7 @@ void wallet2::commit_tx(pending_tx& ptx)
76347635
uint64_t amount_in = 0;
76357636
if (store_tx_info())
76367637
{
7637-
const crypto::hash8 payment_id_8 = wallet::get_pending_tx_payment_id(ptx);
7638+
const crypto::hash8 payment_id_8 = wallet::short_payment_id_ref(ptx.construction_data).value_or(crypto::null_hash8);
76387639
memcpy(&payment_id, &payment_id_8, sizeof(crypto::hash8));
76397640
dests = ptx.dests;
76407641
for(size_t idx: ptx.selected_transfers)

src/wallet/wallet2.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,6 @@ namespace tools
787787
* param: address - public address for all destinations in txs
788788
* param: is_subaddress - true iff `address` refers to a subaddress
789789
* param: outputs - the minimum num of outputs to make per tx (if `address` isn't ours, a change output is included)
790-
* param: payment_id - short payment ID
791790
* param: unused_transfers_indices - indices into `m_transfers` of RingCT & validly-decomposed pre-RingCT inputs
792791
* param: unused_dust_indices - indices into `m_transfers` of non-validly-decomposed pre-RingCT inputs
793792
* param: fake_outs_count - the number of decoys per input, AKA "mixin"

tests/core_tests/fcmp_pp.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,7 @@ bool gen_fcmp_pp_tx_validation_base::generate_with(std::vector<test_event_entry>
407407
n_synced_blocks - 1);
408408
CHECK_AND_ASSERT_MES(tx_proposals.size() == 1, false, "Expected 1 tx proposal");
409409

410-
rct_txes.back() = tools::wallet::finalize_all_proofs_from_transfer_details(tx_proposals.front(),
411-
{wallet2_td},
410+
rct_txes.back() = tools::wallet::finalize_all_fcmp_pp_proofs(tx_proposals.front(),
412411
tree_cache,
413412
*fcmp_pp::curve_trees::curve_trees_v1(),
414413
miner_account.get_keys());

tests/unit_tests/wallet_tx_builder.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -792,8 +792,7 @@ TEST(wallet_tx_builder, wallet2_scan_propose_sign_prove_member_and_scan_1)
792792

793793
// 7.
794794
LOG_PRINT_L2("Alice has something to prove");
795-
tx = tools::wallet::finalize_all_proofs_from_transfer_details(tx_proposal,
796-
alice.m_transfers,
795+
tx = tools::wallet::finalize_all_fcmp_pp_proofs(tx_proposal,
797796
alice.m_tree_cache,
798797
*alice.m_curve_trees,
799798
alice_keys);

0 commit comments

Comments
 (0)