Wallet: Distingush amounts for a single subaddress

Adding a new `amounts` field ot the output of `get_transfers` RPC
method. This field specifies individual payments made to a single
subaddress in a single transaction, e.g., made by this command:

    transfer <addr1> <amount1> <addr1> <amount2>
This commit is contained in:
Tadeas Moravec 2020-01-09 10:01:56 +01:00 committed by Tadeas Moravec
parent 3c01bffd0c
commit 096a9dbdf9
No known key found for this signature in database
GPG key ID: AE1066CC94FA7B49
4 changed files with 38 additions and 2 deletions

View file

@ -1842,7 +1842,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
// (that is, the prunable stuff may or may not be included) // (that is, the prunable stuff may or may not be included)
if (!miner_tx && !pool) if (!miner_tx && !pool)
process_unconfirmed(txid, tx, height); process_unconfirmed(txid, tx, height);
std::unordered_map<cryptonote::subaddress_index, uint64_t> tx_money_got_in_outs; // per receiving subaddress index
// per receiving subaddress index
std::unordered_map<cryptonote::subaddress_index, uint64_t> tx_money_got_in_outs;
std::unordered_map<cryptonote::subaddress_index, amounts_container> tx_amounts_individual_outs;
crypto::public_key tx_pub_key = null_pkey; crypto::public_key tx_pub_key = null_pkey;
bool notify = false; bool notify = false;
@ -1971,6 +1975,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{ {
hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations);
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
if (!tx_scan_info[i].error)
{
tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered);
}
} }
} }
} }
@ -1994,6 +2002,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{ {
hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations);
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
if (!tx_scan_info[i].error)
{
tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered);
}
} }
} }
} }
@ -2010,6 +2022,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
hwdev.set_mode(hw::device::NONE); hwdev.set_mode(hw::device::NONE);
hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations);
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
if (!tx_scan_info[i].error)
{
tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered);
}
} }
} }
} }
@ -2118,6 +2134,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount, THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount,
error::wallet_internal_error, "Unexpected values of new and old outputs"); error::wallet_internal_error, "Unexpected values of new and old outputs");
tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount; tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount;
amounts_container& tx_amounts_this_out = tx_amounts_individual_outs[tx_scan_info[o].received->index]; // Only for readability on the following lines
auto amount_iterator = std::find(tx_amounts_this_out.begin(), tx_amounts_this_out.end(), tx_scan_info[o].amount);
THROW_WALLET_EXCEPTION_IF(amount_iterator == tx_amounts_this_out.end(),
error::wallet_internal_error, "Unexpected values of new and old outputs");
tx_amounts_this_out.erase(amount_iterator);
} }
else else
{ {
@ -2183,6 +2205,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
} }
} }
THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs.size() != tx_amounts_individual_outs.size(), error::wallet_internal_error, "Inconsistent size of output arrays");
uint64_t tx_money_spent_in_ins = 0; uint64_t tx_money_spent_in_ins = 0;
// The line below is equivalent to "boost::optional<uint32_t> subaddr_account;", but avoids the GCC warning: *((void*)& subaddr_account +4) may be used uninitialized in this function // The line below is equivalent to "boost::optional<uint32_t> subaddr_account;", but avoids the GCC warning: *((void*)& subaddr_account +4) may be used uninitialized in this function
// It's a GCC bug with boost::optional, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679 // It's a GCC bug with boost::optional, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679
@ -2286,6 +2310,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (subaddr_account && i->first.major == *subaddr_account) if (subaddr_account && i->first.major == *subaddr_account)
{ {
sub_change += i->second; sub_change += i->second;
tx_amounts_individual_outs.erase(i->first);
i = tx_money_got_in_outs.erase(i); i = tx_money_got_in_outs.erase(i);
} }
else else
@ -2363,6 +2388,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
payment.m_tx_hash = txid; payment.m_tx_hash = txid;
payment.m_fee = fee; payment.m_fee = fee;
payment.m_amount = i.second; payment.m_amount = i.second;
payment.m_amounts = tx_amounts_individual_outs[i.first];
payment.m_block_height = height; payment.m_block_height = height;
payment.m_unlock_time = tx.unlock_time; payment.m_unlock_time = tx.unlock_time;
payment.m_timestamp = ts; payment.m_timestamp = ts;

View file

@ -360,10 +360,12 @@ private:
END_SERIALIZE() END_SERIALIZE()
}; };
typedef std::vector<uint64_t> amounts_container;
struct payment_details struct payment_details
{ {
crypto::hash m_tx_hash; crypto::hash m_tx_hash;
uint64_t m_amount; uint64_t m_amount;
amounts_container m_amounts;
uint64_t m_fee; uint64_t m_fee;
uint64_t m_block_height; uint64_t m_block_height;
uint64_t m_unlock_time; uint64_t m_unlock_time;
@ -1628,7 +1630,7 @@ BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 12)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0) BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 4) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 5)
BOOST_CLASS_VERSION(tools::wallet2::pool_payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::pool_payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 8) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 8)
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6)
@ -1939,6 +1941,9 @@ namespace boost
return; return;
} }
a & x.m_coinbase; a & x.m_coinbase;
if (ver < 5)
return;
a & x.m_amounts;
} }
template <class Archive> template <class Archive>

View file

@ -326,6 +326,7 @@ namespace tools
entry.height = pd.m_block_height; entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp; entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount; entry.amount = pd.m_amount;
entry.amounts = pd.m_amounts;
entry.unlock_time = pd.m_unlock_time; entry.unlock_time = pd.m_unlock_time;
entry.locked = !m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height); entry.locked = !m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height);
entry.fee = pd.m_fee; entry.fee = pd.m_fee;
@ -408,6 +409,7 @@ namespace tools
entry.height = 0; entry.height = 0;
entry.timestamp = pd.m_timestamp; entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount; entry.amount = pd.m_amount;
entry.amounts = pd.m_amounts;
entry.unlock_time = pd.m_unlock_time; entry.unlock_time = pd.m_unlock_time;
entry.locked = true; entry.locked = true;
entry.fee = pd.m_fee; entry.fee = pd.m_fee;

View file

@ -1354,6 +1354,7 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response; typedef epee::misc_utils::struct_init<response_t> response;
}; };
typedef std::vector<uint64_t> amounts_container;
struct transfer_entry struct transfer_entry
{ {
std::string txid; std::string txid;
@ -1361,6 +1362,7 @@ namespace wallet_rpc
uint64_t height; uint64_t height;
uint64_t timestamp; uint64_t timestamp;
uint64_t amount; uint64_t amount;
amounts_container amounts;
uint64_t fee; uint64_t fee;
std::string note; std::string note;
std::list<transfer_destination> destinations; std::list<transfer_destination> destinations;
@ -1380,6 +1382,7 @@ namespace wallet_rpc
KV_SERIALIZE(height); KV_SERIALIZE(height);
KV_SERIALIZE(timestamp); KV_SERIALIZE(timestamp);
KV_SERIALIZE(amount); KV_SERIALIZE(amount);
KV_SERIALIZE(amounts);
KV_SERIALIZE(fee); KV_SERIALIZE(fee);
KV_SERIALIZE(note); KV_SERIALIZE(note);
KV_SERIALIZE(destinations); KV_SERIALIZE(destinations);