Skip to content

Encrypted payment ID is decrypted once per transaction and shared across unrelated accounts #279

Description

@mahnunchik

ownership_test::operator() declares payment_id once for the whole transaction:

std::pair<std::uint8_t, db::output::payment_id_> payment_id;

then loops over every registered account:

for (account& user : users)

and every output:

for (std::size_t index = 0; index < tx.vout.size(); ++index)

Decryption only happens once, guarded by !payment_id.first:

if (extra_nonce && !payment_id.first && cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce->nonce, payment_id.second.short_))
{
payment_id.first = sizeof(crypto::hash8);
lws::decrypt_payment_id(payment_id.second.short_, active_derivation);
}

using whichever (account, output) pair matches first. The resulting payment_id.second is
then attached to every account's own output record for that transaction, not just the one it was
actually encrypted for:

payment_id.second,

Effect: in a transaction that pays multiple accounts (e.g. one recipient with an encrypted/
integrated-address payment ID, other recipients being unrelated regular destinations), whichever
account happens to be scanned first "wins" the correctly-decrypted payment ID - every other
account that received an output in that same transaction gets that same (wrong, foreign) value
recorded against their own output, instead of nothing/their own correct value.

Repro: send one transaction with several destinations across different accounts, where one
destination is an integrated address. Check get_address_txs for the other (non-integrated)
recipients - they show a payment_id that isn't theirs.

Fix direction: payment_id needs to be decrypted per (account, output) that actually owns it,
not once globally per transaction - it can't be hoisted above the for (account& user : users) /
per-output loops the way it is now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions