Skip to content

Commit 2d5419f

Browse files
committed
Merge #15780: wallet: add cachable amounts for caching credit/debit values
c9e6e7e wallet: add cachable amounts for caching credit/debit values (Karl-Johan Alm) Pull request description: This is a refactoring that will make #13756 a lot cleaner and straight-forward, since it adds another combination to the pile (watch-only * spendable * reused). It's also a nice change in general. Tree-SHA512: 6c876d58bbffd5cb85ef632dea4fd6afed163904bbde5efdb307fa119af178ed3cb5df047255da7e9a9136fed876922f1116fce61a3710f308c72275f9b7d18b
2 parents caceff5 + c9e6e7e commit 2d5419f

File tree

4 files changed

+61
-114
lines changed

4 files changed

+61
-114
lines changed

src/script/ismine.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,43 @@
99
#include <script/standard.h>
1010

1111
#include <stdint.h>
12+
#include <bitset>
1213

1314
class CKeyStore;
1415
class CScript;
1516

1617
/** IsMine() return codes */
1718
enum isminetype
1819
{
19-
ISMINE_NO = 0,
20-
ISMINE_WATCH_ONLY = 1,
21-
ISMINE_SPENDABLE = 2,
22-
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
20+
ISMINE_NO = 0,
21+
ISMINE_WATCH_ONLY = 1 << 0,
22+
ISMINE_SPENDABLE = 1 << 1,
23+
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE,
24+
ISMINE_ENUM_ELEMENTS,
2325
};
2426
/** used for bitflags of isminetype */
2527
typedef uint8_t isminefilter;
2628

2729
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
2830
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
2931

32+
/**
33+
* Cachable amount subdivided into watchonly and spendable parts.
34+
*/
35+
struct CachableAmount
36+
{
37+
// NO and ALL are never (supposed to be) cached
38+
std::bitset<ISMINE_ENUM_ELEMENTS> m_cached;
39+
CAmount m_value[ISMINE_ENUM_ELEMENTS];
40+
inline void Reset()
41+
{
42+
m_cached.reset();
43+
}
44+
void Set(isminefilter filter, CAmount value)
45+
{
46+
m_cached.set(filter);
47+
m_value[filter] = value;
48+
}
49+
};
50+
3051
#endif // BITCOIN_SCRIPT_ISMINE_H

src/wallet/test/coinselector_tests.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
6969
std::unique_ptr<CWalletTx> wtx = MakeUnique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
7070
if (fIsFromMe)
7171
{
72-
wtx->fDebitCached = true;
73-
wtx->nDebitCached = 1;
72+
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
7473
}
7574
COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
7675
vCoins.push_back(output);
@@ -115,7 +114,7 @@ inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& coins)
115114
{
116115
static std::vector<OutputGroup> static_groups;
117116
static_groups.clear();
118-
for (auto& coin : coins) static_groups.emplace_back(coin.GetInputCoin(), coin.nDepth, coin.tx->fDebitCached && coin.tx->nDebitCached == 1 /* HACK: we can't figure out the is_me flag so we use the conditions defined above; perhaps set safe to false for !fIsFromMe in add_coin() */, 0, 0);
117+
for (auto& coin : coins) static_groups.emplace_back(coin.GetInputCoin(), coin.nDepth, coin.tx->m_amounts[CWalletTx::DEBIT].m_cached[ISMINE_SPENDABLE] && coin.tx->m_amounts[CWalletTx::DEBIT].m_value[ISMINE_SPENDABLE] == 1 /* HACK: we can't figure out the is_me flag so we use the conditions defined above; perhaps set safe to false for !fIsFromMe in add_coin() */, 0, 0);
119118
return static_groups;
120119
}
121120

src/wallet/wallet.cpp

Lines changed: 27 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,33 +1931,26 @@ std::set<uint256> CWalletTx::GetConflicts() const
19311931
return result;
19321932
}
19331933

