@@ -945,6 +945,37 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
945
945
return success;
946
946
}
947
947
948
+ void CWallet::SetUsedDestinationState (const uint256& hash, unsigned int n, bool used)
949
+ {
950
+ const CWalletTx* srctx = GetWalletTx (hash);
951
+ if (!srctx) return ;
952
+
953
+ CTxDestination dst;
954
+ if (ExtractDestination (srctx->tx ->vout [n].scriptPubKey , dst)) {
955
+ if (::IsMine (*this , dst)) {
956
+ LOCK (cs_wallet);
957
+ if (used && !GetDestData (dst, " used" , nullptr )) {
958
+ AddDestData (dst, " used" , " p" ); // p for "present", opposite of absent (null)
959
+ } else if (!used && GetDestData (dst, " used" , nullptr )) {
960
+ EraseDestData (dst, " used" );
961
+ }
962
+ }
963
+ }
964
+ }
965
+
966
+ bool CWallet::IsUsedDestination (const CTxDestination& dst) const
967
+ {
968
+ LOCK (cs_wallet);
969
+ return ::IsMine (*this , dst) && GetDestData (dst, " used" , nullptr );
970
+ }
971
+
972
+ bool CWallet::IsUsedDestination (const uint256& hash, unsigned int n) const
973
+ {
974
+ CTxDestination dst;
975
+ const CWalletTx* srctx = GetWalletTx (hash);
976
+ return srctx && ExtractDestination (srctx->tx ->vout [n].scriptPubKey , dst) && IsUsedDestination (dst);
977
+ }
978
+
948
979
bool CWallet::AddToWallet (const CWalletTx& wtxIn, bool fFlushOnClose )
949
980
{
950
981
LOCK (cs_wallet);
@@ -953,6 +984,14 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
953
984
954
985
uint256 hash = wtxIn.GetHash ();
955
986
987
+ if (IsWalletFlagSet (WALLET_FLAG_AVOID_REUSE)) {
988
+ // Mark used destinations
989
+ for (const CTxIn& txin : wtxIn.tx ->vin ) {
990
+ const COutPoint& op = txin.prevout ;
991
+ SetUsedDestinationState (op.hash , op.n , true );
992
+ }
993
+ }
994
+
956
995
// Inserts only if not already there, returns tx inserted or tx found
957
996
std::pair<std::map<uint256, CWalletTx>::iterator, bool > ret = mapWallet.insert (std::make_pair (hash, wtxIn));
958
997
CWalletTx& wtx = (*ret.first ).second ;
@@ -2072,7 +2111,7 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
2072
2111
return 0 ;
2073
2112
2074
2113
// Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
2075
- bool allow_cache = filter == ISMINE_SPENDABLE || filter == ISMINE_WATCH_ONLY ;
2114
+ bool allow_cache = ( filter & ISMINE_ALL) && ( filter & ISMINE_ALL) != ISMINE_ALL ;
2076
2115
2077
2116
// Must wait until coinbase is safely deep enough in the chain before valuing it
2078
2117
if (IsImmatureCoinBase (locked_chain))
@@ -2082,12 +2121,12 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
2082
2121
return m_amounts[AVAILABLE_CREDIT].m_value [filter];
2083
2122
}
2084
2123
2124
+ bool allow_used_addresses = (filter & ISMINE_USED) || !pwallet->IsWalletFlagSet (WALLET_FLAG_AVOID_REUSE);
2085
2125
CAmount nCredit = 0 ;
2086
2126
uint256 hashTx = GetHash ();
2087
2127
for (unsigned int i = 0 ; i < tx->vout .size (); i++)
2088
2128
{
2089
- if (!pwallet->IsSpent (locked_chain, hashTx, i))
2090
- {
2129
+ if (!pwallet->IsSpent (locked_chain, hashTx, i) && (allow_used_addresses || !pwallet->IsUsedDestination (hashTx, i))) {
2091
2130
const CTxOut &txout = tx->vout [i];
2092
2131
nCredit += pwallet->GetCredit (txout, filter);
2093
2132
if (!MoneyRange (nCredit))
@@ -2229,9 +2268,10 @@ void MaybeResendWalletTxs()
2229
2268
*/
2230
2269
2231
2270
2232
- CWallet::Balance CWallet::GetBalance (const int min_depth) const
2271
+ CWallet::Balance CWallet::GetBalance (const int min_depth, bool avoid_reuse ) const
2233
2272
{
2234
2273
Balance ret;
2274
+ isminefilter reuse_filter = avoid_reuse ? 0 : ISMINE_USED;
2235
2275
{
2236
2276
auto locked_chain = chain ().lock ();
2237
2277
LOCK (cs_wallet);
@@ -2240,8 +2280,8 @@ CWallet::Balance CWallet::GetBalance(const int min_depth) const
2240
2280
const CWalletTx& wtx = entry.second ;
2241
2281
const bool is_trusted{wtx.IsTrusted (*locked_chain)};
2242
2282
const int tx_depth{wtx.GetDepthInMainChain (*locked_chain)};
2243
- const CAmount tx_credit_mine{wtx.GetAvailableCredit (*locked_chain, /* fUseCache */ true , ISMINE_SPENDABLE)};
2244
- const CAmount tx_credit_watchonly{wtx.GetAvailableCredit (*locked_chain, /* fUseCache */ true , ISMINE_WATCH_ONLY)};
2283
+ const CAmount tx_credit_mine{wtx.GetAvailableCredit (*locked_chain, /* fUseCache */ true , ISMINE_SPENDABLE | reuse_filter )};
2284
+ const CAmount tx_credit_watchonly{wtx.GetAvailableCredit (*locked_chain, /* fUseCache */ true , ISMINE_WATCH_ONLY | reuse_filter )};
2245
2285
if (is_trusted && tx_depth >= min_depth) {
2246
2286
ret.m_mine_trusted += tx_credit_mine;
2247
2287
ret.m_watchonly_trusted += tx_credit_watchonly;
@@ -2279,6 +2319,9 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
2279
2319
2280
2320
vCoins.clear ();
2281
2321
CAmount nTotal = 0 ;
2322
+ // Either the WALLET_FLAG_AVOID_REUSE flag is not set (in which case we always allow), or we default to avoiding, and only in the case where
2323
+ // a coin control object is provided, and has the avoid address reuse flag set to false, do we allow already used addresses
2324
+ bool allow_used_addresses = !IsWalletFlagSet (WALLET_FLAG_AVOID_REUSE) || (coinControl && !coinControl->m_avoid_address_reuse );
2282
2325
2283
2326
for (const auto & entry : mapWallet)
2284
2327
{
@@ -2360,6 +2403,10 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
2360
2403
continue ;
2361
2404
}
2362
2405
2406
+ if (!allow_used_addresses && IsUsedDestination (wtxid, i)) {
2407
+ continue ;
2408
+ }
2409
+
2363
2410
bool solvable = IsSolvable (*this , wtx.tx ->vout [i].scriptPubKey );
2364
2411
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
2365
2412
@@ -4150,16 +4197,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
4150
4197
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
4151
4198
walletInstance->SetMinVersion (FEATURE_LATEST);
4152
4199
4153
- if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
4154
- // selective allow to set flags
4155
- walletInstance->SetWalletFlag (WALLET_FLAG_DISABLE_PRIVATE_KEYS);
4156
- } else if (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET) {
4157
- walletInstance->SetWalletFlag (WALLET_FLAG_BLANK_WALLET);
4158
- } else {
4200
+ walletInstance->SetWalletFlags (wallet_creation_flags, false );
4201
+ if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
4159
4202
// generate a new seed
4160
4203
CPubKey seed = walletInstance->GenerateNewSeed ();
4161
4204
walletInstance->SetHDSeed (seed);
4162
- } // Otherwise, do not generate a new seed
4205
+ }
4163
4206
4164
4207
// Top up the keypool
4165
4208
if (walletInstance->CanGenerateKeys () && !walletInstance->TopUpKeyPool ()) {
0 commit comments