Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

7344 Fix describe_transfer in the case of multiple transactions in the set #7349

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions src/wallet/wallet_rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1197,13 +1197,16 @@ namespace tools
try
{
// gather info to ask the user
std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> dests;
std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> tx_dests;
std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> all_dests;
int first_known_non_zero_change_index = -1;
for (size_t n = 0; n < tx_constructions.size(); ++n)
{
const tools::wallet2::tx_construction_data &cd = tx_constructions[n];
res.desc.push_back({0, 0, std::numeric_limits<uint32_t>::max(), 0, {}, "", 0, "", 0, 0, ""});
wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::transfer_description &desc = res.desc.back();
// Clear the recipients collection ready for this loop iteration
tx_dests.clear();

std::vector<cryptonote::tx_extra_field> tx_extra_fields;
bool has_encrypted_payment_id = false;
Expand Down Expand Up @@ -1242,17 +1245,17 @@ namespace tools
std::string address = cryptonote::get_account_address_as_str(m_wallet->nettype(), entry.is_subaddress, entry.addr);
if (has_encrypted_payment_id && !entry.is_subaddress && address != entry.original)
address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), entry.addr, payment_id8);
auto i = dests.find(entry.addr);
if (i == dests.end())
dests.insert(std::make_pair(entry.addr, std::make_pair(address, entry.amount)));
auto i = tx_dests.find(entry.addr);
if (i == tx_dests.end())
tx_dests.insert(std::make_pair(entry.addr, std::make_pair(address, entry.amount)));
else
i->second.second += entry.amount;
desc.amount_out += entry.amount;
}
if (cd.change_dts.amount > 0)
{
auto it = dests.find(cd.change_dts.addr);
if (it == dests.end())
auto it = tx_dests.find(cd.change_dts.addr);
if (it == tx_dests.end())
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "Claimed change does not go to a paid address";
Expand All @@ -1279,30 +1282,46 @@ namespace tools
desc.change_amount += cd.change_dts.amount;
it->second.second -= cd.change_dts.amount;
if (it->second.second == 0)
dests.erase(cd.change_dts.addr);
tx_dests.erase(cd.change_dts.addr);
}

size_t n_dummy_outputs = 0;
for (auto i = dests.begin(); i != dests.end(); )
for (auto i = tx_dests.begin(); i != tx_dests.end(); ++i)
{
if (i->second.second > 0)
{
desc.recipients.push_back({i->second.first, i->second.second});
auto it_in_all = all_dests.find(i->first);
if (it_in_all == all_dests.end())
all_dests.insert(std::make_pair(i->first, i->second));
else
it_in_all->second.second += i->second.second;
}
else
++desc.dummy_outputs;
++i;
}

if (desc.change_amount > 0)
{
const tools::wallet2::tx_construction_data &cd0 = tx_constructions[0];
desc.change_address = get_account_address_as_str(m_wallet->nettype(), cd0.subaddr_account > 0, cd0.change_dts.addr);
res.summary.change_address = desc.change_address;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That address, if any, could be different for all txes.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that were the case an error would be triggered on line 1278, so it is safe to assume all change goes to one address here.

}

desc.fee = desc.amount_in - desc.amount_out;
desc.unlock_time = cd.unlock_time;
desc.extra = epee::to_hex::string({cd.extra.data(), cd.extra.size()});

// Update summary items
res.summary.amount_in += desc.amount_in;
res.summary.amount_out += desc.amount_out;
res.summary.change_amount += desc.change_amount;
res.summary.fee += desc.fee;
}
// Populate the summary recipients list
for (auto i = all_dests.begin(); i != all_dests.end(); ++i)
{
res.summary.recipients.push_back({i->second.first, i->second.second});
}
}
catch (const std::exception &e)
Expand Down
23 changes: 22 additions & 1 deletion src/wallet/wallet_rpc_server_commands_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
#define WALLET_RPC_VERSION_MINOR 20
#define WALLET_RPC_VERSION_MINOR 21
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
Expand Down Expand Up @@ -625,6 +625,25 @@ namespace wallet_rpc
END_KV_SERIALIZE_MAP()
};

struct txset_summary
{
uint64_t amount_in;
uint64_t amount_out;
std::list<recipient> recipients;
uint64_t change_amount;
std::string change_address;
uint64_t fee;

BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount_in)
KV_SERIALIZE(amount_out)
KV_SERIALIZE(recipients)
KV_SERIALIZE(change_amount)
KV_SERIALIZE(change_address)
KV_SERIALIZE(fee)
END_KV_SERIALIZE_MAP()
};

struct request_t
{
std::string unsigned_txset;
Expand All @@ -640,8 +659,10 @@ namespace wallet_rpc
struct response_t
{
std::list<transfer_description> desc;
struct txset_summary summary;

BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(summary)
KV_SERIALIZE(desc)
END_KV_SERIALIZE_MAP()
};
Expand Down