carrot_impl: more documentation and rename CarrotPreSelectedInput
This commit is contained in:
@@ -55,7 +55,7 @@ static std::ostream &operator<<(std::ostream &os, const CarrotSelectedInput &inp
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static std::ostream &operator<<(std::ostream &os, const CarrotPreSelectedInput &input)
|
||||
static std::ostream &operator<<(std::ostream &os, const InputCandidate &input)
|
||||
{
|
||||
os << "{ core = " << input.core << ", block_index = " << input.block_index
|
||||
<< ", carrot = " << !input.is_pre_carrot << ", external = " << input.is_external << " }";
|
||||
@@ -71,7 +71,7 @@ static std::set<size_t> set_union(const std::set<size_t> &a, const std::set<size
|
||||
};
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static void stable_sort_indices_by_amount(const epee::span<const CarrotPreSelectedInput> input_candidates,
|
||||
static void stable_sort_indices_by_amount(const epee::span<const InputCandidate> input_candidates,
|
||||
std::vector<size_t> &indices_inout)
|
||||
{
|
||||
std::stable_sort(indices_inout.begin(), indices_inout.end(),
|
||||
@@ -85,7 +85,7 @@ static void stable_sort_indices_by_amount(const epee::span<const CarrotPreSelect
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static std::pair<std::size_t, boost::multiprecision::uint128_t> input_count_for_max_usable_money(
|
||||
const epee::span<const CarrotPreSelectedInput> input_candidates,
|
||||
const epee::span<const InputCandidate> input_candidates,
|
||||
const std::set<std::size_t> &selectable_inputs,
|
||||
std::size_t max_num_input_count,
|
||||
const std::map<std::size_t, rct::xmr_amount> &fee_by_input_count)
|
||||
@@ -139,7 +139,7 @@ static std::pair<std::size_t, boost::multiprecision::uint128_t> input_count_for_
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
int compare_input_candidate_same_ki(const CarrotPreSelectedInput &lhs, const CarrotPreSelectedInput &rhs)
|
||||
int compare_input_candidate_same_ki(const InputCandidate &lhs, const InputCandidate &rhs)
|
||||
{
|
||||
CARROT_CHECK_AND_THROW(lhs.core.key_image == rhs.core.key_image,
|
||||
component_out_of_order, "this function is not meant to compare inputs of different key images");
|
||||
@@ -174,7 +174,7 @@ int compare_input_candidate_same_ki(const CarrotPreSelectedInput &lhs, const Car
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::vector<std::set<std::size_t>> form_preferred_input_candidate_subsets(
|
||||
const epee::span<const CarrotPreSelectedInput> input_candidates,
|
||||
const epee::span<const InputCandidate> input_candidates,
|
||||
const std::uint32_t flags,
|
||||
const bool is_normal_transfer)
|
||||
{
|
||||
@@ -190,7 +190,7 @@ std::vector<std::set<std::size_t>> form_preferred_input_candidate_subsets(
|
||||
std::unordered_map<crypto::key_image, std::size_t> best_input_by_key_image;
|
||||
for (size_t i = 0; i < input_candidates.size(); ++i)
|
||||
{
|
||||
const CarrotPreSelectedInput &input_candidate = input_candidates[i];
|
||||
const InputCandidate &input_candidate = input_candidates[i];
|
||||
auto it = best_input_by_key_image.find(input_candidate.core.key_image);
|
||||
if (it == best_input_by_key_image.end())
|
||||
{
|
||||
@@ -198,7 +198,7 @@ std::vector<std::set<std::size_t>> form_preferred_input_candidate_subsets(
|
||||
}
|
||||
else
|
||||
{
|
||||
const CarrotPreSelectedInput &other_input_candidate = input_candidates[it->second];
|
||||
const InputCandidate &other_input_candidate = input_candidates[it->second];
|
||||
if (compare_input_candidate_same_ki(other_input_candidate, input_candidate) < 0)
|
||||
it->second = i;
|
||||
}
|
||||
@@ -338,7 +338,7 @@ std::vector<std::size_t> get_input_counts_in_preferred_order()
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
select_inputs_func_t make_single_transfer_input_selector(
|
||||
const epee::span<const CarrotPreSelectedInput> input_candidates,
|
||||
const epee::span<const InputCandidate> input_candidates,
|
||||
const epee::span<const input_selection_policy_t> policies,
|
||||
const std::uint32_t flags,
|
||||
std::set<size_t> *selected_input_indices_out)
|
||||
@@ -379,7 +379,7 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
|
||||
// 4. Quick check of total money and single tx input count limited total money
|
||||
boost::multiprecision::uint128_t total_candidate_money = 0;
|
||||
for (const CarrotPreSelectedInput &input_candidate : input_candidates)
|
||||
for (const InputCandidate &input_candidate : input_candidates)
|
||||
total_candidate_money += input_candidate.core.amount;
|
||||
CARROT_CHECK_AND_THROW(total_candidate_money >= absolute_minimum_required_money,
|
||||
not_enough_money,
|
||||
@@ -424,7 +424,7 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
"-input subset with tx max usable money: " << cryptonote::print_money(max_usable_money.second));
|
||||
for (const std::size_t selectable_index : input_candidate_subset)
|
||||
{
|
||||
const CarrotPreSelectedInput &input_candidate = input_candidates[selectable_index];
|
||||
const InputCandidate &input_candidate = input_candidates[selectable_index];
|
||||
MDEBUG(" " << input_candidate);
|
||||
}
|
||||
|
||||
@@ -518,7 +518,7 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
namespace ispolicy
|
||||
{
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void select_greedy_aging(const epee::span<const CarrotPreSelectedInput> input_candidates,
|
||||
void select_greedy_aging(const epee::span<const InputCandidate> input_candidates,
|
||||
const std::set<std::size_t> &selectable_inputs,
|
||||
const std::size_t n_inputs,
|
||||
const boost::multiprecision::uint128_t &required_money,
|
||||
@@ -542,7 +542,7 @@ void select_greedy_aging(const epee::span<const CarrotPreSelectedInput> input_ca
|
||||
for (size_t i = 0; i < n_inputs; ++i)
|
||||
{
|
||||
const std::size_t selectable_idx = selectable_inputs_by_amount.at(selectable_inputs_by_amount.size() - i - 1);
|
||||
const CarrotPreSelectedInput &input = input_candidates[selectable_idx];
|
||||
const InputCandidate &input = input_candidates[selectable_idx];
|
||||
input_amount_sum += input.core.amount;
|
||||
selected_inputs_indices_out.insert(selectable_idx);
|
||||
selected_indices_by_block_index.emplace(input.block_index, selectable_idx);
|
||||
@@ -573,7 +573,7 @@ void select_greedy_aging(const epee::span<const CarrotPreSelectedInput> input_ca
|
||||
const std::size_t potential_replacement_idx = *amount_it;
|
||||
if (selected_inputs_indices_out.count(potential_replacement_idx))
|
||||
continue;
|
||||
const CarrotPreSelectedInput &potential_replacement_input = input_candidates[potential_replacement_idx];
|
||||
const InputCandidate &potential_replacement_input = input_candidates[potential_replacement_idx];
|
||||
if (potential_replacement_input.block_index < min_block_index)
|
||||
{
|
||||
min_block_index = potential_replacement_input.block_index;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
struct CarrotPreSelectedInput
|
||||
struct InputCandidate
|
||||
{
|
||||
CarrotSelectedInput core;
|
||||
|
||||
@@ -62,12 +62,22 @@ namespace InputSelectionFlags
|
||||
static constexpr std::uint32_t ALLOW_DUST = 1 << 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* brief: input_selection_policy_t - a functor which implements N-input selection on a subset of candidates
|
||||
* param: input_candidates -
|
||||
* param: selectable_input_indices - subset of indices in `input_candidates` allowed to select from
|
||||
* param: n_inputs - exact number of selected inputs should return
|
||||
* param: required_money - sum of amounts of selected inputs should be greater than or equal to this value
|
||||
* outparam: selected_inputs_indices_out - `n_inputs` subset of `selectable_input_indices`, of selected input indices
|
||||
*
|
||||
* To signify selection failure, `selected_inputs_indices_out` should be empty after end of call.
|
||||
*/
|
||||
using input_selection_policy_t = std::function<void(
|
||||
epee::span<const CarrotPreSelectedInput>, // input candidates
|
||||
const std::set<std::size_t>&, // selectable subset indices
|
||||
std::size_t, // input count
|
||||
const boost::multiprecision::uint128_t&, // required money for input count
|
||||
std::set<std::size_t>& // selected indices
|
||||
epee::span<const InputCandidate> input_candidates,
|
||||
const std::set<std::size_t> &selectable_input_indices,
|
||||
std::size_t n_inputs,
|
||||
const boost::multiprecision::uint128_t &required_money,
|
||||
std::set<std::size_t> &selected_inputs_indices_out
|
||||
)>;
|
||||
|
||||
/**
|
||||
@@ -83,11 +93,11 @@ using input_selection_policy_t = std::function<void(
|
||||
* 3. Is pre-Carrot enote? (`false` is better for spending QFS)
|
||||
* 4. Is external enote? (`false` is better for spending QFS)
|
||||
*/
|
||||
int compare_input_candidate_same_ki(const CarrotPreSelectedInput &lhs, const CarrotPreSelectedInput &rhs);
|
||||
int compare_input_candidate_same_ki(const InputCandidate &lhs, const InputCandidate &rhs);
|
||||
/**
|
||||
* brief: form_preferred_input_candidate_subsets - make subsets of input candidates to try selection in preferred order
|
||||
* param: input_candidates - slice to user-provided input candidates
|
||||
* param: flags - values in InputSelectionFlags namespace OR'ed together
|
||||
* param: flags - see InputSelectionFlags namespace
|
||||
* param: is_normal_transfer - true iff num normal non-dummy payments in tx to perform selection for is >= 1
|
||||
* return: ordered list of subsets (represented by 0-based indices) of input_candidates to try selection on
|
||||
*
|
||||
@@ -134,7 +144,7 @@ int compare_input_candidate_same_ki(const CarrotPreSelectedInput &lhs, const Car
|
||||
* internal due to the lack of the view-balance secret s_vb in legacy key hierarchies.
|
||||
*/
|
||||
std::vector<std::set<std::size_t>> form_preferred_input_candidate_subsets(
|
||||
const epee::span<const CarrotPreSelectedInput> input_candidates,
|
||||
const epee::span<const InputCandidate> input_candidates,
|
||||
const std::uint32_t flags,
|
||||
const bool is_normal_transfer);
|
||||
/**
|
||||
@@ -145,16 +155,37 @@ std::vector<std::set<std::size_t>> form_preferred_input_candidate_subsets(
|
||||
* function is to determine the order in which we should try to select a certain number of inputs.
|
||||
*/
|
||||
std::vector<std::size_t> get_input_counts_in_preferred_order();
|
||||
|
||||
/**
|
||||
* brief: make_single_transfer_input_selector - a customizable input selector for single (i.e. not batched) transfers
|
||||
* param: input_candidates -
|
||||
* param: policies - slice of ISPs to attempt selection on, in order of user's preference
|
||||
* param: flags - see InputSelectionFlags namespace
|
||||
* outparam: selected_input_indices_out - selected indices into `input_candidates` (optional)
|
||||
* return: input selector functor
|
||||
*
|
||||
* The returned input selector considers provided input candidates, and creates subsets of the
|
||||
* candidates as according to `form_preferred_input_candidate_subsets`. Then, in the order of input
|
||||
* counts as according to `get_input_counts_in_preferred_order`, finds the first pair (subset, input
|
||||
* count) that contains enough "usable" money: a sum of money great enough to pay the nominal output
|
||||
* sum, plus any required fees as according to the input count. Once that is found, ISPs are
|
||||
* dispatched in provided user order until one succeeds. If none succeed for that pair, then the
|
||||
* whole of input selection fails, we do not move onto the next (subset, input count) pair.
|
||||
*
|
||||
* SAFETY: The lifetime of objects referenced by `input_candidates` and `selected_input_indices_out`
|
||||
* (if not null) must be valid at least as long as as the last call to the returned functor.
|
||||
*/
|
||||
select_inputs_func_t make_single_transfer_input_selector(
|
||||
const epee::span<const CarrotPreSelectedInput> input_candidates,
|
||||
const epee::span<const InputCandidate> input_candidates,
|
||||
const epee::span<const input_selection_policy_t> policies,
|
||||
const std::uint32_t flags,
|
||||
std::set<size_t> *selected_input_indices_out);
|
||||
|
||||
namespace ispolicy
|
||||
{
|
||||
void select_greedy_aging(const epee::span<const CarrotPreSelectedInput>,
|
||||
/**
|
||||
* brief: select_greedy_aging - an ISP which generally attempts to select old outputs, but isn't necessarily optimal
|
||||
*/
|
||||
void select_greedy_aging(const epee::span<const InputCandidate>,
|
||||
const std::set<std::size_t>&,
|
||||
std::size_t,
|
||||
const boost::multiprecision::uint128_t&,
|
||||
|
||||
@@ -39,9 +39,14 @@
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
/**
|
||||
* brief: subaddress_index -
|
||||
*/
|
||||
struct subaddress_index
|
||||
{
|
||||
// j_major
|
||||
std::uint32_t major;
|
||||
// j_minor
|
||||
std::uint32_t minor;
|
||||
|
||||
bool is_subaddress() const
|
||||
@@ -58,6 +63,9 @@ static inline bool operator!=(const subaddress_index a, const subaddress_index b
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/**
|
||||
* brief: AddressDeriveType - used in hybrid key hierarchies to specify how to derive subaddresses for the same index
|
||||
*/
|
||||
enum class AddressDeriveType
|
||||
{
|
||||
Auto,
|
||||
|
||||
@@ -40,18 +40,39 @@
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
/**
|
||||
* brief: get_output_enote_proposals_from_proposal_v1 - get_output_enote_proposals for transaction proposals
|
||||
* param: tx_proposal - transaction proposal
|
||||
* param: s_view_balance_dev - device for s_vb (optional)
|
||||
* param: k_view_dev - device for k_v (optional)
|
||||
* outparam: output_enote_proposals_out - resultant output enote set
|
||||
* putparam: encrypted_payment_id_out - resultant pid_enc
|
||||
* outparam: payment_proposal_order_out - order of payment proposals in resultant output enote set
|
||||
*/
|
||||
void get_output_enote_proposals_from_proposal_v1(const CarrotTransactionProposalV1 &tx_proposal,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_dev,
|
||||
std::vector<RCTOutputEnoteProposal> &output_enote_proposals_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out,
|
||||
std::vector<std::pair<bool, std::size_t>> *payment_proposal_order_out = nullptr);
|
||||
|
||||
/**
|
||||
* brief: make_signable_tx_hash_from_proposal_v1 - make signable transaction hash from tx proposal and keys
|
||||
* param: tx_proposal - transaction proposal
|
||||
* param: s_view_balance_dev - device for s_vb (optional)
|
||||
* param: k_view_dev - device for k_v (optional)
|
||||
* outparam: signable_tx_hash_out - signable transaction hash
|
||||
*/
|
||||
void make_signable_tx_hash_from_proposal_v1(const CarrotTransactionProposalV1 &tx_proposal,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_dev,
|
||||
crypto::hash &signable_tx_hash_out);
|
||||
|
||||
/**
|
||||
* brief: make_pruned_transaction_from_proposal_v1 - make pruned Carrot/FCMP++ transaction from tx proposal and keys
|
||||
* param: tx_proposal - transaction proposal
|
||||
* param: s_view_balance_dev - device for s_vb (optional)
|
||||
* param: k_view_dev - device for k_v (optional)
|
||||
* outparam: pruned_tx_out - pruned Carrot/FCMP++ transaction represented by transaction proposal
|
||||
*/
|
||||
void make_pruned_transaction_from_proposal_v1(const CarrotTransactionProposalV1 &tx_proposal,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const view_incoming_key_device *k_view_dev,
|
||||
|
||||
@@ -41,6 +41,12 @@
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
/**
|
||||
* brief: CarrotPaymentProposalVerifiableSelfSendV1 - A selfsend payment proposal, verified to an owned address
|
||||
*
|
||||
* The `subaddr_index` field is intended to be be used to derive
|
||||
* `proposal.destination_address_spend_pubkey`, without the need for a subaddress lookahead table.
|
||||
*/
|
||||
struct CarrotPaymentProposalVerifiableSelfSendV1
|
||||
{
|
||||
CarrotPaymentProposalSelfSendV1 proposal;
|
||||
@@ -48,7 +54,17 @@ struct CarrotPaymentProposalVerifiableSelfSendV1
|
||||
};
|
||||
|
||||
/**
|
||||
* brief: CarrotTransactionProposalV1
|
||||
* brief: CarrotTransactionProposalV1 - A specification on how to construct a Carrot transaction, minus key material
|
||||
*
|
||||
* The fields in `CarrotTransactionProposalV1` are chosen as what is the absolute minimum amount of
|
||||
* information required to verifiably, in a human-meaningful way, reconstruct the "signable
|
||||
* transaction hash". The signable transaction hash, (usually written `signable_tx_hash` in code),
|
||||
* is the actual 32-byte message that the FCMP++ Spend-Authorization & Linkability (SA/L) proofs
|
||||
* sign and verify against. In situations where the signing device may be separate from the device
|
||||
* formulating the transaction (e.g. cold signing, hardware devices, multisig, etc), this struct
|
||||
* can be passed amongst signers so that the signers can actually verifying what they are signing.
|
||||
*
|
||||
* For exact details on what goes into the signable transaction hash, see `rct::get_pre_mlsag_hash`.
|
||||
*/
|
||||
struct CarrotTransactionProposalV1
|
||||
{
|
||||
|
||||
@@ -70,13 +70,8 @@ static void append_additional_payment_proposal_if_necessary(
|
||||
|
||||
bool have_payment_type_selfsend = false;
|
||||
for (const CarrotPaymentProposalVerifiableSelfSendV1 &selfsend_payment_proposal : selfsend_payment_proposals_inout)
|
||||
{
|
||||
if (selfsend_payment_proposal.proposal.enote_type == CarrotEnoteType::PAYMENT)
|
||||
{
|
||||
have_payment_type_selfsend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto additional_output_proposal = get_additional_output_proposal(normal_payment_proposals_inout.size(),
|
||||
selfsend_payment_proposals_inout.size(),
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//! @file Utilities for creating Carrot transaction proposals
|
||||
|
||||
#pragma once
|
||||
|
||||
//local headers
|
||||
|
||||
@@ -211,8 +211,8 @@ carrot::select_inputs_func_t make_wallet2_single_transfer_input_selector(
|
||||
const bool allow_pre_carrot_inputs_in_normal_transfers,
|
||||
std::set<size_t> &selected_transfer_indices_out)
|
||||
{
|
||||
// Collect transfer_container into a `std::vector<carrot::CarrotPreSelectedInput>` for usable inputs
|
||||
std::vector<carrot::CarrotPreSelectedInput> input_candidates;
|
||||
// Collect transfer_container into a `std::vector<carrot::InputCandidate>` for usable inputs
|
||||
std::vector<carrot::InputCandidate> input_candidates;
|
||||
std::vector<size_t> input_candidates_transfer_indices;
|
||||
input_candidates.reserve(transfers.size());
|
||||
input_candidates_transfer_indices.reserve(transfers.size());
|
||||
@@ -226,7 +226,7 @@ carrot::select_inputs_func_t make_wallet2_single_transfer_input_selector(
|
||||
ignore_below,
|
||||
top_block_index))
|
||||
{
|
||||
input_candidates.push_back(carrot::CarrotPreSelectedInput{
|
||||
input_candidates.push_back(carrot::InputCandidate{
|
||||
.core = carrot::CarrotSelectedInput{
|
||||
.amount = td.amount(),
|
||||
.key_image = td.m_key_image
|
||||
|
||||
Reference in New Issue
Block a user