wallet: add cachable amounts for caching credit/debit values
This commit is contained in:
parent
dae72998e8
commit
c9e6e7ed79
4 changed files with 61 additions and 114 deletions
|
@ -9,6 +9,7 @@
|
|||
#include <script/standard.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bitset>
|
||||
|
||||
class CKeyStore;
|
||||
class CScript;
|
||||
|
@ -16,10 +17,11 @@ class CScript;
|
|||
/** IsMine() return codes */
|
||||
enum isminetype
|
||||
{
|
||||
ISMINE_NO = 0,
|
||||
ISMINE_WATCH_ONLY = 1,
|
||||
ISMINE_SPENDABLE = 2,
|
||||
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
|
||||
ISMINE_NO = 0,
|
||||
ISMINE_WATCH_ONLY = 1 << 0,
|
||||
ISMINE_SPENDABLE = 1 << 1,
|
||||
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE,
|
||||
ISMINE_ENUM_ELEMENTS,
|
||||
};
|
||||
/** used for bitflags of isminetype */
|
||||
typedef uint8_t isminefilter;
|
||||
|
@ -27,4 +29,23 @@ typedef uint8_t isminefilter;
|
|||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
|
||||
|
||||
/**
|
||||
* Cachable amount subdivided into watchonly and spendable parts.
|
||||
*/
|
||||
struct CachableAmount
|
||||
{
|
||||
// NO and ALL are never (supposed to be) cached
|
||||
std::bitset<ISMINE_ENUM_ELEMENTS> m_cached;
|
||||
CAmount m_value[ISMINE_ENUM_ELEMENTS];
|
||||
inline void Reset()
|
||||
{
|
||||
m_cached.reset();
|
||||
}
|
||||
void Set(isminefilter filter, CAmount value)
|
||||
{
|
||||
m_cached.set(filter);
|
||||
m_value[filter] = value;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_ISMINE_H
|
||||
|
|
|
@ -69,8 +69,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
|
|||
std::unique_ptr<CWalletTx> wtx = MakeUnique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
|
||||
if (fIsFromMe)
|
||||
{
|
||||
wtx->fDebitCached = true;
|
||||
wtx->nDebitCached = 1;
|
||||
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
|
||||
}
|
||||
COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
|
||||
vCoins.push_back(output);
|
||||
|
@ -115,7 +114,7 @@ inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& coins)
|
|||
{
|
||||
static std::vector<OutputGroup> static_groups;
|
||||
static_groups.clear();
|
||||
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);
|
||||
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);
|
||||
return static_groups;
|
||||
}
|
||||
|
||||
|
|
|
@ -1932,33 +1932,26 @@ std::set<uint256> CWalletTx::GetConflicts() const
|
|||
return result;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const
|
||||
{
|
||||
auto& amount = m_amounts[type];
|
||||
if (recalculate || !amount.m_cached[filter]) {
|
||||
amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*tx, filter) : pwallet->GetCredit(*tx, filter));
|
||||
}
|
||||
return amount.m_value[filter];
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetDebit(const isminefilter& filter) const
|
||||
{
|
||||
if (tx->vin.empty())
|
||||
return 0;
|
||||
|
||||
CAmount debit = 0;
|
||||
if(filter & ISMINE_SPENDABLE)
|
||||
{
|
||||
if (fDebitCached)
|
||||
debit += nDebitCached;
|
||||
else
|
||||
{
|
||||
nDebitCached = pwallet->GetDebit(*tx, ISMINE_SPENDABLE);
|
||||
fDebitCached = true;
|
||||
debit += nDebitCached;
|
||||
}
|
||||
if (filter & ISMINE_SPENDABLE) {
|
||||
debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE);
|
||||
}
|
||||
if(filter & ISMINE_WATCH_ONLY)
|
||||
{
|
||||
if(fWatchDebitCached)
|
||||
debit += nWatchDebitCached;
|
||||
else
|
||||
{
|
||||
nWatchDebitCached = pwallet->GetDebit(*tx, ISMINE_WATCH_ONLY);
|
||||
fWatchDebitCached = true;
|
||||
debit += nWatchDebitCached;
|
||||
}
|
||||
if (filter & ISMINE_WATCH_ONLY) {
|
||||
debit += GetCachableAmount(DEBIT, ISMINE_WATCH_ONLY);
|
||||
}
|
||||
return debit;
|
||||
}
|
||||
|
@ -1970,28 +1963,12 @@ CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const ismine
|
|||
return 0;
|
||||
|
||||
CAmount credit = 0;
|
||||
if (filter & ISMINE_SPENDABLE)
|
||||
{
|
||||
if (filter & ISMINE_SPENDABLE) {
|
||||
// GetBalance can assume transactions in mapWallet won't change
|
||||
if (fCreditCached)
|
||||
credit += nCreditCached;
|
||||
else
|
||||
{
|
||||
nCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
|
||||
fCreditCached = true;
|
||||
credit += nCreditCached;
|
||||
}
|
||||
credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE);
|
||||
}
|
||||
if (filter & ISMINE_WATCH_ONLY)
|
||||
{
|
||||
if (fWatchCreditCached)
|
||||
credit += nWatchCreditCached;
|
||||
else
|
||||
{
|
||||
nWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
|
||||
fWatchCreditCached = true;
|
||||
credit += nWatchCreditCached;
|
||||
}
|
||||
if (filter & ISMINE_WATCH_ONLY) {
|
||||
credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY);
|
||||
}
|
||||
return credit;
|
||||
}
|
||||
|
@ -1999,11 +1976,7 @@ CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const ismine
|
|||
CAmount CWalletTx::GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache) const
|
||||
{
|
||||
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
|
||||
if (fUseCache && fImmatureCreditCached)
|
||||
return nImmatureCreditCached;
|
||||
nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
|
||||
fImmatureCreditCached = true;
|
||||
return nImmatureCreditCached;
|
||||
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2014,23 +1987,15 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
|
|||
if (pwallet == nullptr)
|
||||
return 0;
|
||||
|
||||
// Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
|
||||
bool allow_cache = filter == ISMINE_SPENDABLE || filter == ISMINE_WATCH_ONLY;
|
||||
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsImmatureCoinBase(locked_chain))
|
||||
return 0;
|
||||
|
||||
CAmount* cache = nullptr;
|
||||
bool* cache_used = nullptr;
|
||||
|
||||
if (filter == ISMINE_SPENDABLE) {
|
||||
cache = &nAvailableCreditCached;
|
||||
cache_used = &fAvailableCreditCached;
|
||||
} else if (filter == ISMINE_WATCH_ONLY) {
|
||||
cache = &nAvailableWatchCreditCached;
|
||||
cache_used = &fAvailableWatchCreditCached;
|
||||
}
|
||||
|
||||
if (fUseCache && cache_used && *cache_used) {
|
||||
return *cache;
|
||||
if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) {
|
||||
return m_amounts[AVAILABLE_CREDIT].m_value[filter];
|
||||
}
|
||||
|
||||
CAmount nCredit = 0;
|
||||
|
@ -2046,22 +2011,17 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
|
|||
}
|
||||
}
|
||||
|
||||
if (cache) {
|
||||
*cache = nCredit;
|
||||
assert(cache_used);
|
||||
*cache_used = true;
|
||||
if (allow_cache) {
|
||||
m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit);
|
||||
}
|
||||
|
||||
return nCredit;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetImmatureWatchOnlyCredit(interfaces::Chain::Lock& locked_chain, const bool fUseCache) const
|
||||
{
|
||||
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
|
||||
if (fUseCache && fImmatureWatchCreditCached)
|
||||
return nImmatureWatchCreditCached;
|
||||
nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
|
||||
fImmatureWatchCreditCached = true;
|
||||
return nImmatureWatchCreditCached;
|
||||
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -369,24 +369,11 @@ public:
|
|||
std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
|
||||
|
||||
// memory only
|
||||
mutable bool fDebitCached;
|
||||
mutable bool fCreditCached;
|
||||
mutable bool fImmatureCreditCached;
|
||||
mutable bool fAvailableCreditCached;
|
||||
mutable bool fWatchDebitCached;
|
||||
mutable bool fWatchCreditCached;
|
||||
mutable bool fImmatureWatchCreditCached;
|
||||
mutable bool fAvailableWatchCreditCached;
|
||||
enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS };
|
||||
CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const;
|
||||
mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS];
|
||||
mutable bool fChangeCached;
|
||||
mutable bool fInMempool;
|
||||
mutable CAmount nDebitCached;
|
||||
mutable CAmount nCreditCached;
|
||||
mutable CAmount nImmatureCreditCached;
|
||||
mutable CAmount nAvailableCreditCached;
|
||||
mutable CAmount nWatchDebitCached;
|
||||
mutable CAmount nWatchCreditCached;
|
||||
mutable CAmount nImmatureWatchCreditCached;
|
||||
mutable CAmount nAvailableWatchCreditCached;
|
||||
mutable CAmount nChangeCached;
|
||||
|
||||
CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
|
||||
|
@ -403,24 +390,8 @@ public:
|
|||
nTimeReceived = 0;
|
||||
nTimeSmart = 0;
|
||||
fFromMe = false;
|
||||
fDebitCached = false;
|
||||
fCreditCached = false;
|
||||
fImmatureCreditCached = false;
|
||||
fAvailableCreditCached = false;
|
||||
fWatchDebitCached = false;
|
||||
fWatchCreditCached = false;
|
||||
fImmatureWatchCreditCached = false;
|
||||
fAvailableWatchCreditCached = false;
|
||||
fChangeCached = false;
|
||||
fInMempool = false;
|
||||
nDebitCached = 0;
|
||||
nCreditCached = 0;
|
||||
nImmatureCreditCached = 0;
|
||||
nAvailableCreditCached = 0;
|
||||
nWatchDebitCached = 0;
|
||||
nWatchCreditCached = 0;
|
||||
nAvailableWatchCreditCached = 0;
|
||||
nImmatureWatchCreditCached = 0;
|
||||
nChangeCached = 0;
|
||||
nOrderPos = -1;
|
||||
}
|
||||
|
@ -464,14 +435,10 @@ public:
|
|||
//! make sure balances are recalculated
|
||||
void MarkDirty()
|
||||
{
|
||||
fCreditCached = false;
|
||||
fAvailableCreditCached = false;
|
||||
fImmatureCreditCached = false;
|
||||
fWatchDebitCached = false;
|
||||
fWatchCreditCached = false;
|
||||
fAvailableWatchCreditCached = false;
|
||||
fImmatureWatchCreditCached = false;
|
||||
fDebitCached = false;
|
||||
m_amounts[DEBIT].Reset();
|
||||
m_amounts[CREDIT].Reset();
|
||||
m_amounts[IMMATURE_CREDIT].Reset();
|
||||
m_amounts[AVAILABLE_CREDIT].Reset();
|
||||
fChangeCached = false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue