Skip to content

Commit ee2048a

Browse files
laanwjPastaPastaPasta
authored andcommitted
Merge bitcoin#9830: Add safe flag to listunspent result
dcf2112 Add safe flag to listunspent result (NicolasDorier) af61d9f Add COutput::fSafe member for safe handling of unconfirmed outputs (Russell Yanofsky) Tree-SHA512: 311edb6fa8075b3ede5b24cb8c6e5d133ccd8ac9ecafea07b604ffa812ee4f071337e31695e662d8573590a0460af20aaaeb39d49c9ea87924449ea50bdfb0b3
1 parent 914bd78 commit ee2048a

File tree

7 files changed

+34
-18
lines changed

7 files changed

+34
-18
lines changed

qa/rpc-tests/listtransactions.py

100755100644
File mode changed.

src/bench/coin_selection.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<CO
2020
CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx)));
2121

2222
int nAge = 6 * 24;
23-
COutput output(wtx, nInput, nAge, true, true);
23+
COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
2424
vCoins.push_back(output);
2525
}
2626

src/qt/walletmodel.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
670670
if (!wallet->mapWallet.count(outpoint.hash)) continue;
671671
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
672672
if (nDepth < 0) continue;
673-
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true);
673+
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
674674
vOutputs.push_back(out);
675675
}
676676
}
@@ -697,7 +697,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
697697
if (!wallet->mapWallet.count(outpoint.hash)) continue;
698698
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
699699
if (nDepth < 0) continue;
700-
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true);
700+
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
701701
if (outpoint.n < out.tx->tx->vout.size() && wallet->IsMine(out.tx->tx->vout[outpoint.n]) == ISMINE_SPENDABLE)
702702
vCoins.push_back(out);
703703
}
@@ -709,7 +709,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
709709
while (wallet->IsChange(cout.tx->tx->vout[cout.i]) && cout.tx->tx->vin.size() > 0 && wallet->IsMine(cout.tx->tx->vin[0]))
710710
{
711711
if (!wallet->mapWallet.count(cout.tx->tx->vin[0].prevout.hash)) break;
712-
cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0, true, true);
712+
cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0 /* depth */, true /* spendable */, true /* solvable */, true /* safe */);
713713
}
714714

715715
CTxDestination address;

src/wallet/rpcwallet.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -2682,11 +2682,9 @@ UniValue listunspent(const JSONRPCRequest& request)
26822682
" ,...\n"
26832683
" ]\n"
26842684
"4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\n"
2685-
" because they come from unconfirmed untrusted transactions or unconfirmed\n"
2686-
" replacement transactions (cases where we are less sure that a conflicting\n"
2687-
" transaction won't be mined).\n"
2688-
"\nResult:\n"
2689-
"[ (array of json object)\n"
2685+
" See description of \"safe\" attribute below.\n"
2686+
"\nResult\n"
2687+
"[ (array of json object)\n"
26902688
" {\n"
26912689
" \"txid\" : \"txid\", (string) the transaction id \n"
26922690
" \"vout\" : n, (numeric) the vout value\n"
@@ -2698,6 +2696,9 @@ UniValue listunspent(const JSONRPCRequest& request)
26982696
" \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\n"
26992697
" \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n"
27002698
" \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
2699+
" \"safe\" : xxx (bool) Whether this output is considered safe to spend. Unconfirmed transactions\n"
2700+
" from outside keys and unconfirmed replacement transactions are considered unsafe\n"
2701+
" and are not eligible for spending by fundrawtransaction and sendtoaddress.\n"
27012702
" \"ps_rounds\" : n (numeric) The number of PS rounds\n"
27022703
" }\n"
27032704
" ,...\n"
@@ -2783,6 +2784,7 @@ UniValue listunspent(const JSONRPCRequest& request)
27832784
entry.push_back(Pair("confirmations", out.nDepth));
27842785
entry.push_back(Pair("spendable", out.fSpendable));
27852786
entry.push_back(Pair("solvable", out.fSolvable));
2787+
entry.push_back(Pair("safe", out.fSafe));
27862788
entry.push_back(Pair("ps_rounds", pwallet->GetCappedOutpointPrivateSendRounds(COutPoint(out.tx->GetHash(), out.i))));
27872789
results.push_back(entry);
27882790
}

src/wallet/test/wallet_tests.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
5656
wtx->fDebitCached = true;
5757
wtx->nDebitCached = 1;
5858
}
59-
COutput output(wtx.get(), nInput, nAge, true, true);
59+
COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
6060
vCoins.push_back(output);
6161
wtxn.emplace_back(std::move(wtx));
6262
}

src/wallet/wallet.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -2509,7 +2509,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
25092509
return nTotal;
25102510
}
25112511

2512-
void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, AvailableCoinsType nCoinType, bool fUseInstantSend) const
2512+
void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const CCoinControl *coinControl, bool fIncludeZeroValue, AvailableCoinsType nCoinType, bool fUseInstantSend) const
25132513
{
25142514
vCoins.clear();
25152515

@@ -2525,9 +2525,6 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
25252525
if (!CheckFinalTx(*pcoin))
25262526
continue;
25272527

2528-
if (fOnlyConfirmed && !pcoin->IsTrusted())
2529-
continue;
2530-
25312528
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
25322529
continue;
25332530

@@ -2557,6 +2554,12 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
25572554
}
25582555
if(!found) continue;
25592556

2557+
bool safeTx = pcoin->IsTrusted();
2558+
2559+
if (fOnlySafe && !safeTx) {
2560+
continue;
2561+
}
2562+
25602563
isminetype mine = IsMine(pcoin->tx->vout[i]);
25612564
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
25622565
(!IsLockedCoin((*it).first, i) || nCoinType == ONLY_1000) &&
@@ -2565,7 +2568,7 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
25652568
vCoins.push_back(COutput(pcoin, i, nDepth,
25662569
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
25672570
(coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO),
2568-
(mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO));
2571+
(mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, safeTx));
25692572
}
25702573
}
25712574
}

src/wallet/wallet.h

+14-3
Original file line numberDiff line numberDiff line change
@@ -530,12 +530,23 @@ class COutput
530530
const CWalletTx *tx;
531531
int i;
532532
int nDepth;
533+
534+
/** Whether we have the private keys to spend this output */
533535
bool fSpendable;
536+
537+
/** Whether we know how to spend this output, ignoring the lack of keys */
534538
bool fSolvable;
535539

536-
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn)
540+
/**
541+
* Whether this output is considered safe to spend. Unconfirmed transactions
542+
* from outside keys and unconfirmed replacement transactions are considered
543+
* unsafe and will not be used to fund new spending transactions.
544+
*/
545+
bool fSafe;
546+
547+
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn)
537548
{
538-
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn;
549+
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn;
539550
}
540551

541552
//Used with Darksend. Will return largest nondenom, then denominations, then very small inputs
@@ -829,7 +840,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
829840
/**
830841
* populate vCoins with vector of available COutputs.
831842
*/
832-
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = false) const;
843+
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = false) const;
833844

834845
/**
835846
* Shuffle and select coins until nTargetValue is reached while avoiding

0 commit comments

Comments
 (0)