carrot+fcmp: changes to pending_tx for Carrot construction

This commit is contained in:
jeffro256
2025-04-19 21:31:13 -05:00
committed by akildemir
parent 724e2739d4
commit c4ca673074
10 changed files with 383 additions and 71 deletions
+45
View File
@@ -0,0 +1,45 @@
// Copyright (c) 2024, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// 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.
#pragma once
// Check for __VA_OPT__ support
// Apdated from cpplearner's StackOverflow answer: https://stackoverflow.com/a/48045656
#define PP_THIRD_ARG(a,b,c,...) c
#define VA_OPT_SUPPORTED_I(...) PP_THIRD_ARG(__VA_OPT__(,),true,false,)
#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?)
// VA_ARGS_COMMAPREFIX(): VA_ARGS_COMMAPREFIX(__VA_ARGS__) expands to __VA_ARGS__ with a comma in
// front if more than one argument, else nothing.
// If __VA_OPT__ supported, use that. Else, use GCC's ,## hack
#if VA_OPT_SUPPORTED
# define VA_ARGS_COMMAPREFIX(...) __VA_OPT__(,) __VA_ARGS__
#else
# define VA_ARGS_COMMAPREFIX(...) , ## __VA_ARGS__
#endif
+27
View File
@@ -50,6 +50,8 @@
#include <boost/type_traits/integral_constant.hpp>
#include <boost/mpl/bool.hpp>
#include "common/va_args.h"
/*! \struct is_blob_type
*
* \brief a descriptor for dispatching serialize
@@ -139,6 +141,19 @@ inline bool do_serialize(Archive &ar, bool &v)
template <bool W, template <bool> class Archive> \
bool do_serialize_object(Archive<W> &ar){
/*! \macro BEGIN_SERIALIZE_OBJECT_FN
*
* \brief Begins the environment of the DSL as a free function in object-style
*
* Inside, instead of FIELD() and VARINT_FIELD(), use FIELD_F() and
* VARINT_FIELD_F(). Otherwise, this macro is similar to
* BEGIN_SERIALIZE_OBJECT(), as you should list only field serializations.
*/
#define BEGIN_SERIALIZE_OBJECT_FN(stype, ...) \
template <bool W, template <bool> class Archive> \
bool do_serialize_object(Archive<W> &ar, stype &v VA_ARGS_COMMAPREFIX(__VA_ARGS__)) {
/*! \macro PREPARE_CUSTOM_VECTOR_SERIALIZATION
*/
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \
@@ -173,6 +188,12 @@ inline bool do_serialize(Archive &ar, bool &v)
if (!r || !ar.good()) return false; \
} while(0);
/*! \macro FIELD_F(f)
*
* \brief tags the field with the variable name and then serializes it (for use in a free function)
*/
#define FIELD_F(f, ...) FIELD_N(#f, v.f VA_ARGS_COMMAPREFIX(__VA_ARGS__))
/*! \macro FIELDS(f)
*
* \brief does not add a tag to the serialized value
@@ -204,6 +225,12 @@ inline bool do_serialize(Archive &ar, bool &v)
if (!ar.good()) return false; \
} while(0);
/*! \macro VARINT_FIELD_F(f)
*
* \brief tags and serializes the varint \a f (for use in a free function)
*/
#define VARINT_FIELD_F(f) VARINT_FIELD_N(#f, v.f)
/*! \macro MAGIC_FIELD(m)
*/
#define MAGIC_FIELD(m) \
+16 -7
View File
@@ -73,6 +73,7 @@
#include "common/json_util.h"
#include "ringct/rctSigs.h"
#include "multisig/multisig.h"
#include "wallet/tx_builder.h"
#include "wallet/wallet_args.h"
#include "version.h"
#include <stdexcept>
@@ -1480,7 +1481,10 @@ bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, b
bool simple_wallet::accept_loaded_tx(const tools::wallet2::multisig_tx_set &txs)
{
std::string extra_message;
return accept_loaded_tx([&txs](){return txs.m_ptx.size();}, [&txs](size_t n)->const tools::wallet2::tx_construction_data&{return txs.m_ptx[n].construction_data;}, extra_message);
return accept_loaded_tx(
[&txs](){return txs.m_ptx.size();},
[&txs](size_t n)->const auto&{return std::get<tools::wallet2::tx_construction_data>(txs.m_ptx[n].construction_data);},
extra_message);
}
bool simple_wallet::sign_multisig(const std::vector<std::string> &args)
@@ -6669,7 +6673,9 @@ bool simple_wallet::process_ring_members(const std::vector<tools::wallet2::pendi
for (size_t n = 0; n < ptx_vector.size(); ++n)
{
const cryptonote::transaction& tx = ptx_vector[n].tx;
const tools::wallet2::tx_construction_data& construction_data = ptx_vector[n].construction_data;
if (tx.rct_signatures.type >= rct::RCTTypeFcmpPlusPlus)
continue;
const auto& construction_data = std::get<tools::wallet2::tx_construction_data>(ptx_vector[n].construction_data);
if (verbose)
ostr << boost::format(tr("\nTransaction %llu/%llu: txid=%s")) % (n + 1) % ptx_vector.size() % cryptonote::get_transaction_hash(tx);
// for each input
@@ -7284,8 +7290,8 @@ bool simple_wallet::transfer_main(
{
prompt << tr("\nTransaction ") << (n + 1) << "/" << ptx_vector.size() << ":\n";
subaddr_indices.clear();
for (uint32_t i : ptx_vector[n].construction_data.subaddr_indices)
subaddr_indices.insert(i);
for (const std::size_t selected_transfer : ptx_vector.at(n).selected_transfers)
subaddr_indices.insert(m_wallet->get_transfer_details(selected_transfer).m_subaddr_index.minor);
for (uint32_t i : subaddr_indices)
prompt << boost::format(tr("Spending from address index %d\n")) % i;
if (subaddr_indices.size() > 1)
@@ -7847,8 +7853,8 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
{
prompt << tr("\nTransaction ") << (n + 1) << "/" << ptx_vector.size() << ":\n";
subaddr_indices.clear();
for (uint32_t i : ptx_vector[n].construction_data.subaddr_indices)
subaddr_indices.insert(i);
for (const std::size_t selected_transfer : ptx_vector.at(n).selected_transfers)
subaddr_indices.insert(m_wallet->get_transfer_details(selected_transfer).m_subaddr_index.minor);
for (uint32_t i : subaddr_indices)
prompt << boost::format(tr("Spending from address index %d\n")) % i;
if (subaddr_indices.size() > 1)
@@ -8976,7 +8982,10 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::signed_tx_set &txs)
std::string extra_message;
if (!txs.key_images.empty())
extra_message = (boost::format("%u key images to import. ") % (unsigned)txs.key_images.size()).str();
return accept_loaded_tx([&txs](){return txs.ptx.size();}, [&txs](size_t n)->const tools::wallet2::tx_construction_data&{return txs.ptx[n].construction_data;}, extra_message);
return accept_loaded_tx(
[&txs](){return txs.ptx.size();},
[&txs](size_t n)->const auto&{return std::get<tools::wallet2::tx_construction_data>(txs.ptx[n].construction_data);},
extra_message);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
+14 -2
View File
@@ -200,7 +200,13 @@ std::vector<uint32_t> PendingTransactionImpl::subaddrAccount() const
{
std::vector<uint32_t> result;
for (const auto& ptx : m_pending_tx)
result.push_back(ptx.construction_data.subaddr_account);
{
const auto *pre_carrot_constr_data = std::get_if<tools::wallet2::tx_construction_data>(&ptx.construction_data);
if (nullptr != pre_carrot_constr_data)
result.push_back(pre_carrot_constr_data->subaddr_account);
else
result.push_back(ptx.subaddr_account);
}
return result;
}
@@ -208,7 +214,13 @@ std::vector<std::set<uint32_t>> PendingTransactionImpl::subaddrIndices() const
{
std::vector<std::set<uint32_t>> result;
for (const auto& ptx : m_pending_tx)
result.push_back(ptx.construction_data.subaddr_indices);
{
const auto *pre_carrot_constr_data = std::get_if<tools::wallet2::tx_construction_data>(&ptx.construction_data);
if (nullptr != pre_carrot_constr_data)
result.push_back(pre_carrot_constr_data->subaddr_indices);
else
result.push_back(ptx.subaddr_indices);
}
return result;
}
+128 -4
View File
@@ -381,8 +381,6 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
const std::vector<uint8_t> &extra,
const std::uint32_t subaddr_account,
const std::set<uint32_t> &subaddr_indices,
const rct::xmr_amount ignore_above,
const rct::xmr_amount ignore_below,
const wallet2::unique_index_container &subtract_fee_from_outputs)
{
wallet2::transfer_container transfers;
@@ -407,8 +405,8 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
extra,
subaddr_account,
subaddr_indices,
ignore_above,
ignore_below,
w.ignore_outputs_above(),
w.ignore_outputs_below(),
subtract_fee_from_outputs,
top_block_index,
w.get_account().get_keys());
@@ -663,5 +661,131 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
top_block_index,
w.get_account().get_keys());
}
//-------------------------------------------------------------------------------------------------------------------
wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionProposalV1 &tx_proposal,
const wallet2::transfer_container &transfers,
const cryptonote::account_keys &acc_keys)
{
const std::size_t n_inputs = tx_proposal.key_images_sorted.size();
const std::size_t n_outputs = tx_proposal.normal_payment_proposals.size() +
tx_proposal.selfsend_payment_proposals.size();
const bool shared_ephemeral_pubkey = n_outputs == 2;
const crypto::key_image &tx_first_key_image = tx_proposal.key_images_sorted.at(0);
// collect non-burned transfers
const std::unordered_map<crypto::key_image, std::size_t> unburned_transfers_by_key_image =
collect_non_burned_transfers_by_key_image(transfers);
// collect selected_transfers and key_images string
std::vector<std::size_t> selected_transfers;
selected_transfers.reserve(n_inputs);
std::stringstream key_images_string;
for (size_t i = 0; i < n_inputs; ++i)
{
const crypto::key_image &ki = tx_proposal.key_images_sorted.at(i);
const auto ki_it = unburned_transfers_by_key_image.find(ki);
CHECK_AND_ASSERT_THROW_MES(ki_it != unburned_transfers_by_key_image.cend(),
"make_pending_carrot_tx: unrecognized key image in transfers list");
selected_transfers.push_back(ki_it->second);
if (i)
key_images_string << ' ';
key_images_string << ki;
}
//! @TODO: HW device
carrot::view_incoming_key_ram_borrowed_device k_view_dev(acc_keys.m_view_secret_key);
// get order of payment proposals
std::vector<carrot::RCTOutputEnoteProposal> output_enote_proposals;
carrot::encrypted_payment_id_t encrypted_payment_id;
std::vector<std::pair<bool, std::size_t>> sorted_payment_proposal_indices;
carrot::get_output_enote_proposals_from_proposal_v1(tx_proposal,
/*s_view_balance_dev=*/nullptr,
&k_view_dev,
output_enote_proposals,
encrypted_payment_id,
&sorted_payment_proposal_indices);
// calculate change_dst index based whether 2-out tx has a dummy output
// change_dst is set to dummy in 2-out self-send, otherwise last self-send
const bool has_2out_dummy = n_outputs == 2
&& tx_proposal.normal_payment_proposals.size() == 1
&& tx_proposal.normal_payment_proposals.at(0).amount == 0;
CHECK_AND_ASSERT_THROW_MES(!tx_proposal.selfsend_payment_proposals.empty(),
"make_pending_carrot_tx: carrot tx proposal missing a self-send proposal");
const std::pair<bool, std::size_t> change_dst_index{!has_2out_dummy,
has_2out_dummy ? 0 : tx_proposal.selfsend_payment_proposals.size()-1};
// collect destinations and private tx keys for normal enotes
//! @TODO: payment proofs for special self-send, perhaps generate d_e deterministically
cryptonote::tx_destination_entry change_dts;
std::vector<cryptonote::tx_destination_entry> dests;
std::vector<crypto::secret_key> ephemeral_privkeys;
dests.reserve(n_outputs);
ephemeral_privkeys.reserve(n_outputs);
for (const std::pair<bool, std::size_t> &payment_idx : sorted_payment_proposal_indices)
{
cryptonote::tx_destination_entry dest;
const bool is_selfsend = payment_idx.first;
if (is_selfsend)
{
dest = make_tx_destination_entry(tx_proposal.selfsend_payment_proposals.at(payment_idx.second),
k_view_dev);
ephemeral_privkeys.push_back(crypto::null_skey);
}
else // !is_selfsend
{
const carrot::CarrotPaymentProposalV1 &normal_payment_proposal =
tx_proposal.normal_payment_proposals.at(payment_idx.second);
dest = make_tx_destination_entry(normal_payment_proposal);
ephemeral_privkeys.push_back(carrot::get_enote_ephemeral_privkey(normal_payment_proposal,
carrot::make_carrot_input_context(tx_first_key_image)));
}
if (payment_idx == change_dst_index)
change_dts = dest;
else
dests.push_back(dest);
}
// collect subaddr account and minor indices
const std::uint32_t subaddr_account = transfers.at(selected_transfers.at(0)).m_subaddr_index.major;
std::set<std::uint32_t> subaddr_indices;
for (const size_t selected_transfer : selected_transfers)
{
const wallet2::transfer_details &td = transfers.at(selected_transfer);
const std::uint32_t other_subaddr_account = td.m_subaddr_index.major;
if (other_subaddr_account != subaddr_account)
{
MWARNING("make_pending_carrot_tx: conflicting account indices: " << subaddr_account << " vs "
<< other_subaddr_account);
}
subaddr_indices.insert(td.m_subaddr_index.minor);
}
wallet2::pending_tx ptx;
ptx.tx.set_null();
ptx.dust = 0;
ptx.fee = tx_proposal.fee;
ptx.dust_added_to_fee = false;
ptx.change_dts = change_dts;
ptx.selected_transfers = std::move(selected_transfers);
ptx.key_images = key_images_string.str();
ptx.tx_key = shared_ephemeral_pubkey ? ephemeral_privkeys.at(0) : crypto::null_skey;
if (shared_ephemeral_pubkey)
ptx.additional_tx_keys = std::move(ephemeral_privkeys);
else
ptx.additional_tx_keys.clear();
ptx.dests = std::move(dests);
ptx.multisig_sigs = {};
ptx.multisig_tx_key_entropy = {};
ptx.subaddr_account = subaddr_account;
ptx.subaddr_indices = std::move(subaddr_indices);
ptx.construction_data = tx_proposal;
return ptx;
}
//-------------------------------------------------------------------------------------------------------------------
} //namespace wallet
} //namespace tools
+3 -2
View File
@@ -76,8 +76,6 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
const std::vector<uint8_t> &extra,
const std::uint32_t subaddr_account,
const std::set<uint32_t> &subaddr_indices,
const rct::xmr_amount ignore_above,
const rct::xmr_amount ignore_below,
const wallet2::unique_index_container &subtract_fee_from_outputs);
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep(
@@ -123,5 +121,8 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
const std::vector<uint8_t> &extra,
const std::uint32_t subaddr_account,
const std::set<uint32_t> &subaddr_indices);
wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionProposalV1 &tx_proposal,
const wallet2::transfer_container &transfers,
const cryptonote::account_keys &acc_keys);
} //namespace wallet
} //namespace tools
+106 -49
View File
@@ -923,9 +923,25 @@ bool get_short_payment_id(crypto::hash8 &payment_id8, const tools::wallet2::pend
return false;
}
static const tools::wallet2::tx_construction_data &get_construction_data(const tools::wallet2::pending_tx &ptx)
{
THROW_WALLET_EXCEPTION_IF(!std::holds_alternative<tools::wallet2::tx_construction_data>(ptx.construction_data),
tools::error::wallet_internal_error,
"Getting pre-carrot construction data only works for pre-carrot pending txs");
return std::get<tools::wallet2::tx_construction_data>(ptx.construction_data);
}
static tools::wallet2::tx_construction_data &get_construction_data(tools::wallet2::pending_tx &ptx)
{
THROW_WALLET_EXCEPTION_IF(!std::holds_alternative<tools::wallet2::tx_construction_data>(ptx.construction_data),
tools::error::wallet_internal_error,
"Getting pre-carrot construction data only works for pre-carrot pending txs");
return std::get<tools::wallet2::tx_construction_data>(ptx.construction_data);
}
tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev)
{
tools::wallet2::tx_construction_data construction_data = ptx.construction_data;
tools::wallet2::tx_construction_data construction_data = get_construction_data(ptx);
crypto::hash8 payment_id = null_hash8;
if (get_short_payment_id(payment_id, ptx, hwdev))
{
@@ -2052,7 +2068,7 @@ bool wallet2::frozen(const multisig_tx_set& txs) const
std::unordered_set<crypto::key_image> kis_to_sign;
for (const auto& ptx : txs.m_ptx)
{
const tools::wallet2::tx_construction_data& cd = ptx.construction_data;
const tools::wallet2::tx_construction_data& cd = get_construction_data(ptx);
CHECK_AND_ASSERT_THROW_MES(cd.sources.size() == ptx.tx.vin.size(), "mismatched multisg tx set source sizes");
for (size_t src_idx = 0; src_idx < cd.sources.size(); ++src_idx)
{
@@ -7567,6 +7583,43 @@ void wallet2::commit_tx(pending_tx& ptx)
crypto::hash txid;
txid = get_transaction_hash(ptx.tx);
// if it's already processed, bail
if (std::find_if(m_transfers.begin(), m_transfers.end(), [&txid](const transfer_details &td) { return td.m_txid == txid; }) != m_transfers.end())
{
MDEBUG("Transaction " << txid << " already processed");
return;
}
if (m_unconfirmed_txs.find(txid) != m_unconfirmed_txs.end())
{
MDEBUG("Transaction " << txid << " already processed");
return;
}
if (m_confirmed_txs.find(txid) != m_confirmed_txs.end())
{
MDEBUG("Transaction " << txid << " already processed");
return;
}
// collect subaddr account and subaddr indices
std::optional<std::uint32_t> subaddr_account_opt;
std::set<std::uint32_t> subaddr_indices;
for (const size_t selected_transfer : ptx.selected_transfers)
{
const transfer_details &td = m_transfers.at(selected_transfer);
if (subaddr_account_opt && *subaddr_account_opt != td.m_subaddr_index.major)
{
MWARNING("Mismatched subaddr accounts in inputs: " << *subaddr_account_opt << " vs " << td.m_subaddr_index.major);
}
else
{
subaddr_account_opt = td.m_subaddr_index.major;
}
subaddr_indices.insert(td.m_subaddr_index.minor);
}
const std::uint32_t subaddr_account = subaddr_account_opt.value_or(0);
crypto::hash payment_id = crypto::null_hash;
std::vector<cryptonote::tx_destination_entry> dests;
uint64_t amount_in = 0;
@@ -7577,7 +7630,7 @@ void wallet2::commit_tx(pending_tx& ptx)
for(size_t idx: ptx.selected_transfers)
amount_in += m_transfers[idx].amount();
}
add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, subaddr_account, subaddr_indices);
if (store_tx_info() && ptx.tx_key != crypto::null_skey)
{
m_tx_keys[txid] = ptx.tx_key;
@@ -7601,8 +7654,8 @@ void wallet2::commit_tx(pending_tx& ptx)
//fee includes dust if dust policy specified it.
LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
<< "Commission: " << print_money(ptx.fee) << " (dust sent to dust addr: " << print_money((ptx.dust_added_to_fee ? 0 : ptx.dust)) << ")" << ENDL
<< "Balance: " << print_money(balance(ptx.construction_data.subaddr_account, source_asset, false)) << ENDL
<< "Unlocked: " << print_money(unlocked_balance(ptx.construction_data.subaddr_account, source_asset, false)) << ENDL
<< "Balance: " << print_money(balance(subaddr_account, source_asset, false)) << ENDL
<< "Unlocked: " << print_money(unlocked_balance(subaddr_account, source_asset, false)) << ENDL
<< "Please, wait for confirmation for your balance to be unlocked.");
}
@@ -8112,7 +8165,7 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs)
// txes generated, get rid of used k values
for (size_t n = 0; n < txs.m_ptx.size(); ++n)
for (size_t idx: txs.m_ptx[n].construction_data.selected_transfers)
for (size_t idx: get_construction_data(txs.m_ptx[n]).selected_transfers)
{
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
m_transfers[idx].m_multisig_k.clear();
@@ -8121,7 +8174,7 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs)
// zero out some data we don't want to share
for (auto &ptx: txs.m_ptx)
{
for (auto &e: ptx.construction_data.sources)
for (auto &e: get_construction_data(ptx).sources)
memwipe(&e.multisig_kLRki.k, sizeof(e.multisig_kLRki.k));
}
@@ -8234,10 +8287,10 @@ bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx
CHECK_AND_ASSERT_MES(ptx.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched selected_transfers/vin sizes");
for (size_t idx: ptx.selected_transfers)
CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range");
CHECK_AND_ASSERT_MES(ptx.construction_data.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched cd selected_transfers/vin sizes");
for (size_t idx: ptx.construction_data.selected_transfers)
CHECK_AND_ASSERT_MES(get_construction_data(ptx).selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched cd selected_transfers/vin sizes");
for (size_t idx: get_construction_data(ptx).selected_transfers)
CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range");
CHECK_AND_ASSERT_MES(ptx.construction_data.sources.size() == ptx.tx.vin.size(), false, "Mismatched sources/vin sizes");
CHECK_AND_ASSERT_MES(get_construction_data(ptx).sources.size() == ptx.tx.vin.size(), false, "Mismatched sources/vin sizes");
}
return true;
@@ -8325,7 +8378,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
{
tools::wallet2::pending_tx &ptx = exported_txs.m_ptx[n];
THROW_WALLET_EXCEPTION_IF(ptx.multisig_sigs.empty(), error::wallet_internal_error, "No signatures found in multisig tx");
const tools::wallet2::tx_construction_data &sd = ptx.construction_data;
tools::wallet2::tx_construction_data &sd = get_construction_data(ptx);
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << (sd.sources[0].outputs.size()) <<
", signed by " << exported_txs.m_signers.size() << "/" << m_multisig_threshold);
@@ -8335,17 +8388,17 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
THROW_WALLET_EXCEPTION_IF(
not multisig_tx_builder.init(
m_account.get_keys(),
ptx.construction_data.extra,
sd.extra,
ptx.tx.type,
get_current_hard_fork(),
ptx.construction_data.unlock_time,
ptx.construction_data.subaddr_account,
ptx.construction_data.subaddr_indices,
ptx.construction_data.sources,
ptx.construction_data.splitted_dsts,
ptx.construction_data.change_dts,
ptx.construction_data.rct_config,
ptx.construction_data.use_rct,
sd.unlock_time,
sd.subaddr_account,
sd.subaddr_indices,
sd.sources,
sd.splitted_dsts,
sd.change_dts,
sd.rct_config,
sd.use_rct,
true, //true = we are reconstructing the tx (it was first constructed by the tx proposer)
ptx.tx_key,
ptx.additional_tx_keys,
@@ -8419,7 +8472,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
{
THROW_WALLET_EXCEPTION_IF(found, error::wallet_internal_error, "More than one transaction is final");
THROW_WALLET_EXCEPTION_IF(
not multisig_tx_builder.finalize_tx(ptx.construction_data.sources, sig.c_0, sig.s, ptx.tx),
not multisig_tx_builder.finalize_tx(get_construction_data(ptx).sources, sig.c_0, sig.s, ptx.tx),
error::wallet_internal_error,
"error: multisig::signing::tx_builder_ringct_t::finalize_tx"
);
@@ -8441,7 +8494,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
// signatures generated, get rid of any unused k values (must do export_multisig() to make more tx attempts with the
// inputs in the transactions worked on here)
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers)
for (size_t idx: get_construction_data(exported_txs.m_ptx[n]).selected_transfers)
{
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
m_transfers[idx].m_multisig_k.clear();
@@ -9968,21 +10021,23 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
ptx.tx_key = tx_key;
ptx.additional_tx_keys = additional_tx_keys;
ptx.dests = dsts;
ptx.construction_data.sources = sources;
ptx.construction_data.change_dts = change_dts;
ptx.construction_data.splitted_dsts = splitted_dsts;
ptx.construction_data.selected_transfers = selected_transfers;
ptx.construction_data.extra = tx.extra;
ptx.construction_data.unlock_time = unlock_time;
ptx.construction_data.use_rct = false;
ptx.construction_data.rct_config = { rct::RangeProofBorromean, 0 };
ptx.construction_data.use_view_tags = use_view_tags;
ptx.construction_data.dests = dsts;
tx_construction_data pre_carrot_construction_data;
pre_carrot_construction_data.sources = sources;
pre_carrot_construction_data.change_dts = change_dts;
pre_carrot_construction_data.splitted_dsts = splitted_dsts;
pre_carrot_construction_data.selected_transfers = selected_transfers;
pre_carrot_construction_data.extra = tx.extra;
pre_carrot_construction_data.unlock_time = 0;
pre_carrot_construction_data.use_rct = false;
pre_carrot_construction_data.rct_config = { rct::RangeProofBorromean, 0 };
pre_carrot_construction_data.use_view_tags = use_view_tags;
pre_carrot_construction_data.dests = dsts;
// record which subaddress indices are being used as inputs
ptx.construction_data.subaddr_account = subaddr_account;
ptx.construction_data.subaddr_indices.clear();
pre_carrot_construction_data.subaddr_account = subaddr_account;
pre_carrot_construction_data.subaddr_indices.clear();
for (size_t idx: selected_transfers)
ptx.construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor);
pre_carrot_construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor);
ptx.construction_data = pre_carrot_construction_data;
LOG_PRINT_L2("transfer_selected done");
}
@@ -10368,24 +10423,26 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
ptx.dests = dsts;
ptx.multisig_sigs = multisig_sigs;
ptx.multisig_tx_key_entropy = multisig_tx_key_entropy;
ptx.construction_data.sources = sources_copy;
ptx.construction_data.change_dts = change_dts;
ptx.construction_data.splitted_dsts = splitted_dsts;
ptx.construction_data.selected_transfers = ptx.selected_transfers;
ptx.construction_data.extra = tx.extra;
ptx.construction_data.unlock_time = unlock_time;
ptx.construction_data.use_rct = true;
ptx.construction_data.rct_config = rct_config;/*{
tx_construction_data pre_carrot_construction_data;
pre_carrot_construction_data.sources = sources_copy;
pre_carrot_construction_data.change_dts = change_dts;
pre_carrot_construction_data.splitted_dsts = splitted_dsts;
pre_carrot_construction_data.selected_transfers = ptx.selected_transfers;
pre_carrot_construction_data.extra = tx.extra;
pre_carrot_construction_data.unlock_time = 0;
pre_carrot_construction_data.use_rct = true;
pre_carrot_construction_data.rct_config = rct_config; /*{
rct::RangeProofPaddedBulletproof,
use_fork_rules(HF_VERSION_BULLETPROOF_PLUS, -10) ? 4 : 3
};*/
ptx.construction_data.use_view_tags = use_view_tags;//use_fork_rules(get_view_tag_fork(), 0);
ptx.construction_data.dests = dsts;
};*/
pre_carrot_construction_data.use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
pre_carrot_construction_data.dests = dsts;
// record which subaddress indices are being used as inputs
ptx.construction_data.subaddr_account = subaddr_account;
ptx.construction_data.subaddr_indices.clear();
pre_carrot_construction_data.subaddr_account = subaddr_account;
pre_carrot_construction_data.subaddr_indices.clear();
for (size_t idx: selected_transfers)
ptx.construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor);
pre_carrot_construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor);
ptx.construction_data = pre_carrot_construction_data;
LOG_PRINT_L2("transfer_selected_rct done");
}
+42 -5
View File
@@ -41,11 +41,13 @@
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/std_variant_shim.hpp>
#include <boost/thread/lock_guard.hpp>
#include <atomic>
#include <random>
#include "include_base_utils.h"
#include "carrot_impl/carrot_offchain_serialization.h"
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/account_boost_serialization.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
@@ -697,11 +699,17 @@ private:
std::vector<cryptonote::tx_destination_entry> dests;
std::vector<multisig_sig> multisig_sigs;
crypto::secret_key multisig_tx_key_entropy;
uint32_t subaddr_account; // subaddress account of your wallet to be used in this transfer
std::set<uint32_t> subaddr_indices; // set of address indices used as inputs in this transfer
tx_construction_data construction_data;
using tx_reconstruct_variant_t = std::variant<
tx_construction_data,
carrot::CarrotTransactionProposalV1
>;
tx_reconstruct_variant_t construction_data;
BEGIN_SERIALIZE_OBJECT()
VERSION_FIELD(1)
VERSION_FIELD(2)
FIELD(tx)
FIELD(dust)
FIELD(fee)
@@ -712,7 +720,20 @@ private:
FIELD(tx_key)
FIELD(additional_tx_keys)
FIELD(dests)
FIELD(construction_data)
if (version < 2)
{
tx_construction_data pre_carrot_construction_data;
FIELD_N("construction_data", pre_carrot_construction_data)
construction_data = pre_carrot_construction_data;
subaddr_account = pre_carrot_construction_data.subaddr_account;
subaddr_indices = pre_carrot_construction_data.subaddr_indices;
}
else // version >= 2
{
FIELD(construction_data)
FIELD(subaddr_account)
FIELD(subaddr_indices)
}
FIELD(multisig_sigs)
if (version < 1)
{
@@ -2229,7 +2250,7 @@ BOOST_CLASS_VERSION(tools::wallet2::reserve_proof_entry, 0)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 1)
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1)
BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 4)
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3)
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 4)
BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 1)
BOOST_CLASS_VERSION(tools::wallet2::background_synced_tx_t, 0)
BOOST_CLASS_VERSION(tools::wallet2::background_sync_data_t, 0)
@@ -2730,7 +2751,16 @@ namespace boost
a & x.key_images;
a & x.tx_key;
a & x.dests;
a & x.construction_data;
if (ver < 4)
{
tools::wallet2::tx_construction_data pre_carrot_construction_data;
a & pre_carrot_construction_data;
x.construction_data = pre_carrot_construction_data;
}
else // ver >= 4
{
a & x.construction_data;
}
if (ver < 1)
return;
a & x.additional_tx_keys;
@@ -2740,6 +2770,10 @@ namespace boost
if (ver < 3)
return;
a & x.multisig_sigs;
if (ver < 4)
return;
a & x.subaddr_account;
a & x.subaddr_indices;
}
template <class Archive>
@@ -2822,3 +2856,6 @@ namespace tools
}
//----------------------------------------------------------------------------------------------------
}
VARIANT_TAG(binary_archive, tools::wallet2::tx_construction_data, 0x21);
VARIANT_TAG(binary_archive, carrot::CarrotTransactionProposalV1, 0x22);
+1 -1
View File
@@ -1518,7 +1518,7 @@ namespace tools
}
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n) {
tx_constructions.push_back(exported_txs.m_ptx[n].construction_data);
tx_constructions.push_back(std::get<tools::wallet2::tx_construction_data>(exported_txs.m_ptx[n].construction_data));
}
}
catch (const std::exception &e) {