Merge branch 'carrot-integration' of https://github.com/salvium/salvium into carrot-integration
This commit is contained in:
@@ -160,8 +160,8 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
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,
|
||||
size_t change_index_out)
|
||||
size_t &change_index_out,
|
||||
std::vector<std::pair<bool, std::size_t>> *payment_proposal_order_out)
|
||||
{
|
||||
output_enote_proposals_out.clear();
|
||||
encrypted_payment_id_out = {{0}};
|
||||
|
||||
@@ -110,8 +110,8 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
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,
|
||||
size_t change_index_out = 0);
|
||||
size_t &change_index_out,
|
||||
std::vector<std::pair<bool, std::size_t>> *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 -
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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 <class EnoteContainer>
|
||||
static void store_carrot_ephemeral_pubkeys_to_extra(const EnoteContainer &enotes, std::vector<uint8_t> &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,
|
||||
@@ -191,11 +195,13 @@ bool try_load_carrot_extra_v1(
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotEnoteV1> &enotes,
|
||||
const std::vector<crypto::key_image> &key_images,
|
||||
const std::vector<cryptonote::tx_source_entry> &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;
|
||||
@@ -210,13 +216,19 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
tx.rct_signatures.outPk.reserve(nouts);
|
||||
|
||||
//inputs
|
||||
for (const crypto::key_image &ki : key_images)
|
||||
for (size_t i = 0; i < nins; ++i)
|
||||
{
|
||||
// collect key offsets
|
||||
std::vector<uint64_t> 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"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -227,7 +239,8 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
tx.vout.push_back(cryptonote::tx_out{0, cryptonote::txout_to_carrot_v1{
|
||||
.key = enote.onetime_address,
|
||||
.view_tag = enote.view_tag,
|
||||
.encrypted_janus_anchor = enote.anchor_enc
|
||||
.encrypted_janus_anchor = enote.anchor_enc,
|
||||
.asset_type = enote.asset_type,
|
||||
}});
|
||||
|
||||
//a_enc
|
||||
@@ -360,11 +373,11 @@ bool try_load_carrot_from_transaction_v1(const cryptonote::transaction &tx,
|
||||
cryptonote::transaction store_carrot_to_coinbase_transaction_v1(
|
||||
const std::vector<CarrotCoinbaseEnoteV1> &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;
|
||||
@@ -427,7 +440,7 @@ cryptonote::transaction make_single_enote_carrot_coinbase_transaction_v1(const C
|
||||
std::vector<CarrotCoinbaseEnoteV1> 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,
|
||||
|
||||
@@ -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<CarrotEnoteV1> &enotes,
|
||||
const std::vector<crypto::key_image> &key_images,
|
||||
const std::vector<cryptonote::tx_source_entry> &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<CarrotCoinbaseEnoteV1> &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 -
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<crypto::key_image> key_images_sorted;
|
||||
// sources in the same order as key_images_sorted.
|
||||
std::vector<cryptonote::tx_source_entry> sources;
|
||||
|
||||
/// Payment proposals to be converted into output enotes
|
||||
std::vector<CarrotPaymentProposalV1> normal_payment_proposals;
|
||||
|
||||
@@ -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<CarrotPaymentProposalV1> &normal_payment_proposals_in,
|
||||
const std::vector<CarrotPaymentProposalVerifiableSelfSendV1> &selfsend_payment_proposals_in,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &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<CarrotPaymentProposal
|
||||
std::map<size_t, rct::xmr_amount> 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<uint64_t>::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<uint64_t>::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<CarrotPaymentProposalV1> &normal_payment_proposals,
|
||||
const std::vector<CarrotPaymentProposalVerifiableSelfSendV1> &selfsend_payment_proposals_in,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &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_func_t>(select_inputs),
|
||||
std::move(carve_fees_and_balance),
|
||||
@@ -399,6 +396,7 @@ void make_carrot_transaction_proposal_v1_sweep(
|
||||
const std::vector<CarrotPaymentProposalV1> &normal_payment_proposals,
|
||||
const std::vector<CarrotPaymentProposalVerifiableSelfSendV1> &selfsend_payment_proposals,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
std::vector<CarrotSelectedInput> &&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),
|
||||
|
||||
@@ -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<<log_padded_outputs) < n_outputs)
|
||||
++log_padded_outputs;
|
||||
size += (2 * (6 + log_padded_outputs) + (bulletproof_plus ? 6 : (4 + 5))) * 32 + 3;
|
||||
}
|
||||
else
|
||||
size += (2*64*32+32+64*32) * n_outputs;
|
||||
|
||||
// MGs/CLSAGs
|
||||
if (clsag)
|
||||
size += n_inputs * (64 * (mixin+1) + 64);
|
||||
else
|
||||
size += n_inputs * (64 * (mixin+1) + 32);
|
||||
|
||||
if (use_view_tags)
|
||||
size += n_outputs * sizeof(crypto::view_tag);
|
||||
|
||||
// mixRing - not serialized, can be reconstructed
|
||||
/* size += 2 * 32 * (mixin+1) * n_inputs; */
|
||||
|
||||
// pseudoOuts
|
||||
size += 32 * n_inputs;
|
||||
// ecdhInfo
|
||||
size += 8 * n_outputs;
|
||||
// outPk - only commitment is saved
|
||||
size += 32 * n_outputs;
|
||||
// txnFee
|
||||
size += 4;
|
||||
// p_r
|
||||
size += 32;
|
||||
|
||||
// 2 zk proof
|
||||
size += (2 * 96);
|
||||
|
||||
LOG_PRINT_L2("estimated " << (bulletproof_plus ? "bulletproof plus" : bulletproof ? "bulletproof" : "borromean") << " rct tx size for " << n_inputs << " inputs with ring size " << (mixin+1) << " and " << n_outputs << " outputs: " << size << " (" << ((32 * n_inputs/*+1*/) + 2 * 32 * (mixin+1) * n_inputs + 32 * n_outputs) << " saved)");
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t estimate_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)
|
||||
{
|
||||
return estimate_rct_tx_size_carrot(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags);
|
||||
}
|
||||
|
||||
static uint64_t estimate_tx_weigh_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 = estimate_tx_size_carrot(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags);
|
||||
if ((bulletproof || bulletproof_plus) && n_outputs > 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<<log_padded_outputs) < n_outputs)
|
||||
++log_padded_outputs;
|
||||
uint64_t nlr = 2 * (6 + log_padded_outputs);
|
||||
const uint64_t bp_size = 32 * ((bulletproof_plus ? 6 : 9) + nlr);
|
||||
const uint64_t bp_clawback = (bp_base * (1<<log_padded_outputs) - bp_size) * 4 / 5;
|
||||
MDEBUG("clawback on size " << size << ": " << bp_clawback);
|
||||
size += bp_clawback;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint64_t calculate_fee_from_weight_carrot(uint64_t base_fee, uint64_t weight, uint64_t fee_quantization_mask)
|
||||
{
|
||||
uint64_t fee = weight * base_fee;
|
||||
fee = (fee + fee_quantization_mask - 1) / fee_quantization_mask * fee_quantization_mask;
|
||||
return fee;
|
||||
}
|
||||
|
||||
static uint64_t estimate_fee_carrot(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask)
|
||||
{
|
||||
const size_t estimated_tx_weight = estimate_tx_weigh_carrot(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags);
|
||||
return calculate_fee_from_weight_carrot(base_fee, estimated_tx_weight, fee_quantization_mask);
|
||||
}
|
||||
|
||||
void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposalV1> &normal_payment_proposals,
|
||||
const std::vector<CarrotPaymentProposalVerifiableSelfSendV1> &selfsend_payment_proposals,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &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<CarrotPaymentProposalV1> &normal_payment_proposals,
|
||||
const std::vector<CarrotPaymentProposalVerifiableSelfSendV1> &selfsend_payment_proposals,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &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<CarrotPaymentProposalV1> &normal_payment_proposals,
|
||||
const std::vector<CarrotPaymentProposalVerifiableSelfSendV1> &selfsend_payment_proposals,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
std::vector<CarrotSelectedInput> &&selected_inputs,
|
||||
const crypto::public_key &change_address_spend_pubkey,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<txin_to_key>(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<txin_to_key>(tx.vin[n]).k_image);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)}))); }
|
||||
|
||||
@@ -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<txin_to_key>(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");
|
||||
|
||||
+21
-24
@@ -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<std::string> & destination_asset_types,
|
||||
const std::vector<xmr_amount> & inamounts,
|
||||
const std::vector<xmr_amount> & outamounts,
|
||||
xmr_amount txnFee,
|
||||
const ctkeyM & mixRing,
|
||||
const std::vector<unsigned int> & 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<std::string> & destination_asset_types,
|
||||
const std::vector<xmr_amount> & inamounts,
|
||||
const std::vector<xmr_amount> & outamounts,
|
||||
xmr_amount txnFee,
|
||||
const ctkeyM & mixRing,
|
||||
const std::vector<unsigned int> & 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++) {
|
||||
|
||||
@@ -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<xmr_amount> & 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<xmr_amount> & 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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
+154
-121
@@ -128,7 +128,8 @@ static bool build_payment_proposals(std::vector<carrot::CarrotPaymentProposalV1>
|
||||
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<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_transfer(
|
||||
std::vector<cryptonote::tx_source_entry> get_sources(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
const std::vector<std::size_t> &selected_transfers,
|
||||
const std::string &source_asset,
|
||||
wallet2 &w
|
||||
) {
|
||||
// get decoys
|
||||
const size_t fake_outputs_count = 15;
|
||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
|
||||
std::unordered_set<crypto::public_key> 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<cryptonote::tx_source_entry> 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<cryptonote::txin_to_key>(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<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_transfer(
|
||||
wallet2 &w,
|
||||
std::vector<cryptonote::tx_destination_entry> dsts,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const std::uint32_t subaddr_account,
|
||||
const uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &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<carrot::CarrotTransactionProposalV1> tx_proposals;
|
||||
tx_proposals.reserve(dsts.size() / (FCMP_PLUS_PLUS_MAX_OUTPUTS - 1) + 1);
|
||||
@@ -346,8 +447,8 @@ std::vector<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
subtractable_normal_payment_proposals,
|
||||
subtractable_selfsend_payment_proposals,
|
||||
tx_proposal);
|
||||
|
||||
// populate the sources
|
||||
std::vector<size_t> 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<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<uint8_t> &extra,
|
||||
const std::uint64_t top_block_index)
|
||||
{
|
||||
@@ -498,6 +609,7 @@ std::vector<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<uint8_t> &extra,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
@@ -591,6 +706,7 @@ std::vector<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<carrot::CarrotTransactionProposalV1> 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<cryptonote::tx_source_entry> get_sources(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const std::vector<std::size_t> &selected_transfers,
|
||||
const std::string &source_asset,
|
||||
const wallet2 &w
|
||||
) {
|
||||
// get decoys
|
||||
const size_t fake_outputs_count = 15;
|
||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
|
||||
std::unordered_set<crypto::public_key> valid_public_keys_cache;
|
||||
wallet2 &w2 = const_cast<tools::wallet2 &>(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<cryptonote::tx_source_entry> 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<cryptonote::txin_to_key>(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<std::size_t> &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<cryptonote::tx_source_entry> 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
|
||||
);
|
||||
|
||||
@@ -58,15 +58,13 @@ carrot::select_inputs_func_t make_wallet2_single_transfer_input_selector(
|
||||
std::set<size_t> &selected_transfer_indices_out);
|
||||
|
||||
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_transfer(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
wallet2 &w,
|
||||
std::vector<cryptonote::tx_destination_entry> dsts,
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &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<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_transfer(
|
||||
@@ -86,6 +84,7 @@ std::vector<carrot::CarrotTransactionProposalV1> 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<uint8_t> &extra,
|
||||
const std::uint64_t top_block_index);
|
||||
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep(
|
||||
@@ -105,6 +104,7 @@ std::vector<carrot::CarrotTransactionProposalV1> 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<uint8_t> &extra,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &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<std::size_t> &selected_transfers,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const wallet2 &w);
|
||||
|
||||
|
||||
@@ -2035,6 +2035,7 @@ private:
|
||||
public:
|
||||
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct, std::unordered_set<crypto::public_key> &valid_public_keys_cache);
|
||||
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, std::vector<uint64_t> &rct_offsets, std::unordered_set<crypto::public_key> &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<std::vector<tools::wallet2::get_outs_entry>> &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<crypto::public_key> &valid_public_keys_cache) const;
|
||||
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &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<crypto::hash> &txids);
|
||||
void sort_scan_tx_entries(std::vector<process_tx_entry_t> &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<crypto::hash> &tx_hashes_to_reprocess, detached_blockchain_data &dbd);
|
||||
|
||||
Reference in New Issue
Block a user