From 6b803fb1ee1211f23f3e96828d040a0454e66240 Mon Sep 17 00:00:00 2001 From: furszy Date: Thu, 23 Dec 2021 18:30:33 -0300 Subject: [PATCH] validation: create coinspends cache --- src/validation.cpp | 5 +++++ src/zpiv/zpivmodule.cpp | 44 ++++++++++++++++++++++++++++++++++++++++- src/zpiv/zpivmodule.h | 3 +++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 56b444c158661..ee91052ba3f4a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1691,10 +1691,15 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd pindex->nHeight < consensus.height_last_ZC_AccumCheckpoint) { // Legacy Zerocoin DB: If Accumulators Checkpoint is changed, cache the checksums CacheAccChecksum(pindex, true); + // Clean coinspends cache every 50k blocks, so it does not grow unnecessarily + if (pindex->nHeight % 50000 == 0) { + ZPIVModule::CleanCoinSpendsCache(); + } } else if (accumulatorCache && pindex->nHeight > consensus.height_last_ZC_AccumCheckpoint + 100) { // 100 blocks After last Checkpoint block, wipe the checksum database and cache accumulatorCache->Wipe(); accumulatorCache.reset(); + ZPIVModule::CleanCoinSpendsCache(); } // 100 blocks after the last invalid out, clean the map contents diff --git a/src/zpiv/zpivmodule.cpp b/src/zpiv/zpivmodule.cpp index cefdd4c08c21f..4aea78a0ae477 100644 --- a/src/zpiv/zpivmodule.cpp +++ b/src/zpiv/zpivmodule.cpp @@ -114,6 +114,34 @@ static bool TxOutToPublicCoin(const CTxOut& txout, libzerocoin::PublicCoin& pubC return true; } +// TODO: do not create g_coinspends_cache if the node passed the last zc checkpoint. +class CoinSpendCache { +private: + mutable Mutex cs; + std::map cache_coinspend; + std::map cache_public_coinspend; + + template + Optional Get(const CScript& in, const std::map& map) const { + LOCK(cs); + auto it = map.find(in); + return it != map.end() ? Optional{it->second} : nullopt; + } + +public: + void Add(const CScript& in, libzerocoin::CoinSpend& spend) { WITH_LOCK(cs, cache_coinspend.emplace(in, spend)); } + void AddPub(const CScript& in, PublicCoinSpend& spend) { WITH_LOCK(cs, cache_public_coinspend.emplace(in, spend)); } + + Optional Get(const CScript& in) const { return Get(in, cache_coinspend); } + Optional GetPub(const CScript& in) const { return Get(in, cache_public_coinspend); } + void Clear() { + LOCK(cs); + cache_coinspend.clear(); + cache_public_coinspend.clear(); + } +}; +std::unique_ptr g_coinspends_cache = std::make_unique(); + namespace ZPIVModule { // Return stream of CoinSpend from tx input scriptsig @@ -134,6 +162,11 @@ namespace ZPIVModule { } bool parseCoinSpend(const CTxIn &in, const CTransaction &tx, const CTxOut &prevOut, PublicCoinSpend &publicCoinSpend) { + if (auto op = g_coinspends_cache->GetPub(in.scriptSig)) { + publicCoinSpend = *op; + return true; + } + if (!in.IsZerocoinPublicSpend() || !prevOut.IsZerocoinMint()) return error("%s: invalid argument/s", __func__); @@ -151,13 +184,17 @@ namespace ZPIVModule { spend.setDenom(spend.pubCoin.getDenomination()); publicCoinSpend = spend; + g_coinspends_cache->AddPub(in.scriptSig, publicCoinSpend); return true; } libzerocoin::CoinSpend TxInToZerocoinSpend(const CTxIn& txin) { + if (auto op = g_coinspends_cache->Get(txin.scriptSig)) return *op; CDataStream serializedCoinSpend = ScriptSigToSerializedSpend(txin.scriptSig); - return libzerocoin::CoinSpend(serializedCoinSpend); + libzerocoin::CoinSpend spend(serializedCoinSpend); + g_coinspends_cache->Add(txin.scriptSig, spend); + return spend; } bool validateInput(const CTxIn &in, const CTxOut &prevOut, const CTransaction &tx, PublicCoinSpend &publicSpend) { @@ -185,4 +222,9 @@ namespace ZPIVModule { } return true; } + + void CleanCoinSpendsCache() + { + g_coinspends_cache->Clear(); + } } diff --git a/src/zpiv/zpivmodule.h b/src/zpiv/zpivmodule.h index 56435a96587d1..bb7ebabc325d4 100644 --- a/src/zpiv/zpivmodule.h +++ b/src/zpiv/zpivmodule.h @@ -78,6 +78,9 @@ namespace ZPIVModule { * @return true if everything went ok */ bool ParseZerocoinPublicSpend(const CTxIn &in, const CTransaction& tx, CValidationState& state, PublicCoinSpend& publicCoinSpend); + + // Clear the coinspend cache + void CleanCoinSpendsCache(); };