diff --git a/src/Nethermind/Nethermind.Blockchain/FullPruning/PruningTriggerPersistenceStrategy.cs b/src/Nethermind/Nethermind.Blockchain/FullPruning/PruningTriggerPersistenceStrategy.cs index b2d88f9ef7a..6118fc4188a 100644 --- a/src/Nethermind/Nethermind.Blockchain/FullPruning/PruningTriggerPersistenceStrategy.cs +++ b/src/Nethermind/Nethermind.Blockchain/FullPruning/PruningTriggerPersistenceStrategy.cs @@ -67,6 +67,8 @@ public bool ShouldPersist(long blockNumber) return inPruning; } + public bool IsFullPruning => _inPruning != 0; + /// public void Dispose() { diff --git a/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs b/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs index 35c20ecf02b..b36f35af072 100644 --- a/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs @@ -16,6 +16,7 @@ using Nethermind.State; using Nethermind.State.Witnesses; using Nethermind.Trie.Pruning; +using NSubstitute; using NUnit.Framework; namespace Nethermind.Trie.Test.Pruning @@ -822,6 +823,7 @@ public void After_commit_should_have_has_root() trieStore.HasRoot(stateTree.RootHash).Should().BeTrue(); } + [Test] public async Task Will_RemovePastKeys_OnSnapshot() { MemDb memDb = new(); @@ -854,6 +856,35 @@ public async Task Will_RemovePastKeys_OnSnapshot() } } + [Test] + public async Task Will_Not_RemovePastKeys_OnSnapshot_DuringFullPruning() + { + MemDb memDb = new(); + + IPersistenceStrategy isPruningPersistenceStrategy = Substitute.For(); + isPruningPersistenceStrategy.IsFullPruning.Returns(true); + + using TrieStore fullTrieStore = CreateTrieStore( + kvStore: memDb, + pruningStrategy: new TestPruningStrategy(true, true, 100000), + persistenceStrategy: isPruningPersistenceStrategy, + reorgDepthOverride: 2); + + IScopedTrieStore trieStore = fullTrieStore.GetTrieStore(null); + + for (int i = 0; i < 64; i++) + { + TrieNode node = new(NodeType.Leaf, TestItem.Keccaks[i], new byte[2]); + trieStore.CommitNode(i, new NodeCommitInfo(node, TreePath.Empty)); + trieStore.FinishBlockCommit(TrieType.State, i, node); + + // Pruning is done in background + await Task.Delay(TimeSpan.FromMilliseconds(10)); + } + + memDb.Count.Should().Be(61); + } + [Test] public async Task Will_NotRemove_ReCommittedNode() { diff --git a/src/Nethermind/Nethermind.Trie/Pruning/Archive.cs b/src/Nethermind/Nethermind.Trie/Pruning/Archive.cs index 8e534c70c68..1b70bec140d 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/Archive.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/Archive.cs @@ -13,5 +13,7 @@ public bool ShouldPersist(long blockNumber) { return true; } + + public bool IsFullPruning => false; } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/CompositePersistenceStrategy.cs b/src/Nethermind/Nethermind.Trie/Pruning/CompositePersistenceStrategy.cs index 25fdd5e4ed8..25653237786 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/CompositePersistenceStrategy.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/CompositePersistenceStrategy.cs @@ -22,4 +22,5 @@ public IPersistenceStrategy AddStrategy(IPersistenceStrategy strategy) } public bool ShouldPersist(long blockNumber) => _strategies.Any(strategy => strategy.ShouldPersist(blockNumber)); + public bool IsFullPruning => _strategies.Any(strategy => strategy.IsFullPruning); } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/IPersistenceStrategy.cs b/src/Nethermind/Nethermind.Trie/Pruning/IPersistenceStrategy.cs index 69ce05438ca..671663d2aec 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/IPersistenceStrategy.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/IPersistenceStrategy.cs @@ -6,5 +6,6 @@ namespace Nethermind.Trie.Pruning public interface IPersistenceStrategy { bool ShouldPersist(long blockNumber); + bool IsFullPruning { get; } } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/IntervalSnapshotting.cs b/src/Nethermind/Nethermind.Trie/Pruning/IntervalSnapshotting.cs index cff18422c7b..a1440f92b50 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/IntervalSnapshotting.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/IntervalSnapshotting.cs @@ -16,5 +16,7 @@ public bool ShouldPersist(long blockNumber) { return blockNumber % _snapshotInterval == 0; } + + public bool IsFullPruning => false; } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/NoPersistence.cs b/src/Nethermind/Nethermind.Trie/Pruning/NoPersistence.cs index 41f788f3996..4d6d560cec4 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/NoPersistence.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/NoPersistence.cs @@ -13,5 +13,7 @@ public bool ShouldPersist(long blockNumber) { return false; } + + public bool IsFullPruning => false; } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs index 2343bd85bbf..dfcc38a20a4 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs @@ -636,9 +636,16 @@ private bool CanPruneCacheFurther() _commitSetQueue.Enqueue(toAddBack[index]); } + bool shouldDeletePersistedNode = + // Its disabled + _pastPathHash != null && + // Full pruning need to visit all node, so can't delete anything. + !_persistenceStrategy.IsFullPruning && + // If more than one candidate set, its a reorg, we can't remove node as persisted node may not be canonical + candidateSets.Count == 1; + Dictionary<(Hash256?, TinyTreePath), Hash256?>? persistedHashes = - // If its a reorg, we can't remove node as persisted node may not be canonical - _pastPathHash != null && candidateSets.Count == 1 + shouldDeletePersistedNode ? new Dictionary<(Hash256?, TinyTreePath), Hash256?>() : null;