1934+
CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const
1935+
{
1936+
auto& amount = m_amounts[type];
1937+
if (recalculate || !amount.m_cached[filter]) {
1938+
amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*tx, filter) : pwallet->GetCredit(*tx, filter));
1939+
}
1940+
return amount.m_value[filter];
1941+
}
1942+
19341943
CAmount CWalletTx::GetDebit(const isminefilter& filter) const
19351944
{
19361945
if (tx->vin.empty())
19371946
return 0;
19381947

19391948
CAmount debit = 0;
1940-
if(filter & ISMINE_SPENDABLE)
1941-
{
1942-
if (fDebitCached)
1943-
debit += nDebitCached;
1944-
else
1945-
{
1946-
nDebitCached = pwallet->GetDebit(*tx, ISMINE_SPENDABLE);
1947-
fDebitCached = true;
1948-
debit += nDebitCached;
1949-
}
1949+
if (filter & ISMINE_SPENDABLE) {
1950+
debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE);
19501951
}
1951-
if(filter & ISMINE_WATCH_ONLY)
1952-
{
1953-
if(fWatchDebitCached)
1954-
debit += nWatchDebitCached;
1955-
else
1956-
{
1957-
nWatchDebitCached = pwallet->GetDebit(*tx, ISMINE_WATCH_ONLY);
1958-
fWatchDebitCached = true;
1959-
debit += nWatchDebitCached;
1960-
}
1952+
if (filter & ISMINE_WATCH_ONLY) {
1953+
debit += GetCachableAmount(DEBIT, ISMINE_WATCH_ONLY);
19611954
}
19621955
return debit;
19631956
}
@@ -1969,40 +1962,20 @@ CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const ismine
19691962
return 0;
19701963

19711964
CAmount credit = 0;
1972-
if (filter & ISMINE_SPENDABLE)
1973-
{
1965+
if (filter & ISMINE_SPENDABLE) {
19741966
// GetBalance can assume transactions in mapWallet won't change
1975-
if (fCreditCached)
1976-
credit += nCreditCached;
1977-
else
1978-
{
1979-
nCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
1980-
fCreditCached = true;
1981-
credit += nCreditCached;
1982-
}
1967+
credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE);
19831968
}
1984-
if (filter & ISMINE_WATCH_ONLY)
1985-
{
1986-
if (fWatchCreditCached)
1987-
credit += nWatchCreditCached;
1988-
else
1989-
{
1990-
nWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
1991-
fWatchCreditCached = true;
1992-
credit += nWatchCreditCached;
1993-
}
1969+
if (filter & ISMINE_WATCH_ONLY) {
1970+
credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY);
19941971
}
19951972
return credit;
19961973
}
19971974

19981975
CAmount CWalletTx::GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache) const
19991976
{
20001977
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
2001-
if (fUseCache && fImmatureCreditCached)
2002-
return nImmatureCreditCached;
2003-
nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
2004-
fImmatureCreditCached = true;
2005-
return nImmatureCreditCached;
1978+
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
20061979
}
20071980

20081981
return 0;
@@ -2013,23 +1986,15 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
20131986
if (pwallet == nullptr)
20141987
return 0;
20151988

1989+
// Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
1990+
bool allow_cache = filter == ISMINE_SPENDABLE || filter == ISMINE_WATCH_ONLY;
1991+
20161992
// Must wait until coinbase is safely deep enough in the chain before valuing it
20171993
if (IsImmatureCoinBase(locked_chain))
20181994
return 0;
20191995

2020-
CAmount* cache = nullptr;
2021-
bool* cache_used = nullptr;
2022-
2023-
if (filter == ISMINE_SPENDABLE) {
2024-
cache = &nAvailableCreditCached;
2025-
cache_used = &fAvailableCreditCached;
2026-
} else if (filter == ISMINE_WATCH_ONLY) {
2027-
cache = &nAvailableWatchCreditCached;
2028-
cache_used = &fAvailableWatchCreditCached;
2029-
}
2030-
2031-
if (fUseCache && cache_used && *cache_used) {
2032-
return *cache;
1996+
if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) {
1997+
return m_amounts[AVAILABLE_CREDIT].m_value[filter];
20331998
}
20341999

