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:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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 +=
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user