partial fix to the detection of return payments - ECDH is an issue again, but reversion to using F point should resolve this and complete the implementation

This commit is contained in:
Some Random Crypto Guy
2024-05-27 10:38:44 +01:00
parent 42d8dc5ece
commit e23423c16d
7 changed files with 449 additions and 99 deletions
@@ -419,6 +419,40 @@ namespace cryptonote
// 6. Create the key_image needed to be able to spend the output
hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
return true;
} else if (origin_tx_data.tx_type == (uint8_t)(cryptonote::transaction_type::TRANSFER)) {
// 1. Obtain P_change from the output (it is the subaddress public key)
crypto::public_key P_change = crypto::null_pkey;
//hwdev.derive_subaddress_public_key(out_key, recv_derivation, real_output_index, P_change);
hwdev.derive_subaddress_public_key(out_key, recv_derivation, origin_tx_data.uniqueness, P_change);
// 2. Obtain a separate key_derivation for the _original_ P_change output
// (using the TX public key from the CONVERT TX and the sender's private view key)
crypto::key_derivation derivation_P_change_tx = AUTO_VAL_INIT(derivation_P_change_tx);
CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(origin_tx_data.tx_pub_key, ack.m_view_secret_key, derivation_P_change_tx), false, "Failed to generate key_derivation for P_change");
// 3. Calculate the secret spend key "x_change" for the change output of the CONVERT TX
crypto::secret_key sk_spend = crypto::null_skey;
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation_P_change_tx, origin_tx_data.uniqueness, spend_skey, sk_spend), false, "Failed to derive secret key for P_change");
// 4. Derive the public key from the secret key for verification purposes
crypto::public_key change_pk;
CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(sk_spend, change_pk), false, "Failed to derive public key for P_change");
if (P_change == change_pk) {
// 5. Calculate the secret spend key "x_return"
//CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, real_output_index, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, origin_tx_data.uniqueness, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
in_ephemeral.sec = scalar_step1;
CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive one-time output public key 'P_return'");
if (in_ephemeral.pub == out_key) {
// 6. Create the key_image needed to be able to spend the output
hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
return true;
}
}
}
// computes Hs(a*R || uniqueness) + b
+41 -14
View File
@@ -812,7 +812,10 @@ namespace cryptonote
tx.extra = extra;
crypto::public_key txkey_pub;
tx.type = tx_type;
if (tx_type == cryptonote::transaction_type::RETURN)
tx.type = cryptonote::TRANSFER;
else
tx.type = tx_type;
// Set the source and destination asset_type values
tx.source_asset_type = source_asset;
@@ -993,10 +996,10 @@ namespace cryptonote
// we don't need to include additional tx keys if:
// - all the destinations are standard addresses
// - there's only one destination which is a subaddress
bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
bool need_additional_txkeys = (tx_type == cryptonote::transaction_type::RETURN) || (num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1));
if (need_additional_txkeys)
CHECK_AND_ASSERT_MES(destinations.size() == additional_tx_keys.size(), false, "Wrong amount of additional tx keys");
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
@@ -1030,25 +1033,32 @@ namespace cryptonote
// Get the uniqueness for this TX
CHECK_AND_ASSERT_MES(!tx.vin.empty(), false, "tx.vin[] is empty");
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), false, "incorrect tx.vin[0] type for YIELD TX");
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), false, "incorrect tx.vin[0] type");
crypto::key_image k_image = boost::get<cryptonote::txin_to_key>(tx.vin[0]).k_image;
ec_scalar uniqueness;
CHECK_AND_ASSERT_MES(calculate_uniqueness(tx.type, k_image, 0, output_index, uniqueness), false, "Failed to calculate uniqueness for the transaction");
hwdev.generate_output_ephemeral_keys(tx.version,sender_account_keys, txkey_pub, tx_key,
dst_entr, change_addr, output_index,
need_additional_txkeys, additional_tx_keys,
additional_tx_public_keys, amount_keys, out_eph_public_key,
use_view_tags, view_tag, uniqueness);
CHECK_AND_ASSERT_MES(calculate_uniqueness(tx_type == cryptonote::transaction_type::RETURN ? cryptonote::TRANSFER : tx_type, k_image, 0, output_index, uniqueness), false, "Failed to calculate uniqueness for the transaction");
hwdev.generate_output_ephemeral_keys(tx.version,sender_account_keys, txkey_pub, tx_key,
dst_entr, change_addr, output_index,
need_additional_txkeys, additional_tx_keys,
additional_tx_public_keys, amount_keys, out_eph_public_key,
use_view_tags, view_tag, uniqueness);
// Is this a RETURN payment? If so we have to use the provided return_pubkey and return_address
tx_out out;
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, dst_entr.is_change ? 0 : unlock_time, out_eph_public_key, use_view_tags, view_tag, out);
if (tx_type == cryptonote::transaction_type::RETURN) {
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, unlock_time, dst_entr.addr.m_spend_public_key, false, crypto::view_tag{}, out);
additional_tx_public_keys[output_index] = sources[0].origin_tx_data.tx_pub_key;
} else {
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, dst_entr.is_change ? 0 : unlock_time, out_eph_public_key, use_view_tags, view_tag, out);
}
tx.vout.push_back(out);
output_index++;
summary_outs_money += dst_entr.amount;
}
CHECK_AND_ASSERT_MES(additional_tx_public_keys.size() == additional_tx_keys.size(), false, "Internal error creating additional public keys");
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys));
// Is this a CONVERT tx?
@@ -1102,6 +1112,23 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
// Now generate the return address and TX pubkey
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, uniqueness, sender_account_keys, P_change, txkey_pub, tx.return_address, tx.return_pubkey, hwdev), false, "Failed to get protocol destination address");
} else if (tx_type == cryptonote::transaction_type::RETURN) {
// Get the uniqueness for this TX
CHECK_AND_ASSERT_MES(!tx.vin.empty(), false, "tx.vin[] is empty");
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), false, "incorrect tx.vin[0] type for RETURN TX");
crypto::key_image k_image = boost::get<cryptonote::txin_to_key>(tx.vin[0]).k_image;
ec_scalar uniqueness;
CHECK_AND_ASSERT_MES(calculate_uniqueness(cryptonote::TRANSFER, k_image, 0, 0, uniqueness), false, "Failed to calculate uniqueness for the transaction");
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
CHECK_AND_ASSERT_MES(tx.vout.size() == 2, false, "Internal error - incorrect number of outputs (!=2) for RETURN tx");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for RETURN tx");
// Now generate the return address and TX pubkey
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, uniqueness, sender_account_keys, P_change, txkey_pub, tx.return_address, tx.return_pubkey, hwdev), false, "Failed to get protocol destination address");
}
@@ -1350,7 +1377,7 @@ namespace cryptonote
size_t num_subaddresses = 0;
account_public_address single_dest_subaddress;
classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress);
bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
bool need_additional_txkeys = (tx_type == cryptonote::transaction_type::RETURN) || (num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1));
if (need_additional_txkeys)
{
additional_tx_keys.clear();
+149 -36
View File
@@ -162,7 +162,8 @@ enum TransferType {
TransferLocked,
Convert,
Burn,
LockForYield
LockForYield,
Return
};
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
@@ -5779,6 +5780,23 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
} else {
if (tx.type == cryptonote::transaction_type::BURN) {
message_writer(console_color_yellow, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("burnt ") << print_money(tx.amount_burnt) << " " << asset_type;
} else if (tx.type == cryptonote::transaction_type::CONVERT) {
message_writer(console_color_blue, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("converting ") << print_money(tx.amount_burnt) << " " << asset_type;
} else if (tx.type == cryptonote::transaction_type::YIELD) {
message_writer(console_color_cyan, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("staked ") << print_money(tx.amount_burnt) << " " << asset_type;
}
message_writer(asset_type == "SAL" ? console_color_green : console_color_blue, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
@@ -5840,24 +5858,6 @@ void simple_wallet::on_money_spent(uint64_t height, const crypto::hash &txid, co
tr("txid ") << txid << ", " <<
tr("spent ") << print_money(amount) << " " << asset_type << ", " <<
tr("idx ") << subaddr_index;
std::stringstream burn;
if (in_tx.type == cryptonote::transaction_type::BURN) {
message_writer(console_color_yellow, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("burnt ") << print_money(in_tx.amount_burnt) << " " << asset_type;
} else if (in_tx.type == cryptonote::transaction_type::CONVERT) {
message_writer(console_color_blue, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("converting ") << print_money(in_tx.amount_burnt) << " " << asset_type;
} else if (in_tx.type == cryptonote::transaction_type::YIELD) {
message_writer(console_color_cyan, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("staked ") << print_money(in_tx.amount_burnt) << " " << asset_type;
} else {
}
if (m_auto_refresh_refreshing)
m_cmd_binder.print_prompt();
else
@@ -7532,7 +7532,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
try
{
// figure out what tx will be necessary
auto ptx_vector = m_wallet->create_transactions_all(below, asset_type, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, account, subaddr_indices);
auto ptx_vector = m_wallet->create_transactions_all(below, cryptonote::transaction_type::TRANSFER, asset_type, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, account, subaddr_indices);
if (ptx_vector.empty())
{
@@ -7789,7 +7789,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
try
{
// figure out what tx will be necessary
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, outputs, fake_outs_count, 0 /* unlock_time */, priority, extra);
auto ptx_vector = m_wallet->create_transactions_single(ki, cryptonote::transaction_type::TRANSFER, info.address, info.is_subaddress, outputs, fake_outs_count, 0 /* unlock_time */, priority, extra);
if (ptx_vector.empty())
{
@@ -7963,11 +7963,13 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
// Get the TX details
tools::wallet2::transfer_container transfers;
crypto::key_image ki;
std::string asset_type;
bool found_ki = false;
m_wallet->get_transfers(transfers);
for (const auto& td: transfers) {
std::vector<size_t> transfers_indices = {};
for (size_t idx=0; idx < transfers.size(); ++idx) {
// Get the TD by reference
tools::wallet2::transfer_details& td = transfers[idx];
// Skip entries we don't care about
if (td.m_txid != txid) continue;
@@ -7990,23 +7992,129 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
}
// We found the one we were looking for - take a copy of the key_image, etc.
ki = td.m_key_image;
asset_type = td.asset_type;
found_ki = true;
transfers_indices.push_back(idx);
break;
}
// Check we have a valid key_image
if (!found_ki) {
if (transfers_indices.empty()) {
fail_msg_writer() << tr("key image is unavailable (partial / unknown / spent / frozen) for txid ") << args_[0];
return true;
}
// Build the arguments list
std::vector<std::string> local_args;
local_args.insert(local_args.end(), args_.begin(), args_.end());
local_args.push_back(epee::string_tools::pod_to_hex(ki));
transfer_main(Transfer, asset_type, asset_type, local_args, false);
SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return false;);
try
{
// Call the wallet create_transactions_return() method
auto ptx_vector = m_wallet->create_transactions_return(transfers_indices);
if (ptx_vector.empty())
{
fail_msg_writer() << tr("No outputs found");
return true;
}
if (ptx_vector.size() > 1)
{
fail_msg_writer() << tr("Multiple transactions are created, which is not supposed to happen");
return true;
}
if (ptx_vector[0].selected_transfers.size() != 1)
{
fail_msg_writer() << tr("The transaction uses multiple or no inputs, which is not supposed to happen");
return true;
}
// give user total and fee, and prompt to confirm
uint64_t total_fee = ptx_vector[0].fee;
uint64_t total_sent = m_wallet->get_transfer_details(ptx_vector[0].selected_transfers.front()).amount();
std::ostringstream prompt;
if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
return true;
prompt << boost::format(tr("Returning %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
{
fail_msg_writer() << tr("transaction cancelled.");
return true;
}
// actually commit the transactions
if (m_wallet->multisig())
{
CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
}
}
else if (m_wallet->get_account().get_device().has_tx_cold_sign())
{
try
{
fail_msg_writer() << tr("cold-signing of return TXs not yet implemented");
return true;
/*
tools::wallet2::signed_tx_set signed_tx;
std::vector<cryptonote::address_parse_info> dsts_info;
dsts_info.push_back(info);
if (!cold_sign_tx(ptx_vector, signed_tx, dsts_info, [&](const tools::wallet2::signed_tx_set &tx){ return accept_loaded_tx(tx); })){
fail_msg_writer() << tr("Failed to cold sign transaction with HW wallet");
return true;
}
commit_or_save(signed_tx.ptx, m_do_not_relay);
success_msg_writer(true) << tr("Money successfully sent, transaction: ") << get_transaction_hash(ptx_vector[0].tx);
*/
}
catch (const std::exception& e)
{
handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
LOG_ERROR("Unknown error");
fail_msg_writer() << tr("unknown error");
}
}
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_monero_tx";
}
}
else
{
m_wallet->commit_tx(ptx_vector[0]);
success_msg_writer(true) << tr("Money successfully sent, transaction: ") << get_transaction_hash(ptx_vector[0].tx);
}
}
catch (const std::exception& e)
{
handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
LOG_ERROR("unknown error");
fail_msg_writer() << tr("unknown error");
}
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -9295,6 +9403,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
type,
true,
pd.m_amount,
pd.m_asset_type,
pd.m_tx_hash,
payment_id,
(pd.m_tx_type == cryptonote::transaction_type::YIELD) ? pd.m_fee : 0,
@@ -9334,6 +9443,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
"out",
true,
pd.m_amount_in - change - fee,
pd.m_tx.source_asset_type,
i->first,
payment_id,
fee,
@@ -9375,6 +9485,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
"in",
false,
pd.m_amount,
pd.m_asset_type,
pd.m_tx_hash,
payment_id,
0,
@@ -9416,6 +9527,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
"out",
false,
amount - pd.m_change - fee,
pd.m_tx.source_asset_type,
i->first,
payment_id,
fee,
@@ -9478,7 +9590,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
}
}
auto formatter = boost::format("%8.8llu %6.6s %8.8s %25.25s %20.20s %s %s %14.14s %s %s - %s");
auto formatter = boost::format("%8.8llu %6.6s %8.8s %25.25s %20.20s %4.4s %s %s %14.14s %s %s - %s");
message_writer(color, false) << formatter
% transfer.block
@@ -9486,6 +9598,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
% transfer.unlocked
% tools::get_human_readable_timestamp(transfer.timestamp)
% print_money(transfer.amount)
% transfer.asset_type
% string_tools::pod_to_hex(transfer.hash)
% transfer.payment_id
% print_money(transfer.fee)
+1
View File
@@ -303,6 +303,7 @@ namespace cryptonote
std::string direction;
bool confirmed;
uint64_t amount;
std::string asset_type;
crypto::hash hash;
std::string payment_id;
uint64_t fee;
+218 -44
View File
@@ -1891,6 +1891,41 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
origin_tx_data.input_k_image = boost::get<cryptonote::txin_to_key>(td_origin.m_tx.vin[0]).k_image;
THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td_origin.m_tx.type, origin_tx_data.input_k_image, td_origin.m_block_height, i, origin_tx_data.uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness");
} else if (tx.type == cryptonote::transaction_type::TRANSFER) {
// Calculate the subaddress public_key (P_change)
crypto::public_key pk_change = crypto::null_pkey;
bool ok = m_account.get_device().derive_subaddress_public_key(output_public_key, tx_scan_info.received->derivation, i, pk_change);
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to derive subaddress public key for CONVERT/YIELD TX");
// Find the TX public key for P_change
//auto search = m_protocol_txs.find(pk_change);
auto search = m_protocol_txs.find(output_public_key);
if (search != m_protocol_txs.end()) {
// This is a RETURN
size_t idx = search->second;
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers");
const transfer_details& td_origin = get_transfer_details(idx);
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::TRANSFER, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers");
origin_tx_data.tx_type = (uint8_t)(tx.type);
origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx);
// Create a "uniqueness" value - both CONVERT and YIELD use the same uniqueness format, based on the first input key_image
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided");
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "tx.vin[0] in origin TX must be of type txin_to_key");
origin_tx_data.input_k_image = boost::get<cryptonote::txin_to_key>(td_origin.m_tx.vin[0]).k_image;
THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td_origin.m_tx.type, origin_tx_data.input_k_image, td_origin.m_block_height, i, origin_tx_data.uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness");
} else {
// Normal behaviour
LOG_ERROR("DEBUG HERE");
origin_tx_data.tx_type = (uint8_t)(tx.type);
origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(tx);
origin_tx_data.uniqueness = tx_scan_info.uniqueness;
}
} else {
// Expect a uniqueness value to have been provided by tx_scan_info
@@ -2131,7 +2166,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
std::vector<crypto::key_derivation> additional_derivations;
tx_extra_additional_pub_keys additional_tx_pub_keys;
const wallet2::is_out_data *is_out_data_ptr = NULL;
if (tx_cache_data.primary.empty() || tx.type == cryptonote::PROTOCOL)
if (true)
//if (tx_cache_data.primary.empty() || tx.type == cryptonote::PROTOCOL)
{
hw::device &hwdev = m_account.get_device();
boost::unique_lock<hw::device> hwdev_lock (hwdev);
@@ -2221,7 +2257,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
for (size_t i = 0; i < tx.vout.size(); ++i)
{
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
// If we get here, we should already HAVE the derivation(s) we need - PROTOCOL_TXs will have them in "additional_derivations"
@@ -2231,42 +2267,100 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
// Calculate the subaddress public_key (P_change)
crypto::public_key pk_change = crypto::null_pkey;
bool ok = m_account.get_device().derive_subaddress_public_key(output_public_key, additional_derivations[i], i, pk_change);
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to derive subaddress public key for CONVERT/YIELD TX");
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to derive subaddress public key for CONVERT/YIELD/TRANSFER TX");
// Find the TX public key for P_change
//auto search = m_protocol_txs.find(pk_change);
auto search = m_protocol_txs.find(output_public_key);
if (search == m_protocol_txs.end()) {
LOG_PRINT_L3("failed to locate protocol_tx entry for this vout - skipping");
continue;
}
THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate protocol_tx entry to permit source usage");
size_t idx = search->second;
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers");
const transfer_details& td_origin = get_transfer_details(idx);
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::CONVERT && td_origin.m_tx.type != cryptonote::transaction_type::YIELD,
error::wallet_internal_error,
"incorrect TX type for protocol_tx origin in m_transfers");
crypto::public_key pk_change_tx = get_tx_pub_key_from_extra(td_origin.m_tx);
// Create a "uniqueness" value - both CONVERT and YIELD use the same uniqueness format, based on the first input key_image
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided");
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "tx.vin[0] in origin TX must be of type txin_to_key");
crypto::key_image k_image = boost::get<cryptonote::txin_to_key>(td_origin.m_tx.vin[0]).k_image;
THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td_origin.m_tx.type, k_image, td_origin.m_block_height, i, tx_scan_info[i].uniqueness),
error::wallet_internal_error,
"Failed to calculate uniqueness from origin TX");
THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate protocol_tx entry to permit source usage");
size_t idx = search->second;
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers");
const transfer_details& td_origin = get_transfer_details(idx);
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::CONVERT && td_origin.m_tx.type != cryptonote::transaction_type::YIELD,
error::wallet_internal_error,
"incorrect TX type for protocol_tx origin in m_transfers");
crypto::public_key pk_change_tx = get_tx_pub_key_from_extra(td_origin.m_tx);
// Create a "uniqueness" value - both CONVERT and YIELD use the same uniqueness format, based on the first input key_image
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided");
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "tx.vin[0] in origin TX must be of type txin_to_key");
crypto::key_image k_image = boost::get<cryptonote::txin_to_key>(td_origin.m_tx.vin[0]).k_image;
THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td_origin.m_tx.type, k_image, td_origin.m_block_height, i, tx_scan_info[i].uniqueness),
error::wallet_internal_error,
"Failed to calculate uniqueness from origin TX");
// At this point, we know that we are receiving something - store the origin TD index
origin_td_idx = idx;
// At this point, we need to clear the "locked coins" count, because otherwise we will be counting yield stakes twice in our balance
// At this point, we need to clear the "locked coins" count, because otherwise we will be counting yield stakes twice in our balance
// Get the output key for the change entry
crypto::public_key pk_locked_coins = crypto::null_pkey;
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(td_origin.m_tx.vout[td_origin.m_internal_output_index], pk_locked_coins), error::wallet_internal_error, "Failed to get output public key for locked coins");
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(td_origin.m_tx.vout[td_origin.m_internal_output_index], pk_locked_coins), error::wallet_internal_error, "Failed to get output public key for locked coins");
THROW_WALLET_EXCEPTION_IF(!m_locked_coins.erase(pk_locked_coins), error::wallet_internal_error, "Failed to remove PROTOCOL_TX entry from m_locked_coins");
} else if (tx.type == cryptonote::transaction_type::TRANSFER and additional_derivations.size()) {
// SRCG: This is where it should detect a RETURN payment, but it FAILS
// If we get here, we should already HAVE the derivation(s) we need - PROTOCOL_TXs will have them in "additional_derivations"
crypto::public_key output_public_key = crypto::null_pkey;
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(tx.vout[i], output_public_key), error::wallet_internal_error, "Failed to get output public key");
// Calculate the subaddress public_key (P_change)
crypto::public_key pk_change = crypto::null_pkey;
bool ok = m_account.get_device().derive_subaddress_public_key(output_public_key, additional_derivations[i], i, pk_change);
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to derive subaddress public key for CONVERT/YIELD/TRANSFER TX");
// Find the TX public key for P_change
//auto search = m_protocol_txs.find(pk_change);
auto search = m_protocol_txs.find(output_public_key);
if (search != m_protocol_txs.end()) {
THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate protocol_tx entry to permit source usage");
size_t idx = search->second;
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers");
const transfer_details& td_origin = get_transfer_details(idx);
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::TRANSFER,
error::wallet_internal_error,
"incorrect TX type for TRANSFER origin in m_transfers");
crypto::public_key pk_change_tx = get_tx_pub_key_from_extra(td_origin.m_tx);
// Create a "uniqueness" value - both CONVERT and YIELD use the same uniqueness format, based on the first input key_image
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided");
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "tx.vin[0] in origin TX must be of type txin_to_key");
crypto::key_image k_image = boost::get<cryptonote::txin_to_key>(td_origin.m_tx.vin[0]).k_image;
THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td_origin.m_tx.type, k_image, td_origin.m_block_height, i, tx_scan_info[i].uniqueness),
error::wallet_internal_error,
"Failed to calculate uniqueness from origin TX");
// At this point, we know that we are receiving something - store the origin TD index
origin_td_idx = idx;
/*
// At this point, we need to clear the "locked coins" count, because otherwise we will be counting yield stakes twice in our balance
// Get the output key for the change entry
crypto::public_key pk_locked_coins = crypto::null_pkey;
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(td_origin.m_tx.vout[td_origin.m_internal_output_index], pk_locked_coins), error::wallet_internal_error, "Failed to get output public key for locked coins");
THROW_WALLET_EXCEPTION_IF(!m_locked_coins.erase(pk_locked_coins), error::wallet_internal_error, "Failed to remove PROTOCOL_TX entry from m_locked_coins");
*/
} else {
// Get the uniqueness value
THROW_WALLET_EXCEPTION_IF(tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided");
crypto::key_image k_image;
if (tx.vin[0].type() == typeid(cryptonote::txin_to_key)) {
k_image = boost::get<cryptonote::txin_to_key>(tx.vin[0]).k_image;
}
THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(tx.type, k_image, height, i, tx_scan_info[i].uniqueness), error::wallet_internal_error, "Failed to calculate TX output uniqueness");
}
} else {
// Get the uniqueness value
@@ -2424,6 +2518,21 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_locked_coins.insert({P_change, {0, tx.amount_burnt}});
}
}
else if (tx.type == cryptonote::transaction_type::TRANSFER)
{
// The TRANSFER TX MAY HAVE BEEN created by us - if it _was_, we need to expect an output in a future TRANSFER TX
// It could be a refund or a conversion
THROW_WALLET_EXCEPTION_IF(tx.vout.size() != 2, error::wallet_internal_error, "Incorrect number of outputs from TRANSFER TX");
for (const auto& entry: tx.vout) {
// Add the change output_public_key to the list of subaddresses to check
crypto::public_key P_change = crypto::null_pkey;
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(entry, P_change), error::wallet_internal_error, "Failed to get output public key");
m_subaddresses[P_change] = {0,0};
}
m_protocol_txs.insert({tx.return_address, m_transfers.size()-1});
}
}
else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx_scan_info[o].amount)
{
@@ -2521,7 +2630,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_subaddresses[P_change] = {0,0};
//m_protocol_txs.insert({P_change, m_transfers.size()-1});
m_protocol_txs.insert({tx.return_address, m_transfers.size()-1});
}
} else if (tx.type == cryptonote::transaction_type::TRANSFER) {
m_subaddresses[tx.return_address] = {0,0};
//m_protocol_txs.insert({P_change, m_transfers.size()-1});
m_protocol_txs.insert({tx.return_address, m_transfers.size()-1});
}
}
}
}
@@ -2604,7 +2717,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
}
}
/*
// Report the "staked" funds
if (0 != m_callback)
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::YIELD)
m_callback->on_money_received(height, txid, tx, tx.amount_burnt, tx.source_asset_type, cryptonote::subaddress_index{0,0}, false, 0, ((uint64_t)-1));
*/
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
if (tx_money_spent_in_ins > 0 && !pool)
@@ -9404,6 +9522,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
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;
}
@@ -9439,6 +9558,23 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
splitted_dsts.push_back(change_dts);
}
// Handle RETURN_PAYMENT TXs
if (tx_type == cryptonote::RETURN) {
// Find the appropriate transfer_details
THROW_WALLET_EXCEPTION_IF(selected_transfers.empty() || selected_transfers.size()>1, error::wallet_internal_error, "Incorrect number of selected_transfers on return_payment");
size_t origin_idx = selected_transfers[0];
THROW_WALLET_EXCEPTION_IF(origin_idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate return_payment origin index in m_transfers");
const transfer_details& td_origin = get_transfer_details(origin_idx);
// Populate the source information
sources[0].origin_tx_data.tx_type = ((uint8_t)cryptonote::TRANSFER);
sources[0].origin_tx_data.tx_pub_key = td_origin.m_tx.return_pubkey;
// Populate the destination information
splitted_dsts[0].addr.m_spend_public_key = splitted_dsts[0].addr.m_view_public_key = td_origin.m_tx.return_address;
}
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
crypto::secret_key multisig_tx_key_entropy;
@@ -10456,7 +10592,7 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, s
return true;
}
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const std::string &asset_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, cryptonote::transaction_type tx_type, const std::string &asset_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices;
@@ -10529,14 +10665,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
}
}
return create_transactions_from(address, asset_type, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
return create_transactions_from(address, tx_type, asset_type, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
}
std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::transaction_type tx_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
{
std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices;
const bool use_rct = use_fork_rules(4, 0);
const bool use_rct = true;
std::string asset_type = "SAL";
// Verify that we have outputs in our wallet for the correct asset_type
@@ -10556,10 +10692,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
break;
}
}
return create_transactions_from(address, asset_type, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
return create_transactions_from(address, tx_type, asset_type, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
}
std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, const std::string &asset_type, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, const cryptonote::transaction_type tx_type, const std::string &asset_type, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
{
//ensure device is let in NONE mode in any case
hw::device &hwdev = m_account.get_device();
@@ -10661,15 +10797,27 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
const size_t num_outputs = get_num_outputs(tx.dsts, m_transfers, tx.selected_transfers);
needed_fee = estimate_fee(use_per_byte_fee, use_rct, tx.selected_transfers.size(), fake_outs_count, num_outputs, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags, base_fee, fee_quantization_mask);
// add N - 1 outputs for correct initial fee estimation
for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i)
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
if (tx_type == cryptonote::RETURN) {
// Create the single destination that we need
tx.dsts.push_back(tx_destination_entry());
tx.dsts.back().amount = td.amount() - needed_fee;
tx.dsts.back().asset_type = asset_type;
tx.dsts.back().is_subaddress = false;
tx.dsts.back().is_change = false;
} else {
// add N - 1 outputs for correct initial fee estimation
for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i)
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
tx.dsts.back().asset_type = asset_type;
}
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
tx.selected_transfers.size() << " outputs");
if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, cryptonote::transaction_type::TRANSFER/*, oracle::pricing_record()*/);
test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, tx_type/*, oracle::pricing_record()*/);
else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
@@ -10706,7 +10854,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
}
if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, cryptonote::transaction_type::TRANSFER/*, oracle::pricing_record()*/);
test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, tx_type/*, oracle::pricing_record()*/);
else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
@@ -10745,7 +10893,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
pending_tx test_ptx;
if (use_rct) {
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, cryptonote::transaction_type::TRANSFER/*, oracle::pricing_record()*/);
test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, tx_type/*, oracle::pricing_record()*/);
} else {
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
@@ -10780,12 +10928,36 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
a -= tx.ptx.fee;
}
std::vector<cryptonote::tx_destination_entry> synthetic_dsts(1, cryptonote::tx_destination_entry("", a, address, is_subaddress));
THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, synthetic_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
if (tx_type != cryptonote::transaction_type::RETURN)
THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, synthetic_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
// if we made it this far, we're OK to actually send the transactions
return ptx_vector;
}
//----------------------------------------------------------------------------------------------------
std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector<size_t> transfers_indices)
{
// Get the asset_type and associated information
THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>1, error::wallet_internal_error, "Incorrect number of transfers_indices on return_payment");
size_t idx = transfers_indices[0];
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate return_payment origin index in m_transfers");
const transfer_details& td_origin = get_transfer_details(idx);
const std::string asset_type = td_origin.m_tx.source_asset_type;
bool is_subaddress = false;
size_t outputs = 1;
std::vector<size_t> unused_dust_indices = {};
size_t fake_outs_count = get_min_ring_size() - 1; // Use the default ring size
uint64_t unlock_time = 0;
uint32_t priority = adjust_priority(0);
std::vector<uint8_t> extra; // No need for a TX extra beyond that which will be calculated herein
// Cobble together a hacked version of the address and TX pubkey, so that it can be passed downstream
cryptonote::account_public_address address;
// Call the necessary handler
return create_transactions_from(address, cryptonote::transaction_type::RETURN, asset_type, is_subaddress, outputs, transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
}
//----------------------------------------------------------------------------------------------------
void wallet2::cold_tx_aux_import(const std::vector<pending_tx> & ptx, const std::vector<std::string> & tx_device_aux)
{
CHECK_AND_ASSERT_THROW_MES(ptx.size() == tx_device_aux.size(), "TX aux has invalid size");
@@ -11056,7 +11228,7 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions()
unmixable_transfer_outputs.push_back(n);
}
return create_transactions_from(m_account_public_address, "SAL", false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>());
return create_transactions_from(m_account_public_address, cryptonote::transaction_type::TRANSFER, "SAL", false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>());
}
//----------------------------------------------------------------------------------------------------
void wallet2::discard_unmixable_outputs()
@@ -11807,10 +11979,12 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
std::vector<crypto::key_derivation> additional_derivations(num_sigs - 1);
for (size_t i = 1; i < num_sigs; ++i)
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
uint64_t received;
check_tx_key_helper(tx, derivation, additional_derivations, address, received);
THROW_WALLET_EXCEPTION_IF(!received, error::wallet_internal_error, tr("No funds received in this tx."));
if (tx.type != cryptonote::transaction_type::RETURN) {
uint64_t received;
check_tx_key_helper(tx, derivation, additional_derivations, address, received);
THROW_WALLET_EXCEPTION_IF(!received, error::wallet_internal_error, tr("No funds received in this tx."));
}
// concatenate all signature strings
for (size_t i = 0; i < num_sigs; ++i)
sig_str +=
+4 -3
View File
@@ -1111,9 +1111,10 @@ private:
bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const crypto::key_image& ki_return); // pass subaddr_indices by value on purpose
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const std::string &asset_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, const std::string &asset_type, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::transaction_type tx_type, const std::string &asset_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::transaction_type tx_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, const cryptonote::transaction_type tx_type, const std::string &asset_type, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_return(std::vector<size_t> transfers_indices);
bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, std::vector<cryptonote::tx_destination_entry> dsts) const;
void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux);
void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux);
+2 -2
View File
@@ -1617,7 +1617,7 @@ namespace tools
{
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, asset_type, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, subaddr_indices);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, cryptonote::transaction_type::TRANSFER, asset_type, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, subaddr_indices);
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er);
@@ -1674,7 +1674,7 @@ namespace tools
{
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, cryptonote::transaction_type::TRANSFER, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra);
if (ptx_vector.empty())
{