20352000
CAmount nCredit = 0;
@@ -2045,22 +2010,17 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
20452010
}
20462011
}
20472012

2048-
if (cache) {
2049-
*cache = nCredit;
2050-
assert(cache_used);
2051-
*cache_used = true;
2013+
if (allow_cache) {
2014+
m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit);
20522015
}
2016+
20532017
return nCredit;
20542018
}
20552019

20562020
CAmount CWalletTx::GetImmatureWatchOnlyCredit(interfaces::Chain::Lock& locked_chain, const bool fUseCache) const
20572021
{
20582022
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
2059-
if (fUseCache && fImmatureWatchCreditCached)
2060-
return nImmatureWatchCreditCached;
2061-
nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
2062-
fImmatureWatchCreditCached = true;
2063-
return nImmatureWatchCreditCached;
2023+
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
20642024
}
20652025

20662026
return 0;

src/wallet/wallet.h

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -369,24 +369,11 @@ class CWalletTx : public CMerkleTx
369369
std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
370370

371371
// memory only
372-
mutable bool fDebitCached;
373-
mutable bool fCreditCached;
374-
mutable bool fImmatureCreditCached;
375-
mutable bool fAvailableCreditCached;
376-
mutable bool fWatchDebitCached;
377-
mutable bool fWatchCreditCached;
378-
mutable bool fImmatureWatchCreditCached;
379-
mutable bool fAvailableWatchCreditCached;
372+
enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS };
373+
CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const;
374+
mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS];
380375
mutable bool fChangeCached;
381376
mutable bool fInMempool;
382-
mutable CAmount nDebitCached;
383-
mutable CAmount nCreditCached;
384-
mutable CAmount nImmatureCreditCached;
385-
mutable CAmount nAvailableCreditCached;
386-
mutable CAmount nWatchDebitCached;
387-
mutable CAmount nWatchCreditCached;
388-
mutable CAmount nImmatureWatchCreditCached;
389-
mutable CAmount nAvailableWatchCreditCached;
390377
mutable CAmount nChangeCached;
391378

392379
CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
@@ -403,24 +390,8 @@ class CWalletTx : public CMerkleTx
403390
nTimeReceived = 0;
404391
nTimeSmart = 0;
405392
fFromMe = false;
406-
fDebitCached = false;
407-
fCreditCached = false;
408-
fImmatureCreditCached = false;
409-
fAvailableCreditCached = false;
410-
fWatchDebitCached = false;
411-
fWatchCreditCached = false;
412-
fImmatureWatchCreditCached = false;
413-
fAvailableWatchCreditCached = false;
414393
fChangeCached = false;
415394
fInMempool = false;
416-
nDebitCached = 0;
417-
nCreditCached = 0;
418-
nImmatureCreditCached = 0;
419-
nAvailableCreditCached = 0;
420-
nWatchDebitCached = 0;
421-
nWatchCreditCached = 0;
422-
nAvailableWatchCreditCached = 0;
423-
nImmatureWatchCreditCached = 0;
424395
nChangeCached = 0;
425396
nOrderPos = -1;
426397
}
@@ -464,14 +435,10 @@ class CWalletTx : public CMerkleTx
464435
//! make sure balances are recalculated
465436
void MarkDirty()
466437
{
467-
fCreditCached = false;
468-
fAvailableCreditCached = false;
469-
fImmatureCreditCached = false;
470-
fWatchDebitCached = false;
471-
fWatchCreditCached = false;
472-
fAvailableWatchCreditCached = false;
473-
fImmatureWatchCreditCached = false;
474-
fDebitCached = false;
438+
m_amounts[DEBIT].Reset();
439+
m_amounts[CREDIT].Reset();
440+
m_amounts[IMMATURE_CREDIT].Reset();
441+
m_amounts[AVAILABLE_CREDIT].Reset();
475442
fChangeCached = false;
476443
}
477444

0 commit comments

Comments
 (0)