From e5f9536c24000d1933d6fa506f5d9b6a1fc223d7 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 13:21:57 +0800 Subject: [PATCH 1/9] Add edge cases --- .../Nethermind.Core/Crypto/Hash256.cs | 10 +++ .../Nethermind.Synchronization.Test.csproj | 19 ++++++ .../SnapSync/SnapProviderTests.cs | 47 +++++++++++++ .../TestFixtures/badreq-roothash-2.zip | Bin 0 -> 23690 bytes .../TestFixtures/badreq-roothash-3.zip | Bin 0 -> 83360 bytes .../SnapSync/TestFixtures/badreq-roothash.zip | Bin 0 -> 33522 bytes .../TestFixtures/badreq-trieexception.zip | Bin 0 -> 23092 bytes .../SnapSync/ProgressTracker.cs | 16 ++--- .../SnapSync/SnapProvider.cs | 27 ++++---- .../SnapSync/SnapProviderHelper.cs | 63 ++++++++++++++++-- .../Nethermind.Trie/Pruning/TreePath.cs | 2 +- 11 files changed, 157 insertions(+), 27 deletions(-) create mode 100644 src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-roothash-2.zip create mode 100644 src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-roothash-3.zip create mode 100644 src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-roothash.zip create mode 100644 src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-trieexception.zip diff --git a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs index cc317af86fb..253b6bcd92f 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs @@ -9,6 +9,7 @@ using System.Text.Json.Serialization; using Nethermind.Core.Extensions; +using Nethermind.Int256; using Nethermind.Serialization.Json; namespace Nethermind.Core.Crypto @@ -58,6 +59,10 @@ public ValueHash256(ReadOnlySpan bytes) _bytes = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); } + public ValueHash256(UInt256 uint256): this(uint256.ToBigEndian()) + { + } + public override bool Equals(object? obj) => obj is ValueHash256 keccak && Equals(keccak); public bool Equals(ValueHash256 other) => _bytes.Equals(other._bytes); @@ -112,6 +117,11 @@ public Hash256 ToCommitment() public static bool operator >=(in ValueHash256 left, in ValueHash256 right) => left.CompareTo(in right) >= 0; public static bool operator <=(in ValueHash256 left, in ValueHash256 right) => left.CompareTo(in right) <= 0; public static implicit operator Hash256(in ValueHash256 keccak) => new(keccak); + + public UInt256 ToUInt256() + { + return new UInt256(Bytes, isBigEndian: true); + } } public readonly struct Hash256AsKey(Hash256 key) : IEquatable diff --git a/src/Nethermind/Nethermind.Synchronization.Test/Nethermind.Synchronization.Test.csproj b/src/Nethermind/Nethermind.Synchronization.Test/Nethermind.Synchronization.Test.csproj index adc3e797f41..abcafea8c9f 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/Nethermind.Synchronization.Test.csproj +++ b/src/Nethermind/Nethermind.Synchronization.Test/Nethermind.Synchronization.Test.csproj @@ -27,4 +27,23 @@ + + + + PreserveNewest + + + + PreserveNewest + + + + PreserveNewest + + + + PreserveNewest + + + diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs index 58e0a808b06..ef5f56e4f0b 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs @@ -14,6 +14,14 @@ using NUnit.Framework; using System; using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Text.Json; +using Nethermind.Core; +using Nethermind.Core.Test; +using Nethermind.Serialization.Rlp; +using Nethermind.State; +using Nethermind.Trie.Pruning; namespace Nethermind.Synchronization.Test.SnapSync; @@ -59,4 +67,43 @@ public void AddAccountRange_ResponseHasEmptyListOfAccountsAndOneProof_ReturnsExp sut.AddAccountRange(accountRange, accountsAndProofs).Should().Be(AddRangeResult.ExpiredRootHash); } + [TestCase("badreq-roothash.zip")] + [TestCase("badreq-roothash-2.zip")] + [TestCase("badreq-roothash-3.zip")] + [TestCase("badreq-trieexception.zip")] + public void TestStrangeCase2(string testFileName) + { + using DeflateStream decompressor = + new DeflateStream( + GetType().Assembly + .GetManifestResourceStream($"Nethermind.Synchronization.Test.SnapSync.TestFixtures.{testFileName}")!, + CompressionMode.Decompress); + BadReq asReq = JsonSerializer.Deserialize(decompressor)!; + + AccountDecoder acd = new AccountDecoder(); + Account[] accounts = asReq.Accounts.Select((bt) => acd.Decode(new RlpStream(Bytes.FromHexString(bt)))!).ToArray(); + ValueHash256[] paths = asReq.Paths.Select((bt) => new ValueHash256(Bytes.FromHexString(bt))).ToArray(); + + List pathWithAccounts = accounts.Select((acc, idx) => new PathWithAccount(paths[idx], acc)).ToList(); + List proofs = asReq.Proofs.Select((str) => Bytes.FromHexString(str)).ToList(); + + StateTree stree = new StateTree(new TrieStore(new TestMemDb(), LimboLogs.Instance), LimboLogs.Instance); + SnapProviderHelper.AddAccountRange( + stree, + 0, + new ValueHash256(asReq.Root), + new ValueHash256(asReq.StartingHash), + new ValueHash256(asReq.LimitHash), + pathWithAccounts, + proofs).result.Should().Be(AddRangeResult.OK); + } + + private record BadReq( + string Root, + string StartingHash, + string LimitHash, + List Proofs, + List Paths, + List Accounts + ); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-roothash-2.zip b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-roothash-2.zip new file mode 100644 index 0000000000000000000000000000000000000000..3912b5872693d02d2fbffd43b7ddaa32fa289641 GIT binary patch literal 23690 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 literal 0 HcmV?d00001 diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-roothash-3.zip b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/TestFixtures/badreq-roothash-3.zip new file mode 100644 index 0000000000000000000000000000000000000000..1e4fd13e1234ebec36b67e8c665f68e43a8ee8f1 GIT binary patch literal 83360 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%0A^qs3=o)W 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%0AEm0!t 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 T2Vx2h|MTPD{{R30|NjF3_KZLf literal 0 HcmV?d00001 diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index 132ff77c0da..50c54a443d5 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Buffers.Binary; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -72,7 +73,7 @@ public ProgressTracker(IBlockTree blockTree, IDb db, ILogManager logManager, int _pivot = new Pivot(blockTree, logManager); - if (accountRangePartitionCount < 1 || accountRangePartitionCount > 256) + if (accountRangePartitionCount < 1 || accountRangePartitionCount > int.MaxValue) throw new ArgumentException("Account range partition must be between 1 to 256."); _accountRangePartitionCount = accountRangePartitionCount; @@ -84,23 +85,20 @@ public ProgressTracker(IBlockTree blockTree, IDb db, ILogManager logManager, int private void SetupAccountRangePartition() { - // Confusingly dividing the range evenly via UInt256 for example, consistently cause root hash mismatch. - // The mismatch happens on exactly the same partition every time, suggesting tome kind of boundary issues - // either on proof generation or validation. - byte curStartingPath = 0; - int partitionSize = (256 / _accountRangePartitionCount); + uint curStartingPath = 0; + uint partitionSize = (uint)(((ulong)uint.MaxValue + 1) / (ulong)_accountRangePartitionCount); for (var i = 0; i < _accountRangePartitionCount; i++) { AccountRangePartition partition = new AccountRangePartition(); Hash256 startingPath = new Hash256(Keccak.Zero.Bytes); - startingPath.Bytes[0] = curStartingPath; + BinaryPrimitives.WriteUInt32BigEndian(startingPath.Bytes, curStartingPath); partition.NextAccountPath = startingPath; partition.AccountPathStart = startingPath; - curStartingPath += (byte)partitionSize; + curStartingPath += partitionSize; Hash256 limitPath; @@ -112,7 +110,7 @@ private void SetupAccountRangePartition() else { limitPath = new Hash256(Keccak.Zero.Bytes); - limitPath.Bytes[0] = curStartingPath; + BinaryPrimitives.WriteUInt32BigEndian(limitPath.Bytes, curStartingPath); } partition.AccountPathLimit = limitPath; diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs index 51548bfa9f6..f291b90cfe4 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs @@ -15,6 +15,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Db; +using Nethermind.Int256; using Nethermind.Logging; using Nethermind.State; using Nethermind.State.Snap; @@ -61,17 +62,17 @@ public AddRangeResult AddAccountRange(AccountRange request, AccountsAndProofs re } else { - result = AddAccountRange( - request.BlockNumber.Value, - request.RootHash, - request.StartingHash, - response.PathAndAccounts, - response.Proofs, - hashLimit: request.LimitHash); - - if (result == AddRangeResult.OK) - { - Interlocked.Add(ref Metrics.SnapSyncedAccounts, response.PathAndAccounts.Count); + result = AddAccountRange( + request.BlockNumber.Value, + request.RootHash, + request.StartingHash, + response.PathAndAccounts, + response.Proofs, + hashLimit: request.LimitHash); + + if (result == AddRangeResult.OK) + { + Interlocked.Add(ref Metrics.SnapSyncedAccounts, response.PathAndAccounts.Count); } } @@ -120,7 +121,9 @@ public AddRangeResult AddAccountRange( _progressTracker.EnqueueCodeHashes(filteredCodeHashes.AsSpan()); - _progressTracker.UpdateAccountRangePartitionProgress(effectiveHashLimit, accounts[^1].Path, moreChildrenToRight); + UInt256 nextPath = accounts[^1].Path.ToUInt256(); + nextPath += UInt256.One; + _progressTracker.UpdateAccountRangePartitionProgress(effectiveHashLimit, new ValueHash256(nextPath), moreChildrenToRight); } else if (result == AddRangeResult.MissingRootHashInProofs) { diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index 967e10cad47..cf6a908c0a2 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -44,13 +44,21 @@ public static (AddRangeResult result, bool moreChildrenToRight, List accountsWithStorage = new(); List codeHashes = new(); + bool hasExtraStorage = false; for (var index = 0; index < accounts.Count; index++) { PathWithAccount account = accounts[index]; if (account.Account.HasStorage) { - accountsWithStorage.Add(account); + if (account.Path >= limitHash) + { + hasExtraStorage = true; + } + else + { + accountsWithStorage.Add(account); + } } if (account.Account.HasCode) @@ -72,7 +80,30 @@ public static (AddRangeResult result, bool moreChildrenToRight, List= limitHash) continue; + _ = tree.Set(account.Path, account.Account); + } + } + else + { + StitchBoundaries(sortedBoundaryList, tree.TrieStore); + } tree.Commit(skipRoot: true, writeFlags: WriteFlags.DisableWAL); @@ -188,12 +219,14 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary } else { - Span pathSpan = CollectionsMarshal.AsSpan(path); - if (Bytes.BytesComparer.Compare(pathSpan, leftBoundary[0..path.Count]) >= 0 + TreePath extensionChildPath = TreePath.FromNibble(CollectionsMarshal.AsSpan(path)); + extensionChildPath = extensionChildPath.Append(node.Key); + TreePath firstKeyPath = TreePath.FromPath(effectiveStartingHAsh.Bytes).Truncate(extensionChildPath.Length); + if (extensionChildPath.CompareTo(firstKeyPath) >= 0 && parent is not null && parent.IsBranch) { - for (int i = 0; i < 15; i++) + for (int i = 0; i < 16; i++) { if (parent.GetChildHashAsValueKeccak(i, out ValueHash256 kec) && kec == node.Keccak) { @@ -243,6 +276,26 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary proofNodesToProcess.Push((node, child, pathIndex, newPath)); sortedBoundaryList.Add((child, TreePath.FromNibble(CollectionsMarshal.AsSpan(newPath)))); } + else + { + // Sometimes a leaf becomes a proof. + // we add them. + TreePath tPath = TreePath.FromNibble(CollectionsMarshal.AsSpan(path)); + tPath.AppendMut(ci); + + List newPath = new(path) + { + (byte)ci + }; + + TreePath wholePath = tPath.Append(child.Key); + if (wholePath.Path < startingHash || wholePath.Path > endHash) + { + node.SetChild(ci, child); + proofNodesToProcess.Push((node, child, pathIndex, newPath)); + sortedBoundaryList.Add((child, tPath)); + } + } } } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs b/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs index 36306f16241..aae323323b0 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs @@ -136,7 +136,7 @@ internal void AppendMut(ReadOnlySpan nibbles) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void AppendMut(int nib) + public void AppendMut(int nib) { this[Length] = nib; Length++; From 674662cd98d47f35f2673252c4f605652e3ee81e Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 15:14:27 +0800 Subject: [PATCH 2/9] Use tree path --- .../SnapSync/SnapProviderHelper.cs | 73 ++++++++----------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index cf6a908c0a2..1b29e048eae 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -179,30 +179,28 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary return (AddRangeResult.MissingRootHashInProofs, null, true); } - // BytesToNibbleBytes will throw if the input is not 32 bytes long, so we can use stackalloc+SkipLocalsInit - Span leftBoundary = stackalloc byte[64]; - Nibbles.BytesToNibbleBytes(effectiveStartingHAsh.Bytes, leftBoundary); - Span rightBoundary = stackalloc byte[64]; - Nibbles.BytesToNibbleBytes(endHash.Bytes, rightBoundary); - Span rightLimit = stackalloc byte[64]; - Nibbles.BytesToNibbleBytes(limitHash.Bytes, rightLimit); + TreePath leftBoundaryPath = TreePath.FromPath(effectiveStartingHAsh.Bytes); + TreePath rightBoundaryPath = TreePath.FromPath(endHash.Bytes); + TreePath rightLimitPath = TreePath.FromPath(limitHash.Bytes); // For when in very-very unlikely case where the last remaining address is Keccak.MaxValue, (who knows why, // the chain have special handling for it maybe) and it is not included the returned account range, (again, // very-very unlikely), we want `moreChildrenToRight` to return true. bool noLimit = limitHash == ValueKeccak.MaxValue; - Stack<(TrieNode parent, TrieNode node, int pathIndex, List path)> proofNodesToProcess = new(); + // Connect the proofs with proof head. + // It also remove child path which is within the start/end range. If key are missing, the resolved + // hash will not match. + Stack<(TrieNode parent, TrieNode node, TreePath path)> proofNodesToProcess = new(); tree.RootRef = root; - proofNodesToProcess.Push((null, root, -1, new List())); + proofNodesToProcess.Push((null, root, TreePath.Empty)); sortedBoundaryList.Add((root, TreePath.Empty)); bool moreChildrenToRight = false; - while (proofNodesToProcess.Count > 0) { - (TrieNode parent, TrieNode node, int pathIndex, List path) = proofNodesToProcess.Pop(); + (TrieNode parent, TrieNode node, TreePath path) = proofNodesToProcess.Pop(); if (node.IsExtension) { @@ -212,16 +210,19 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary { node.SetChild(0, child); - pathIndex += node.Key.Length; - path.AddRange(node.Key); - proofNodesToProcess.Push((node, child, pathIndex, path)); - sortedBoundaryList.Add((child, TreePath.FromNibble(CollectionsMarshal.AsSpan(path)))); + TreePath childPath = path.Append(node.Key); + + proofNodesToProcess.Push((node, child, childPath)); + sortedBoundaryList.Add((child, childPath)); } else { - TreePath extensionChildPath = TreePath.FromNibble(CollectionsMarshal.AsSpan(path)); - extensionChildPath = extensionChildPath.Append(node.Key); - TreePath firstKeyPath = TreePath.FromPath(effectiveStartingHAsh.Bytes).Truncate(extensionChildPath.Length); + // Sometimes, the proof ends with the extension, the branch of at the end of extension is + // not included. So we remove the extension, but only if it is after or the left boundary + // as it will be re-created by the path. If it is before the left boundary however, it is + // part of a proof. + TreePath extensionChildPath = path.Append(node.Key); + TreePath firstKeyPath = leftBoundaryPath.Truncate(extensionChildPath.Length); if (extensionChildPath.CompareTo(firstKeyPath) >= 0 && parent is not null && parent.IsBranch) @@ -241,12 +242,9 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary if (node.IsBranch) { - pathIndex++; - - Span pathSpan = CollectionsMarshal.AsSpan(path); - int left = Bytes.BytesComparer.Compare(pathSpan, leftBoundary[0..path.Count]) == 0 ? leftBoundary[pathIndex] : 0; - int right = Bytes.BytesComparer.Compare(pathSpan, rightBoundary[0..path.Count]) == 0 ? rightBoundary[pathIndex] : 15; - int limit = Bytes.BytesComparer.Compare(pathSpan, rightLimit[0..path.Count]) == 0 ? rightLimit[pathIndex] : 15; + int left = path == leftBoundaryPath.Truncate(path.Length) ? leftBoundaryPath[path.Length] : 0; + int right = path == rightBoundaryPath.Truncate(path.Length) ? rightBoundaryPath[path.Length] : 15; + int limit = path == rightLimitPath.Truncate(path.Length) ? rightLimitPath[path.Length] : 15; int maxIndex = moreChildrenToRight ? right : 15; @@ -263,37 +261,24 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary if (hasKeccak && (ci == left || ci == right) && dict.TryGetValue(childKeccak, out TrieNode child)) { + TreePath childPath = path.Append(ci); + if (!child.IsLeaf) { node.SetChild(ci, child); - // TODO: we should optimize it - copy only if there are two boundary children - List newPath = new(path) - { - (byte)ci - }; - - proofNodesToProcess.Push((node, child, pathIndex, newPath)); - sortedBoundaryList.Add((child, TreePath.FromNibble(CollectionsMarshal.AsSpan(newPath)))); + proofNodesToProcess.Push((node, child, childPath)); + sortedBoundaryList.Add((child, childPath)); } else { // Sometimes a leaf becomes a proof. - // we add them. - TreePath tPath = TreePath.FromNibble(CollectionsMarshal.AsSpan(path)); - tPath.AppendMut(ci); - - List newPath = new(path) - { - (byte)ci - }; - - TreePath wholePath = tPath.Append(child.Key); + TreePath wholePath = childPath.Append(child.Key); if (wholePath.Path < startingHash || wholePath.Path > endHash) { node.SetChild(ci, child); - proofNodesToProcess.Push((node, child, pathIndex, newPath)); - sortedBoundaryList.Add((child, tPath)); + proofNodesToProcess.Push((node, child, childPath)); + sortedBoundaryList.Add((child, childPath)); } } } From 429edd6d814f6fd25fed0411d867afaf2f992911 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 15:33:34 +0800 Subject: [PATCH 3/9] Cleanup --- .../SnapSync/ProgressTracker.cs | 2 +- .../SnapSync/SnapProvider.cs | 22 +++++++++---------- .../SnapSync/SnapProviderHelper.cs | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index 50c54a443d5..4b97e4c6fe3 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -74,7 +74,7 @@ public ProgressTracker(IBlockTree blockTree, IDb db, ILogManager logManager, int _pivot = new Pivot(blockTree, logManager); if (accountRangePartitionCount < 1 || accountRangePartitionCount > int.MaxValue) - throw new ArgumentException("Account range partition must be between 1 to 256."); + throw new ArgumentException($"Account range partition must be between 1 to {int.MaxValue}."); _accountRangePartitionCount = accountRangePartitionCount; SetupAccountRangePartition(); diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs index f291b90cfe4..99e598804c8 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs @@ -62,17 +62,17 @@ public AddRangeResult AddAccountRange(AccountRange request, AccountsAndProofs re } else { - result = AddAccountRange( - request.BlockNumber.Value, - request.RootHash, - request.StartingHash, - response.PathAndAccounts, - response.Proofs, - hashLimit: request.LimitHash); - - if (result == AddRangeResult.OK) - { - Interlocked.Add(ref Metrics.SnapSyncedAccounts, response.PathAndAccounts.Count); + result = AddAccountRange( + request.BlockNumber.Value, + request.RootHash, + request.StartingHash, + response.PathAndAccounts, + response.Proofs, + hashLimit: request.LimitHash); + + if (result == AddRangeResult.OK) + { + Interlocked.Add(ref Metrics.SnapSyncedAccounts, response.PathAndAccounts.Count); } } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index 1b29e048eae..f90aa475a7d 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -188,7 +188,7 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary // very-very unlikely), we want `moreChildrenToRight` to return true. bool noLimit = limitHash == ValueKeccak.MaxValue; - // Connect the proofs with proof head. + // Connect the proof nodes starting from state root. // It also remove child path which is within the start/end range. If key are missing, the resolved // hash will not match. Stack<(TrieNode parent, TrieNode node, TreePath path)> proofNodesToProcess = new(); @@ -218,7 +218,7 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary else { // Sometimes, the proof ends with the extension, the branch of at the end of extension is - // not included. So we remove the extension, but only if it is after or the left boundary + // not included. So we remove the extension, but only if it is after the left boundary // as it will be re-created by the path. If it is before the left boundary however, it is // part of a proof. TreePath extensionChildPath = path.Append(node.Key); From 06f8a0abe4f29c88a02a6a8ad403a5293c691b8a Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 16:19:42 +0800 Subject: [PATCH 4/9] Simplify --- .../SnapSync/SnapProviderHelper.cs | 58 ++++++++----------- .../Nethermind.Trie/Pruning/TreePath.cs | 6 ++ 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index f90aa475a7d..7d1366eb11a 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -191,16 +191,16 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary // Connect the proof nodes starting from state root. // It also remove child path which is within the start/end range. If key are missing, the resolved // hash will not match. - Stack<(TrieNode parent, TrieNode node, TreePath path)> proofNodesToProcess = new(); + Stack<(TrieNode node, TreePath path)> proofNodesToProcess = new(); tree.RootRef = root; - proofNodesToProcess.Push((null, root, TreePath.Empty)); + proofNodesToProcess.Push((root, TreePath.Empty)); sortedBoundaryList.Add((root, TreePath.Empty)); bool moreChildrenToRight = false; while (proofNodesToProcess.Count > 0) { - (TrieNode parent, TrieNode node, TreePath path) = proofNodesToProcess.Pop(); + (TrieNode node, TreePath path) = proofNodesToProcess.Pop(); if (node.IsExtension) { @@ -212,39 +212,17 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary TreePath childPath = path.Append(node.Key); - proofNodesToProcess.Push((node, child, childPath)); + proofNodesToProcess.Push((child, childPath)); sortedBoundaryList.Add((child, childPath)); } - else - { - // Sometimes, the proof ends with the extension, the branch of at the end of extension is - // not included. So we remove the extension, but only if it is after the left boundary - // as it will be re-created by the path. If it is before the left boundary however, it is - // part of a proof. - TreePath extensionChildPath = path.Append(node.Key); - TreePath firstKeyPath = leftBoundaryPath.Truncate(extensionChildPath.Length); - if (extensionChildPath.CompareTo(firstKeyPath) >= 0 - && parent is not null - && parent.IsBranch) - { - for (int i = 0; i < 16; i++) - { - if (parent.GetChildHashAsValueKeccak(i, out ValueHash256 kec) && kec == node.Keccak) - { - parent.SetChild(i, null); - break; - } - } - } - } } } if (node.IsBranch) { - int left = path == leftBoundaryPath.Truncate(path.Length) ? leftBoundaryPath[path.Length] : 0; - int right = path == rightBoundaryPath.Truncate(path.Length) ? rightBoundaryPath[path.Length] : 15; - int limit = path == rightLimitPath.Truncate(path.Length) ? rightLimitPath[path.Length] : 15; + int left = leftBoundaryPath.CompareToTruncated(path, path.Length) == 0 ? leftBoundaryPath[path.Length] : 0; + int right = rightBoundaryPath.CompareToTruncated(path, path.Length) == 0 ? rightBoundaryPath[path.Length] : 15; + int limit = rightLimitPath.CompareToTruncated(path, path.Length) == 0 ? rightLimitPath[path.Length] : 15; int maxIndex = moreChildrenToRight ? right : 15; @@ -256,6 +234,7 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary if (ci >= left && ci <= right) { + // Clear child within boundary node.SetChild(ci, null); } @@ -263,21 +242,32 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary { TreePath childPath = path.Append(ci); - if (!child.IsLeaf) + if (child.IsBranch) { node.SetChild(ci, child); - proofNodesToProcess.Push((node, child, childPath)); + proofNodesToProcess.Push((child, childPath)); sortedBoundaryList.Add((child, childPath)); } + else if (child.IsExtension) + { + // If its an extension, its path + key must be outside or equal to the boundary. + TreePath wholePath = childPath.Append(child.Key); + if (leftBoundaryPath.CompareToTruncated(wholePath, wholePath.Length) >= 0 || rightBoundaryPath.CompareToTruncated(wholePath, wholePath.Length) <= 0) + { + node.SetChild(ci, child); + proofNodesToProcess.Push((child, childPath)); + sortedBoundaryList.Add((child, childPath)); + } + } else { - // Sometimes a leaf becomes a proof. + // If its a leaf, its path + key must be outside the boundary. TreePath wholePath = childPath.Append(child.Key); - if (wholePath.Path < startingHash || wholePath.Path > endHash) + if (leftBoundaryPath.CompareToTruncated(wholePath, wholePath.Length) > 0 || rightBoundaryPath.CompareToTruncated(wholePath, wholePath.Length) < 0) { node.SetChild(ci, child); - proofNodesToProcess.Push((node, child, childPath)); + proofNodesToProcess.Push((child, childPath)); sortedBoundaryList.Add((child, childPath)); } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs b/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs index aae323323b0..16f36170263 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TreePath.cs @@ -309,6 +309,12 @@ public readonly int CompareTo(in TreePath otherTree) return Length.CompareTo(otherTree.Length); } + /// + /// Compare with otherTree, as if this TreePath was truncated to `length`. + /// + /// + /// + /// public readonly int CompareToTruncated(in TreePath otherTree, int length) { int minLength = Math.Min(length, otherTree.Length); From aacc5c719ac4b7bee1b3604a0c39e6b61f97560f Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 16:32:57 +0800 Subject: [PATCH 5/9] Whitespace --- src/Nethermind/Nethermind.Core/Crypto/Hash256.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs index 253b6bcd92f..fca024ed620 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs @@ -59,7 +59,7 @@ public ValueHash256(ReadOnlySpan bytes) _bytes = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); } - public ValueHash256(UInt256 uint256): this(uint256.ToBigEndian()) + public ValueHash256(UInt256 uint256) : this(uint256.ToBigEndian()) { } From 44d964892ae9fd28ef070d7ba41780195e016081 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 19:29:44 +0800 Subject: [PATCH 6/9] More unit tests --- src/Nethermind/Nethermind.Api/IBasicApi.cs | 5 +- .../ContainerBuilderExtensions.cs | 9 + src/Nethermind/Nethermind.Db/DbModule.cs | 79 +++++ src/Nethermind/Nethermind.Db/IDbProvider.cs | 29 -- .../RecreateStateFromAccountRangesTests.cs | 330 ------------------ .../RecreateStateFromStorageRangesTests.cs | 179 ---------- .../IContainerSynchronizerTestExtensions.cs | 26 ++ .../OldStyleFullSynchronizerTests.cs | 5 +- .../SnapSync/SnapProviderTests.cs | 142 ++++++-- .../SyncThreadTests.cs | 4 +- .../SynchronizerTests.cs | 5 +- .../TestSynchronizerModule.cs | 31 ++ 12 files changed, 274 insertions(+), 570 deletions(-) create mode 100644 src/Nethermind/Nethermind.Db/DbModule.cs delete mode 100644 src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs delete mode 100644 src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromStorageRangesTests.cs create mode 100644 src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs create mode 100644 src/Nethermind/Nethermind.Synchronization.Test/TestSynchronizerModule.cs diff --git a/src/Nethermind/Nethermind.Api/IBasicApi.cs b/src/Nethermind/Nethermind.Api/IBasicApi.cs index 1ba0adb91f9..d6d8d320ef3 100644 --- a/src/Nethermind/Nethermind.Api/IBasicApi.cs +++ b/src/Nethermind/Nethermind.Api/IBasicApi.cs @@ -63,9 +63,8 @@ public ContainerBuilder ConfigureContainerBuilderFromBasicApi(ContainerBuilder b { builder .AddPropertiesFrom(this) - .AddSingleton(ConfigProvider.GetConfig()); - - DbProvider!.ConfigureServiceCollection(builder); + .AddSingleton(ConfigProvider.GetConfig()) + .AddModule(new DbModule()); return builder; } diff --git a/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs b/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs index a64ba5d833a..d7f25a723ff 100644 --- a/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs +++ b/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs @@ -123,6 +123,15 @@ public static ContainerBuilder AddModule(this ContainerBuilder builder, IModule return builder; } + + public static ContainerBuilder Map(this ContainerBuilder builder, Func mapper) where TFrom : notnull where TTo : notnull + { + builder.Register(mapper) + .As() + .ExternallyOwned(); + + return builder; + } } /// diff --git a/src/Nethermind/Nethermind.Db/DbModule.cs b/src/Nethermind/Nethermind.Db/DbModule.cs new file mode 100644 index 00000000000..59fefea8b93 --- /dev/null +++ b/src/Nethermind/Nethermind.Db/DbModule.cs @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Autofac; +using Nethermind.Core; + +namespace Nethermind.Db; + +public class DbModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + builder.AddSingleton(this); + + // TODO: Have hooks that automatically get these + string[] dbNames = [ + DbNames.State, + DbNames.Code, + DbNames.Metadata, + DbNames.Blocks, + DbNames.Headers, + DbNames.BlockInfos, + DbNames.BadBlocks, + DbNames.Bloom, + DbNames.Metadata, + ]; + foreach (string dbName in dbNames) + { + ConfigureDb(builder, dbName); + } + + ConfigureColumnDb(builder, DbNames.Receipts); + } + + private static void ConfigureDb(ContainerBuilder builder, string dbName) + { + builder.Register((ctx) => + { + IDbProvider dbProvider = ctx.Resolve(); + IDb db = dbProvider.GetDb(dbName); + return db; + }) + .ExternallyOwned() + .Named(dbName) + .Named(dbName); + + builder.Register((ctx) => + { + IDbProvider dbProvider = ctx.Resolve(); + IDb db = dbProvider.GetDb(dbName); + return db as ITunableDb ?? new NoopTunableDb(); + }) + .ExternallyOwned() + .Named(dbName); + } + + + private static void ConfigureColumnDb(ContainerBuilder builder, string dbName) + { + builder.Register((ctx) => + { + IDbProvider dbProvider = ctx.Resolve(); + IColumnsDb db = dbProvider.GetColumnDb(dbName); + return db; + }) + .ExternallyOwned() + .As>(); + + builder.Register((ctx) => + { + IDbProvider dbProvider = ctx.Resolve(); + IColumnsDb db = dbProvider.GetColumnDb(dbName); + return db as ITunableDb ?? new NoopTunableDb(); + }) + .ExternallyOwned() + .Named(dbName); + } +} diff --git a/src/Nethermind/Nethermind.Db/IDbProvider.cs b/src/Nethermind/Nethermind.Db/IDbProvider.cs index 6a0380b0446..d3676082f49 100644 --- a/src/Nethermind/Nethermind.Db/IDbProvider.cs +++ b/src/Nethermind/Nethermind.Db/IDbProvider.cs @@ -33,34 +33,5 @@ public interface IDbProvider : IDisposable void RegisterDb(string dbName, T db) where T : class, IDb; void RegisterColumnDb(string dbName, IColumnsDb db); IEnumerable> GetAllDbMeta(); - - void ConfigureServiceCollection(ContainerBuilder sc) - { - sc.AddSingleton(this); - - // TODO: Have hooks that automatically get these - string[] dbNames = [ - DbNames.State, - DbNames.Code, - DbNames.Metadata, - DbNames.Blocks, - DbNames.Headers, - DbNames.BlockInfos, - DbNames.BadBlocks, - DbNames.Bloom, - DbNames.Metadata, - ]; - foreach (string dbName in dbNames) - { - var db = GetDb(dbName); - sc.AddKeyedSingleton(dbName, db); - sc.AddKeyedSingleton(dbName, db); - sc.AddKeyedSingleton(dbName, db as ITunableDb ?? new NoopTunableDb()); - } - - IColumnsDb receiptColumnDb = GetColumnDb(DbNames.Receipts); - sc.AddSingleton>(receiptColumnDb); - sc.AddKeyedSingleton(DbNames.Receipts, receiptColumnDb as ITunableDb ?? new NoopTunableDb()); - } } } diff --git a/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs b/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs deleted file mode 100644 index 0b0ce1d8b2b..00000000000 --- a/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs +++ /dev/null @@ -1,330 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; -using FluentAssertions; -using Nethermind.Blockchain; -using Nethermind.Core; -using Nethermind.Core.Crypto; -using Nethermind.Core.Test.Builders; -using Nethermind.Db; -using Nethermind.Logging; -using Nethermind.State; -using Nethermind.State.Proofs; -using Nethermind.State.Snap; -using Nethermind.Synchronization.SnapSync; -using Nethermind.Trie; -using Nethermind.Trie.Pruning; -using NUnit.Framework; - -namespace Nethermind.Store.Test; - -public class RecreateStateFromAccountRangesTests -{ - private StateTree _inputTree; - - [OneTimeSetUp] - public void Setup() - { - _inputTree = TestItem.Tree.GetStateTree(); - } - - //[Test] - public void Test01() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - - AccountProofCollector accountProofCollector = new(TestItem.Tree.AccountsWithPaths[0].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] firstProof = accountProofCollector.BuildResult().Proof; - - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] lastProof = accountProofCollector.BuildResult().Proof; - - MemDb db = new(); - IScopedTrieStore store = new TrieStore(db, LimboLogs.Instance).GetTrieStore(null); - StateTree tree = new(store, LimboLogs.Instance); - - IList nodes = new List(); - - for (int i = 0; i < (firstProof!).Length; i++) - { - byte[] nodeBytes = (firstProof!)[i]; - var node = new TrieNode(NodeType.Unknown, nodeBytes); - TreePath emptyPath = TreePath.Empty; - node.ResolveKey(store, ref emptyPath, i == 0); - - nodes.Add(node); - if (i < (firstProof!).Length - 1) - { - //IBatch batch = store.GetOrStartNewBatch(); - //batch[node.Keccak!.Bytes] = nodeBytes; - //db.Set(node.Keccak!, nodeBytes); - } - } - - for (int i = 0; i < (lastProof!).Length; i++) - { - byte[] nodeBytes = (lastProof!)[i]; - var node = new TrieNode(NodeType.Unknown, nodeBytes); - TreePath emptyPath = TreePath.Empty; - node.ResolveKey(store, ref emptyPath, i == 0); - - nodes.Add(node); - if (i < (lastProof!).Length - 1) - { - //IBatch batch = store.GetOrStartNewBatch(); - //batch[node.Keccak!.Bytes] = nodeBytes; - //db.Set(node.Keccak!, nodeBytes); - } - } - - tree.RootRef = nodes[0]; - - tree.Set(TestItem.Tree.AccountsWithPaths[0].Path, TestItem.Tree.AccountsWithPaths[0].Account); - tree.Set(TestItem.Tree.AccountsWithPaths[1].Path, TestItem.Tree.AccountsWithPaths[1].Account); - tree.Set(TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2].Account); - tree.Set(TestItem.Tree.AccountsWithPaths[3].Path, TestItem.Tree.AccountsWithPaths[3].Account); - tree.Set(TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4].Account); - tree.Set(TestItem.Tree.AccountsWithPaths[5].Path, TestItem.Tree.AccountsWithPaths[5].Account); - - tree.Commit(); - - Assert.That(tree.RootHash, Is.EqualTo(_inputTree.RootHash)); - Assert.That(db.Keys.Count, Is.EqualTo(6)); // we don't persist proof nodes (boundary nodes) - Assert.That(db.KeyExists(rootHash), Is.False); // the root node is a part of the proof nodes - } - - [Test] - public void RecreateAccountStateFromOneRangeWithNonExistenceProof() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - - AccountProofCollector accountProofCollector = new(Keccak.Zero.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] lastProof = accountProofCollector.BuildResult().Proof; - - MemDb db = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - AddRangeResult result = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths, firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(result, Is.EqualTo(AddRangeResult.OK)); - Assert.That(db.Keys.Count, Is.EqualTo(10)); // we persist proof nodes (boundary nodes) via stitching - Assert.That(db.KeyExists(rootHash), Is.False); - } - - [Test] - public void RecreateAccountStateFromOneRangeWithExistenceProof() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - - AccountProofCollector accountProofCollector = new(TestItem.Tree.AccountsWithPaths[0].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] lastProof = accountProofCollector.BuildResult().Proof; - - MemDb db = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - var result = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[0].Path, TestItem.Tree.AccountsWithPaths, firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(result, Is.EqualTo(AddRangeResult.OK)); - Assert.That(db.Keys.Count, Is.EqualTo(10)); // we persist proof nodes (boundary nodes) via stitching - Assert.That(db.KeyExists(rootHash), Is.False); - } - - [Test] - public void RecreateAccountStateFromOneRangeWithoutProof() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - - MemDb db = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - var result = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[0].Path, TestItem.Tree.AccountsWithPaths); - - Assert.That(result, Is.EqualTo(AddRangeResult.OK)); - Assert.That(db.Keys.Count, Is.EqualTo(10)); // we don't have the proofs so we persist all nodes - Assert.That(db.KeyExists(rootHash), Is.False); // the root node is NOT a part of the proof nodes - } - - [Test] - public void RecreateAccountStateFromMultipleRange() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - - // output state - MemDb db = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - - AccountProofCollector accountProofCollector = new(Keccak.Zero.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] lastProof = accountProofCollector.BuildResult().Proof; - - var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(db.Keys.Count, Is.EqualTo(2)); - - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - lastProof = accountProofCollector.BuildResult().Proof; - - var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2..4], firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(db.Keys.Count, Is.EqualTo(5)); // we don't persist proof nodes (boundary nodes) - - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - lastProof = accountProofCollector.BuildResult().Proof; - - var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(result1, Is.EqualTo(AddRangeResult.OK)); - Assert.That(result2, Is.EqualTo(AddRangeResult.OK)); - Assert.That(result3, Is.EqualTo(AddRangeResult.OK)); - Assert.That(db.Keys.Count, Is.EqualTo(10)); // we persist proof nodes (boundary nodes) via stitching - Assert.That(db.KeyExists(rootHash), Is.False); - } - - [Test] - public void MissingAccountFromRange() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - - // output state - MemDb db = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - - AccountProofCollector accountProofCollector = new(Keccak.Zero.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - byte[][] lastProof = accountProofCollector.BuildResult().Proof; - - var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(db.Keys.Count, Is.EqualTo(2)); - - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - lastProof = accountProofCollector.BuildResult().Proof; - - // missing TestItem.Tree.AccountsWithHashes[2] - var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[3..4], firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(db.Keys.Count, Is.EqualTo(2)); - - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - firstProof = accountProofCollector.BuildResult().Proof; - accountProofCollector = new(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - _inputTree.Accept(accountProofCollector, _inputTree.RootHash); - lastProof = accountProofCollector.BuildResult().Proof; - - var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); - - Assert.That(result1, Is.EqualTo(AddRangeResult.OK)); - Assert.That(result2, Is.EqualTo(AddRangeResult.DifferentRootHash)); - Assert.That(result3, Is.EqualTo(AddRangeResult.OK)); - Assert.That(db.Keys.Count, Is.EqualTo(6)); - Assert.That(db.KeyExists(rootHash), Is.False); - } - - [Test] - public void Will_not_redownload_persisted_code() - { - MemDb db = new(); - MemDb codeDb = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - dbProvider.RegisterDb(DbNames.Code, codeDb); - - BlockTree tree = Build.A.BlockTree().OfChainLength(5).TestObject; - using ProgressTracker progressTracker = new(tree, dbProvider.GetDb(DbNames.State), LimboLogs.Instance, - accountRangePartitionCount: 1); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - - PathWithAccount[] accountsWithPath = - [ - new PathWithAccount(new Hash256("0000000000000000000000000000000000000000000000000000000001112345"), - new Account(0, 0, Keccak.EmptyTreeHash, TestItem.Keccaks[0])), - new PathWithAccount(new Hash256("0000000000000000000000000000000000000000000000000000000001113456"), - new Account(0, 0, Keccak.EmptyTreeHash, TestItem.Keccaks[1])), - new PathWithAccount(new Hash256("0000000000000000000000000000000000000000000000000000000001114567"), - new Account(0, 0, Keccak.EmptyTreeHash, TestItem.Keccaks[2])), - new PathWithAccount(new Hash256("0000000000000000000000000000000000000000000000000000000001123456"), - new Account(0, 0, Keccak.EmptyTreeHash, TestItem.Keccaks[3])), - new PathWithAccount(new Hash256("0000000000000000000000000000000000000000000000000000000001123457"), - new Account(0, 0, Keccak.EmptyTreeHash, TestItem.Keccaks[4])) - ]; - - codeDb[TestItem.Keccaks[1].Bytes] = [1]; - codeDb[TestItem.Keccaks[2].Bytes] = [1]; - - StateTree stateTree = new StateTree(); - foreach (PathWithAccount pathWithAccount in accountsWithPath) - { - stateTree.Set(pathWithAccount.Path, pathWithAccount.Account); - } - - stateTree.UpdateRootHash(); - - snapProvider.AddAccountRange(1, - stateTree.RootHash, - accountsWithPath[0].Path, - accountsWithPath); - - progressTracker.IsFinished(out SnapSyncBatch nextRequest).Should().BeFalse(); - progressTracker.IsFinished(out nextRequest).Should().BeFalse(); - nextRequest.CodesRequest.Count.Should().Be(3); - } - - private SnapProvider CreateSnapProvider(ProgressTracker progressTracker, IDbProvider dbProvider) - { - try - { - IDb _ = dbProvider.CodeDb; - } - catch (ArgumentException) - { - dbProvider.RegisterDb(DbNames.Code, new MemDb()); - } - return new(progressTracker, dbProvider.CodeDb, new NodeStorage(dbProvider.StateDb), LimboLogs.Instance); - } -} diff --git a/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromStorageRangesTests.cs b/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromStorageRangesTests.cs deleted file mode 100644 index a4dc0f7ef38..00000000000 --- a/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromStorageRangesTests.cs +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -#nullable disable - -using System; -using System.Linq; -using Nethermind.Core; -using Nethermind.Core.Crypto; -using Nethermind.Core.Test.Builders; -using Nethermind.Db; -using Nethermind.Int256; -using Nethermind.Logging; -using Nethermind.State; -using Nethermind.State.Proofs; -using Nethermind.State.Snap; -using Nethermind.Synchronization.SnapSync; -using Nethermind.Trie; -using Nethermind.Trie.Pruning; -using NUnit.Framework; - -namespace Nethermind.Store.Test -{ - [TestFixture] - public class RecreateStateFromStorageRangesTests - { - - private TrieStore _store; - private StateTree _inputStateTree; - private StorageTree _inputStorageTree; - private readonly PathWithAccount _pathWithAccount = new PathWithAccount(TestItem.Tree.AccountAddress0.ValueHash256, new Account(UInt256.Zero)); - - [OneTimeSetUp] - public void Setup() - { - _store = new TrieStore(new MemDb(), LimboLogs.Instance); - (_inputStateTree, _inputStorageTree, _) = TestItem.Tree.GetTrees(_store); - } - - [OneTimeTearDown] - public void TearDown() => _store?.Dispose(); - - [Test] - public void RecreateStorageStateFromOneRangeWithNonExistenceProof() - { - Hash256 rootHash = _inputStorageTree!.RootHash; // "..." - - AccountProofCollector accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { Keccak.Zero, TestItem.Tree.SlotsWithPaths[5].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - var proof = accountProofCollector.BuildResult(); - - MemDb db = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - var result = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, Keccak.Zero, TestItem.Tree.SlotsWithPaths, proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - Assert.That(result, Is.EqualTo(AddRangeResult.OK)); - } - - [Test] - public void RecreateAccountStateFromOneRangeWithExistenceProof() - { - Hash256 rootHash = _inputStorageTree!.RootHash; // "..." - - AccountProofCollector accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { TestItem.Tree.SlotsWithPaths[0].Path, TestItem.Tree.SlotsWithPaths[5].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - var proof = accountProofCollector.BuildResult(); - - MemDb db = new(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - var result = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, Keccak.Zero, TestItem.Tree.SlotsWithPaths, proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - Assert.That(result, Is.EqualTo(AddRangeResult.OK)); - } - - [Test] - public void RecreateStorageStateFromOneRangeWithoutProof() - { - Hash256 rootHash = _inputStorageTree!.RootHash; // "..." - - MemDb db = new MemDb(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - var result = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, TestItem.Tree.SlotsWithPaths[0].Path, TestItem.Tree.SlotsWithPaths); - - Assert.That(result, Is.EqualTo(AddRangeResult.OK)); - } - - [Test] - public void RecreateAccountStateFromMultipleRange() - { - Hash256 rootHash = _inputStorageTree!.RootHash; // "..." - - // output state - MemDb db = new MemDb(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - - AccountProofCollector accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { Keccak.Zero, TestItem.Tree.SlotsWithPaths[1].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - var proof = accountProofCollector.BuildResult(); - - var result1 = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, Keccak.Zero, TestItem.Tree.SlotsWithPaths[0..2], proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { TestItem.Tree.SlotsWithPaths[2].Path, TestItem.Tree.SlotsWithPaths[3].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - proof = accountProofCollector.BuildResult(); - - var result2 = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, TestItem.Tree.SlotsWithPaths[2].Path, TestItem.Tree.SlotsWithPaths[2..4], proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { TestItem.Tree.SlotsWithPaths[4].Path, TestItem.Tree.SlotsWithPaths[5].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - proof = accountProofCollector.BuildResult(); - - var result3 = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, TestItem.Tree.SlotsWithPaths[4].Path, TestItem.Tree.SlotsWithPaths[4..6], proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - Assert.That(result1, Is.EqualTo(AddRangeResult.OK)); - Assert.That(result2, Is.EqualTo(AddRangeResult.OK)); - Assert.That(result3, Is.EqualTo(AddRangeResult.OK)); - } - - [Test] - public void MissingAccountFromRange() - { - Hash256 rootHash = _inputStorageTree!.RootHash; // "..." - - // output state - MemDb db = new MemDb(); - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(null, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - SnapProvider snapProvider = CreateSnapProvider(progressTracker, dbProvider); - - AccountProofCollector accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { Keccak.Zero, TestItem.Tree.SlotsWithPaths[1].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - var proof = accountProofCollector.BuildResult(); - - var result1 = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, Keccak.Zero, TestItem.Tree.SlotsWithPaths[0..2], proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { TestItem.Tree.SlotsWithPaths[2].Path, TestItem.Tree.SlotsWithPaths[3].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - proof = accountProofCollector.BuildResult(); - - var result2 = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, TestItem.Tree.SlotsWithPaths[2].Path, TestItem.Tree.SlotsWithPaths[3..4], proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - accountProofCollector = new(TestItem.Tree.AccountAddress0.Bytes, new ValueHash256[] { TestItem.Tree.SlotsWithPaths[4].Path, TestItem.Tree.SlotsWithPaths[5].Path }); - _inputStateTree!.Accept(accountProofCollector, _inputStateTree.RootHash); - proof = accountProofCollector.BuildResult(); - - var result3 = snapProvider.AddStorageRange(1, _pathWithAccount, rootHash, TestItem.Tree.SlotsWithPaths[4].Path, TestItem.Tree.SlotsWithPaths[4..6], proof!.StorageProofs![0].Proof!.Concat(proof!.StorageProofs![1].Proof!).ToArray()); - - Assert.That(result1, Is.EqualTo(AddRangeResult.OK)); - Assert.That(result2, Is.EqualTo(AddRangeResult.DifferentRootHash)); - Assert.That(result3, Is.EqualTo(AddRangeResult.OK)); - } - - private SnapProvider CreateSnapProvider(ProgressTracker progressTracker, IDbProvider dbProvider) - { - try - { - IDb _ = dbProvider.CodeDb; - } - catch (ArgumentException) - { - dbProvider.RegisterDb(DbNames.Code, new MemDb()); - } - return new(progressTracker, dbProvider.CodeDb, new NodeStorage(dbProvider.StateDb), LimboLogs.Instance); - } - } -} diff --git a/src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs b/src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs new file mode 100644 index 00000000000..5622a96675f --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Autofac; +using Nethermind.Blockchain; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Test.Builders; +using NSubstitute; + +namespace Nethermind.Synchronization.Test; + +public static class IContainerSynchronizerTestExtensions +{ + public static ContainerBuilder WithSuggestedHeaderOfStateRoot(this ContainerBuilder builder, Hash256 stateRoot) + { + IBlockTree blockTree = Substitute.For(); + BlockHeader header = Build.A.BlockHeader.WithStateRoot(stateRoot).TestObject; + blockTree.FindHeader(Arg.Any()).Returns(header); + blockTree.BestSuggestedHeader.Returns(header); + + builder.AddSingleton(blockTree); + + return builder; + } +} diff --git a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs index 50b6b6a54eb..1b482b53077 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs @@ -68,6 +68,8 @@ public async Task Setup() IStateReader stateReader = new StateReader(trieStore, _codeDb, LimboLogs.Instance); ContainerBuilder builder = new ContainerBuilder() + .AddModule(new SynchronizerModule(syncConfig)) + .AddModule(new DbModule()) .AddSingleton(nodeStorage) .AddSingleton(MainnetSpecProvider.Instance) .AddSingleton(_blockTree) @@ -84,9 +86,6 @@ public async Task Setup() .AddSingleton(stateReader) .AddSingleton(No.BeaconSync) .AddSingleton(LimboLogs.Instance); - dbProvider.ConfigureServiceCollection(builder); - - builder.RegisterModule(new SynchronizerModule(syncConfig)); IContainer container = builder.Build(); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs index ef5f56e4f0b..1529dc46714 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapProviderTests.cs @@ -5,7 +5,6 @@ using Nethermind.Blockchain; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; -using Nethermind.Db; using Nethermind.Logging; using Nethermind.State.Snap; using Nethermind.Synchronization.SnapSync; @@ -17,30 +16,35 @@ using System.IO.Compression; using System.Linq; using System.Text.Json; +using Autofac; +using Nethermind.Blockchain.Synchronization; +using Nethermind.Blockchain.Utils; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Test; +using Nethermind.Core.Test.Builders; +using Nethermind.Db; using Nethermind.Serialization.Rlp; using Nethermind.State; using Nethermind.Trie.Pruning; +using AccountRange = Nethermind.State.Snap.AccountRange; namespace Nethermind.Synchronization.Test.SnapSync; [TestFixture] public class SnapProviderTests { - [Test] public void AddAccountRange_AccountListIsEmpty_ThrowArgumentException() { - MemDb db = new(); - IDbProvider dbProvider = new DbProvider(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(Substitute.For(), dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - dbProvider.RegisterDb(DbNames.Code, new MemDb()); - SnapProvider sut = new(progressTracker, dbProvider.CodeDb, new NodeStorage(dbProvider.StateDb), LimboLogs.Instance); + using IContainer container = new ContainerBuilder() + .AddModule(new TestSynchronizerModule(new SyncConfig())) + .Build(); + + SnapProvider snapProvider = container.Resolve(); Assert.That( - () => sut.AddAccountRange( + () => snapProvider.AddAccountRange( 0, Keccak.Zero, Keccak.Zero, @@ -48,30 +52,111 @@ public void AddAccountRange_AccountListIsEmpty_ThrowArgumentException() Array.Empty().AsReadOnly()), Throws.ArgumentException); } - [Test] public void AddAccountRange_ResponseHasEmptyListOfAccountsAndOneProof_ReturnsExpiredRootHash() { - MemDb db = new(); - IDbProvider dbProvider = new DbProvider(); - dbProvider.RegisterDb(DbNames.State, db); - using ProgressTracker progressTracker = new(Substitute.For(), dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - dbProvider.RegisterDb(DbNames.Code, new MemDb()); - AccountRange accountRange = new(Keccak.Zero, Keccak.Zero, Keccak.MaxValue); + using IContainer container = new ContainerBuilder() + .AddModule(new TestSynchronizerModule(new SyncConfig())) + .Build(); + + SnapProvider snapProvider = container.Resolve(); + using AccountsAndProofs accountsAndProofs = new(); + AccountRange accountRange = new(Keccak.Zero, Keccak.Zero, Keccak.MaxValue); accountsAndProofs.PathAndAccounts = new List().ToPooledList(); accountsAndProofs.Proofs = new List { new byte[] { 0x0 } }.ToPooledList(); - SnapProvider sut = new(progressTracker, dbProvider.CodeDb, new NodeStorage(dbProvider.StateDb), LimboLogs.Instance); + snapProvider.AddAccountRange(accountRange, accountsAndProofs).Should().Be(AddRangeResult.ExpiredRootHash); + } + + [Test] + public void AddAccountRange_SetStartRange_ToAfterLastPath() + { + (Hash256, Account)[] entries = + [ + (TestItem.KeccakA, TestItem.GenerateRandomAccount()), + (TestItem.KeccakB, TestItem.GenerateRandomAccount()), + (TestItem.KeccakC, TestItem.GenerateRandomAccount()), + (TestItem.KeccakD, TestItem.GenerateRandomAccount()), + (TestItem.KeccakE, TestItem.GenerateRandomAccount()), + (TestItem.KeccakF, TestItem.GenerateRandomAccount()), + ]; + Array.Sort(entries, (e1, e2) => e1.Item1.CompareTo(e2.Item1)); + + (SnapServer ss, Hash256 root) = BuildSnapServerFromEntries(entries); + + using IContainer container = new ContainerBuilder() + .AddModule(new TestSynchronizerModule(new SyncConfig() + { + SnapSyncAccountRangePartitionCount = 1 + })) + .WithSuggestedHeaderOfStateRoot(root) + .Build(); + + SnapProvider snapProvider = container.Resolve(); + ProgressTracker progressTracker = container.Resolve(); + + (IOwnedReadOnlyList accounts, IOwnedReadOnlyList proofs) res = ss.GetAccountRanges( + root, Keccak.Zero, entries[3].Item1, 1.MB(), default); + + progressTracker.IsFinished(out SnapSyncBatch? batch).Should().Be(false); + + using AccountsAndProofs accountsAndProofs = new(); + accountsAndProofs.PathAndAccounts = res.accounts; + accountsAndProofs.Proofs = res.proofs; - sut.AddAccountRange(accountRange, accountsAndProofs).Should().Be(AddRangeResult.ExpiredRootHash); + snapProvider.AddAccountRange(batch?.AccountRangeRequest!, accountsAndProofs).Should().Be(AddRangeResult.OK); + progressTracker.IsFinished(out batch).Should().Be(false); + batch?.AccountRangeRequest?.StartingHash.Should().BeGreaterThan(entries[3].Item1); + batch?.AccountRangeRequest?.StartingHash.Should().BeLessThan(entries[4].Item1); + } + + [Test] + public void AddAccountRange_ShouldNotStoreStorageAfterLimit() + { + (Hash256, Account)[] entries = + [ + (TestItem.KeccakA, TestItem.GenerateRandomAccount().WithChangedStorageRoot(TestItem.GetRandomKeccak())), + (TestItem.KeccakB, TestItem.GenerateRandomAccount().WithChangedStorageRoot(TestItem.GetRandomKeccak())), + (TestItem.KeccakC, TestItem.GenerateRandomAccount().WithChangedStorageRoot(TestItem.GetRandomKeccak())), + (TestItem.KeccakD, TestItem.GenerateRandomAccount().WithChangedStorageRoot(TestItem.GetRandomKeccak())), + (TestItem.KeccakE, TestItem.GenerateRandomAccount().WithChangedStorageRoot(TestItem.GetRandomKeccak())), + (TestItem.KeccakF, TestItem.GenerateRandomAccount().WithChangedStorageRoot(TestItem.GetRandomKeccak())), + ]; + Array.Sort(entries, (e1, e2) => e1.Item1.CompareTo(e2.Item1)); + + (SnapServer ss, Hash256 root) = BuildSnapServerFromEntries(entries); + + using IContainer container = new ContainerBuilder() + .AddModule(new TestSynchronizerModule(new SyncConfig() + { + SnapSyncAccountRangePartitionCount = 2 + })) + .WithSuggestedHeaderOfStateRoot(root) + .Build(); + + SnapProvider snapProvider = container.Resolve(); + ProgressTracker progressTracker = container.Resolve(); + + (IOwnedReadOnlyList accounts, IOwnedReadOnlyList proofs) res = ss.GetAccountRanges( + root, Keccak.Zero, Keccak.MaxValue, 1.MB(), default); + + progressTracker.IsFinished(out SnapSyncBatch? batch).Should().Be(false); + + using AccountsAndProofs accountsAndProofs = new(); + accountsAndProofs.PathAndAccounts = res.accounts; + accountsAndProofs.Proofs = res.proofs; + + snapProvider.AddAccountRange(batch?.AccountRangeRequest!, accountsAndProofs).Should().Be(AddRangeResult.OK); + + container.ResolveNamed(DbNames.State).GetAllKeys().Count().Should().Be(6); } [TestCase("badreq-roothash.zip")] [TestCase("badreq-roothash-2.zip")] [TestCase("badreq-roothash-3.zip")] [TestCase("badreq-trieexception.zip")] - public void TestStrangeCase2(string testFileName) + public void Test_EdgeCases(string testFileName) { using DeflateStream decompressor = new DeflateStream( @@ -79,11 +164,9 @@ public void TestStrangeCase2(string testFileName) .GetManifestResourceStream($"Nethermind.Synchronization.Test.SnapSync.TestFixtures.{testFileName}")!, CompressionMode.Decompress); BadReq asReq = JsonSerializer.Deserialize(decompressor)!; - AccountDecoder acd = new AccountDecoder(); Account[] accounts = asReq.Accounts.Select((bt) => acd.Decode(new RlpStream(Bytes.FromHexString(bt)))!).ToArray(); ValueHash256[] paths = asReq.Paths.Select((bt) => new ValueHash256(Bytes.FromHexString(bt))).ToArray(); - List pathWithAccounts = accounts.Select((acc, idx) => new PathWithAccount(paths[idx], acc)).ToList(); List proofs = asReq.Proofs.Select((str) => Bytes.FromHexString(str)).ToList(); @@ -106,4 +189,21 @@ private record BadReq( List Paths, List Accounts ); + + private static (SnapServer, Hash256) BuildSnapServerFromEntries((Hash256, Account)[] entries) + { + TestMemDb stateDb = new TestMemDb(); + TrieStore trieStore = new TrieStore(stateDb, LimboLogs.Instance); + StateTree st = new StateTree(trieStore, LimboLogs.Instance); + foreach (var entry in entries) + { + st.Set(entry.Item1, entry.Item2); + } + st.Commit(); + + ILastNStateRootTracker stateRootTracker = Substitute.For(); + stateRootTracker.HasStateRoot(st.RootHash).Returns(true); + var ss = new SnapServer(trieStore.AsReadOnly(), new TestMemDb(), stateRootTracker, LimboLogs.Instance); + return (ss, st.RootHash); + } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs index 6e57e836982..bb6cc747ee5 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs @@ -361,6 +361,8 @@ private SyncTestContext CreateSyncManager(int index) ContainerBuilder builder = new ContainerBuilder(); builder + .AddModule(new DbModule()) + .AddModule(new SynchronizerModule(syncConfig)) .AddSingleton(dbProvider) .AddSingleton(new NodeStorage(dbProvider.StateDb)) .AddSingleton(MainnetSpecProvider.Instance) @@ -379,8 +381,6 @@ private SyncTestContext CreateSyncManager(int index) .AddSingleton(receiptStorage) .AddSingleton(No.BeaconSync) .AddSingleton(logManager); - dbProvider.ConfigureServiceCollection(builder); - builder.RegisterModule(new SynchronizerModule(syncConfig)); IContainer container = builder.Build(); Synchronizer synchronizer = container.Resolve(); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index 47c721d274c..f0d71662b6b 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -345,9 +345,10 @@ ISyncConfig GetSyncConfig() => IInvalidChainTracker invalidChainTracker = new NoopInvalidChainTracker(); ContainerBuilder builder = new ContainerBuilder(); - dbProvider.ConfigureServiceCollection(builder); builder + .AddModule(new DbModule()) + .AddModule(new SynchronizerModule(syncConfig)) .AddSingleton(dbProvider) .AddSingleton(nodeStorage) .AddSingleton(MainnetSpecProvider.Instance) @@ -370,8 +371,6 @@ ISyncConfig GetSyncConfig() => .AddSingleton(beaconPivot) .AddSingleton(_logManager); - builder.RegisterModule(new SynchronizerModule(syncConfig)); - if (IsMerge(synchronizerType)) { builder.RegisterModule(new MergeSynchronizerModule()); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/TestSynchronizerModule.cs b/src/Nethermind/Nethermind.Synchronization.Test/TestSynchronizerModule.cs new file mode 100644 index 00000000000..d6868ba4f09 --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization.Test/TestSynchronizerModule.cs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Autofac; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Synchronization; +using Nethermind.Core; +using Nethermind.Db; +using Nethermind.Logging; +using Nethermind.Trie; +using NSubstitute; + +namespace Nethermind.Synchronization.Test; + +public class TestSynchronizerModule(ISyncConfig syncConfig) : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + + builder + .AddModule(new SynchronizerModule(syncConfig)) + .AddModule(new DbModule()) + .AddSingleton(TestMemDbProvider.Init()) + .Map(dbProvider => new NodeStorage(dbProvider.StateDb)) + .AddSingleton(Substitute.For()) + .AddSingleton(syncConfig) + .AddSingleton(LimboLogs.Instance); + + } +} From 7b1f2366cad089323991ff5e5ef748d1e33e75db Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 19:36:58 +0800 Subject: [PATCH 7/9] Fixx test --- .../OldStyleFullSynchronizerTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs index 1b482b53077..3a6d64f36a7 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs @@ -70,6 +70,7 @@ public async Task Setup() ContainerBuilder builder = new ContainerBuilder() .AddModule(new SynchronizerModule(syncConfig)) .AddModule(new DbModule()) + .AddSingleton(dbProvider) .AddSingleton(nodeStorage) .AddSingleton(MainnetSpecProvider.Instance) .AddSingleton(_blockTree) From 92240d663fd03d2096728db965d7573b912e47e9 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 4 Nov 2024 20:00:41 +0800 Subject: [PATCH 8/9] You know what, just in case --- .../Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index 7d1366eb11a..2bf517043f2 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -51,7 +51,7 @@ public static (AddRangeResult result, bool moreChildrenToRight, List= limitHash) + if (account.Path >= limitHash || account.Path < startingHash) { hasExtraStorage = true; } @@ -96,7 +96,7 @@ public static (AddRangeResult result, bool moreChildrenToRight, List= limitHash) continue; + if (account.Path >= limitHash || account.Path < startingHash) continue; _ = tree.Set(account.Path, account.Account); } } From 1a61d188d3b727a52423c9601cb4c9b6bd77edc3 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 5 Nov 2024 12:00:05 +0800 Subject: [PATCH 9/9] Add big endian --- src/Nethermind/Nethermind.Core/Crypto/Hash256.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs index fca024ed620..cdaa6200985 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs @@ -59,7 +59,7 @@ public ValueHash256(ReadOnlySpan bytes) _bytes = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); } - public ValueHash256(UInt256 uint256) : this(uint256.ToBigEndian()) + public ValueHash256(UInt256 uint256, bool isBigEndian = true) : this(isBigEndian ? uint256.ToBigEndian() : uint256.ToLittleEndian()) { } @@ -118,9 +118,9 @@ public Hash256 ToCommitment() public static bool operator <=(in ValueHash256 left, in ValueHash256 right) => left.CompareTo(in right) <= 0; public static implicit operator Hash256(in ValueHash256 keccak) => new(keccak); - public UInt256 ToUInt256() + public UInt256 ToUInt256(bool isBigEndian = true) { - return new UInt256(Bytes, isBigEndian: true); + return new UInt256(Bytes, isBigEndian: isBigEndian); } }