carrot+fcmp: changes to pending_tx for Carrot construction
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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_)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user