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

wallet, rpc: Fix for self-transactions in listtransactions #1852

Merged
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
10 changes: 10 additions & 0 deletions src/qt/transactionrecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,22 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
bool fAllFromMe = true;
for (auto const& txin : wtx.vin)
{
fAllFromMe = fAllFromMe && (wallet->IsMine(txin) != ISMINE_NO);

// Once false, no point in continuing.
if (!fAllFromMe) break;
}

bool fAllToMe = true;
for (auto const& txout : wtx.vout)
{
fAllToMe = fAllToMe && (wallet->IsMine(txout) != ISMINE_NO);

// Once false, no point in continuing.
if (!fAllToMe) break;
}

if (fAllFromMe && fAllToMe)
{
// Payment to self
Expand Down
50 changes: 45 additions & 5 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,19 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, list<COutputEntry>&

strSentAccount = strFromAccount;

// This is the same as nDebit > 0, i.e. we sent the transaction.
bool fIsFromMe = IsFromMe();

// This will be true if this is a self-transaction.
bool fIsAllToMe = true;
for (auto const& txout : vout)
{
fIsAllToMe = fIsAllToMe && (pwallet->IsMine(txout) != ISMINE_NO);
jamescowens marked this conversation as resolved.
Show resolved Hide resolved

// Once false, no point in continuing.
if (!fIsAllToMe) break;
}

// Used for coinstake rollup.
int64_t amount = 0;

Expand All @@ -790,11 +801,11 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, list<COutputEntry>&

// Compute fee:
int64_t nDebit = GetDebit(filter);
// debit > 0 means we signed/sent this transaction, we do not record a fee for
// fIsFromMe true means we signed/sent this transaction, we do not record a fee for
// coinstakes. The fees collected from other transactions in the block are added
// to the staker's output(s) that are the staker's. Therefore fees only need
// to be shown for non-coinstake send transactions.
if (nDebit > 0 && !fIsCoinStake)
if (fIsFromMe && !fIsCoinStake)
{
int64_t nValueOut = GetValueOut();
nFee = nDebit - nValueOut;
Expand All @@ -808,7 +819,7 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, list<COutputEntry>&
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
// 2) the output is to us (received)
if (nDebit > 0)
if (fIsFromMe)
{
// If not a coinstake, don't report 'change' txouts. Txouts on change addresses for coinstakes
// must be reported because a change address itself can stake, and there is no "change" on a
Expand All @@ -829,8 +840,9 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, list<COutputEntry>&
// OR (not a coinstake and nDebit > 0, i.e. a normal send transaction)), add the output as a "sent" entry.
// We exclude coinstake outputs 0 and 1 from sends, because output 0 is empty and output 1 MUST go back to
// the staker (i.e. is not a send by definition). Notice that for a normal self-transaction, the send and
// receive details will be suppressed; however, the fee will be reported in the nFee parameter.
if (fIsMine == ISMINE_NO && ((i > 1 && fIsCoinStakeMine) || (!fIsCoinStake && nDebit > 0)))
// receive details will be suppressed in this block. There is a separate section to deal with self-transactions
// below.
if (fIsMine == ISMINE_NO && ((i > 1 && fIsCoinStakeMine) || (!fIsCoinStake && fIsFromMe)))
{
if (!ExtractDestination(txout.scriptPubKey, address))
{
Expand Down Expand Up @@ -888,6 +900,34 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, list<COutputEntry>&
output = {address, txout.nValue, (int) i};
listReceived.push_back(output);
}

// Self-transactions...

if (fIsFromMe && fIsAllToMe)
{
if (!ExtractDestination(txout.scriptPubKey, address))
{
if (txout.scriptPubKey[0] != OP_RETURN)
{
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s",
this->GetHash().ToString().c_str());
}

address = CNoDestination();
}

// For a self-transaction, the output has to be both a send and a receive. Note that an
// unfortunate side-effect of this solution for self-transaction listing is that the fee
// will be reported on both the send and receive transactions in the ListTransactions that
// normally calls this function, but that is better than simply reporting the receive side only
// of a self-transaction, which is typically what is done.
//
// Also, a mixed transaction where some of the outputs are back to oneself, and others are to
// other addressees, does not qualify here. Those only the output sends will be reported.
output = {address, txout.nValue, (int) i};
listSent.push_back(output);
listReceived.push_back(output);
}
}
}

Expand Down