From a85aa2b69e987b558342882ac5dccf485d81a1c0 Mon Sep 17 00:00:00 2001 From: Cy Rossignol Date: Thu, 6 Aug 2020 09:51:27 -0500 Subject: [PATCH] Optimize contract replay after chain reorganization This improves the performance of contract replay when the chain reorganizes. Instead of reverting each contract for each of the disconnected blocks, we can just wipe the cached state for each of the contract handlers. Replay fills the caches with 6 months of contract data again afterward. This partially solves the unnecessary retention of contracts in memory for long-running nodes because the reorganization occurs often enough that nodes will clear historical data before these caches grow too large. Future improvements will enable contract handlers to manage historical data more precisely. --- src/main.cpp | 5 ----- src/neuralnet/beacon.cpp | 6 ++++++ src/neuralnet/beacon.h | 6 ++++++ src/neuralnet/contract/contract.cpp | 28 ++++++++++++++++++++++++++++ src/neuralnet/contract/handler.h | 6 ++++++ src/neuralnet/project.cpp | 5 +++++ src/neuralnet/project.h | 6 ++++++ 7 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2b9d574153..c881266291 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2226,11 +2226,6 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) { bDiscTxFailed = true; } - - if (pindex->nIsContract == 1) - { - NN::RevertContracts(vtx[i], pindex); - } } // Update block index on disk without changing it in memory. diff --git a/src/neuralnet/beacon.cpp b/src/neuralnet/beacon.cpp index c9d53c25f6..ae7961c2dd 100644 --- a/src/neuralnet/beacon.cpp +++ b/src/neuralnet/beacon.cpp @@ -319,6 +319,12 @@ bool BeaconRegistry::ContainsActive(const Cpid& cpid) const return ContainsActive(cpid, GetAdjustedTime()); } +void BeaconRegistry::Reset() +{ + m_beacons.clear(); + m_pending.clear(); +} + void BeaconRegistry::Add(const ContractContext& ctx) { BeaconPayload payload = ctx->CopyPayloadAs(); diff --git a/src/neuralnet/beacon.h b/src/neuralnet/beacon.h index 7c9813995d..0f3c664fc9 100644 --- a/src/neuralnet/beacon.h +++ b/src/neuralnet/beacon.h @@ -465,6 +465,12 @@ class BeaconRegistry : public IContractHandler //! bool ContainsActive(const Cpid& cpid) const; + //! + //! \brief Destroy the contract handler state to prepare for historical + //! contract replay. + //! + void Reset() override; + //! //! \brief Determine whether a beacon contract is valid. //! diff --git a/src/neuralnet/contract/contract.cpp b/src/neuralnet/contract/contract.cpp index f92acc1a56..7f9b37c5be 100644 --- a/src/neuralnet/contract/contract.cpp +++ b/src/neuralnet/contract/contract.cpp @@ -144,6 +144,15 @@ class LegacyPayload : public IContractPayload //! class AppCacheContractHandler : public IContractHandler { +public: + void Reset() override + { + ClearCache(Section::POLL); + ClearCache(Section::PROTOCOL); + ClearCache(Section::SCRAPER); + ClearCache(Section::VOTE); + } + bool Validate(const Contract& contract, const CTransaction& tx) const override { return true; // No contextual validation needed yet @@ -182,6 +191,12 @@ class AppCacheContractHandler : public IContractHandler //! class UnknownContractHandler : public IContractHandler { +public: + void Reset() override + { + // Nothing to do. + } + bool Validate(const Contract& contract, const CTransaction& tx) const override { return true; // No contextual validation needed yet @@ -225,6 +240,17 @@ class UnknownContractHandler : public IContractHandler class Dispatcher { public: + //! + //! \brief Reset the cached state of each contract handler to prepare for + //! historical contract replay. + //! + void ResetHandlers() + { + GetBeaconRegistry().Reset(); + GetWhitelist().Reset(); + m_appcache_handler.Reset(); + } + //! //! \brief Validate the provided contract and forward it to the appropriate //! contract handler. @@ -343,6 +369,8 @@ void NN::ReplayContracts(const CBlockIndex* pindex) return; } + g_dispatcher.ResetHandlers(); + CBlock block; // These are memorized consecutively in order from oldest to newest. diff --git a/src/neuralnet/contract/handler.h b/src/neuralnet/contract/handler.h index 9f39bb32d9..1726b33a34 100644 --- a/src/neuralnet/contract/handler.h +++ b/src/neuralnet/contract/handler.h @@ -77,6 +77,12 @@ struct IContractHandler //! virtual bool Validate(const Contract& contract, const CTransaction& tx) const = 0; + //! + //! \brief Destroy the contract handler state to prepare for historical + //! contract replay. + //! + virtual void Reset() = 0; + //! //! \brief Handle an contract addition. //! diff --git a/src/neuralnet/project.cpp b/src/neuralnet/project.cpp index 2403cc0d6f..0efb73a79d 100644 --- a/src/neuralnet/project.cpp +++ b/src/neuralnet/project.cpp @@ -154,6 +154,11 @@ WhitelistSnapshot Whitelist::Snapshot() const return WhitelistSnapshot(std::atomic_load(&m_projects)); } +void Whitelist::Reset() +{ + std::atomic_store(&m_projects, std::make_shared()); +} + void Whitelist::Add(const ContractContext& ctx) { Project project = ctx->CopyPayloadAs(); diff --git a/src/neuralnet/project.h b/src/neuralnet/project.h index 7939b90ba2..fb11ee6fdb 100644 --- a/src/neuralnet/project.h +++ b/src/neuralnet/project.h @@ -280,6 +280,12 @@ class Whitelist : public IContractHandler //! WhitelistSnapshot Snapshot() const; + //! + //! \brief Destroy the contract handler state to prepare for historical + //! contract replay. + //! + void Reset() override; + //! //! \brief Perform contextual validation for the provided contract. //!