diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props index 7bf34ecfeb5..a82c8f71f14 100644 --- a/src/Nethermind/Directory.Packages.props +++ b/src/Nethermind/Directory.Packages.props @@ -57,9 +57,9 @@ - - - + + + diff --git a/src/Nethermind/Ethereum.Abi.Test/Tests.cs b/src/Nethermind/Ethereum.Abi.Test/Tests.cs index 3edf18e0567..3b6c1d24c89 100644 --- a/src/Nethermind/Ethereum.Abi.Test/Tests.cs +++ b/src/Nethermind/Ethereum.Abi.Test/Tests.cs @@ -53,7 +53,7 @@ public void Test_abi_encoding() } catch (IOException) { - TestContext.WriteLine($"Could not find test in {potentialLocation}"); + TestContext.Out.WriteLine($"Could not find test in {potentialLocation}"); } } diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ArgsZeroOneBalanceTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ArgsZeroOneBalanceTests.cs index 81db55dd96d..c8ee2ce85e1 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ArgsZeroOneBalanceTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ArgsZeroOneBalanceTests.cs @@ -5,22 +5,20 @@ using Ethereum.Test.Base; using NUnit.Framework; -namespace Ethereum.Blockchain.Legacy.Test +namespace Ethereum.Blockchain.Legacy.Test; + +[Parallelizable(ParallelScope.All)] +public class ArgsZeroOneBalanaceTests : GeneralStateTestBase { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class ArgsZeroOneBalanaceTests : GeneralStateTestBase + [TestCaseSource(nameof(LoadTests))] + public void Test(GeneralStateTest test) { - [TestCaseSource(nameof(LoadTests))] - public void Test(GeneralStateTest test) - { - Assert.True(RunTest(test).Pass); - } + Assert.That(RunTest(test).Pass, Is.True); + } - public static IEnumerable LoadTests() - { - var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stArgsZeroOneBalance"); - return (IEnumerable)loader.LoadTests(); - } + public static IEnumerable LoadTests() + { + var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stArgsZeroOneBalance"); + return (IEnumerable)loader.LoadTests(); } } diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/AttackTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/AttackTests.cs index 60057dc2bcd..4083eaca5ce 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/AttackTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/AttackTests.cs @@ -5,22 +5,20 @@ using Ethereum.Test.Base; using NUnit.Framework; -namespace Ethereum.Blockchain.Legacy.Test +namespace Ethereum.Blockchain.Legacy.Test; + +[Parallelizable(ParallelScope.All)] +public class AttackTests : GeneralStateTestBase { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class AttackTests : GeneralStateTestBase + [TestCaseSource(nameof(LoadTests))] + public void Test(GeneralStateTest test) { - [TestCaseSource(nameof(LoadTests))] - public void Test(GeneralStateTest test) - { - Assert.True(RunTest(test).Pass); - } + Assert.That(RunTest(test).Pass, Is.True); + } - public static IEnumerable LoadTests() - { - var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stAttackTest"); - return (IEnumerable)loader.LoadTests(); - } + public static IEnumerable LoadTests() + { + var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stAttackTest"); + return (IEnumerable)loader.LoadTests(); } } diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BadOpCodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BadOpCodeTests.cs index 9161df19653..881c72bc5e8 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BadOpCodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BadOpCodeTests.cs @@ -5,22 +5,20 @@ using Ethereum.Test.Base; using NUnit.Framework; -namespace Ethereum.Blockchain.Legacy.Test +namespace Ethereum.Blockchain.Legacy.Test; + +[Parallelizable(ParallelScope.All)] +public class BadOpCodeTests : GeneralStateTestBase { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class BadOpCodeTests : GeneralStateTestBase + [TestCaseSource(nameof(LoadTests))] + public void Test(GeneralStateTest test) { - [TestCaseSource(nameof(LoadTests))] - public void Test(GeneralStateTest test) - { - Assert.True(RunTest(test).Pass); - } + Assert.That(RunTest(test).Pass, Is.True); + } - public static IEnumerable LoadTests() - { - var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stBadOpcode"); - return (IEnumerable)loader.LoadTests(); - } + public static IEnumerable LoadTests() + { + var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stBadOpcode"); + return (IEnumerable)loader.LoadTests(); } } diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BugsTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BugsTests.cs index f8d97d9f2c5..9c4f2e6beec 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BugsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/BugsTests.cs @@ -5,22 +5,20 @@ using Ethereum.Test.Base; using NUnit.Framework; -namespace Ethereum.Blockchain.Legacy.Test +namespace Ethereum.Blockchain.Legacy.Test; + +[Parallelizable(ParallelScope.All)] +public class BugsTets : GeneralStateTestBase { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class BugsTets : GeneralStateTestBase + [TestCaseSource(nameof(LoadTests))] + public void Test(GeneralStateTest test) { - [TestCaseSource(nameof(LoadTests))] - public void Test(GeneralStateTest test) - { - Assert.True(RunTest(test).Pass); - } + Assert.That(RunTest(test).Pass, Is.True); + } - public static IEnumerable LoadTests() - { - var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stBugs"); - return (IEnumerable)loader.LoadTests(); - } + public static IEnumerable LoadTests() + { + var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stBugs"); + return (IEnumerable)loader.LoadTests(); } } diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCodesTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCodesTests.cs index 7cf48ca1ad1..e9906133cf2 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCodesTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCodesTests.cs @@ -5,21 +5,19 @@ using Ethereum.Test.Base; using NUnit.Framework; -namespace Ethereum.Blockchain.Legacy.Test +namespace Ethereum.Blockchain.Legacy.Test; + +[Parallelizable(ParallelScope.All)] +public class CallCodesTests : GeneralStateTestBase { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class CallCodesTests : GeneralStateTestBase + [TestCaseSource(nameof(LoadTests))] + public void Test(GeneralStateTest test) + { + Assert.That(RunTest(test).Pass, Is.True); + } + public static IEnumerable LoadTests() { - [TestCaseSource(nameof(LoadTests))] - public void Test(GeneralStateTest test) - { - Assert.True(RunTest(test).Pass); - } - public static IEnumerable LoadTests() - { - var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stCallCodes"); - return (IEnumerable)loader.LoadTests(); - } + var loader = new TestsSourceLoader(new LoadLegacyGeneralStateTestsStrategy(), "stCallCodes"); + return (IEnumerable)loader.LoadTests(); } } diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCreateCallCodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCreateCallCodeTests.cs index 6005eb16d10..30651ec8df2 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCreateCallCodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallCreateCallCodeTests.cs @@ -14,7 +14,7 @@ public class CallCreateCallCodeTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesCallCodeHomesteadTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesCallCodeHomesteadTests.cs index d32977b101b..e739212b9f3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesCallCodeHomesteadTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesCallCodeHomesteadTests.cs @@ -14,7 +14,7 @@ public class CallDelegateCodesCallCodeHomesteadTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesHomesteadTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesHomesteadTests.cs index dcd1b8b11cd..4fcba7c54c4 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesHomesteadTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CallDelegateCodesHomesteadTests.cs @@ -14,7 +14,7 @@ public class CallDelegateCodesHomesteadTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() { diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ChangedEIP150Tests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ChangedEIP150Tests.cs index 5e59862afd8..8a4d19007d3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ChangedEIP150Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ChangedEIP150Tests.cs @@ -14,7 +14,7 @@ public class ChangedEIP150Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeCopyTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeCopyTests.cs index e8762eaca82..9dabdeb8db8 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeCopyTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeCopyTests.cs @@ -14,7 +14,7 @@ public class CodeCopyTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeSizeLimitTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeSizeLimitTests.cs index 985472b5910..0e6a0a1a3be 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeSizeLimitTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CodeSizeLimitTests.cs @@ -14,7 +14,7 @@ public class CodeSizeLimitTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Create2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Create2Tests.cs index 242ba20a2e7..35d2bca5afa 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Create2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Create2Tests.cs @@ -14,7 +14,7 @@ public class Create2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CreateTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CreateTests.cs index 83453c975c0..17882e6bfc7 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CreateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/CreateTests.cs @@ -14,7 +14,7 @@ public class CreateTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/DelegateCallTestHomesteadTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/DelegateCallTestHomesteadTests.cs index f392fd2be7f..885b20650d0 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/DelegateCallTestHomesteadTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/DelegateCallTestHomesteadTests.cs @@ -14,7 +14,7 @@ public class DelegateCallTestHomesteadTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/EIP150SingleCodeGasPricesTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/EIP150SingleCodeGasPricesTests.cs index ce4998a73c8..d1618b3ad18 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/EIP150SingleCodeGasPricesTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/EIP150SingleCodeGasPricesTests.cs @@ -14,7 +14,7 @@ public class EIP150SingleCodeGasPricesTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip150SpecificTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip150SpecificTests.cs index 4dd920396a7..a47b3306aee 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip150SpecificTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip150SpecificTests.cs @@ -14,7 +14,7 @@ public class Eip150SpecificTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip158SpecificTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip158SpecificTests.cs index b4af049d9f6..abdfd91772e 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip158SpecificTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Eip158SpecificTests.cs @@ -14,7 +14,7 @@ public class Eip158SpecificTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExampleTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExampleTests.cs index a05eef7b8f1..9cc75a46334 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExampleTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExampleTests.cs @@ -14,7 +14,7 @@ public class ExampleTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExtCodeHashTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExtCodeHashTests.cs index 0f45d9cc570..4baf5578084 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExtCodeHashTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ExtCodeHashTests.cs @@ -14,7 +14,7 @@ public class ExtCodeHashTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/HomesteadSpecificTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/HomesteadSpecificTests.cs index 6d5ae56843e..316e690a128 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/HomesteadSpecificTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/HomesteadSpecificTests.cs @@ -14,7 +14,7 @@ public class HomesteadSpecificTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/InitCodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/InitCodeTests.cs index 3dac60373ad..440c7cd2905 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/InitCodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/InitCodeTests.cs @@ -14,7 +14,7 @@ public class InitCodeTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/LogTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/LogTests.cs index 80058cbad05..22719043928 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/LogTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/LogTests.cs @@ -14,7 +14,7 @@ public class LogTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemExpandingEip150CallsTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemExpandingEip150CallsTests.cs index 1df386c0bd1..260f4b4045b 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemExpandingEip150CallsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemExpandingEip150CallsTests.cs @@ -14,7 +14,7 @@ public class MemExpandingEip150CallsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryStressTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryStressTests.cs index 9636d95c535..5f5d46fcceb 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryStressTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryStressTests.cs @@ -14,7 +14,7 @@ public class MemoryStressTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryTests.cs index cac3fd8557f..8da88320042 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/MemoryTests.cs @@ -14,7 +14,7 @@ public class MemoryTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() { diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/NonZeroCallTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/NonZeroCallTests.cs index 59d47c52402..a18fc5dbcd5 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/NonZeroCallTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/NonZeroCallTests.cs @@ -14,7 +14,7 @@ public class NonZeroCallTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContracts2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContracts2Tests.cs index 25be4699f8c..0157e2d52d5 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContracts2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContracts2Tests.cs @@ -14,7 +14,7 @@ public class PreCompiledContracts2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContractsTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContractsTests.cs index e8f3666137b..683397c7341 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContractsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/PreCompiledContractsTests.cs @@ -14,7 +14,7 @@ public class PreCompiledContractsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/QuadraticComplexityTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/QuadraticComplexityTests.cs index dfa26f83600..b69e62e832b 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/QuadraticComplexityTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/QuadraticComplexityTests.cs @@ -14,7 +14,7 @@ public class QuadraticComplexityTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Random2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Random2Tests.cs index 7783bcb03d2..085c9057bb9 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Random2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/Random2Tests.cs @@ -14,7 +14,7 @@ public class Random2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RandomTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RandomTests.cs index 45103b0b33a..f4e873bc876 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RandomTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RandomTests.cs @@ -14,7 +14,7 @@ public class RandomTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RecursiveCreateTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RecursiveCreateTests.cs index 532d3eac6aa..fba11d1ea19 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RecursiveCreateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RecursiveCreateTests.cs @@ -14,7 +14,7 @@ public class RecursiveCreateTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RefundTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RefundTests.cs index c718c700800..c3e2edf5ec2 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RefundTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RefundTests.cs @@ -14,7 +14,7 @@ public class RefundTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ReturnDataTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ReturnDataTests.cs index b17848977a5..2e213865216 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ReturnDataTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ReturnDataTests.cs @@ -14,7 +14,7 @@ public class ReturnDataTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RevertTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RevertTests.cs index 1811a5dea22..713c649a2c5 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RevertTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/RevertTests.cs @@ -15,7 +15,7 @@ public class RevertTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SStoreTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SStoreTests.cs index d98891e599d..3b451e3f25a 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SStoreTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SStoreTests.cs @@ -14,7 +14,7 @@ public class SStoreTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ShiftTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ShiftTests.cs index 181e07df104..fb5e7fa6f69 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ShiftTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ShiftTests.cs @@ -14,7 +14,7 @@ public class ShiftTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SolidityTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SolidityTests.cs index 4f4286de4fa..dde781ad0c8 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SolidityTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SolidityTests.cs @@ -14,7 +14,7 @@ public class SolidityTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SpecialTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SpecialTests.cs index 15269bdfd83..826fe9ab636 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SpecialTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SpecialTests.cs @@ -15,7 +15,7 @@ public class SpecialTests : GeneralStateTestBase [Retry(3)] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StackTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StackTests.cs index 9537453d16c..6c8600ceabd 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StackTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StackTests.cs @@ -14,7 +14,7 @@ public class StackTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StaticCallTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StaticCallTests.cs index cc03dbdd226..7ff4fa7a9d2 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StaticCallTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/StaticCallTests.cs @@ -14,7 +14,7 @@ public class StaticCallTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SystemOperationsTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SystemOperationsTests.cs index 6fb261a0187..f64a2c715f9 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SystemOperationsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/SystemOperationsTests.cs @@ -14,7 +14,7 @@ public class SystemOperationsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TimeConsumingTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TimeConsumingTests.cs index 7e4cb1ef3b6..2c297fdaac0 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TimeConsumingTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TimeConsumingTests.cs @@ -14,7 +14,7 @@ public class TimeConsumingTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransactionTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransactionTests.cs index 1396faaa933..2736ccdcb1d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransactionTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransactionTests.cs @@ -14,7 +14,7 @@ public class TransactionTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransitionTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransitionTests.cs index 150e263ff62..24327c15260 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransitionTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/TransitionTests.cs @@ -14,7 +14,7 @@ public class TransitionTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/WalletTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/WalletTests.cs index b0156f84e66..f13698011c3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/WalletTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/WalletTests.cs @@ -14,7 +14,7 @@ public class WalletTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsRevertTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsRevertTests.cs index ea3cb94386e..bdf69dd1b69 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsRevertTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsRevertTests.cs @@ -14,7 +14,7 @@ public class ZeroCallsRevertTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsTests.cs index 0cb161edd47..89f957ecf83 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroCallsTests.cs @@ -14,7 +14,7 @@ public class ZeroCallsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledge2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledge2Tests.cs index d7387613dd4..559441d537d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledge2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledge2Tests.cs @@ -14,7 +14,7 @@ public class ZeroKnowledge2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledgeTests.cs b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledgeTests.cs index 8f5daf72c75..026fcd0fcf3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledgeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Legacy.Test/ZeroKnowledgeTests.cs @@ -14,7 +14,7 @@ public class ZeroKnowledgeTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ArgsZeroOneBalanceTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ArgsZeroOneBalanceTests.cs index 5db1726704f..98f88a5df87 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ArgsZeroOneBalanceTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ArgsZeroOneBalanceTests.cs @@ -14,7 +14,7 @@ public class ArgsZeroOneBalanceTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/AttackTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/AttackTests.cs index 37a37b89a7a..7807c5e51a0 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/AttackTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/AttackTests.cs @@ -14,7 +14,7 @@ public class AttackTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/BadOpcodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/BadOpcodeTests.cs index e90821b0a4a..54ee33d93b9 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/BadOpcodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/BadOpcodeTests.cs @@ -16,7 +16,7 @@ public class BadOpcodeTests : GeneralStateTestBase [Retry(3)] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/BlockhashTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/BlockhashTests.cs index 29963fbcaf2..7e621f779f3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/BlockhashTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/BlockhashTests.cs @@ -16,7 +16,7 @@ public class BlockhashTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/BugsTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/BugsTests.cs index cf531d83418..c1bf2149470 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/BugsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/BugsTests.cs @@ -14,7 +14,7 @@ public class BugsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/CallCodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/CallCodeTests.cs index b7a15e7a94b..bda00b0f1f4 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/CallCodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/CallCodeTests.cs @@ -14,7 +14,7 @@ public class CallCodesTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/CallCreateCallCodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/CallCreateCallCodeTests.cs index be1a7831e17..1d3ea3c7e94 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/CallCreateCallCodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/CallCreateCallCodeTests.cs @@ -14,7 +14,7 @@ public class CallCreateCallCodeTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesCallCodeHomesteadTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesCallCodeHomesteadTests.cs index 397609494fc..20cd25070b3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesCallCodeHomesteadTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesCallCodeHomesteadTests.cs @@ -14,7 +14,7 @@ public class CallDelegateCodesCallCodeHomesteadTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesHomesteadTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesHomesteadTests.cs index 3f98125a892..e88999d517d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesHomesteadTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/CallDelegateCodesHomesteadTests.cs @@ -14,7 +14,7 @@ public class CallDelegateCodesHomesteadTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ChainIdTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ChainIdTests.cs index 9711e655a5d..fb32ef488fb 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ChainIdTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ChainIdTests.cs @@ -14,7 +14,7 @@ public class ChainIdTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/CodeCopyTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/CodeCopyTests.cs index 0e86ed2cca5..1cca26a70e7 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/CodeCopyTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/CodeCopyTests.cs @@ -14,7 +14,7 @@ public class CodeCopyTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/CodeSizeLimitTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/CodeSizeLimitTests.cs index 2a34e531437..8355900e130 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/CodeSizeLimitTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/CodeSizeLimitTests.cs @@ -14,7 +14,7 @@ public class CodeSizeLimitTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Create2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Create2Tests.cs index d70554854c6..a518ec7f3c8 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Create2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Create2Tests.cs @@ -14,7 +14,7 @@ public class Create2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/CreateTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/CreateTests.cs index b84a7b55eb3..9dbd4c59b38 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/CreateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/CreateTests.cs @@ -15,7 +15,7 @@ public class CreateTests : GeneralStateTestBase [Retry(3)] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/DelegateCallTestHomesteadTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/DelegateCallTestHomesteadTests.cs index 71b2e32acb1..07b38e904c5 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/DelegateCallTestHomesteadTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/DelegateCallTestHomesteadTests.cs @@ -14,7 +14,7 @@ public class DelegateCallTestHomesteadTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/EIP150SingleCodeGasPricesTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/EIP150SingleCodeGasPricesTests.cs index 64cb2ca29d9..9ec5c5f902c 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/EIP150SingleCodeGasPricesTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/EIP150SingleCodeGasPricesTests.cs @@ -14,7 +14,7 @@ public class Eip150SingleCodeGasPricesTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/EIP6110Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/EIP6110Tests.cs index d55bf6b3af1..64b6e80209d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/EIP6110Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/EIP6110Tests.cs @@ -14,7 +14,7 @@ public class Eip6110Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip1153Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip1153Tests.cs index 056d80d94f0..fbb7baa2c1f 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip1153Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip1153Tests.cs @@ -14,7 +14,7 @@ public class EIP1153transientStorageTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip150SpecificTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip150SpecificTests.cs index 6ff98009dc9..1e2cca8beac 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip150SpecificTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip150SpecificTests.cs @@ -14,7 +14,7 @@ public class Eip150SpecificTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip1559Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip1559Tests.cs index 27f847e1541..0f8f14effc1 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip1559Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip1559Tests.cs @@ -14,7 +14,7 @@ public class Eip1559Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip158SpecificTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip158SpecificTests.cs index 59d8e46b707..2cba21a51c9 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip158SpecificTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip158SpecificTests.cs @@ -14,7 +14,7 @@ public class Eip158SpecificTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs index 23fe74ca1a3..ec0b408d0db 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs @@ -14,7 +14,7 @@ public class Eip2537Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip2930Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip2930Tests.cs index bbdfee1df2d..28d80c6bfbe 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip2930Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip2930Tests.cs @@ -14,7 +14,7 @@ public class Eip2930Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip3540Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip3540Tests.cs index 7d39ed7ef51..9e9d5dc1924 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip3540Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip3540Tests.cs @@ -16,7 +16,7 @@ public class Eip3540Tests : GeneralStateTestBase // [TestCaseSource(nameof(LoadTests))] // public void Test(GeneralStateTest test) // { - // Assert.True(RunTest(test).Pass); + // Assert.That(RunTest(test).Pass, Is.True); // } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip3607Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip3607Tests.cs index afcca56a34c..c8f7121207d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip3607Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip3607Tests.cs @@ -14,7 +14,7 @@ public class Eip3607Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip3651WarmCoinbaseTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip3651WarmCoinbaseTests.cs index 7628583e30e..567c97f0cd4 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip3651WarmCoinbaseTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip3651WarmCoinbaseTests.cs @@ -14,7 +14,7 @@ public class Eip3651WarmCoinbaseTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip3855Push0Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip3855Push0Tests.cs index c54418db7f3..4915e9ec236 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip3855Push0Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip3855Push0Tests.cs @@ -14,7 +14,7 @@ public class Eip3855Push0Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip3860LimitmeterInitCodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip3860LimitmeterInitCodeTests.cs index baebeaab864..70c0295872b 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip3860LimitmeterInitCodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip3860LimitmeterInitCodeTests.cs @@ -14,7 +14,7 @@ public class Eip3860LimitmeterInitCodeTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip4844Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip4844Tests.cs index 76fedb8c2e5..f8ede23b307 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip4844Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip4844Tests.cs @@ -14,7 +14,7 @@ public class EIP4844blobtransactionsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip5656Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip5656Tests.cs index 1a48e321290..979d03a3d88 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip5656Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip5656Tests.cs @@ -14,7 +14,7 @@ public class EIP5656MCOPYTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/EofTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/EofTests.cs index f4fad766299..251ec083de0 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/EofTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/EofTests.cs @@ -16,7 +16,7 @@ public class EOFTests : GeneralStateTestBase // [TestCaseSource(nameof(LoadTests))] // public void Test(GeneralStateTest test) // { - // Assert.True(RunTest(test).Pass); + // Assert.That(RunTest(test).Pass, Is.True); // } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ExampleTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ExampleTests.cs index c241f7697fa..eacd39a47d9 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ExampleTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ExampleTests.cs @@ -14,7 +14,7 @@ public class ExampleTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ExtCodeHashTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ExtCodeHashTests.cs index 72eb4715fbf..4e37b44b359 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ExtCodeHashTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ExtCodeHashTests.cs @@ -14,7 +14,7 @@ public class ExtCodeHashTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/HomesteadSpecificTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/HomesteadSpecificTests.cs index 02c154318a0..04669079f47 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/HomesteadSpecificTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/HomesteadSpecificTests.cs @@ -14,7 +14,7 @@ public class HomesteadSpecificTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/InitCodeTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/InitCodeTests.cs index f258d7e1ad4..47e2827a89d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/InitCodeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/InitCodeTests.cs @@ -14,7 +14,7 @@ public class InitCodeTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/LogTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/LogTests.cs index 2b0aab864ea..a78da46e41f 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/LogTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/LogTests.cs @@ -14,7 +14,7 @@ public class LogTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/MemExpandingEip150CallsTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/MemExpandingEip150CallsTests.cs index 0449aece457..ec5f3da4479 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/MemExpandingEip150CallsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/MemExpandingEip150CallsTests.cs @@ -14,7 +14,7 @@ public class MemExpandingEip150CallsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/MemoryStressTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/MemoryStressTests.cs index 480fa423113..f3c9b1431bd 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/MemoryStressTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/MemoryStressTests.cs @@ -14,7 +14,7 @@ public class MemoryStressTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/MemoryTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/MemoryTests.cs index 3997ca78cff..33089138878 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/MemoryTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/MemoryTests.cs @@ -15,7 +15,7 @@ public class MemoryTests : GeneralStateTestBase [Retry(3)] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/NonZeroCallTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/NonZeroCallTests.cs index 4019346834d..9df35201ced 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/NonZeroCallTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/NonZeroCallTests.cs @@ -14,7 +14,7 @@ public class NonZeroCallsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContracts2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContracts2Tests.cs index 99ccd78a2aa..2108d914093 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContracts2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContracts2Tests.cs @@ -14,7 +14,7 @@ public class PreCompiledContracts2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContractsTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContractsTests.cs index 00c97d29fab..fbce44d6ac6 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContractsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/PreCompiledContractsTests.cs @@ -14,7 +14,7 @@ public class PreCompiledContractsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/QuadraticComplexityTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/QuadraticComplexityTests.cs index 9180dd2a78c..d8cb9d42dcc 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/QuadraticComplexityTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/QuadraticComplexityTests.cs @@ -14,7 +14,7 @@ public class QuadraticComplexityTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Random2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Random2Tests.cs index 44b9d8b75b2..09124501f9d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Random2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Random2Tests.cs @@ -14,7 +14,7 @@ public class Random2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/RandomTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/RandomTests.cs index 503b3684e68..066c6c83954 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/RandomTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/RandomTests.cs @@ -14,7 +14,7 @@ public class RandomTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/RecursiveCreateTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/RecursiveCreateTests.cs index fa97c5ea69f..30f64caca8f 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/RecursiveCreateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/RecursiveCreateTests.cs @@ -14,7 +14,7 @@ public class RecursiveCreateTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/RefundTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/RefundTests.cs index 38570e8fa1f..df0937aacf6 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/RefundTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/RefundTests.cs @@ -14,7 +14,7 @@ public class RefundTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ReturnDataTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ReturnDataTests.cs index 00e4c57b2c6..86ce0cc3971 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ReturnDataTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ReturnDataTests.cs @@ -14,7 +14,7 @@ public class ReturnDataTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/RevertTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/RevertTests.cs index 33588d24396..c40d233e72e 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/RevertTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/RevertTests.cs @@ -14,7 +14,7 @@ public class RevertTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/SLoadTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/SLoadTests.cs index 4fa452180d4..9bd635b50a3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/SLoadTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/SLoadTests.cs @@ -14,7 +14,7 @@ public class SLoadTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/SStoreTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/SStoreTests.cs index f2e98a5c73d..7b35c7950c1 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/SStoreTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/SStoreTests.cs @@ -14,7 +14,7 @@ public class SStoreTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/SelfBalanceTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/SelfBalanceTests.cs index a18b603bb47..aaebbbac289 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/SelfBalanceTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/SelfBalanceTests.cs @@ -14,7 +14,7 @@ public class SelfBalanceTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ShiftTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ShiftTests.cs index e8ccd020c15..cccf0e78808 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ShiftTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ShiftTests.cs @@ -14,7 +14,7 @@ public class ShiftTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/SolidityTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/SolidityTests.cs index 98e97de0806..ce0941fb082 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/SolidityTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/SolidityTests.cs @@ -15,7 +15,7 @@ public class SolidityTests : GeneralStateTestBase [Retry(3)] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/SpecialTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/SpecialTests.cs index d931e0b88c4..b3a30484320 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/SpecialTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/SpecialTests.cs @@ -14,7 +14,7 @@ public class SpecialTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests)), Retry(3)] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/StackTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/StackTests.cs index 14293bb58ae..b966cf1f84a 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/StackTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/StackTests.cs @@ -14,7 +14,7 @@ public class StackTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/StaticCallTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/StaticCallTests.cs index f2eff44c1bf..09fd0875f07 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/StaticCallTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/StaticCallTests.cs @@ -14,7 +14,7 @@ public class StaticCallTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/StaticFlagEnabledTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/StaticFlagEnabledTests.cs index 45af9c583ad..d66cf77d0f3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/StaticFlagEnabledTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/StaticFlagEnabledTests.cs @@ -14,7 +14,7 @@ public class StaticFlagEnabledTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/SystemOperationsTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/SystemOperationsTests.cs index 5ecf1b56f68..242d460cdd7 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/SystemOperationsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/SystemOperationsTests.cs @@ -14,7 +14,7 @@ public class SystemOperationsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/TimeConsumingTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/TimeConsumingTests.cs index 0967afdcf8d..f49ecc8a56c 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/TimeConsumingTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/TimeConsumingTests.cs @@ -14,7 +14,7 @@ public class TimeConsumingTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/TransactionTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/TransactionTests.cs index bc7b054e356..a546bf2eebb 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/TransactionTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/TransactionTests.cs @@ -27,7 +27,7 @@ public void Test(GeneralStateTest test) return; } - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/TransitionTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/TransitionTests.cs index d426ce9d76b..aa1a185e5d5 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/TransitionTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/TransitionTests.cs @@ -14,7 +14,7 @@ public class TransitionTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/WalletTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/WalletTests.cs index d5b980c3c2f..ee26a53f650 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/WalletTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/WalletTests.cs @@ -14,7 +14,7 @@ public class WalletTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsRevertTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsRevertTests.cs index 02c345a93e3..5a2896ad9f3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsRevertTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsRevertTests.cs @@ -14,7 +14,7 @@ public class ZeroCallsRevertTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsTests.cs index 9ce090e67a8..a46ab6da3d4 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ZeroCallsTests.cs @@ -14,7 +14,7 @@ public class ZeroCallsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledge2Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledge2Tests.cs index eb6cd15ed94..5f79784913d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledge2Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledge2Tests.cs @@ -14,7 +14,7 @@ public class ZeroKnowledge2Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledgeTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledgeTests.cs index a66827e60e7..99e70ed5aae 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledgeTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/ZeroKnowledgeTests.cs @@ -14,7 +14,7 @@ public class ZeroKnowledgeTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index ba62c18508e..6f8afe58043 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -39,436 +39,435 @@ using Nethermind.TxPool; using NUnit.Framework; -namespace Ethereum.Test.Base +namespace Ethereum.Test.Base; + +public abstract class BlockchainTestBase { - public abstract class BlockchainTestBase + private static InterfaceLogger _logger = new NUnitLogger(LogLevel.Trace); + // private static ILogManager _logManager = new OneLoggerLogManager(_logger); + private static ILogManager _logManager = LimboLogs.Instance; + private static ISealValidator Sealer { get; } + private static DifficultyCalculatorWrapper DifficultyCalculator { get; } + + static BlockchainTestBase() { - private static InterfaceLogger _logger = new NUnitLogger(LogLevel.Trace); - // private static ILogManager _logManager = new OneLoggerLogManager(_logger); - private static ILogManager _logManager = LimboLogs.Instance; - private static ISealValidator Sealer { get; } - private static DifficultyCalculatorWrapper DifficultyCalculator { get; } + DifficultyCalculator = new DifficultyCalculatorWrapper(); + Sealer = new EthashSealValidator(_logManager, DifficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default); // temporarily keep reusing the same one as otherwise it would recreate cache for each test + } - static BlockchainTestBase() - { - DifficultyCalculator = new DifficultyCalculatorWrapper(); - Sealer = new EthashSealValidator(_logManager, DifficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default); // temporarily keep reusing the same one as otherwise it would recreate cache for each test - } + [SetUp] + public void Setup() + { + } - [SetUp] - public void Setup() + private class DifficultyCalculatorWrapper : IDifficultyCalculator + { + public IDifficultyCalculator? Wrapped { get; set; } + + public UInt256 Calculate(BlockHeader header, BlockHeader parent) { + if (Wrapped is null) + { + throw new InvalidOperationException( + $"Cannot calculate difficulty before the {nameof(Wrapped)} calculator is set."); + } + + return Wrapped.Calculate(header, parent); } + } - private class DifficultyCalculatorWrapper : IDifficultyCalculator - { - public IDifficultyCalculator? Wrapped { get; set; } + protected async Task RunTest(BlockchainTest test, Stopwatch? stopwatch = null, bool failOnInvalidRlp = true) + { + TestContext.Out.WriteLine($"Running {test.Name}, Network: [{test.Network.Name}] at {DateTime.UtcNow:HH:mm:ss.ffffff}"); + if (test.NetworkAfterTransition is not null) + TestContext.Out.WriteLine($"Network after transition: [{test.NetworkAfterTransition.Name}] at {test.TransitionForkActivation}"); + Assert.That(test.LoadFailure, Is.Null, "test data loading failure"); - public UInt256 Calculate(BlockHeader header, BlockHeader parent) - { - if (Wrapped is null) - { - throw new InvalidOperationException( - $"Cannot calculate difficulty before the {nameof(Wrapped)} calculator is set."); - } + IDb stateDb = new MemDb(); + IDb codeDb = new MemDb(); - return Wrapped.Calculate(header, parent); - } + ISpecProvider specProvider; + if (test.NetworkAfterTransition is not null) + { + specProvider = new CustomSpecProvider( + ((ForkActivation)0, Frontier.Instance), + ((ForkActivation)1, test.Network), + (test.TransitionForkActivation!.Value, test.NetworkAfterTransition)); + } + else + { + specProvider = new CustomSpecProvider( + ((ForkActivation)0, Frontier.Instance), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier + ((ForkActivation)1, test.Network)); } - protected async Task RunTest(BlockchainTest test, Stopwatch? stopwatch = null, bool failOnInvalidRlp = true) + if (specProvider.GenesisSpec != Frontier.Instance) { - TestContext.WriteLine($"Running {test.Name}, Network: [{test.Network.Name}] at {DateTime.UtcNow:HH:mm:ss.ffffff}"); - if (test.NetworkAfterTransition is not null) - TestContext.WriteLine($"Network after transition: [{test.NetworkAfterTransition.Name}] at {test.TransitionForkActivation}"); - Assert.IsNull(test.LoadFailure, "test data loading failure"); + Assert.Fail("Expected genesis spec to be Frontier for blockchain tests"); + } - IDb stateDb = new MemDb(); - IDb codeDb = new MemDb(); + if (test.Network is Cancun || test.NetworkAfterTransition is Cancun) + { + await KzgPolynomialCommitments.InitializeAsync(); + } - ISpecProvider specProvider; - if (test.NetworkAfterTransition is not null) - { - specProvider = new CustomSpecProvider( - ((ForkActivation)0, Frontier.Instance), - ((ForkActivation)1, test.Network), - (test.TransitionForkActivation!.Value, test.NetworkAfterTransition)); - } - else - { - specProvider = new CustomSpecProvider( - ((ForkActivation)0, Frontier.Instance), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier - ((ForkActivation)1, test.Network)); - } + DifficultyCalculator.Wrapped = new EthashDifficultyCalculator(specProvider); + IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); + bool isPostMerge = test.Network != London.Instance && + test.Network != Berlin.Instance && + test.Network != MuirGlacier.Instance && + test.Network != Istanbul.Instance && + test.Network != ConstantinopleFix.Instance && + test.Network != Constantinople.Instance && + test.Network != Byzantium.Instance && + test.Network != SpuriousDragon.Instance && + test.Network != TangerineWhistle.Instance && + test.Network != Dao.Instance && + test.Network != Homestead.Instance && + test.Network != Frontier.Instance && + test.Network != Olympic.Instance; + if (isPostMerge) + { + rewardCalculator = NoBlockRewards.Instance; + specProvider.UpdateMergeTransitionInfo(0, 0); + } - if (specProvider.GenesisSpec != Frontier.Instance) + IEthereumEcdsa ecdsa = new EthereumEcdsa(specProvider.ChainId); + + TrieStore trieStore = new(stateDb, _logManager); + IWorldState stateProvider = new WorldState(trieStore, codeDb, _logManager); + IBlockTree blockTree = Build.A.BlockTree() + .WithSpecProvider(specProvider) + .WithoutSettingHead + .TestObject; + ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(specProvider, blockTree); + IStateReader stateReader = new StateReader(trieStore, codeDb, _logManager); + + IReceiptStorage receiptStorage = NullReceiptStorage.Instance; + IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, specProvider, stateProvider, _logManager); + ITxValidator txValidator = new TxValidator(TestBlockchainIds.ChainId); + IHeaderValidator headerValidator = new HeaderValidator(blockTree, Sealer, specProvider, _logManager); + IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager); + IBlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, unclesValidator, specProvider, _logManager); + CodeInfoRepository codeInfoRepository = new(); + IVirtualMachine virtualMachine = new VirtualMachine( + blockhashProvider, + specProvider, + codeInfoRepository, + _logManager); + + TransactionProcessor transactionProcessor = new( + specProvider, + stateProvider, + virtualMachine, + codeInfoRepository, + _logManager); + + IBlockProcessor blockProcessor = new BlockProcessor( + specProvider, + blockValidator, + rewardCalculator, + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), + stateProvider, + receiptStorage, + transactionProcessor, + new BeaconBlockRootHandler(transactionProcessor), + new BlockhashStore(specProvider, stateProvider), + _logManager); + + IBlockchainProcessor blockchainProcessor = new BlockchainProcessor( + blockTree, + blockProcessor, + new RecoverSignatures(ecdsa, NullTxPool.Instance, specProvider, _logManager), + stateReader, + _logManager, + BlockchainProcessor.Options.NoReceipts); + + InitializeTestState(test, stateProvider, specProvider); + + stopwatch?.Start(); + List<(Block Block, string ExpectedException)> correctRlp = DecodeRlps(test, failOnInvalidRlp); + + test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader))); + + Block genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes); + Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); + + ManualResetEvent genesisProcessed = new(false); + + blockTree.NewHeadBlock += (_, args) => + { + if (args.Block.Number == 0) { - Assert.Fail("Expected genesis spec to be Frontier for blockchain tests"); + Assert.That(stateProvider.StateRoot, Is.EqualTo(genesisBlock.Header.StateRoot)); + genesisProcessed.Set(); } + }; - if (test.Network is Cancun || test.NetworkAfterTransition is Cancun) - { - await KzgPolynomialCommitments.InitializeAsync(); - } + blockchainProcessor.Start(); + blockTree.SuggestBlock(genesisBlock); - DifficultyCalculator.Wrapped = new EthashDifficultyCalculator(specProvider); - IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); - bool isPostMerge = test.Network != London.Instance && - test.Network != Berlin.Instance && - test.Network != MuirGlacier.Instance && - test.Network != Istanbul.Instance && - test.Network != ConstantinopleFix.Instance && - test.Network != Constantinople.Instance && - test.Network != Byzantium.Instance && - test.Network != SpuriousDragon.Instance && - test.Network != TangerineWhistle.Instance && - test.Network != Dao.Instance && - test.Network != Homestead.Instance && - test.Network != Frontier.Instance && - test.Network != Olympic.Instance; - if (isPostMerge) + genesisProcessed.WaitOne(); + for (int i = 0; i < correctRlp.Count; i++) + { + if (correctRlp[i].Block.Hash is null) { - rewardCalculator = NoBlockRewards.Instance; - specProvider.UpdateMergeTransitionInfo(0, 0); + Assert.Fail($"null hash in {test.Name} block {i}"); } - IEthereumEcdsa ecdsa = new EthereumEcdsa(specProvider.ChainId); - - TrieStore trieStore = new(stateDb, _logManager); - IWorldState stateProvider = new WorldState(trieStore, codeDb, _logManager); - IBlockTree blockTree = Build.A.BlockTree() - .WithSpecProvider(specProvider) - .WithoutSettingHead - .TestObject; - ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(specProvider, blockTree); - IStateReader stateReader = new StateReader(trieStore, codeDb, _logManager); - - IReceiptStorage receiptStorage = NullReceiptStorage.Instance; - IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, specProvider, stateProvider, _logManager); - ITxValidator txValidator = new TxValidator(TestBlockchainIds.ChainId); - IHeaderValidator headerValidator = new HeaderValidator(blockTree, Sealer, specProvider, _logManager); - IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager); - IBlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, unclesValidator, specProvider, _logManager); - CodeInfoRepository codeInfoRepository = new(); - IVirtualMachine virtualMachine = new VirtualMachine( - blockhashProvider, - specProvider, - codeInfoRepository, - _logManager); - - TransactionProcessor transactionProcessor = new( - specProvider, - stateProvider, - virtualMachine, - codeInfoRepository, - _logManager); - - IBlockProcessor blockProcessor = new BlockProcessor( - specProvider, - blockValidator, - rewardCalculator, - new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), - stateProvider, - receiptStorage, - transactionProcessor, - new BeaconBlockRootHandler(transactionProcessor), - new BlockhashStore(specProvider, stateProvider), - _logManager); - - IBlockchainProcessor blockchainProcessor = new BlockchainProcessor( - blockTree, - blockProcessor, - new RecoverSignatures(ecdsa, NullTxPool.Instance, specProvider, _logManager), - stateReader, - _logManager, - BlockchainProcessor.Options.NoReceipts); - - InitializeTestState(test, stateProvider, specProvider); - - stopwatch?.Start(); - List<(Block Block, string ExpectedException)> correctRlp = DecodeRlps(test, failOnInvalidRlp); - - test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader))); - - Block genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes); - Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); - - ManualResetEvent genesisProcessed = new(false); - - blockTree.NewHeadBlock += (_, args) => - { - if (args.Block.Number == 0) - { - Assert.That(stateProvider.StateRoot, Is.EqualTo(genesisBlock.Header.StateRoot)); - genesisProcessed.Set(); - } - }; - - blockchainProcessor.Start(); - blockTree.SuggestBlock(genesisBlock); - - genesisProcessed.WaitOne(); - for (int i = 0; i < correctRlp.Count; i++) + try { - if (correctRlp[i].Block.Hash is null) + // TODO: mimic the actual behaviour where block goes through validating sync manager? + correctRlp[i].Block.Header.IsPostMerge = correctRlp[i].Block.Difficulty == 0; + if (!test.SealEngineUsed || blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, out _)) { - Assert.Fail($"null hash in {test.Name} block {i}"); + blockTree.SuggestBlock(correctRlp[i].Block); } - - try - { - // TODO: mimic the actual behaviour where block goes through validating sync manager? - correctRlp[i].Block.Header.IsPostMerge = correctRlp[i].Block.Difficulty == 0; - if (!test.SealEngineUsed || blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, out _)) - { - blockTree.SuggestBlock(correctRlp[i].Block); - } - else - { - if (correctRlp[i].ExpectedException is not null) - { - Assert.Fail($"Unexpected invalid block {correctRlp[i].Block.Hash}"); - } - } - } - catch (InvalidBlockException e) + else { if (correctRlp[i].ExpectedException is not null) { - Assert.Fail($"Unexpected invalid block {correctRlp[i].Block.Hash}: {e}"); + Assert.Fail($"Unexpected invalid block {correctRlp[i].Block.Hash}"); } } - catch (Exception e) + } + catch (InvalidBlockException e) + { + if (correctRlp[i].ExpectedException is not null) { - Assert.Fail($"Unexpected exception during processing: {e}"); + Assert.Fail($"Unexpected invalid block {correctRlp[i].Block.Hash}: {e}"); } } + catch (Exception e) + { + Assert.Fail($"Unexpected exception during processing: {e}"); + } + } - await blockchainProcessor.StopAsync(true); - stopwatch?.Stop(); + await blockchainProcessor.StopAsync(true); + stopwatch?.Stop(); - List differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), stateProvider); + List differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), stateProvider); - Assert.Zero(differences.Count, "differences"); + Assert.That(differences.Count, Is.Zero, "differences"); - return new EthereumTestResult - ( - test.Name, - null, - differences.Count == 0 - ); - } + return new EthereumTestResult + ( + test.Name, + null, + differences.Count == 0 + ); + } - private List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp) + private List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp) + { + List<(Block Block, string ExpectedException)> correctRlp = new(); + for (int i = 0; i < test.Blocks.Length; i++) { - List<(Block Block, string ExpectedException)> correctRlp = new(); - for (int i = 0; i < test.Blocks.Length; i++) + TestBlockJson testBlockJson = test.Blocks[i]; + try { - TestBlockJson testBlockJson = test.Blocks[i]; - try + var rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream(); + Block suggestedBlock = Rlp.Decode(rlpContext); + suggestedBlock.Header.SealEngineType = + test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None; + + if (testBlockJson.BlockHeader is not null) { - var rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream(); - Block suggestedBlock = Rlp.Decode(rlpContext); - suggestedBlock.Header.SealEngineType = - test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None; + Assert.That(suggestedBlock.Header.Hash, Is.EqualTo(new Hash256(testBlockJson.BlockHeader.Hash))); - if (testBlockJson.BlockHeader is not null) + for (int uncleIndex = 0; uncleIndex < suggestedBlock.Uncles.Length; uncleIndex++) { - Assert.That(suggestedBlock.Header.Hash, Is.EqualTo(new Hash256(testBlockJson.BlockHeader.Hash))); - - for (int uncleIndex = 0; uncleIndex < suggestedBlock.Uncles.Length; uncleIndex++) - { - Assert.That(suggestedBlock.Uncles[uncleIndex].Hash, Is.EqualTo(new Hash256(testBlockJson.UncleHeaders[uncleIndex].Hash))); - } - - correctRlp.Add((suggestedBlock, testBlockJson.ExpectedException)); + Assert.That(suggestedBlock.Uncles[uncleIndex].Hash, Is.EqualTo(new Hash256(testBlockJson.UncleHeaders[uncleIndex].Hash))); } + + correctRlp.Add((suggestedBlock, testBlockJson.ExpectedException)); } - catch (Exception e) + } + catch (Exception e) + { + if (testBlockJson.ExpectedException is null) { - if (testBlockJson.ExpectedException is null) + string invalidRlpMessage = $"Invalid RLP ({i}) {e}"; + if (failOnInvalidRlp) { - string invalidRlpMessage = $"Invalid RLP ({i}) {e}"; - if (failOnInvalidRlp) - { - Assert.Fail(invalidRlpMessage); - } - else - { - // ForgedTests don't have ExpectedException and at the same time have invalid rlps - // Don't fail here. If test executed incorrectly will fail at last check - _logger.Warn(invalidRlpMessage); - } + Assert.Fail(invalidRlpMessage); } else { - _logger.Info($"Expected invalid RLP ({i})"); + // ForgedTests don't have ExpectedException and at the same time have invalid rlps + // Don't fail here. If test executed incorrectly will fail at last check + _logger.Warn(invalidRlpMessage); } } - } - - if (correctRlp.Count == 0) - { - Assert.NotNull(test.GenesisBlockHeader); - Assert.That(test.LastBlockHash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); - } - - return correctRlp; - } - - private void InitializeTestState(BlockchainTest test, IWorldState stateProvider, ISpecProvider specProvider) - { - foreach (KeyValuePair accountState in - ((IEnumerable>)test.Pre ?? Array.Empty>())) - { - foreach (KeyValuePair storageItem in accountState.Value.Storage) - { - stateProvider.Set(new StorageCell(accountState.Key, storageItem.Key), storageItem.Value); - } - - stateProvider.CreateAccount(accountState.Key, accountState.Value.Balance); - stateProvider.InsertCode(accountState.Key, accountState.Value.Code, specProvider.GenesisSpec); - for (int i = 0; i < accountState.Value.Nonce; i++) + else { - stateProvider.IncrementNonce(accountState.Key); + _logger.Info($"Expected invalid RLP ({i})"); } } - - stateProvider.Commit(specProvider.GenesisSpec); - - stateProvider.CommitTree(0); - - stateProvider.Reset(); } - private List RunAssertions(BlockchainTest test, Block headBlock, IWorldState stateProvider) + if (correctRlp.Count == 0) { - if (test.PostStateRoot is not null) - { - return test.PostStateRoot != stateProvider.StateRoot ? new List { "state root mismatch" } : Enumerable.Empty().ToList(); - } - - TestBlockHeaderJson testHeaderJson = (test.Blocks? - .Where(b => b.BlockHeader is not null) - .SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader) ?? test.GenesisBlockHeader; - BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson); - List differences = new(); + Assert.That(test.GenesisBlockHeader, Is.Not.Null); + Assert.That(test.LastBlockHash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); + } - IEnumerable> deletedAccounts = test.Pre? - .Where(pre => !(test.PostState?.ContainsKey(pre.Key) ?? false)) ?? Array.Empty>(); + return correctRlp; + } - foreach (KeyValuePair deletedAccount in deletedAccounts) + private void InitializeTestState(BlockchainTest test, IWorldState stateProvider, ISpecProvider specProvider) + { + foreach (KeyValuePair accountState in + ((IEnumerable>)test.Pre ?? Array.Empty>())) + { + foreach (KeyValuePair storageItem in accountState.Value.Storage) { - if (stateProvider.AccountExists(deletedAccount.Key)) - { - differences.Add($"Pre state account {deletedAccount.Key} was not deleted as expected."); - } + stateProvider.Set(new StorageCell(accountState.Key, storageItem.Key), storageItem.Value); } - foreach ((Address acountAddress, AccountState accountState) in test.PostState) + stateProvider.CreateAccount(accountState.Key, accountState.Value.Balance); + stateProvider.InsertCode(accountState.Key, accountState.Value.Code, specProvider.GenesisSpec); + for (int i = 0; i < accountState.Value.Nonce; i++) { - int differencesBefore = differences.Count; + stateProvider.IncrementNonce(accountState.Key); + } + } - if (differences.Count > 8) - { - Console.WriteLine("More than 8 differences..."); - break; - } + stateProvider.Commit(specProvider.GenesisSpec); - bool accountExists = stateProvider.AccountExists(acountAddress); - UInt256? balance = accountExists ? stateProvider.GetBalance(acountAddress) : (UInt256?)null; - UInt256? nonce = accountExists ? stateProvider.GetNonce(acountAddress) : (UInt256?)null; + stateProvider.CommitTree(0); - if (accountState.Balance != balance) - { - differences.Add($"{acountAddress} balance exp: {accountState.Balance}, actual: {balance}, diff: {(balance > accountState.Balance ? balance - accountState.Balance : accountState.Balance - balance)}"); - } + stateProvider.Reset(); + } - if (accountState.Nonce != nonce) - { - differences.Add($"{acountAddress} nonce exp: {accountState.Nonce}, actual: {nonce}"); - } + private List RunAssertions(BlockchainTest test, Block headBlock, IWorldState stateProvider) + { + if (test.PostStateRoot is not null) + { + return test.PostStateRoot != stateProvider.StateRoot ? new List { "state root mismatch" } : Enumerable.Empty().ToList(); + } - byte[] code = accountExists ? stateProvider.GetCode(acountAddress) : new byte[0]; - if (!Bytes.AreEqual(accountState.Code, code)) - { - differences.Add($"{acountAddress} code exp: {accountState.Code?.Length}, actual: {code?.Length}"); - } + TestBlockHeaderJson testHeaderJson = (test.Blocks? + .Where(b => b.BlockHeader is not null) + .SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader) ?? test.GenesisBlockHeader; + BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson); + List differences = new(); - if (differences.Count != differencesBefore) - { - _logger.Info($"ACCOUNT STATE ({acountAddress}) HAS DIFFERENCES"); - } + IEnumerable> deletedAccounts = test.Pre? + .Where(pre => !(test.PostState?.ContainsKey(pre.Key) ?? false)) ?? Array.Empty>(); - differencesBefore = differences.Count; + foreach (KeyValuePair deletedAccount in deletedAccounts) + { + if (stateProvider.AccountExists(deletedAccount.Key)) + { + differences.Add($"Pre state account {deletedAccount.Key} was not deleted as expected."); + } + } - KeyValuePair[] clearedStorages = new KeyValuePair[0]; - if (test.Pre.ContainsKey(acountAddress)) - { - clearedStorages = test.Pre[acountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key)).ToArray(); - } + foreach ((Address acountAddress, AccountState accountState) in test.PostState) + { + int differencesBefore = differences.Count; - foreach (KeyValuePair clearedStorage in clearedStorages) - { - ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); - if (!value.IsZero()) - { - differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}"); - } - } + if (differences.Count > 8) + { + Console.WriteLine("More than 8 differences..."); + break; + } - foreach (KeyValuePair storageItem in accountState.Storage) - { - ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)); - if (!Bytes.AreEqual(storageItem.Value, value)) - { - differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}"); - } - } + bool accountExists = stateProvider.AccountExists(acountAddress); + UInt256? balance = accountExists ? stateProvider.GetBalance(acountAddress) : (UInt256?)null; + UInt256? nonce = accountExists ? stateProvider.GetNonce(acountAddress) : (UInt256?)null; - if (differences.Count != differencesBefore) - { - _logger.Info($"ACCOUNT STORAGE ({acountAddress}) HAS DIFFERENCES"); - } + if (accountState.Balance != balance) + { + differences.Add($"{acountAddress} balance exp: {accountState.Balance}, actual: {balance}, diff: {(balance > accountState.Balance ? balance - accountState.Balance : accountState.Balance - balance)}"); } - BigInteger gasUsed = headBlock.Header.GasUsed; - if ((testHeader?.GasUsed ?? 0) != gasUsed) + if (accountState.Nonce != nonce) { - differences.Add($"GAS USED exp: {testHeader?.GasUsed ?? 0}, actual: {gasUsed}"); + differences.Add($"{acountAddress} nonce exp: {accountState.Nonce}, actual: {nonce}"); } - if (headBlock.Transactions.Any() && testHeader.Bloom.ToString() != headBlock.Header.Bloom.ToString()) + byte[] code = accountExists ? stateProvider.GetCode(acountAddress) : new byte[0]; + if (!Bytes.AreEqual(accountState.Code, code)) { - differences.Add($"BLOOM exp: {testHeader.Bloom}, actual: {headBlock.Header.Bloom}"); + differences.Add($"{acountAddress} code exp: {accountState.Code?.Length}, actual: {code?.Length}"); } - if (testHeader.StateRoot != stateProvider.StateRoot) + if (differences.Count != differencesBefore) { - differences.Add($"STATE ROOT exp: {testHeader.StateRoot}, actual: {stateProvider.StateRoot}"); + _logger.Info($"ACCOUNT STATE ({acountAddress}) HAS DIFFERENCES"); } - if (testHeader.TxRoot != headBlock.Header.TxRoot) + differencesBefore = differences.Count; + + KeyValuePair[] clearedStorages = new KeyValuePair[0]; + if (test.Pre.ContainsKey(acountAddress)) { - differences.Add($"TRANSACTIONS ROOT exp: {testHeader.TxRoot}, actual: {headBlock.Header.TxRoot}"); + clearedStorages = test.Pre[acountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key)).ToArray(); } - if (testHeader.ReceiptsRoot != headBlock.Header.ReceiptsRoot) + foreach (KeyValuePair clearedStorage in clearedStorages) { - differences.Add($"RECEIPT ROOT exp: {testHeader.ReceiptsRoot}, actual: {headBlock.Header.ReceiptsRoot}"); + ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); + if (!value.IsZero()) + { + differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}"); + } } - if (test.LastBlockHash != headBlock.Hash) + foreach (KeyValuePair storageItem in accountState.Storage) { - differences.Add($"LAST BLOCK HASH exp: {test.LastBlockHash}, actual: {headBlock.Hash}"); + ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)); + if (!Bytes.AreEqual(storageItem.Value, value)) + { + differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}"); + } } - foreach (string difference in differences) + if (differences.Count != differencesBefore) { - _logger.Info(difference); + _logger.Info($"ACCOUNT STORAGE ({acountAddress}) HAS DIFFERENCES"); } + } - return differences; + BigInteger gasUsed = headBlock.Header.GasUsed; + if ((testHeader?.GasUsed ?? 0) != gasUsed) + { + differences.Add($"GAS USED exp: {testHeader?.GasUsed ?? 0}, actual: {gasUsed}"); } + + if (headBlock.Transactions.Any() && testHeader.Bloom.ToString() != headBlock.Header.Bloom.ToString()) + { + differences.Add($"BLOOM exp: {testHeader.Bloom}, actual: {headBlock.Header.Bloom}"); + } + + if (testHeader.StateRoot != stateProvider.StateRoot) + { + differences.Add($"STATE ROOT exp: {testHeader.StateRoot}, actual: {stateProvider.StateRoot}"); + } + + if (testHeader.TxRoot != headBlock.Header.TxRoot) + { + differences.Add($"TRANSACTIONS ROOT exp: {testHeader.TxRoot}, actual: {headBlock.Header.TxRoot}"); + } + + if (testHeader.ReceiptsRoot != headBlock.Header.ReceiptsRoot) + { + differences.Add($"RECEIPT ROOT exp: {testHeader.ReceiptsRoot}, actual: {headBlock.Header.ReceiptsRoot}"); + } + + if (test.LastBlockHash != headBlock.Hash) + { + differences.Add($"LAST BLOCK HASH exp: {test.LastBlockHash}, actual: {headBlock.Hash}"); + } + + foreach (string difference in differences) + { + _logger.Info(difference); + } + + return differences; } } diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs index 99faa058359..120c146c6d3 100644 --- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs @@ -57,8 +57,8 @@ protected EthereumTestResult RunTest(GeneralStateTest test) protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer) { - TestContext.Write($"Running {test.Name} at {DateTime.UtcNow:HH:mm:ss.ffffff}"); - Assert.IsNull(test.LoadFailure, "test data loading failure"); + TestContext.Out.Write($"Running {test.Name} at {DateTime.UtcNow:HH:mm:ss.ffffff}"); + Assert.That(test.LoadFailure, Is.Null, "test data loading failure"); IDb stateDb = new MemDb(); IDb codeDb = new MemDb(); diff --git a/src/Nethermind/Ethereum.Test.Base/TestLoader.cs b/src/Nethermind/Ethereum.Test.Base/TestLoader.cs index 4a910f73123..ecc5202c148 100644 --- a/src/Nethermind/Ethereum.Test.Base/TestLoader.cs +++ b/src/Nethermind/Ethereum.Test.Base/TestLoader.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Numerics; @@ -13,73 +12,72 @@ using NUnit.Framework; -namespace Ethereum.Test.Base +namespace Ethereum.Test.Base; + +public static class TestLoader { - public static class TestLoader + public static object PrepareInput(object input) { - public static object PrepareInput(object input) + if (input is string s && s.StartsWith("#")) { - if (input is string s && s.StartsWith("#")) - { - BigInteger bigInteger = BigInteger.Parse(s.Substring(1)); - input = bigInteger; - } + BigInteger bigInteger = BigInteger.Parse(s.Substring(1)); + input = bigInteger; + } - JsonElement token = (JsonElement)input; + JsonElement token = (JsonElement)input; - if (token.ValueKind == JsonValueKind.Array) + if (token.ValueKind == JsonValueKind.Array) + { + object[] array = new object[token.GetArrayLength()]; + for (int i = 0; i < array.Length; i++) { - object[] array = new object[token.GetArrayLength()]; - for (int i = 0; i < array.Length; i++) - { - array[i] = PrepareInput(token[i]); - } - - input = array; + array[i] = PrepareInput(token[i]); } - if (token.ValueKind == JsonValueKind.String) - { - return token.GetString()!; - } + input = array; + } - if (token.ValueKind == JsonValueKind.Number) - { - return token.GetInt64(); - } + if (token.ValueKind == JsonValueKind.String) + { + return token.GetString()!; + } - return input; + if (token.ValueKind == JsonValueKind.Number) + { + return token.GetInt64(); } - public static IEnumerable LoadFromFile( - string testFileName, - Func> testExtractor) + return input; + } + + public static IEnumerable LoadFromFile( + string testFileName, + Func> testExtractor) + { + Assembly assembly = typeof(TTest).Assembly; + string[] resourceNames = assembly.GetManifestResourceNames(); + string resourceName = resourceNames.SingleOrDefault(r => r.Contains(testFileName)); + if (resourceName is null) { - Assembly assembly = typeof(TTest).Assembly; - string[] resourceNames = assembly.GetManifestResourceNames(); - string resourceName = resourceNames.SingleOrDefault(r => r.Contains(testFileName)); - if (resourceName is null) - { - throw new ArgumentException($"Cannot find test resource: {testFileName}"); - } + throw new ArgumentException($"Cannot find test resource: {testFileName}"); + } - var jsonOptions = new JsonSerializerOptions() - { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, - NumberHandling = JsonNumberHandling.AllowReadingFromString - }; - using (Stream stream = assembly.GetManifestResourceStream(resourceName)) + var jsonOptions = new JsonSerializerOptions() + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, + NumberHandling = JsonNumberHandling.AllowReadingFromString + }; + using (Stream stream = assembly.GetManifestResourceStream(resourceName)) + { + Assert.That(stream, Is.Not.Null); + using (StreamReader reader = new(stream)) { - Assert.NotNull(stream); - using (StreamReader reader = new(stream)) - { - string testJson = reader.ReadToEnd(); - TContainer testSpecs = - JsonSerializer.Deserialize(testJson, jsonOptions); - return testExtractor(testSpecs); - } + string testJson = reader.ReadToEnd(); + TContainer testSpecs = + JsonSerializer.Deserialize(testJson, jsonOptions); + return testExtractor(testSpecs); } } } diff --git a/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs b/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs index ec1f5c3b4ce..b292e38393a 100644 --- a/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs +++ b/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using System.Text.Json; - using Nethermind.Consensus.Validators; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -14,252 +13,250 @@ using Nethermind.Core.Specs; using Nethermind.Crypto; using Nethermind.Int256; -using Nethermind.Logging; using Nethermind.Serialization.Rlp; using Nethermind.Specs.Forks; using NUnit.Framework; -namespace Ethereum.Transaction.Test +namespace Ethereum.Transaction.Test; + +public class TransactionTests { - public class TransactionTests + [OneTimeSetUp] + public void SetUp() { - [OneTimeSetUp] - public void SetUp() - { - Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); - } + Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); + } - private static IEnumerable LoadTests(string testSet) + private static IEnumerable LoadTests(string testSet) + { + Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); + IEnumerable testDirs = Directory.EnumerateDirectories(".", "tt" + testSet); + Dictionary> testJsons = + new(); + foreach (string testDir in testDirs) { - Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); - IEnumerable testDirs = Directory.EnumerateDirectories(".", "tt" + testSet); - Dictionary> testJsons = - new(); - foreach (string testDir in testDirs) + testJsons[testDir] = new Dictionary(); + IEnumerable testFiles = Directory.EnumerateFiles(testDir).ToList(); + foreach (string testFile in testFiles) { - testJsons[testDir] = new Dictionary(); - IEnumerable testFiles = Directory.EnumerateFiles(testDir).ToList(); - foreach (string testFile in testFiles) + string json = File.ReadAllText(testFile); + Dictionary testsInFile = JsonSerializer.Deserialize>(json); + foreach (KeyValuePair namedTest in testsInFile) { - string json = File.ReadAllText(testFile); - Dictionary testsInFile = JsonSerializer.Deserialize>(json); - foreach (KeyValuePair namedTest in testsInFile) - { - testJsons[testDir].Add(namedTest.Key, namedTest.Value); - } + testJsons[testDir].Add(namedTest.Key, namedTest.Value); } } + } - List tests = new(); - foreach (KeyValuePair> byDir in testJsons) + List tests = new(); + foreach (KeyValuePair> byDir in testJsons) + { + foreach (KeyValuePair byName in byDir.Value) { - foreach (KeyValuePair byName in byDir.Value) + TransactionJson transactionJson = byName.Value.Transaction; + TransactionTest test; + if (transactionJson is not null) { - TransactionJson transactionJson = byName.Value.Transaction; - TransactionTest test; - if (transactionJson is not null) - { - test = new ValidTransactionTest(byDir.Key, byName.Key, byName.Value.Rlp); - ValidTransactionTest validTest = (ValidTransactionTest)test; - validTest.BlockNumber = Bytes.FromHexString(byName.Value.BlockNumber).ToUInt256(); - validTest.Data = Bytes.FromHexString(transactionJson.Data); - validTest.GasLimit = Bytes.FromHexString(transactionJson.GasLimit).ToUInt256(); - validTest.GasPrice = Bytes.FromHexString(transactionJson.GasPrice).ToUInt256(); - validTest.Nonce = Bytes.FromHexString(transactionJson.Nonce).ToUInt256(); - validTest.R = Bytes.FromHexString(transactionJson.R).ToUInt256(); - validTest.S = Bytes.FromHexString(transactionJson.S).ToUInt256(); - validTest.V = Bytes.FromHexString(transactionJson.V)[0]; - validTest.Sender = new Address(byName.Value.Sender); - validTest.Value = Bytes.FromHexString(transactionJson.Value).ToUInt256(); - validTest.To = string.IsNullOrEmpty(transactionJson.To) ? null : new Address(transactionJson.To); - } - else - { - test = new TransactionTest(byDir.Key, byName.Key, byName.Value.Rlp); - } - - tests.Add(test); + test = new ValidTransactionTest(byDir.Key, byName.Key, byName.Value.Rlp); + ValidTransactionTest validTest = (ValidTransactionTest)test; + validTest.BlockNumber = Bytes.FromHexString(byName.Value.BlockNumber).ToUInt256(); + validTest.Data = Bytes.FromHexString(transactionJson.Data); + validTest.GasLimit = Bytes.FromHexString(transactionJson.GasLimit).ToUInt256(); + validTest.GasPrice = Bytes.FromHexString(transactionJson.GasPrice).ToUInt256(); + validTest.Nonce = Bytes.FromHexString(transactionJson.Nonce).ToUInt256(); + validTest.R = Bytes.FromHexString(transactionJson.R).ToUInt256(); + validTest.S = Bytes.FromHexString(transactionJson.S).ToUInt256(); + validTest.V = Bytes.FromHexString(transactionJson.V)[0]; + validTest.Sender = new Address(byName.Value.Sender); + validTest.Value = Bytes.FromHexString(transactionJson.Value).ToUInt256(); + validTest.To = string.IsNullOrEmpty(transactionJson.To) ? null : new Address(transactionJson.To); + } + else + { + test = new TransactionTest(byDir.Key, byName.Key, byName.Value.Rlp); } - } - return tests; + tests.Add(test); + } } - [TestCaseSource(nameof(LoadTests), new object[] { "Address" })] - public void Test_Address(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + return tests; + } - [TestCaseSource(nameof(LoadTests), new object[] { "Data" })] - public void Test_Data(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "Address" })] + public void Test_Address(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - [TestCaseSource(nameof(LoadTests), new object[] { "EIP2028" })] - public void Test_EIP2028(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "Data" })] + public void Test_Data(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - [TestCaseSource(nameof(LoadTests), new object[] { "GasLimit" })] - public void Test_GasLimit(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "EIP2028" })] + public void Test_EIP2028(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - [TestCaseSource(nameof(LoadTests), new object[] { "GasPrice" })] - public void Test_GasPrice(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "GasLimit" })] + public void Test_GasLimit(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - [TestCaseSource(nameof(LoadTests), new object[] { "Nonce" })] - public void Test_Nonce(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "GasPrice" })] + public void Test_GasPrice(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - [TestCaseSource(nameof(LoadTests), new object[] { "RSValue" })] - public void Test_RSValue(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "Nonce" })] + public void Test_Nonce(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - [TestCaseSource(nameof(LoadTests), new object[] { "Signature" })] - public void Test_Signature(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "RSValue" })] + public void Test_RSValue(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - [TestCaseSource(nameof(LoadTests), new object[] { "Value" })] - public void Test_Value(TransactionTest test) - { - RunTest(test, Frontier.Instance); - } + [TestCaseSource(nameof(LoadTests), new object[] { "Signature" })] + public void Test_Signature(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } + + [TestCaseSource(nameof(LoadTests), new object[] { "Value" })] + public void Test_Value(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } - // ToDo: this tests are not starting because of TargetInvocationException - // [TestCaseSource(nameof(LoadTests), new object[] { "VValue" })] - // public void Test_VValue(TransactionTest test) - // { - // RunTest(test, Frontier.Instance); - // } + // ToDo: this tests are not starting because of TargetInvocationException + // [TestCaseSource(nameof(LoadTests), new object[] { "VValue" })] + // public void Test_VValue(TransactionTest test) + // { + // RunTest(test, Frontier.Instance); + // } - [TestCaseSource(nameof(LoadTests), new object[] { "WrongRLP" })] - public void Test_WrongRLP(TransactionTest test) + [TestCaseSource(nameof(LoadTests), new object[] { "WrongRLP" })] + public void Test_WrongRLP(TransactionTest test) + { + RunTest(test, Frontier.Instance); + } + + private void RunTest(TransactionTest test, IReleaseSpec spec) + { + //TestContext.CurrentContext.Test.Properties.Set("Category", test.Network); // no longer public + + ValidTransactionTest validTest = test as ValidTransactionTest; + Nethermind.Core.Transaction transaction; + try { - RunTest(test, Frontier.Instance); + Rlp rlp = new(Bytes.FromHexString(test.Rlp)); + transaction = Rlp.Decode(rlp); } - - private void RunTest(TransactionTest test, IReleaseSpec spec) + catch (Exception) { - //TestContext.CurrentContext.Test.Properties.Set("Category", test.Network); // no longer public - - ValidTransactionTest validTest = test as ValidTransactionTest; - Nethermind.Core.Transaction transaction; - try + if (validTest is null) { - Rlp rlp = new(Bytes.FromHexString(test.Rlp)); - transaction = Rlp.Decode(rlp); + return; } - catch (Exception) - { - if (validTest is null) - { - return; - } - throw; - } + throw; + } - bool useChainId = transaction.Signature.V > 28UL; + bool useChainId = transaction.Signature.V > 28UL; - TxValidator validator = new(useChainId ? BlockchainIds.Mainnet : 0UL); + TxValidator validator = new(useChainId ? BlockchainIds.Mainnet : 0UL); - if (validTest is not null) - { - Assert.That(transaction.Value, Is.EqualTo(validTest.Value), "value"); - Assert.That(transaction.Data.AsArray(), Is.EqualTo(validTest.Data), "data"); - Assert.That(transaction.GasLimit, Is.EqualTo(validTest.GasLimit.ToInt64(null)), "gasLimit"); - Assert.That(transaction.GasPrice, Is.EqualTo(validTest.GasPrice), "gasPrice"); - Assert.That(transaction.Nonce, Is.EqualTo(validTest.Nonce), "nonce"); - Assert.That(transaction.To, Is.EqualTo(validTest.To), "to"); - Assert.True(validator.IsWellFormed(transaction, spec)); - - Signature expectedSignature = new(validTest.R, validTest.S, validTest.V); - Assert.That(transaction.Signature, Is.EqualTo(expectedSignature), "signature"); - - IEthereumEcdsa ecdsa = new EthereumEcdsa(useChainId ? BlockchainIds.Mainnet : 0UL); - bool verified = ecdsa.Verify( - validTest.Sender, - transaction); - Assert.True(verified); - } - else - { - Assert.False(validator.IsWellFormed(transaction, spec)); - } + if (validTest is not null) + { + Assert.That(transaction.Value, Is.EqualTo(validTest.Value), "value"); + Assert.That(transaction.Data.AsArray(), Is.EqualTo(validTest.Data), "data"); + Assert.That(transaction.GasLimit, Is.EqualTo(validTest.GasLimit.ToInt64(null)), "gasLimit"); + Assert.That(transaction.GasPrice, Is.EqualTo(validTest.GasPrice), "gasPrice"); + Assert.That(transaction.Nonce, Is.EqualTo(validTest.Nonce), "nonce"); + Assert.That(transaction.To, Is.EqualTo(validTest.To), "to"); + Assert.That(validator.IsWellFormed(transaction, spec), Is.True); + + Signature expectedSignature = new(validTest.R, validTest.S, validTest.V); + Assert.That(transaction.Signature, Is.EqualTo(expectedSignature), "signature"); + + IEthereumEcdsa ecdsa = new EthereumEcdsa(useChainId ? BlockchainIds.Mainnet : 0UL); + bool verified = ecdsa.Verify( + validTest.Sender, + transaction); + Assert.That(verified, Is.True); } - - public class TransactionTest + else { - public TransactionTest(string network, string name, string rlp) - { - Network = network; - Name = name; - Rlp = rlp; - } - - public string Network { get; set; } - public string Name { get; set; } - public string Rlp { get; set; } - - public override string ToString() - { - return string.Concat(Network, "->", Name); - } + Assert.That(validator.IsWellFormed(transaction, spec), Is.False); } + } - public class TransactionJson + public class TransactionTest + { + public TransactionTest(string network, string name, string rlp) { - public string Nonce { get; set; } - public string GasPrice { get; set; } - public string GasLimit { get; set; } - public string To { get; set; } - public string Value { get; set; } - public string V { get; set; } - public string R { get; set; } - public string S { get; set; } - public string Data { get; set; } + Network = network; + Name = name; + Rlp = rlp; } - public class TransactionTestJson + public string Network { get; set; } + public string Name { get; set; } + public string Rlp { get; set; } + + public override string ToString() { - public string Rlp { get; set; } - public string Sender { get; set; } - public string BlockNumber { get; set; } - public TransactionJson Transaction { get; set; } + return string.Concat(Network, "->", Name); } + } - public class ValidTransactionTest : TransactionTest - { - public ValidTransactionTest(string network, string name, string rlp) - : base(network, name, rlp) - { - } + public class TransactionJson + { + public string Nonce { get; set; } + public string GasPrice { get; set; } + public string GasLimit { get; set; } + public string To { get; set; } + public string Value { get; set; } + public string V { get; set; } + public string R { get; set; } + public string S { get; set; } + public string Data { get; set; } + } - public Address Sender { get; set; } - public UInt256 BlockNumber { get; set; } - public UInt256 Nonce { get; set; } - public UInt256 GasPrice { get; set; } - public UInt256 GasLimit { get; set; } - public Address To { get; set; } - public UInt256 Value { get; set; } - public byte V { get; set; } - public UInt256 R { get; set; } - public UInt256 S { get; set; } - public byte[] Data { get; set; } + public class TransactionTestJson + { + public string Rlp { get; set; } + public string Sender { get; set; } + public string BlockNumber { get; set; } + public TransactionJson Transaction { get; set; } + } + + public class ValidTransactionTest : TransactionTest + { + public ValidTransactionTest(string network, string name, string rlp) + : base(network, name, rlp) + { } + + public Address Sender { get; set; } + public UInt256 BlockNumber { get; set; } + public UInt256 Nonce { get; set; } + public UInt256 GasPrice { get; set; } + public UInt256 GasLimit { get; set; } + public Address To { get; set; } + public UInt256 Value { get; set; } + public byte V { get; set; } + public UInt256 R { get; set; } + public UInt256 S { get; set; } + public byte[] Data { get; set; } } } diff --git a/src/Nethermind/Ethereum.Trie.Test/TrieTests.cs b/src/Nethermind/Ethereum.Trie.Test/TrieTests.cs index 113a3c6f88e..ab7f94d6220 100644 --- a/src/Nethermind/Ethereum.Trie.Test/TrieTests.cs +++ b/src/Nethermind/Ethereum.Trie.Test/TrieTests.cs @@ -134,7 +134,7 @@ private void RunTest(TrieTest test, bool secure) string permutationDescription = string.Join(Environment.NewLine, test.Input.Select(p => $"{p.Key} -> {p.Value}")); - TestContext.WriteLine(Surrounded(permutationDescription)); + TestContext.Out.WriteLine(Surrounded(permutationDescription)); PatriciaTree patriciaTree = new PatriciaTree(_db, Keccak.EmptyTreeHash, false, true, NullLogManager.Instance); foreach (KeyValuePair keyValuePair in test.Input) @@ -150,8 +150,8 @@ private void RunTest(TrieTest test, bool secure) ? Bytes.FromHexString(valueString) : Encoding.ASCII.GetBytes(valueString); - TestContext.WriteLine(); - TestContext.WriteLine($"Setting {keyString} -> {valueString}"); + TestContext.Out.WriteLine(); + TestContext.Out.WriteLine($"Setting {keyString} -> {valueString}"); patriciaTree.Set(key.ToPackedByteArray(), value); } diff --git a/src/Nethermind/Ethereum.VM.Test/AbiTests.cs b/src/Nethermind/Ethereum.VM.Test/AbiTests.cs index c9294d276a2..284e159fe91 100644 --- a/src/Nethermind/Ethereum.VM.Test/AbiTests.cs +++ b/src/Nethermind/Ethereum.VM.Test/AbiTests.cs @@ -3,75 +3,73 @@ using System.Collections.Generic; using System.Linq; - using Ethereum.Test.Base; using Nethermind.Abi; using Nethermind.Core.Extensions; using NUnit.Framework; -namespace Ethereum.VM.Test +namespace Ethereum.VM.Test; + +internal class AbiTests { - internal class AbiTests + private static readonly Dictionary TypesByName = new Dictionary { - private static readonly Dictionary TypesByName = new Dictionary - { - {"uint256", AbiType.UInt256}, - {"uint32[]", new AbiArray(new AbiUInt(32))}, - {"bytes10", new AbiBytes(10)}, - {"bytes", AbiType.DynamicBytes}, - {"address", AbiType.Address} - }; + {"uint256", AbiType.UInt256}, + {"uint32[]", new AbiArray(new AbiUInt(32))}, + {"bytes10", new AbiBytes(10)}, + {"bytes", AbiType.DynamicBytes}, + {"address", AbiType.Address} + }; - private static AbiType ToAbiType(string typeName) - { - return TypesByName[typeName]; - } + private static AbiType ToAbiType(string typeName) + { + return TypesByName[typeName]; + } - private static AbiTest Convert(string name, AbiTestJson testJson) - { - AbiTest test = new AbiTest(); - test.Name = name; - test.Result = Bytes.FromHexString(testJson.Result); - test.Types = testJson.Types.Select(ToAbiType).ToArray(); - test.Args = testJson.Args.Select(TestLoader.PrepareInput).ToArray(); - return test; - } + private static AbiTest Convert(string name, AbiTestJson testJson) + { + AbiTest test = new AbiTest(); + test.Name = name; + test.Result = Bytes.FromHexString(testJson.Result); + test.Types = testJson.Types.Select(ToAbiType).ToArray(); + test.Args = testJson.Args.Select(TestLoader.PrepareInput).ToArray(); + return test; + } - private static IEnumerable LoadBasicAbiTests() - { - IEnumerable tests = TestLoader.LoadFromFile, AbiTest>( - "basic_abi_tests.json", - allTests => allTests.Select(namedTest => Convert(namedTest.Key, namedTest.Value))); - return tests; - } + private static IEnumerable LoadBasicAbiTests() + { + IEnumerable tests = TestLoader.LoadFromFile, AbiTest>( + "basic_abi_tests.json", + allTests => allTests.Select(namedTest => Convert(namedTest.Key, namedTest.Value))); + return tests; + } - [TestCaseSource(nameof(LoadBasicAbiTests))] - public void Test(AbiTest abiTest) - { - AbiEncoder encoder = new AbiEncoder(); - AbiSignature signature = new AbiSignature(abiTest.Name, abiTest.Types); - byte[] encoded = encoder.Encode(AbiEncodingStyle.IncludeSignature, signature, abiTest.Args).Slice(4); - Assert.True(Bytes.AreEqual(abiTest.Result, encoded)); - } + [TestCaseSource(nameof(LoadBasicAbiTests))] + public void Test(AbiTest abiTest) + { + AbiEncoder encoder = new AbiEncoder(); + AbiSignature signature = new AbiSignature(abiTest.Name, abiTest.Types); + byte[] encoded = encoder.Encode(AbiEncodingStyle.IncludeSignature, signature, abiTest.Args).Slice(4); + Assert.That(Bytes.AreEqual(abiTest.Result, encoded), Is.True); + } - public class AbiTestJson - { - public object[] Args { get; set; } - public string Result { get; set; } - public string[] Types { get; set; } - } + public class AbiTestJson + { + public object[] Args { get; set; } + public string Result { get; set; } + public string[] Types { get; set; } + } - public class AbiTest - { - public string Name { get; set; } - public object[] Args { get; set; } - public byte[] Result { get; set; } - public AbiType[] Types { get; set; } + public class AbiTest + { + public string Name { get; set; } + public object[] Args { get; set; } + public byte[] Result { get; set; } + public AbiType[] Types { get; set; } - public override string ToString() - { - return Name; - } + public override string ToString() + { + return Name; } } } diff --git a/src/Nethermind/Ethereum.VM.Test/ArithmeticTests.cs b/src/Nethermind/Ethereum.VM.Test/ArithmeticTests.cs index 222efbcfa08..b6aeef88107 100644 --- a/src/Nethermind/Ethereum.VM.Test/ArithmeticTests.cs +++ b/src/Nethermind/Ethereum.VM.Test/ArithmeticTests.cs @@ -14,7 +14,7 @@ public class ArithmeticTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.VM.Test/BitwiseLogicOperationTests.cs b/src/Nethermind/Ethereum.VM.Test/BitwiseLogicOperationTests.cs index 438de123e02..32ac5b5532f 100644 --- a/src/Nethermind/Ethereum.VM.Test/BitwiseLogicOperationTests.cs +++ b/src/Nethermind/Ethereum.VM.Test/BitwiseLogicOperationTests.cs @@ -14,7 +14,7 @@ public class BitwiseLogicOperationTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.VM.Test/IOAndFlowOperationsTests.cs b/src/Nethermind/Ethereum.VM.Test/IOAndFlowOperationsTests.cs index 5cf7f3234fc..4049e40b9f2 100644 --- a/src/Nethermind/Ethereum.VM.Test/IOAndFlowOperationsTests.cs +++ b/src/Nethermind/Ethereum.VM.Test/IOAndFlowOperationsTests.cs @@ -15,7 +15,7 @@ public class IOAndFlowOperationsTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.VM.Test/LogTests.cs b/src/Nethermind/Ethereum.VM.Test/LogTests.cs index 79dc0cd218d..abfc7ea9eee 100644 --- a/src/Nethermind/Ethereum.VM.Test/LogTests.cs +++ b/src/Nethermind/Ethereum.VM.Test/LogTests.cs @@ -14,7 +14,7 @@ public class LogTests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.VM.Test/PerformanceTests.cs b/src/Nethermind/Ethereum.VM.Test/PerformanceTests.cs index 9c94dc066ab..f3d9ae83d5f 100644 --- a/src/Nethermind/Ethereum.VM.Test/PerformanceTests.cs +++ b/src/Nethermind/Ethereum.VM.Test/PerformanceTests.cs @@ -16,7 +16,7 @@ public class PerformanceTests : GeneralStateTestBase [Retry(3)] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Ethereum.VM.Test/Tests.cs b/src/Nethermind/Ethereum.VM.Test/Tests.cs index 32901a87e43..077dc9c3401 100644 --- a/src/Nethermind/Ethereum.VM.Test/Tests.cs +++ b/src/Nethermind/Ethereum.VM.Test/Tests.cs @@ -15,7 +15,7 @@ public class Tests : GeneralStateTestBase [TestCaseSource(nameof(LoadTests))] public void Test(GeneralStateTest test) { - Assert.True(RunTest(test).Pass); + Assert.That(RunTest(test).Pass, Is.True); } public static IEnumerable LoadTests() diff --git a/src/Nethermind/Nethermind.Abi.Test/AbiTests.cs b/src/Nethermind/Nethermind.Abi.Test/AbiTests.cs index ffe63f77382..45999c2344c 100644 --- a/src/Nethermind/Nethermind.Abi.Test/AbiTests.cs +++ b/src/Nethermind/Nethermind.Abi.Test/AbiTests.cs @@ -16,7 +16,6 @@ namespace Nethermind.Abi.Test; -[TestFixture] public class AbiTests { private readonly AbiEncoder _abiEncoder = AbiEncoder.Instance; @@ -132,7 +131,7 @@ public void Test_bytes(AbiEncodingStyle encodingStyle) AbiSignature signature = new AbiSignature("abc", type); byte[] encoded = _abiEncoder.Encode(encodingStyle, signature, data); object[] arguments = _abiEncoder.Decode(encodingStyle, signature, encoded); - Assert.True(Bytes.AreEqual((byte[])arguments[0], data)); + Assert.That(Bytes.AreEqual((byte[])arguments[0], data), Is.True); } [TestCase(AbiEncodingStyle.IncludeSignature)] @@ -158,7 +157,7 @@ public void Test_dynamic_bytes(AbiEncodingStyle encodingStyle) AbiSignature signature = new AbiSignature("abc", type); byte[] encoded = _abiEncoder.Encode(encodingStyle, signature, data); object[] arguments = _abiEncoder.Decode(encodingStyle, signature, encoded); - Assert.True(Bytes.AreEqual((byte[])arguments[0], data)); + Assert.That(Bytes.AreEqual((byte[])arguments[0], data), Is.True); } [TestCase(AbiEncodingStyle.IncludeSignature)] @@ -213,7 +212,7 @@ public void Test_single_function(AbiEncodingStyle encodingStyle) AbiSignature signature = new AbiSignature("abc", type); byte[] encoded = _abiEncoder.Encode(encodingStyle, signature, data); object[] arguments = _abiEncoder.Decode(encodingStyle, signature, encoded); - Assert.True(Bytes.AreEqual((byte[])arguments[0], data)); + Assert.That(Bytes.AreEqual((byte[])arguments[0], data), Is.True); } [TestCase(AbiEncodingStyle.IncludeSignature)] diff --git a/src/Nethermind/Nethermind.Api.Test/PluginLoaderTests.cs b/src/Nethermind/Nethermind.Api.Test/PluginLoaderTests.cs index d95cc1988b4..9671c959d0f 100644 --- a/src/Nethermind/Nethermind.Api.Test/PluginLoaderTests.cs +++ b/src/Nethermind/Nethermind.Api.Test/PluginLoaderTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO.Abstractions; -using System.Linq; using Nethermind.Api.Extensions; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.Clique; @@ -37,7 +36,7 @@ public void full_lexicographical_order() typeof(HivePlugin), typeof(TestPlugin) }; - CollectionAssert.AreEqual(expected, loader.PluginTypes.ToList()); + Assert.That(expected, Is.EqualTo(loader.PluginTypes).AsCollection); } [Test] @@ -60,7 +59,7 @@ public void full_order() typeof(HivePlugin), typeof(TestPlugin) }; - CollectionAssert.AreEqual(expected, loader.PluginTypes.ToList()); + Assert.That(expected, Is.EqualTo(loader.PluginTypes).AsCollection); } [Test] @@ -83,7 +82,7 @@ public void partial_lexicographical_order() typeof(HivePlugin), typeof(TestPlugin) }; - CollectionAssert.AreEqual(expected, loader.PluginTypes.ToList()); + Assert.That(expected, Is.EqualTo(loader.PluginTypes).AsCollection); } [Test] @@ -106,6 +105,6 @@ public void default_config() typeof(HealthChecksPlugin), typeof(HivePlugin) }; - CollectionAssert.AreEqual(expected, loader.PluginTypes.ToList()); + Assert.That(expected, Is.EqualTo(loader.PluginTypes).AsCollection); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockFinderExtensionsTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockFinderExtensionsTests.cs index 409e4d9f4dc..7665e94c284 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockFinderExtensionsTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockFinderExtensionsTests.cs @@ -9,25 +9,23 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +public class BlockFinderExtensionsTests { - [TestFixture] - public class BlockFinderExtensionsTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_upgrade_maybe_parent() { - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_upgrade_maybe_parent() - { - BlockHeader parent = Build.A.BlockHeader.TestObject; - BlockHeader parentWithTotalDiff = Build.A.BlockHeader.WithTotalDifficulty(1).TestObject; - BlockHeader child = Build.A.BlockHeader.WithParent(parent).TestObject; - parent.TotalDifficulty.Should().BeNull(); // just to avoid the testing rig change without this test being updated + BlockHeader parent = Build.A.BlockHeader.TestObject; + BlockHeader parentWithTotalDiff = Build.A.BlockHeader.WithTotalDifficulty(1).TestObject; + BlockHeader child = Build.A.BlockHeader.WithParent(parent).TestObject; + parent.TotalDifficulty.Should().BeNull(); // just to avoid the testing rig change without this test being updated - IBlockFinder blockFinder = Substitute.For(); - blockFinder.FindHeader(child.ParentHash!, BlockTreeLookupOptions.TotalDifficultyNotNeeded, blockNumber: child.Number - 1).Returns(parent); - blockFinder.FindHeader(child.ParentHash!, BlockTreeLookupOptions.None, blockNumber: child.Number - 1).Returns(parentWithTotalDiff); + IBlockFinder blockFinder = Substitute.For(); + blockFinder.FindHeader(child.ParentHash!, BlockTreeLookupOptions.TotalDifficultyNotNeeded, blockNumber: child.Number - 1).Returns(parent); + blockFinder.FindHeader(child.ParentHash!, BlockTreeLookupOptions.None, blockNumber: child.Number - 1).Returns(parentWithTotalDiff); - blockFinder.FindParentHeader(child, BlockTreeLookupOptions.TotalDifficultyNotNeeded).Should().Be(parent); - blockFinder.FindParentHeader(child, BlockTreeLookupOptions.None)!.TotalDifficulty.Should().Be((UInt256?)UInt256.One); - } + blockFinder.FindParentHeader(child, BlockTreeLookupOptions.TotalDifficultyNotNeeded).Should().Be(parent); + blockFinder.FindParentHeader(child, BlockTreeLookupOptions.None)!.TotalDifficulty.Should().Be((UInt256?)UInt256.One); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs index 935b102d61f..60c7c37b66e 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs @@ -30,107 +30,105 @@ using Nethermind.Core.Test.Blockchain; using Nethermind.Evm.TransactionProcessing; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +public class BlockProcessorTests { - [TestFixture] - public class BlockProcessorTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void Prepared_block_contains_author_field() { - [Test, Timeout(Timeout.MaxTestTime)] - public void Prepared_block_contains_author_field() - { - IDb stateDb = new MemDb(); - IDb codeDb = new MemDb(); - TrieStore trieStore = new(stateDb, LimboLogs.Instance); - IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance); - ITransactionProcessor transactionProcessor = Substitute.For(); - BlockProcessor processor = new( - HoleskySpecProvider.Instance, - TestBlockValidator.AlwaysValid, - NoBlockRewards.Instance, - new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), - stateProvider, - NullReceiptStorage.Instance, - transactionProcessor, - new BeaconBlockRootHandler(transactionProcessor), - Substitute.For(), - LimboLogs.Instance); + IDb stateDb = new MemDb(); + IDb codeDb = new MemDb(); + TrieStore trieStore = new(stateDb, LimboLogs.Instance); + IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance); + ITransactionProcessor transactionProcessor = Substitute.For(); + BlockProcessor processor = new( + HoleskySpecProvider.Instance, + TestBlockValidator.AlwaysValid, + NoBlockRewards.Instance, + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), + stateProvider, + NullReceiptStorage.Instance, + transactionProcessor, + new BeaconBlockRootHandler(transactionProcessor), + Substitute.For(), + LimboLogs.Instance); - BlockHeader header = Build.A.BlockHeader.WithAuthor(TestItem.AddressD).TestObject; - Block block = Build.A.Block.WithHeader(header).TestObject; - Block[] processedBlocks = processor.Process( - Keccak.EmptyTreeHash, - new List { block }, - ProcessingOptions.None, - NullBlockTracer.Instance); - Assert.That(processedBlocks.Length, Is.EqualTo(1), "length"); - Assert.That(processedBlocks[0].Author, Is.EqualTo(block.Author), "author"); - } + BlockHeader header = Build.A.BlockHeader.WithAuthor(TestItem.AddressD).TestObject; + Block block = Build.A.Block.WithHeader(header).TestObject; + Block[] processedBlocks = processor.Process( + Keccak.EmptyTreeHash, + new List { block }, + ProcessingOptions.None, + NullBlockTracer.Instance); + Assert.That(processedBlocks.Length, Is.EqualTo(1), "length"); + Assert.That(processedBlocks[0].Author, Is.EqualTo(block.Author), "author"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Recovers_state_on_cancel() - { - IDb stateDb = new MemDb(); - IDb codeDb = new MemDb(); - TrieStore trieStore = new(stateDb, LimboLogs.Instance); - IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance); - ITransactionProcessor transactionProcessor = Substitute.For(); - BlockProcessor processor = new( - HoleskySpecProvider.Instance, - TestBlockValidator.AlwaysValid, - new RewardCalculator(MainnetSpecProvider.Instance), - new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), - stateProvider, - NullReceiptStorage.Instance, - transactionProcessor, - new BeaconBlockRootHandler(transactionProcessor), - Substitute.For(), - LimboLogs.Instance); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Recovers_state_on_cancel() + { + IDb stateDb = new MemDb(); + IDb codeDb = new MemDb(); + TrieStore trieStore = new(stateDb, LimboLogs.Instance); + IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance); + ITransactionProcessor transactionProcessor = Substitute.For(); + BlockProcessor processor = new( + HoleskySpecProvider.Instance, + TestBlockValidator.AlwaysValid, + new RewardCalculator(MainnetSpecProvider.Instance), + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), + stateProvider, + NullReceiptStorage.Instance, + transactionProcessor, + new BeaconBlockRootHandler(transactionProcessor), + Substitute.For(), + LimboLogs.Instance); - BlockHeader header = Build.A.BlockHeader.WithNumber(1).WithAuthor(TestItem.AddressD).TestObject; - Block block = Build.A.Block.WithTransactions(1, MuirGlacier.Instance).WithHeader(header).TestObject; - Assert.Throws(() => processor.Process( - Keccak.EmptyTreeHash, - new List { block }, - ProcessingOptions.None, - AlwaysCancelBlockTracer.Instance)); + BlockHeader header = Build.A.BlockHeader.WithNumber(1).WithAuthor(TestItem.AddressD).TestObject; + Block block = Build.A.Block.WithTransactions(1, MuirGlacier.Instance).WithHeader(header).TestObject; + Assert.Throws(() => processor.Process( + Keccak.EmptyTreeHash, + new List { block }, + ProcessingOptions.None, + AlwaysCancelBlockTracer.Instance)); - Assert.Throws(() => processor.Process( - Keccak.EmptyTreeHash, - new List { block }, - ProcessingOptions.None, - AlwaysCancelBlockTracer.Instance)); - } + Assert.Throws(() => processor.Process( + Keccak.EmptyTreeHash, + new List { block }, + ProcessingOptions.None, + AlwaysCancelBlockTracer.Instance)); + } - [Timeout(Timeout.MaxTestTime)] - [TestCase(20)] - [TestCase(63)] - [TestCase(64)] - [TestCase(65)] - [TestCase(127)] - [TestCase(128)] - [TestCase(129)] - [TestCase(130)] - [TestCase(1000)] - [TestCase(2000)] - public async Task Process_long_running_branch(int blocksAmount) + [MaxTime(Timeout.MaxTestTime)] + [TestCase(20)] + [TestCase(63)] + [TestCase(64)] + [TestCase(65)] + [TestCase(127)] + [TestCase(128)] + [TestCase(129)] + [TestCase(130)] + [TestCase(1000)] + [TestCase(2000)] + public async Task Process_long_running_branch(int blocksAmount) + { + Address address = TestItem.Addresses[0]; + TestSingleReleaseSpecProvider spec = new TestSingleReleaseSpecProvider(ConstantinopleFix.Instance); + TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev) + .Build(spec); + testRpc.TestWallet.UnlockAccount(address, new SecureString()); + await testRpc.AddFunds(address, 1.Ether()); + await testRpc.AddBlock(); + SemaphoreSlim suggestedBlockResetEvent = new SemaphoreSlim(0); + testRpc.BlockTree.NewHeadBlock += (_, _) => { - Address address = TestItem.Addresses[0]; - TestSingleReleaseSpecProvider spec = new TestSingleReleaseSpecProvider(ConstantinopleFix.Instance); - TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev) - .Build(spec); - testRpc.TestWallet.UnlockAccount(address, new SecureString()); - await testRpc.AddFunds(address, 1.Ether()); - await testRpc.AddBlock(); - SemaphoreSlim suggestedBlockResetEvent = new SemaphoreSlim(0); - testRpc.BlockTree.NewHeadBlock += (_, _) => - { - suggestedBlockResetEvent.Release(1); - }; + suggestedBlockResetEvent.Release(1); + }; - int branchLength = blocksAmount + (int)testRpc.BlockTree.BestKnownNumber + 1; - ((BlockTree)testRpc.BlockTree).AddBranch(branchLength, (int)testRpc.BlockTree.BestKnownNumber); - (await suggestedBlockResetEvent.WaitAsync(TestBlockchain.DefaultTimeout * 10)).Should().BeTrue(); - Assert.That((int)testRpc.BlockTree.BestKnownNumber, Is.EqualTo(branchLength - 1)); - } + int branchLength = blocksAmount + (int)testRpc.BlockTree.BestKnownNumber + 1; + ((BlockTree)testRpc.BlockTree).AddBranch(branchLength, (int)testRpc.BlockTree.BestKnownNumber); + (await suggestedBlockResetEvent.WaitAsync(TestBlockchain.DefaultTimeout * 10)).Should().BeTrue(); + Assert.That((int)testRpc.BlockTree.BestKnownNumber, Is.EqualTo(branchLength - 1)); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs index db457642581..bdf990467bd 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs @@ -30,1952 +30,1948 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test -{ - [TestFixture] - public class BlockTreeTests - { - private TestMemDb _blocksInfosDb = null!; - private TestMemDb _headersDb = null!; - private TestMemDb _blocksDb = null!; +namespace Nethermind.Blockchain.Test; - [TearDown] - public void TearDown() - { - _blocksDb?.Dispose(); - _headersDb?.Dispose(); - } +public class BlockTreeTests +{ + private TestMemDb _blocksInfosDb = null!; + private TestMemDb _headersDb = null!; + private TestMemDb _blocksDb = null!; - private BlockTree BuildBlockTree() - { - _blocksDb = new TestMemDb(); - _headersDb = new TestMemDb(); - _blocksInfosDb = new TestMemDb(); - BlockTreeBuilder builder = Build.A.BlockTree() - .WithBlocksDb(_blocksDb) - .WithHeadersDb(_headersDb) - .WithBlockInfoDb(_blocksInfosDb) - .WithoutSettingHead; - return builder.TestObject; - } + [TearDown] + public void TearDown() + { + _blocksDb?.Dispose(); + _headersDb?.Dispose(); + } - private static void AddToMain(BlockTree blockTree, Block block0) - { - blockTree.SuggestBlock(block0); - blockTree.UpdateMainChain(new[] { block0 }, true); - } + private BlockTree BuildBlockTree() + { + _blocksDb = new TestMemDb(); + _headersDb = new TestMemDb(); + _blocksInfosDb = new TestMemDb(); + BlockTreeBuilder builder = Build.A.BlockTree() + .WithBlocksDb(_blocksDb) + .WithHeadersDb(_headersDb) + .WithBlockInfoDb(_blocksInfosDb) + .WithoutSettingHead; + return builder.TestObject; + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Add_genesis_shall_notify() - { - bool hasNotified = false; - BlockTree blockTree = BuildBlockTree(); - blockTree.NewHeadBlock += (_, _) => { hasNotified = true; }; + private static void AddToMain(BlockTree blockTree, Block block0) + { + blockTree.SuggestBlock(block0); + blockTree.UpdateMainChain(new[] { block0 }, true); + } - bool hasNotifiedNewSuggested = false; - blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Add_genesis_shall_notify() + { + bool hasNotified = false; + BlockTree blockTree = BuildBlockTree(); + blockTree.NewHeadBlock += (_, _) => { hasNotified = true; }; - Block block = Build.A.Block.WithNumber(0).TestObject; - AddBlockResult result = blockTree.SuggestBlock(block); - blockTree.UpdateMainChain(block); + bool hasNotifiedNewSuggested = false; + blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; - Assert.True(hasNotified, "notification"); - Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); - Assert.True(hasNotifiedNewSuggested, "NewSuggestedBlock"); - } + Block block = Build.A.Block.WithNumber(0).TestObject; + AddBlockResult result = blockTree.SuggestBlock(block); + blockTree.UpdateMainChain(block); - [Test, Timeout(Timeout.MaxTestTime)] - public void Add_genesis_shall_work_even_with_0_difficulty() - { - bool hasNotified = false; - BlockTree blockTree = BuildBlockTree(); - blockTree.NewBestSuggestedBlock += (_, _) => { hasNotified = true; }; + Assert.That(hasNotified, Is.True, "notification"); + Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); + Assert.That(hasNotifiedNewSuggested, Is.True, "NewSuggestedBlock"); + } - bool hasNotifiedNewSuggested = false; - blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Add_genesis_shall_work_even_with_0_difficulty() + { + bool hasNotified = false; + BlockTree blockTree = BuildBlockTree(); + blockTree.NewBestSuggestedBlock += (_, _) => { hasNotified = true; }; - Block block = Build.A.Block.WithNumber(0).WithDifficulty(0).TestObject; - AddBlockResult result = blockTree.SuggestBlock(block); + bool hasNotifiedNewSuggested = false; + blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; - Assert.True(hasNotified, "notification"); - Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); - Assert.True(hasNotifiedNewSuggested, "NewSuggestedBlock"); - } + Block block = Build.A.Block.WithNumber(0).WithDifficulty(0).TestObject; + AddBlockResult result = blockTree.SuggestBlock(block); - [Test, Timeout(Timeout.MaxTestTime)] - public void Suggesting_genesis_many_times_does_not_cause_any_trouble() - { - BlockTree blockTree = BuildBlockTree(); - Block blockA = Build.A.Block.WithNumber(0).TestObject; - Block blockB = Build.A.Block.WithNumber(0).TestObject; - blockTree.SuggestBlock(blockA).Should().Be(AddBlockResult.Added); - blockTree.SuggestBlock(blockB).Should().Be(AddBlockResult.AlreadyKnown); - } + Assert.That(hasNotified, Is.True, "notification"); + Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); + Assert.That(hasNotifiedNewSuggested, Is.True, "NewSuggestedBlock"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Shall_notify_on_new_head_block_after_genesis() - { - bool hasNotified = false; - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - blockTree.SuggestBlock(block0); - blockTree.NewHeadBlock += (_, _) => { hasNotified = true; }; - - bool hasNotifiedNewSuggested = false; - blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; - - AddBlockResult result = blockTree.SuggestBlock(block1); - blockTree.UpdateMainChain(block1); - - Assert.True(hasNotified, "notification"); - Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); - Assert.True(hasNotifiedNewSuggested, "NewSuggestedBlock"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Suggesting_genesis_many_times_does_not_cause_any_trouble() + { + BlockTree blockTree = BuildBlockTree(); + Block blockA = Build.A.Block.WithNumber(0).TestObject; + Block blockB = Build.A.Block.WithNumber(0).TestObject; + blockTree.SuggestBlock(blockA).Should().Be(AddBlockResult.Added); + blockTree.SuggestBlock(blockB).Should().Be(AddBlockResult.AlreadyKnown); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Shall_notify_new_head_block_once_and_block_added_to_main_multiple_times_when_adding_multiple_blocks_at_once() - { - int newHeadBlockNotifications = 0; - int blockAddedToMainNotifications = 0; - - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(0).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(0).WithParent(block2).TestObject; - - blockTree.SuggestBlock(block0); - blockTree.NewHeadBlock += (_, _) => { newHeadBlockNotifications++; }; - blockTree.BlockAddedToMain += (_, _) => { blockAddedToMainNotifications++; }; - - blockTree.SuggestBlock(block1); - blockTree.SuggestBlock(block2); - blockTree.SuggestBlock(block3); - blockTree.UpdateMainChain(new[] { block1, block2, block3 }, true); - - newHeadBlockNotifications.Should().Be(1, "new head block"); - blockAddedToMainNotifications.Should().Be(3, "block added to main"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Shall_notify_on_new_head_block_after_genesis() + { + bool hasNotified = false; + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + blockTree.SuggestBlock(block0); + blockTree.NewHeadBlock += (_, _) => { hasNotified = true; }; + + bool hasNotifiedNewSuggested = false; + blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; + + AddBlockResult result = blockTree.SuggestBlock(block1); + blockTree.UpdateMainChain(block1); + + Assert.That(hasNotified, Is.True, "notification"); + Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); + Assert.That(hasNotifiedNewSuggested, Is.True, "NewSuggestedBlock"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Shall_notify_on_new_suggested_block_after_genesis() - { - bool hasNotified = false; - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - blockTree.SuggestBlock(block0); - blockTree.NewBestSuggestedBlock += (_, _) => { hasNotified = true; }; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Shall_notify_new_head_block_once_and_block_added_to_main_multiple_times_when_adding_multiple_blocks_at_once() + { + int newHeadBlockNotifications = 0; + int blockAddedToMainNotifications = 0; + + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(0).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(0).WithParent(block2).TestObject; + + blockTree.SuggestBlock(block0); + blockTree.NewHeadBlock += (_, _) => { newHeadBlockNotifications++; }; + blockTree.BlockAddedToMain += (_, _) => { blockAddedToMainNotifications++; }; + + blockTree.SuggestBlock(block1); + blockTree.SuggestBlock(block2); + blockTree.SuggestBlock(block3); + blockTree.UpdateMainChain(new[] { block1, block2, block3 }, true); + + newHeadBlockNotifications.Should().Be(1, "new head block"); + blockAddedToMainNotifications.Should().Be(3, "block added to main"); + } - bool hasNotifiedNewSuggested = false; - blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Shall_notify_on_new_suggested_block_after_genesis() + { + bool hasNotified = false; + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + blockTree.SuggestBlock(block0); + blockTree.NewBestSuggestedBlock += (_, _) => { hasNotified = true; }; - AddBlockResult result = blockTree.SuggestBlock(block1); + bool hasNotifiedNewSuggested = false; + blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; - Assert.True(hasNotified, "notification"); - Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); - Assert.True(hasNotifiedNewSuggested, "NewSuggestedBlock"); - } + AddBlockResult result = blockTree.SuggestBlock(block1); - [Test, Timeout(Timeout.MaxTestTime)] - public void Shall_not_notify_but_add_on_lower_difficulty() - { - bool hasNotifiedBest = false; - bool hasNotifiedHead = false; - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - blockTree.SuggestBlock(block0); - blockTree.SuggestBlock(block1); - blockTree.NewHeadBlock += (_, _) => { hasNotifiedHead = true; }; - blockTree.NewBestSuggestedBlock += (_, _) => { hasNotifiedBest = true; }; - - bool hasNotifiedNewSuggested = false; - blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; - - AddBlockResult result = blockTree.SuggestBlock(block2); - - Assert.False(hasNotifiedBest, "notification best"); - Assert.False(hasNotifiedHead, "notification head"); - Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); - Assert.True(hasNotifiedNewSuggested, "NewSuggestedBlock"); - } + Assert.That(hasNotified, Is.True, "notification"); + Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); + Assert.That(hasNotifiedNewSuggested, Is.True, "NewSuggestedBlock"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Shall_ignore_orphans() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).TestObject; - blockTree.SuggestBlock(block0); - AddBlockResult result = blockTree.SuggestBlock(block2); - Assert.That(result, Is.EqualTo(AddBlockResult.UnknownParent)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Shall_not_notify_but_add_on_lower_difficulty() + { + bool hasNotifiedBest = false; + bool hasNotifiedHead = false; + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + blockTree.NewHeadBlock += (_, _) => { hasNotifiedHead = true; }; + blockTree.NewBestSuggestedBlock += (_, _) => { hasNotifiedBest = true; }; + + bool hasNotifiedNewSuggested = false; + blockTree.NewSuggestedBlock += (_, _) => { hasNotifiedNewSuggested = true; }; + + AddBlockResult result = blockTree.SuggestBlock(block2); + + Assert.That(hasNotifiedBest, Is.False, "notification best"); + Assert.That(hasNotifiedHead, Is.False, "notification head"); + Assert.That(result, Is.EqualTo(AddBlockResult.Added), "result"); + Assert.That(hasNotifiedNewSuggested, Is.True, "NewSuggestedBlock"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Shall_ignore_known() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - blockTree.SuggestBlock(block0); - blockTree.SuggestBlock(block1); - AddBlockResult result = blockTree.SuggestBlock(block1); - Assert.That(result, Is.EqualTo(AddBlockResult.AlreadyKnown)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Shall_ignore_orphans() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).TestObject; + blockTree.SuggestBlock(block0); + AddBlockResult result = blockTree.SuggestBlock(block2); + Assert.That(result, Is.EqualTo(AddBlockResult.UnknownParent)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Cleans_invalid_blocks_before_starting() - { - MemDb blockInfosDb = new MemDb(); - BlockTreeBuilder builder = Build.A.BlockTree() - .WithBlockInfoDb(blockInfosDb) - .WithoutSettingHead; - IBlockStore blockStore = builder.BlockStore; - BlockTree tree = builder.TestObject; - - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - - blockInfosDb.Set(BlockTree.DeletePointerAddressInDb, block1.Hash!.Bytes); - BlockTree tree2 = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Shall_ignore_known() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + AddBlockResult result = blockTree.SuggestBlock(block1); + Assert.That(result, Is.EqualTo(AddBlockResult.AlreadyKnown)); + } - Assert.That(tree2.BestKnownNumber, Is.EqualTo(0L), "best known"); - Assert.That(tree2.Head, Is.EqualTo(null), "head"); - Assert.That(tree2.BestSuggestedHeader!.Number, Is.EqualTo(0L), "suggested"); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cleans_invalid_blocks_before_starting() + { + MemDb blockInfosDb = new MemDb(); + BlockTreeBuilder builder = Build.A.BlockTree() + .WithBlockInfoDb(blockInfosDb) + .WithoutSettingHead; + IBlockStore blockStore = builder.BlockStore; + BlockTree tree = builder.TestObject; + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + + blockInfosDb.Set(BlockTree.DeletePointerAddressInDb, block1.Hash!.Bytes); + BlockTree tree2 = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .TestObject; + + Assert.That(tree2.BestKnownNumber, Is.EqualTo(0L), "best known"); + Assert.That(tree2.Head, Is.EqualTo(null), "head"); + Assert.That(tree2.BestSuggestedHeader!.Number, Is.EqualTo(0L), "suggested"); + Assert.That(blockStore.Get(block2.Number, block2.Hash!), Is.Null, "block 1"); + Assert.That(blockStore.Get(block2.Number, block2.Hash!), Is.Null, "block 2"); + Assert.That(blockStore.Get(block3.Number, block3.Hash!), Is.Null, "block 3"); + Assert.That(blockInfosDb.Get(2), Is.Null, "level 1"); + Assert.That(blockInfosDb.Get(2), Is.Null, "level 2"); + Assert.That(blockInfosDb.Get(3), Is.Null, "level 3"); + } - Assert.IsNull(blockStore.Get(block2.Number, block2.Hash!), "block 1"); - Assert.IsNull(blockStore.Get(block2.Number, block2.Hash!), "block 2"); - Assert.IsNull(blockStore.Get(block3.Number, block3.Hash!), "block 3"); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_cleaning_descendants_of_invalid_does_not_touch_other_branches() + { + MemDb blockInfosDb = new(); + BlockTreeBuilder builder = Build.A.BlockTree() + .WithBlockInfoDb(blockInfosDb) + .WithoutSettingHead; + IBlockStore blockStore = builder.BlockStore; + BlockTree tree = builder.TestObject; + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + + Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; + Block block2B = Build.A.Block.WithNumber(2).WithDifficulty(1).WithParent(block1B).TestObject; + Block block3B = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2B).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + + tree.SuggestBlock(block1B); + tree.SuggestBlock(block2B); + tree.SuggestBlock(block3B); + + blockInfosDb.Set(BlockTree.DeletePointerAddressInDb, block1.Hash!.Bytes); + BlockTree tree2 = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .TestObject; + + Assert.That(tree2.BestKnownNumber, Is.EqualTo(3L), "best known"); + Assert.That(tree2.Head, Is.EqualTo(null), "head"); + Assert.That(tree2.BestSuggestedHeader!.Hash, Is.EqualTo(block3B.Hash), "suggested"); + + blockStore.Get(block1.Number, block1.Hash!).Should().BeNull("block 1"); + blockStore.Get(block2.Number, block2.Hash!).Should().BeNull("block 2"); + blockStore.Get(block3.Number, block3.Hash!).Should().BeNull("block 3"); + + Assert.That(blockInfosDb.Get(1), Is.Not.Null, "level 1"); + Assert.That(blockInfosDb.Get(2), Is.Not.Null, "level 2"); + Assert.That(blockInfosDb.Get(3), Is.Not.Null, "level 3"); + } - Assert.IsNull(blockInfosDb.Get(2), "level 1"); - Assert.IsNull(blockInfosDb.Get(2), "level 2"); - Assert.IsNull(blockInfosDb.Get(3), "level 3"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_load_best_known_up_to_256million() + { + _blocksDb = new TestMemDb(); + _headersDb = new TestMemDb(); + TestMemDb blocksInfosDb = new TestMemDb(); - [Test, Timeout(Timeout.MaxTestTime)] - public void When_cleaning_descendants_of_invalid_does_not_touch_other_branches() + Rlp chainLevel = Rlp.Encode(new ChainLevelInfo(true, new BlockInfo(TestItem.KeccakA, 1))); + blocksInfosDb.ReadFunc = (key) => { - MemDb blockInfosDb = new(); - BlockTreeBuilder builder = Build.A.BlockTree() - .WithBlockInfoDb(blockInfosDb) - .WithoutSettingHead; - IBlockStore blockStore = builder.BlockStore; - BlockTree tree = builder.TestObject; - - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - - Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; - Block block2B = Build.A.Block.WithNumber(2).WithDifficulty(1).WithParent(block1B).TestObject; - Block block3B = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2B).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - - tree.SuggestBlock(block1B); - tree.SuggestBlock(block2B); - tree.SuggestBlock(block3B); - - blockInfosDb.Set(BlockTree.DeletePointerAddressInDb, block1.Hash!.Bytes); - BlockTree tree2 = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .TestObject; - - Assert.That(tree2.BestKnownNumber, Is.EqualTo(3L), "best known"); - Assert.That(tree2.Head, Is.EqualTo(null), "head"); - Assert.That(tree2.BestSuggestedHeader!.Hash, Is.EqualTo(block3B.Hash), "suggested"); + if (!Bytes.AreEqual(key, BlockTree.DeletePointerAddressInDb.Bytes)) + { + return chainLevel.Bytes; + } - blockStore.Get(block1.Number, block1.Hash!).Should().BeNull("block 1"); - blockStore.Get(block2.Number, block2.Hash!).Should().BeNull("block 2"); - blockStore.Get(block3.Number, block3.Hash!).Should().BeNull("block 3"); + return null!; + }; - Assert.NotNull(blockInfosDb.Get(1), "level 1"); - Assert.NotNull(blockInfosDb.Get(2), "level 2"); - Assert.NotNull(blockInfosDb.Get(3), "level 3"); - } + BlockTree blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlocksDb(_blocksDb) + .WithHeadersDb(_headersDb) + .WithBlockInfoDb(blocksInfosDb) + .TestObject; - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_load_best_known_up_to_256million() - { - _blocksDb = new TestMemDb(); - _headersDb = new TestMemDb(); - TestMemDb blocksInfosDb = new TestMemDb(); + Assert.That(blockTree.BestKnownNumber, Is.EqualTo(256000000)); + } - Rlp chainLevel = Rlp.Encode(new ChainLevelInfo(true, new BlockInfo(TestItem.KeccakA, 1))); - blocksInfosDb.ReadFunc = (key) => - { - if (!Bytes.AreEqual(key, BlockTree.DeletePointerAddressInDb.Bytes)) - { - return chainLevel.Bytes; - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Add_and_find_branch() + { + BlockTree blockTree = BuildBlockTree(); + Block block = Build.A.Block.TestObject; + blockTree.SuggestBlock(block); + Block? found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.None); + Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block.Hash)); + } - return null!; - }; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Add_on_branch_move_find() + { + BlockTree blockTree = BuildBlockTree(); + Block block = Build.A.Block.TestObject; + AddToMain(blockTree, block); + Block? found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.RequireCanonical); + Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block.Hash)); + } - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlocksDb(_blocksDb) - .WithHeadersDb(_headersDb) - .WithBlockInfoDb(blocksInfosDb) - .TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Add_on_branch_move_find_via_block_finder_interface() + { + BlockTree blockTree = BuildBlockTree(); + Block block = Build.A.Block.TestObject; + AddToMain(blockTree, block); + Block? found = ((IBlockFinder)blockTree).FindBlock(new BlockParameter(block.Hash!, true)); + Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block.Hash)); + } - Assert.That(blockTree.BestKnownNumber, Is.EqualTo(256000000)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Add_on_branch_and_not_find_on_main() + { + BlockTree blockTree = BuildBlockTree(); + Block block = Build.A.Block.TestObject; + blockTree.SuggestBlock(block); + Block? found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.RequireCanonical); + Assert.That(found, Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Add_and_find_branch() - { - BlockTree blockTree = BuildBlockTree(); - Block block = Build.A.Block.TestObject; - blockTree.SuggestBlock(block); - Block? found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.None); - Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Add_on_branch_and_not_find_on_main_via_block_finder_interface() + { + BlockTree blockTree = BuildBlockTree(); + Block block = Build.A.Block.TestObject; + blockTree.SuggestBlock(block); + Block? found = ((IBlockFinder)blockTree).FindBlock(new BlockParameter(block.Hash!, true)); + Assert.That(found, Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Add_on_branch_move_find() - { - BlockTree blockTree = BuildBlockTree(); - Block block = Build.A.Block.TestObject; - AddToMain(blockTree, block); - Block? found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.RequireCanonical); - Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_by_number_basic() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + Block? found = blockTree.FindBlock(2, BlockTreeLookupOptions.None); + Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block2.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Add_on_branch_move_find_via_block_finder_interface() - { - BlockTree blockTree = BuildBlockTree(); - Block block = Build.A.Block.TestObject; - AddToMain(blockTree, block); - Block? found = ((IBlockFinder)blockTree).FindBlock(new BlockParameter(block.Hash!, true)); - Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_by_number_beyond_what_is_known_returns_null() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + Block? found = blockTree.FindBlock(1920000, BlockTreeLookupOptions.None); + Assert.That(found, Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Add_on_branch_and_not_find_on_main() - { - BlockTree blockTree = BuildBlockTree(); - Block block = Build.A.Block.TestObject; - blockTree.SuggestBlock(block); - Block? found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.RequireCanonical); - Assert.IsNull(found); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_by_number_returns_null_when_block_is_missing() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + + Block? found = blockTree.FindBlock(5, BlockTreeLookupOptions.None); + Assert.That(found, Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Add_on_branch_and_not_find_on_main_via_block_finder_interface() - { - BlockTree blockTree = BuildBlockTree(); - Block block = Build.A.Block.TestObject; - blockTree.SuggestBlock(block); - Block? found = ((IBlockFinder)blockTree).FindBlock(new BlockParameter(block.Hash!, true)); - Assert.IsNull(found); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_headers_basic() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 2, 0, false); + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); + Assert.That(headers[1].Hash, Is.EqualTo(block1.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_by_number_basic() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - Block? found = blockTree.FindBlock(2, BlockTreeLookupOptions.None); - Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block2.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_headers_skip() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 2, 1, false); + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); + Assert.That(headers[1].Hash, Is.EqualTo(block2.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_by_number_beyond_what_is_known_returns_null() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - Block? found = blockTree.FindBlock(1920000, BlockTreeLookupOptions.None); - Assert.Null(found); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_headers_reverse() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithParent(block2).TestObject; + Block block4 = Build.A.Block.WithNumber(4).WithParent(block3).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + AddToMain(blockTree, block3); + AddToMain(blockTree, block4); + + using IOwnedReadOnlyList headers = blockTree.FindHeaders(block2.Hash, 2, 0, true); + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers[0].Hash, Is.EqualTo(block2.Hash)); + Assert.That(headers[1].Hash, Is.EqualTo(block1.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_by_number_returns_null_when_block_is_missing() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - - Block? found = blockTree.FindBlock(5, BlockTreeLookupOptions.None); - Assert.IsNull(found); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_headers_reverse_skip() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList headers = blockTree.FindHeaders(block2.Hash, 2, 1, true); + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers[0].Hash, Is.EqualTo(block2.Hash)); + Assert.That(headers[1].Hash, Is.EqualTo(block0.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_headers_basic() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 2, 0, false); - Assert.That(headers.Count, Is.EqualTo(2)); - Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); - Assert.That(headers[1].Hash, Is.EqualTo(block1.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_headers_reverse_below_zero() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 2, 1, true); + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); + Assert.That(headers[1], Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_headers_skip() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 2, 1, false); - Assert.That(headers.Count, Is.EqualTo(2)); - Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); - Assert.That(headers[1].Hash, Is.EqualTo(block2.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_finding_headers_does_not_find_a_header_it_breaks_the_loop() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 100, 0, false); + Assert.That(headers.Count, Is.EqualTo(100)); + Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); + Assert.That(headers[3], Is.Null); + + Assert.That(_headersDb.ReadsCount, Is.EqualTo(0)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_headers_reverse() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithParent(block2).TestObject; - Block block4 = Build.A.Block.WithNumber(4).WithParent(block3).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - AddToMain(blockTree, block3); - AddToMain(blockTree, block4); - - using IOwnedReadOnlyList headers = blockTree.FindHeaders(block2.Hash, 2, 0, true); - Assert.That(headers.Count, Is.EqualTo(2)); - Assert.That(headers[0].Hash, Is.EqualTo(block2.Hash)); - Assert.That(headers[1].Hash, Is.EqualTo(block1.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_finding_blocks_does_not_find_a_block_it_breaks_the_loop() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 100, 0, false); + Assert.That(headers.Count, Is.EqualTo(100)); + Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); + Assert.That(headers[3], Is.Null); + + Assert.That(_headersDb.ReadsCount, Is.EqualTo(0)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_headers_reverse_skip() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList headers = blockTree.FindHeaders(block2.Hash, 2, 1, true); - Assert.That(headers.Count, Is.EqualTo(2)); - Assert.That(headers[0].Hash, Is.EqualTo(block2.Hash)); - Assert.That(headers[1].Hash, Is.EqualTo(block0.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_basic_longer() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + int length = 256; + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, length, 0, false); + Assert.That(blocks.Count, Is.EqualTo(length)); + Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block0.Hash)); + Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block1.Hash)); + Assert.That(blocks[2].CalculateHash(), Is.EqualTo(block2.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_headers_reverse_below_zero() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 2, 1, true); - Assert.That(headers.Count, Is.EqualTo(2)); - Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); - Assert.Null(headers[1]); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_basic_shorter() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + int length = 2; + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block1.Hash, length, 0, false); + Assert.That(blocks.Count, Is.EqualTo(length)); + Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block1.Hash)); + Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block2.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_finding_headers_does_not_find_a_header_it_breaks_the_loop() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 100, 0, false); - Assert.That(headers.Count, Is.EqualTo(100)); - Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); - Assert.Null(headers[3]); - - Assert.That(_headersDb.ReadsCount, Is.EqualTo(0)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_basic() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + int length = 3; + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, length, 0, false); + Assert.That(blocks.Count, Is.EqualTo(length)); + Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block0.Hash)); + Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block1.Hash)); + Assert.That(blocks[2].CalculateHash(), Is.EqualTo(block2.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_finding_blocks_does_not_find_a_block_it_breaks_the_loop() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList headers = blockTree.FindHeaders(block0.Hash, 100, 0, false); - Assert.That(headers.Count, Is.EqualTo(100)); - Assert.That(headers[0].Hash, Is.EqualTo(block0.Hash)); - Assert.Null(headers[3]); - - Assert.That(_headersDb.ReadsCount, Is.EqualTo(0)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_reverse() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block2.Hash, 3, 0, true); + Assert.That(blocks.Count, Is.EqualTo(3)); + + Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block2.Hash)); + Assert.That(blocks[2].CalculateHash(), Is.EqualTo(block0.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_basic_longer() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - int length = 256; - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, length, 0, false); - Assert.That(blocks.Count, Is.EqualTo(length)); - Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block0.Hash)); - Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block1.Hash)); - Assert.That(blocks[2].CalculateHash(), Is.EqualTo(block2.Hash)); - } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_basic_shorter() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - int length = 2; - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block1.Hash, length, 0, false); - Assert.That(blocks.Count, Is.EqualTo(length)); - Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block1.Hash)); - Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block2.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_zero_blocks() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 0, 0, false); + Assert.That(blocks.Count, Is.EqualTo(0)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_basic() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - int length = 3; - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, length, 0, false); - Assert.That(blocks.Count, Is.EqualTo(length)); - Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block0.Hash)); - Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block1.Hash)); - Assert.That(blocks[2].CalculateHash(), Is.EqualTo(block2.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_one_block() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block2.Hash, 1, 0, false); + Assert.That(blocks.Count, Is.EqualTo(1)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_reverse() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block2.Hash, 3, 0, true); - Assert.That(blocks.Count, Is.EqualTo(3)); - - Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block2.Hash)); - Assert.That(blocks[2].CalculateHash(), Is.EqualTo(block0.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_basic_skip() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 2, 1, false); + Assert.That(blocks.Count, Is.EqualTo(2), "length"); + Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block0.Hash)); + Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block2.Hash)); + } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Find_sequence_some_empty() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + AddToMain(blockTree, block2); + + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 4, 0, false); + Assert.That(blocks.Count, Is.EqualTo(4)); + Assert.That(blocks[3], Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_zero_blocks() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 0, 0, false); - Assert.That(blocks.Count, Is.EqualTo(0)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Total_difficulty_is_calculated_when_exists_parent_with_total_difficulty() + { + BlockTree blockTree = BuildBlockTree(); + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + blockTree.SuggestBlock(block0); + Block block1 = Build.A.Block.WithNumber(1).WithParentHash(block0.Hash!).WithDifficulty(2).TestObject; + blockTree.SuggestBlock(block1); + block1.TotalDifficulty.Should().NotBeNull(); + Assert.That((int)block1.TotalDifficulty!, Is.EqualTo(3)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_one_block() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block2.Hash, 1, 0, false); - Assert.That(blocks.Count, Is.EqualTo(1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Total_difficulty_is_null_when_no_parent() + { + BlockTree blockTree = BuildBlockTree(); - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_basic_skip() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 2, 1, false); - Assert.That(blocks.Count, Is.EqualTo(2), "length"); - Assert.That(blocks[0].CalculateHash(), Is.EqualTo(block0.Hash)); - Assert.That(blocks[1].CalculateHash(), Is.EqualTo(block2.Hash)); - } + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + blockTree.SuggestBlock(block0); - [Test, Timeout(Timeout.MaxTestTime)] - public void Find_sequence_some_empty() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithParent(block1).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - AddToMain(blockTree, block2); - - using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 4, 0, false); - Assert.That(blocks.Count, Is.EqualTo(4)); - Assert.IsNull(blocks[3]); - } + Block block2 = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParentHash(Keccak.Zero).TestObject; + blockTree.SuggestBlock(block2); + Assert.That(block2.TotalDifficulty, Is.EqualTo(null)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Total_difficulty_is_calculated_when_exists_parent_with_total_difficulty() - { - BlockTree blockTree = BuildBlockTree(); - - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - blockTree.SuggestBlock(block0); - Block block1 = Build.A.Block.WithNumber(1).WithParentHash(block0.Hash!).WithDifficulty(2).TestObject; - blockTree.SuggestBlock(block1); - block1.TotalDifficulty.Should().NotBeNull(); - Assert.That((int)block1.TotalDifficulty!, Is.EqualTo(3)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Head_block_gets_updated() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); - [Test, Timeout(Timeout.MaxTestTime)] - public void Total_difficulty_is_null_when_no_parent() - { - BlockTree blockTree = BuildBlockTree(); + Assert.That(blockTree.Head!.CalculateHash(), Is.EqualTo(block1.Hash)); + } - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - blockTree.SuggestBlock(block0); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Best_suggested_block_gets_updated() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + AddToMain(blockTree, block0); + blockTree.SuggestBlock(block1); + + Assert.That(blockTree.Head!.CalculateHash(), Is.EqualTo(block0.Hash), "head block"); + Assert.That(blockTree.BestSuggestedHeader!.CalculateHash(), Is.EqualTo(block1.Hash), "best suggested"); + } - Block block2 = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParentHash(Keccak.Zero).TestObject; - blockTree.SuggestBlock(block2); - Assert.That(block2.TotalDifficulty, Is.EqualTo(null)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Sets_genesis_block() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + AddToMain(blockTree, block0); - [Test, Timeout(Timeout.MaxTestTime)] - public void Head_block_gets_updated() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); + Assert.That(blockTree.Genesis!.CalculateHash(), Is.EqualTo(block0.Hash)); + } - Assert.That(blockTree.Head!.CalculateHash(), Is.EqualTo(block1.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void ForkChoiceUpdated_update_hashes() + { + BlockTree blockTree = BuildBlockTree(); + Hash256 finalizedBlockHash = TestItem.KeccakB; + Hash256 safeBlockHash = TestItem.KeccakC; + blockTree.ForkChoiceUpdated(finalizedBlockHash, safeBlockHash); + Assert.That(blockTree.FinalizedHash, Is.EqualTo(finalizedBlockHash)); + Assert.That(blockTree.SafeHash, Is.EqualTo(safeBlockHash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Best_suggested_block_gets_updated() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - AddToMain(blockTree, block0); - blockTree.SuggestBlock(block1); - - Assert.That(blockTree.Head!.CalculateHash(), Is.EqualTo(block0.Hash), "head block"); - Assert.That(blockTree.BestSuggestedHeader!.CalculateHash(), Is.EqualTo(block1.Hash), "best suggested"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Stores_multiple_blocks_per_level() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParent(block0).TestObject; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); + blockTree.SuggestBlock(block1B); - [Test, Timeout(Timeout.MaxTestTime)] - public void Sets_genesis_block() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - AddToMain(blockTree, block0); + Block? found = blockTree.FindBlock(block1B.Hash, BlockTreeLookupOptions.None); - Assert.That(blockTree.Genesis!.CalculateHash(), Is.EqualTo(block0.Hash)); - } + Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block1B.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void ForkChoiceUpdated_update_hashes() - { - BlockTree blockTree = BuildBlockTree(); - Hash256 finalizedBlockHash = TestItem.KeccakB; - Hash256 safeBlockHash = TestItem.KeccakC; - blockTree.ForkChoiceUpdated(finalizedBlockHash, safeBlockHash); - Assert.That(blockTree.FinalizedHash, Is.EqualTo(finalizedBlockHash)); - Assert.That(blockTree.SafeHash, Is.EqualTo(safeBlockHash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_init_head_block_from_db_by_hash() + { + Block genesisBlock = Build.A.Block.Genesis.TestObject; + Block headBlock = genesisBlock; + + BlockStore blockStore = new BlockStore(new MemDb()); + blockStore.Insert(genesisBlock); + + TestMemDb headersDb = new(); + headersDb.Set(genesisBlock.Hash!, Rlp.Encode(genesisBlock.Header).Bytes); + + TestMemDb blockInfosDb = new(); + blockInfosDb.Set(Keccak.Zero, genesisBlock.Hash!.Bytes); + ChainLevelInfo level = new(true, new BlockInfo(headBlock.Hash!, headBlock.Difficulty)); + level.BlockInfos[0].WasProcessed = true; + + blockInfosDb.Set(0, Rlp.Encode(level).Bytes); + + BlockTree blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockStore(blockStore) + .WithHeadersDb(headersDb) + .WithBlockInfoDb(blockInfosDb) + .WithSpecProvider(OlympicSpecProvider.Instance) + .TestObject; + Assert.That(blockTree.Head?.Hash, Is.EqualTo(headBlock.Hash), "head"); + Assert.That(blockTree.Genesis?.Hash, Is.EqualTo(headBlock.Hash), "genesis"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Stores_multiple_blocks_per_level() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParent(block0).TestObject; - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); - blockTree.SuggestBlock(block1B); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Sets_head_block_hash_in_db_on_new_head_block() + { + TestMemDb blockInfosDb = new(); - Block? found = blockTree.FindBlock(block1B.Hash, BlockTreeLookupOptions.None); + BlockTree blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .TestObject; - Assert.That(found?.Header.CalculateHash(), Is.EqualTo(block1B.Hash)); - } + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_init_head_block_from_db_by_hash() - { - Block genesisBlock = Build.A.Block.Genesis.TestObject; - Block headBlock = genesisBlock; + AddToMain(blockTree, block0); + AddToMain(blockTree, block1); - BlockStore blockStore = new BlockStore(new MemDb()); - blockStore.Insert(genesisBlock); + Hash256 dec = new Hash256(blockInfosDb.Get(Keccak.Zero)!); + Assert.That(dec, Is.EqualTo(block1.Hash)); + } - TestMemDb headersDb = new(); - headersDb.Set(genesisBlock.Hash!, Rlp.Encode(genesisBlock.Header).Bytes); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_check_if_block_was_processed() + { + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + + BlockTree blockTree = BuildBlockTree(); + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + Assert.That(blockTree.WasProcessed(block1.Number, block1.Hash!), Is.False, "before"); + blockTree.UpdateMainChain(new[] { block0, block1 }, true); + Assert.That(blockTree.WasProcessed(block1.Number, block1.Hash!), Is.True, "after"); + } - TestMemDb blockInfosDb = new(); - blockInfosDb.Set(Keccak.Zero, genesisBlock.Hash!.Bytes); - ChainLevelInfo level = new(true, new BlockInfo(headBlock.Hash!, headBlock.Difficulty)); - level.BlockInfos[0].WasProcessed = true; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Best_known_number_is_set() + { + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - blockInfosDb.Set(0, Rlp.Encode(level).Bytes); + BlockTree blockTree = BuildBlockTree(); + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + Assert.That(blockTree.BestKnownNumber, Is.EqualTo(1L)); + } - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockStore(blockStore) - .WithHeadersDb(headersDb) - .WithBlockInfoDb(blockInfosDb) - .WithSpecProvider(OlympicSpecProvider.Instance) - .TestObject; - Assert.That(blockTree.Head?.Hash, Is.EqualTo(headBlock.Hash), "head"); - Assert.That(blockTree.Genesis?.Hash, Is.EqualTo(headBlock.Hash), "genesis"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Is_main_chain_returns_false_when_on_branch() + { + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - [Test, Timeout(Timeout.MaxTestTime)] - public void Sets_head_block_hash_in_db_on_new_head_block() - { - TestMemDb blockInfosDb = new(); + BlockTree blockTree = BuildBlockTree(); + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + Assert.That(blockTree.IsMainChain(block1.Hash!), Is.False); + } - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockInfoDb(blockInfosDb) - .TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Is_main_chain_returns_true_when_on_main() + { + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + + BlockTree blockTree = BuildBlockTree(); + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + blockTree.UpdateMainChain(block1); + Assert.That(blockTree.IsMainChain(block1.Hash!), Is.True); + } - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Pending_returns_head() + { + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + + BlockTree blockTree = BuildBlockTree(); + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + blockTree.UpdateMainChain(block0); + blockTree.BestSuggestedHeader.Should().Be(block1.Header); + blockTree.PendingHash.Should().Be(block0.Hash!); + ((IBlockFinder)blockTree).FindPendingHeader().Should().BeSameAs(block0.Header); + ((IBlockFinder)blockTree).FindPendingBlock().Should().BeSameAs(block0); + } - AddToMain(blockTree, block0); - AddToMain(blockTree, block1); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Is_main_chain_returns_true_on_fast_sync_block() + { + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + BlockTree blockTree = BuildBlockTree(); + blockTree.SuggestBlock(block0, BlockTreeSuggestOptions.None); + blockTree.IsMainChain(block0.Hash!).Should().BeTrue(); + } - Hash256 dec = new Hash256(blockInfosDb.Get(Keccak.Zero)!); - Assert.That(dec, Is.EqualTo(block1.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Was_processed_returns_true_on_fast_sync_block() + { + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + BlockTree blockTree = BuildBlockTree(); + blockTree.SuggestBlock(block0, BlockTreeSuggestOptions.None); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_check_if_block_was_processed() - { - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - - BlockTree blockTree = BuildBlockTree(); - blockTree.SuggestBlock(block0); - blockTree.SuggestBlock(block1); - Assert.False(blockTree.WasProcessed(block1.Number, block1.Hash!), "before"); - blockTree.UpdateMainChain(new[] { block0, block1 }, true); - Assert.True(blockTree.WasProcessed(block1.Number, block1.Hash!), "after"); - } + [Test(Description = "There was a bug where we switched positions and used the index from before the positions were switched"), MaxTime(Timeout.MaxTestTime)] + public void When_moving_to_main_one_of_the_two_blocks_at_given_level_the_was_processed_check_is_executed_on_the_correct_block_index_regression() + { + TestMemDb blockInfosDb = new(); - [Test, Timeout(Timeout.MaxTestTime)] - public void Best_known_number_is_set() - { - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + BlockTree blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .TestObject; + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParent(block0).TestObject; - BlockTree blockTree = BuildBlockTree(); - blockTree.SuggestBlock(block0); - blockTree.SuggestBlock(block1); - Assert.That(blockTree.BestKnownNumber, Is.EqualTo(1L)); - } + AddToMain(blockTree, block0); - [Test, Timeout(Timeout.MaxTestTime)] - public void Is_main_chain_returns_false_when_on_branch() - { - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + blockTree.SuggestBlock(block2); + blockTree.SuggestBlock(block1); + blockTree.UpdateMainChain(block1); - BlockTree blockTree = BuildBlockTree(); - blockTree.SuggestBlock(block0); - blockTree.SuggestBlock(block1); - Assert.False(blockTree.IsMainChain(block1.Hash!)); - } + Hash256 storedInDb = new(blockInfosDb.Get(Keccak.Zero)!); + Assert.That(storedInDb, Is.EqualTo(block1.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Is_main_chain_returns_true_when_on_main() - { - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - - BlockTree blockTree = BuildBlockTree(); - blockTree.SuggestBlock(block0); - blockTree.SuggestBlock(block1); - blockTree.UpdateMainChain(block1); - Assert.True(blockTree.IsMainChain(block1.Hash!)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_deleting_invalid_block_sets_head_bestKnown_and_suggested_right() + { + BlockTree tree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + + tree.UpdateMainChain(block0); + tree.UpdateMainChain(block1); + tree.DeleteInvalidBlock(block2); + + Assert.That(tree.BestKnownNumber, Is.EqualTo(block1.Number)); + Assert.That(tree.Head?.Header, Is.EqualTo(block1.Header)); + Assert.That(tree.BestSuggestedHeader, Is.EqualTo(block1.Header)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Pending_returns_head() - { - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - - BlockTree blockTree = BuildBlockTree(); - blockTree.SuggestBlock(block0); - blockTree.SuggestBlock(block1); - blockTree.UpdateMainChain(block0); - blockTree.BestSuggestedHeader.Should().Be(block1.Header); - blockTree.PendingHash.Should().Be(block0.Hash!); - ((IBlockFinder)blockTree).FindPendingHeader().Should().BeSameAs(block0.Header); - ((IBlockFinder)blockTree).FindPendingBlock().Should().BeSameAs(block0); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_deleting_invalid_block_deletes_its_descendants() + { + BlockStore blockStore = new(new MemDb()); + MemDb blockInfosDb = new(); + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .WithBlockStore(blockStore) + .TestObject; + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + + tree.UpdateMainChain(block0); + tree.UpdateMainChain(block1); + tree.DeleteInvalidBlock(block2); + + Assert.That(tree.BestKnownNumber, Is.EqualTo(1L), "best known"); + Assert.That(tree.Head!.Number, Is.EqualTo(1L), "head"); + Assert.That(tree.BestSuggestedHeader!.Number, Is.EqualTo(1L), "suggested"); + + Assert.That(blockStore.Get(block1.Number, block1.Hash!), Is.Not.Null, "block 1"); + Assert.That(blockStore.Get(block2.Number, block2.Hash!), Is.Null, "block 2"); + Assert.That(blockStore.Get(block3.Number, block3.Hash!), Is.Null, "block 3"); + + Assert.That(blockInfosDb.Get(1), Is.Not.Null, "level 1"); + Assert.That(blockInfosDb.Get(2), Is.Null, "level 2"); + Assert.That(blockInfosDb.Get(3), Is.Null, "level 3"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Is_main_chain_returns_true_on_fast_sync_block() - { - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - BlockTree blockTree = BuildBlockTree(); - blockTree.SuggestBlock(block0, BlockTreeSuggestOptions.None); - blockTree.IsMainChain(block0.Hash!).Should().BeTrue(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_deleting_invalid_block_deletes_its_descendants_even_if_not_first() + { + BlockStore blockStore = new(new MemDb()); + MemDb blockInfosDb = new(); + ChainLevelInfoRepository repository = new(blockInfosDb); + + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .WithBlockStore(blockStore) + .TestObject; + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + + Block block1b = Build.A.Block.WithNumber(1).WithDifficulty(2).WithExtraData(new byte[] { 1 }).WithParent(block0).TestObject; + Block block2b = Build.A.Block.WithNumber(2).WithDifficulty(3).WithExtraData(new byte[] { 1 }).WithParent(block1b).TestObject; + Block block3b = Build.A.Block.WithNumber(3).WithDifficulty(4).WithExtraData(new byte[] { 1 }).WithParent(block2b).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + + tree.SuggestBlock(block1b); + tree.SuggestBlock(block2b); + tree.SuggestBlock(block3b); + + tree.UpdateMainChain(block0); + tree.UpdateMainChain(block1); + tree.DeleteInvalidBlock(block1b); + + Assert.That(tree.BestKnownNumber, Is.EqualTo(3L), "best known"); + Assert.That(tree.Head!.Number, Is.EqualTo(1L), "head"); + Assert.That(tree.BestSuggestedHeader!.Number, Is.EqualTo(1L), "suggested"); + + Assert.That(blockStore.Get(block1.Number, block1.Hash!), Is.Not.Null, "block 1"); + Assert.That(blockStore.Get(block2.Number, block2.Hash!), Is.Not.Null, "block 2"); + Assert.That(blockStore.Get(block3.Number, block3.Hash!), Is.Not.Null, "block 3"); + Assert.That(blockStore.Get(block1b.Number, block1b.Hash!), Is.Null, "block 1b"); + Assert.That(blockStore.Get(block2b.Number, block2b.Hash!), Is.Null, "block 2b"); + Assert.That(blockStore.Get(block3b.Number, block3b.Hash!), Is.Null, "block 3b"); + + Assert.That(blockInfosDb.Get(1), Is.Not.Null, "level 1"); + Assert.That(blockInfosDb.Get(2), Is.Not.Null, "level 2"); + Assert.That(blockInfosDb.Get(3), Is.Not.Null, "level 3"); + + Assert.That(blockInfosDb.Get(1), Is.Not.Null, "level 1b"); + Assert.That(blockInfosDb.Get(2), Is.Not.Null, "level 2b"); + Assert.That(blockInfosDb.Get(3), Is.Not.Null, "level 3b"); + + repository.LoadLevel(1)!.BlockInfos.Length.Should().Be(1); + repository.LoadLevel(2)!.BlockInfos.Length.Should().Be(1); + repository.LoadLevel(3)!.BlockInfos.Length.Should().Be(1); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Was_processed_returns_true_on_fast_sync_block() - { - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - BlockTree blockTree = BuildBlockTree(); - blockTree.SuggestBlock(block0, BlockTreeSuggestOptions.None); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void After_removing_invalid_block_will_not_accept_it_again() + { + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .TestObject; + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + + tree.DeleteInvalidBlock(block1); + AddBlockResult result = tree.SuggestBlock(block1); + Assert.That(result, Is.EqualTo(AddBlockResult.InvalidBlock)); + } - [Test(Description = "There was a bug where we switched positions and used the index from before the positions were switched"), Timeout(Timeout.MaxTestTime)] - public void When_moving_to_main_one_of_the_two_blocks_at_given_level_the_was_processed_check_is_executed_on_the_correct_block_index_regression() - { - TestMemDb blockInfosDb = new(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void After_deleting_invalid_block_will_accept_other_blocks() + { + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .TestObject; - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockInfoDb(blockInfosDb) - .TestObject; - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(1).WithDifficulty(3).WithParent(block0).TestObject; + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - AddToMain(blockTree, block0); + Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; - blockTree.SuggestBlock(block2); - blockTree.SuggestBlock(block1); - blockTree.UpdateMainChain(block1); + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); - Hash256 storedInDb = new(blockInfosDb.Get(Keccak.Zero)!); - Assert.That(storedInDb, Is.EqualTo(block1.Hash)); - } + tree.DeleteInvalidBlock(block1); + AddBlockResult result = tree.SuggestBlock(block1B); + Assert.That(result, Is.EqualTo(AddBlockResult.Added)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_deleting_invalid_block_sets_head_bestKnown_and_suggested_right() - { - BlockTree tree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - - tree.UpdateMainChain(block0); - tree.UpdateMainChain(block1); - tree.DeleteInvalidBlock(block2); - - Assert.That(tree.BestKnownNumber, Is.EqualTo(block1.Number)); - Assert.That(tree.Head?.Header, Is.EqualTo(block1.Header)); - Assert.That(tree.BestSuggestedHeader, Is.EqualTo(block1.Header)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_deleting_invalid_block_does_not_delete_blocks_that_are_not_its_descendants() + { + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .TestObject; + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; + Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; + + Block block3bad = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + tree.SuggestBlock(block4); + tree.SuggestBlock(block5); + + tree.SuggestBlock(block3bad); + + tree.UpdateMainChain(block5); + tree.DeleteInvalidBlock(block3bad); + + Assert.That(tree.BestKnownNumber, Is.EqualTo(5L), "best known"); + Assert.That(tree.Head?.Header, Is.EqualTo(block5.Header), "head"); + Assert.That(tree.BestSuggestedHeader!.Hash, Is.EqualTo(block5.Hash), "suggested"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_deleting_invalid_block_deletes_its_descendants() - { - BlockStore blockStore = new(new MemDb()); - MemDb blockInfosDb = new(); - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockInfoDb(blockInfosDb) - .WithBlockStore(blockStore) - .TestObject; - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - - tree.UpdateMainChain(block0); - tree.UpdateMainChain(block1); - tree.DeleteInvalidBlock(block2); - - Assert.That(tree.BestKnownNumber, Is.EqualTo(1L), "best known"); - Assert.That(tree.Head!.Number, Is.EqualTo(1L), "head"); - Assert.That(tree.BestSuggestedHeader!.Number, Is.EqualTo(1L), "suggested"); - - Assert.NotNull(blockStore.Get(block1.Number, block1.Hash!), "block 1"); - Assert.IsNull(blockStore.Get(block2.Number, block2.Hash!), "block 2"); - Assert.IsNull(blockStore.Get(block3.Number, block3.Hash!), "block 3"); - - Assert.NotNull(blockInfosDb.Get(1), "level 1"); - Assert.IsNull(blockInfosDb.Get(2), "level 2"); - Assert.IsNull(blockInfosDb.Get(3), "level 3"); - } + [Test, MaxTime(Timeout.MaxTestTime), TestCaseSource(nameof(SourceOfBSearchTestCases))] + public void Loads_lowest_inserted_header_correctly(long beginIndex, long insertedBlocks) + { + long? expectedResult = insertedBlocks == 0L ? null : beginIndex - insertedBlocks + 1L; - [Test, Timeout(Timeout.MaxTestTime)] - public void When_deleting_invalid_block_deletes_its_descendants_even_if_not_first() + SyncConfig syncConfig = new() { - BlockStore blockStore = new(new MemDb()); - MemDb blockInfosDb = new(); - ChainLevelInfoRepository repository = new(blockInfosDb); - - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockInfoDb(blockInfosDb) - .WithBlockStore(blockStore) - .TestObject; + FastSync = true, + PivotNumber = beginIndex.ToString(), + }; - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - - Block block1b = Build.A.Block.WithNumber(1).WithDifficulty(2).WithExtraData(new byte[] { 1 }).WithParent(block0).TestObject; - Block block2b = Build.A.Block.WithNumber(2).WithDifficulty(3).WithExtraData(new byte[] { 1 }).WithParent(block1b).TestObject; - Block block3b = Build.A.Block.WithNumber(3).WithDifficulty(4).WithExtraData(new byte[] { 1 }).WithParent(block2b).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - - tree.SuggestBlock(block1b); - tree.SuggestBlock(block2b); - tree.SuggestBlock(block3b); - - tree.UpdateMainChain(block0); - tree.UpdateMainChain(block1); - tree.DeleteInvalidBlock(block1b); - - Assert.That(tree.BestKnownNumber, Is.EqualTo(3L), "best known"); - Assert.That(tree.Head!.Number, Is.EqualTo(1L), "head"); - Assert.That(tree.BestSuggestedHeader!.Number, Is.EqualTo(1L), "suggested"); - - Assert.NotNull(blockStore.Get(block1.Number, block1.Hash!), "block 1"); - Assert.NotNull(blockStore.Get(block2.Number, block2.Hash!), "block 2"); - Assert.NotNull(blockStore.Get(block3.Number, block3.Hash!), "block 3"); - Assert.Null(blockStore.Get(block1b.Number, block1b.Hash!), "block 1b"); - Assert.Null(blockStore.Get(block2b.Number, block2b.Hash!), "block 2b"); - Assert.Null(blockStore.Get(block3b.Number, block3b.Hash!), "block 3b"); - - Assert.NotNull(blockInfosDb.Get(1), "level 1"); - Assert.NotNull(blockInfosDb.Get(2), "level 2"); - Assert.NotNull(blockInfosDb.Get(3), "level 3"); - - Assert.NotNull(blockInfosDb.Get(1), "level 1b"); - Assert.NotNull(blockInfosDb.Get(2), "level 2b"); - Assert.NotNull(blockInfosDb.Get(3), "level 3b"); - - repository.LoadLevel(1)!.BlockInfos.Length.Should().Be(1); - repository.LoadLevel(2)!.BlockInfos.Length.Should().Be(1); - repository.LoadLevel(3)!.BlockInfos.Length.Should().Be(1); - } + BlockTreeBuilder builder = Build.A + .BlockTree() + .WithSyncConfig(syncConfig) + .WithoutSettingHead; + BlockTree tree = builder.TestObject; + tree.SuggestBlock(Build.A.Block.Genesis.TestObject); - [Test, Timeout(Timeout.MaxTestTime)] - public void After_removing_invalid_block_will_not_accept_it_again() + for (long i = beginIndex; i > beginIndex - insertedBlocks; i--) { - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .TestObject; - - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - - tree.DeleteInvalidBlock(block1); - AddBlockResult result = tree.SuggestBlock(block1); - Assert.That(result, Is.EqualTo(AddBlockResult.InvalidBlock)); + tree.Insert(Build.A.BlockHeader.WithNumber(i).WithTotalDifficulty(i).TestObject); } - [Test, Timeout(Timeout.MaxTestTime)] - public void After_deleting_invalid_block_will_accept_other_blocks() - { - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .TestObject; - - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + BlockTree loadedTree = Build.A.BlockTree() + .WithDatabaseFrom(builder) + .WithSyncConfig(syncConfig) + .TestObject; - Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; + Assert.That(tree.LowestInsertedHeader?.Number, Is.EqualTo(expectedResult), "tree"); + Assert.That(loadedTree.LowestInsertedHeader?.Number, Is.EqualTo(expectedResult), "loaded tree"); + } - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); + [Test, MaxTime(Timeout.MaxTestTime), TestCaseSource(nameof(SourceOfBSearchTestCases))] + public void Loads_lowest_inserted_body_correctly(long beginIndex, long insertedBlocks) + { + // left old code to prove that it does not matter for the result nowadays + // we store and no longer binary search lowest body number - tree.DeleteInvalidBlock(block1); - AddBlockResult result = tree.SuggestBlock(block1B); - Assert.That(result, Is.EqualTo(AddBlockResult.Added)); - } + MemDb blocksDb = new(); + blocksDb.Set(BlockTree.LowestInsertedBodyNumberDbEntryAddress, Rlp.Encode(1L).Bytes); - [Test, Timeout(Timeout.MaxTestTime)] - public void When_deleting_invalid_block_does_not_delete_blocks_that_are_not_its_descendants() + SyncConfig syncConfig = new() { - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .TestObject; - - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; - Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; - - Block block3bad = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - tree.SuggestBlock(block4); - tree.SuggestBlock(block5); + PivotNumber = beginIndex.ToString(), + }; - tree.SuggestBlock(block3bad); + BlockTreeBuilder builder = Build.A.BlockTree() + .WithBlocksDb(blocksDb) + .WithSyncConfig(syncConfig) + .WithoutSettingHead; - tree.UpdateMainChain(block5); - tree.DeleteInvalidBlock(block3bad); + BlockTree tree = builder.TestObject; - Assert.That(tree.BestKnownNumber, Is.EqualTo(5L), "best known"); - Assert.That(tree.Head?.Header, Is.EqualTo(block5.Header), "head"); - Assert.That(tree.BestSuggestedHeader!.Hash, Is.EqualTo(block5.Hash), "suggested"); - } + tree.SuggestBlock(Build.A.Block.Genesis.TestObject); - [Test, Timeout(Timeout.MaxTestTime), TestCaseSource(nameof(SourceOfBSearchTestCases))] - public void Loads_lowest_inserted_header_correctly(long beginIndex, long insertedBlocks) + for (long i = beginIndex; i > beginIndex - insertedBlocks; i--) { - long? expectedResult = insertedBlocks == 0L ? null : beginIndex - insertedBlocks + 1L; - - SyncConfig syncConfig = new() - { - FastSync = true, - PivotNumber = beginIndex.ToString(), - }; - - BlockTreeBuilder builder = Build.A - .BlockTree() - .WithSyncConfig(syncConfig) - .WithoutSettingHead; - BlockTree tree = builder.TestObject; - tree.SuggestBlock(Build.A.Block.Genesis.TestObject); - - for (long i = beginIndex; i > beginIndex - insertedBlocks; i--) - { - tree.Insert(Build.A.BlockHeader.WithNumber(i).WithTotalDifficulty(i).TestObject); - } - - BlockTree loadedTree = Build.A.BlockTree() - .WithDatabaseFrom(builder) - .WithSyncConfig(syncConfig) - .TestObject; - - Assert.That(tree.LowestInsertedHeader?.Number, Is.EqualTo(expectedResult), "tree"); - Assert.That(loadedTree.LowestInsertedHeader?.Number, Is.EqualTo(expectedResult), "loaded tree"); + Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(i).TestObject; + tree.Insert(block.Header); + tree.Insert(block); } - [Test, Timeout(Timeout.MaxTestTime), TestCaseSource(nameof(SourceOfBSearchTestCases))] - public void Loads_lowest_inserted_body_correctly(long beginIndex, long insertedBlocks) - { - // left old code to prove that it does not matter for the result nowadays - // we store and no longer binary search lowest body number - - MemDb blocksDb = new(); - blocksDb.Set(BlockTree.LowestInsertedBodyNumberDbEntryAddress, Rlp.Encode(1L).Bytes); - - SyncConfig syncConfig = new() - { - PivotNumber = beginIndex.ToString(), - }; - - BlockTreeBuilder builder = Build.A.BlockTree() - .WithBlocksDb(blocksDb) - .WithSyncConfig(syncConfig) - .WithoutSettingHead; - - BlockTree tree = builder.TestObject; - - tree.SuggestBlock(Build.A.Block.Genesis.TestObject); + BlockTree loadedTree = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .WithSyncConfig(syncConfig) + .TestObject; - for (long i = beginIndex; i > beginIndex - insertedBlocks; i--) - { - Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(i).TestObject; - tree.Insert(block.Header); - tree.Insert(block); - } - - BlockTree loadedTree = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .WithSyncConfig(syncConfig) - .TestObject; + Assert.That(tree.LowestInsertedBodyNumber, Is.EqualTo(null), "tree"); + Assert.That(loadedTree.LowestInsertedBodyNumber, Is.EqualTo(1), "loaded tree"); + } - Assert.That(tree.LowestInsertedBodyNumber, Is.EqualTo(null), "tree"); - Assert.That(loadedTree.LowestInsertedBodyNumber, Is.EqualTo(1), "loaded tree"); - } + private static readonly object[] SourceOfBSearchTestCases = + { + new object[] {1L, 0L}, + new object[] {1L, 1L}, + new object[] {2L, 0L}, + new object[] {2L, 1L}, + new object[] {2L, 2L}, + new object[] {3L, 0L}, + new object[] {3L, 1L}, + new object[] {3L, 2L}, + new object[] {3L, 3L}, + new object[] {4L, 0L}, + new object[] {4L, 1L}, + new object[] {4L, 2L}, + new object[] {4L, 3L}, + new object[] {4L, 4L}, + new object[] {5L, 0L}, + new object[] {5L, 1L}, + new object[] {5L, 2L}, + new object[] {5L, 3L}, + new object[] {5L, 4L}, + new object[] {5L, 5L}, + new object[] {728000, 0L}, + new object[] {7280000L, 1L} + }; + + [Test, MaxTime(Timeout.MaxTestTime), TestCaseSource(nameof(SourceOfBSearchTestCases))] + public void Loads_best_known_correctly_on_inserts(long beginIndex, long insertedBlocks) + { + long expectedResult = insertedBlocks == 0L ? 0L : beginIndex; - private static readonly object[] SourceOfBSearchTestCases = + SyncConfig syncConfig = new() { - new object[] {1L, 0L}, - new object[] {1L, 1L}, - new object[] {2L, 0L}, - new object[] {2L, 1L}, - new object[] {2L, 2L}, - new object[] {3L, 0L}, - new object[] {3L, 1L}, - new object[] {3L, 2L}, - new object[] {3L, 3L}, - new object[] {4L, 0L}, - new object[] {4L, 1L}, - new object[] {4L, 2L}, - new object[] {4L, 3L}, - new object[] {4L, 4L}, - new object[] {5L, 0L}, - new object[] {5L, 1L}, - new object[] {5L, 2L}, - new object[] {5L, 3L}, - new object[] {5L, 4L}, - new object[] {5L, 5L}, - new object[] {728000, 0L}, - new object[] {7280000L, 1L} + PivotNumber = beginIndex.ToString(), + FastSync = true, }; - [Test, Timeout(Timeout.MaxTestTime), TestCaseSource(nameof(SourceOfBSearchTestCases))] - public void Loads_best_known_correctly_on_inserts(long beginIndex, long insertedBlocks) - { - long expectedResult = insertedBlocks == 0L ? 0L : beginIndex; - - SyncConfig syncConfig = new() - { - PivotNumber = beginIndex.ToString(), - FastSync = true, - }; + BlockTreeBuilder builder = Build.A.BlockTree() + .WithoutSettingHead + .WithSyncConfig(syncConfig); - BlockTreeBuilder builder = Build.A.BlockTree() - .WithoutSettingHead - .WithSyncConfig(syncConfig); + BlockTree tree = builder.TestObject; - BlockTree tree = builder.TestObject; + tree.SuggestBlock(Build.A.Block.Genesis.TestObject); - tree.SuggestBlock(Build.A.Block.Genesis.TestObject); + for (long i = beginIndex; i > beginIndex - insertedBlocks; i--) + { + Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(i).TestObject; + tree.Insert(block.Header); + tree.Insert(block); + } - for (long i = beginIndex; i > beginIndex - insertedBlocks; i--) - { - Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(i).TestObject; - tree.Insert(block.Header); - tree.Insert(block); - } + BlockTree loadedTree = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .WithSyncConfig(syncConfig) + .TestObject; - BlockTree loadedTree = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .WithSyncConfig(syncConfig) - .TestObject; + Assert.That(tree.BestKnownNumber, Is.EqualTo(expectedResult), "tree"); + Assert.That(loadedTree.BestKnownNumber, Is.EqualTo(expectedResult), "loaded tree"); + } - Assert.That(tree.BestKnownNumber, Is.EqualTo(expectedResult), "tree"); - Assert.That(loadedTree.BestKnownNumber, Is.EqualTo(expectedResult), "loaded tree"); - } + [Test] + public void Loads_best_head_up_to_best_persisted_state() + { + MemDb metadataDb = new(); + metadataDb.Set(MetadataDbKeys.BeaconSyncPivotNumber, Rlp.Encode(51).Bytes); - [Test] - public void Loads_best_head_up_to_best_persisted_state() + SyncConfig syncConfig = new() { - MemDb metadataDb = new(); - metadataDb.Set(MetadataDbKeys.BeaconSyncPivotNumber, Rlp.Encode(51).Bytes); - - SyncConfig syncConfig = new() - { - PivotNumber = "0", - FastSync = true, - }; + PivotNumber = "0", + FastSync = true, + }; - BlockTreeBuilder builder = Build.A.BlockTree() - .WithoutSettingHead - .WithMetadataDb(metadataDb) - .WithSyncConfig(syncConfig); + BlockTreeBuilder builder = Build.A.BlockTree() + .WithoutSettingHead + .WithMetadataDb(metadataDb) + .WithSyncConfig(syncConfig); - BlockTree tree = builder.TestObject; - Block genesis = Build.A.Block.Genesis.TestObject; - tree.SuggestBlock(genesis); - Block parent = genesis; + BlockTree tree = builder.TestObject; + Block genesis = Build.A.Block.Genesis.TestObject; + tree.SuggestBlock(genesis); + Block parent = genesis; - List blocks = new() { genesis }; + List blocks = new() { genesis }; - for (long i = 1; i < 100; i++) + for (long i = 1; i < 100; i++) + { + Block block = Build.A.Block + .WithNumber(i) + .WithParent(parent) + .WithTotalDifficulty(i).TestObject; + blocks.Add(block); + parent = block; + if (i <= 50) { - Block block = Build.A.Block - .WithNumber(i) - .WithParent(parent) - .WithTotalDifficulty(i).TestObject; - blocks.Add(block); - parent = block; - if (i <= 50) - { - // tree.Insert(block.Header); - tree.SuggestBlock(block); - } - else - { - tree.Insert(block, BlockTreeInsertBlockOptions.SaveHeader, BlockTreeInsertHeaderOptions.BeaconBodyMetadata); - } + // tree.Insert(block.Header); + tree.SuggestBlock(block); + } + else + { + tree.Insert(block, BlockTreeInsertBlockOptions.SaveHeader, BlockTreeInsertHeaderOptions.BeaconBodyMetadata); } - tree.UpdateMainChain(blocks.ToArray(), true); - tree.BestPersistedState = 50; + } + tree.UpdateMainChain(blocks.ToArray(), true); + tree.BestPersistedState = 50; - BlockTree loadedTree = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .WithSyncConfig(syncConfig) - .TestObject; + BlockTree loadedTree = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .WithSyncConfig(syncConfig) + .TestObject; - Assert.That(loadedTree.Head?.Number, Is.EqualTo(50)); - } + Assert.That(loadedTree.Head?.Number, Is.EqualTo(50)); + } - [Timeout(Timeout.MaxTestTime)] - [TestCase(1L)] - [TestCase(2L)] - [TestCase(3L)] - public void Loads_best_known_correctly_on_inserts_followed_by_suggests(long pivotNumber) + [MaxTime(Timeout.MaxTestTime)] + [TestCase(1L)] + [TestCase(2L)] + [TestCase(3L)] + public void Loads_best_known_correctly_on_inserts_followed_by_suggests(long pivotNumber) + { + SyncConfig syncConfig = new() { - SyncConfig syncConfig = new() - { - PivotNumber = pivotNumber.ToString(), - }; - BlockTreeBuilder builder = Build.A.BlockTree() - .WithoutSettingHead - .WithSyncConfig(syncConfig); + PivotNumber = pivotNumber.ToString(), + }; + BlockTreeBuilder builder = Build.A.BlockTree() + .WithoutSettingHead + .WithSyncConfig(syncConfig); - BlockTree tree = builder.TestObject; - tree.SuggestBlock(Build.A.Block.Genesis.TestObject); + BlockTree tree = builder.TestObject; + tree.SuggestBlock(Build.A.Block.Genesis.TestObject); - Block? pivotBlock = null; - for (long i = pivotNumber; i > 0; i--) - { - Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(i).TestObject; - pivotBlock ??= block; - tree.Insert(block.Header); - } + Block? pivotBlock = null; + for (long i = pivotNumber; i > 0; i--) + { + Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(i).TestObject; + pivotBlock ??= block; + tree.Insert(block.Header); + } - tree.SuggestHeader(Build.A.BlockHeader.WithNumber(pivotNumber + 1).WithParent(pivotBlock!.Header).TestObject); + tree.SuggestHeader(Build.A.BlockHeader.WithNumber(pivotNumber + 1).WithParent(pivotBlock!.Header).TestObject); - BlockTree loadedTree = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .WithSyncConfig(syncConfig) - .TestObject; + BlockTree loadedTree = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .WithSyncConfig(syncConfig) + .TestObject; - Assert.That(tree.BestKnownNumber, Is.EqualTo(pivotNumber + 1), "tree"); - Assert.That(tree.LowestInsertedHeader?.Number, Is.EqualTo(1), "loaded tree - lowest header"); - Assert.That(tree.LowestInsertedBodyNumber, Is.EqualTo(null), "loaded tree - lowest body"); - Assert.That(loadedTree.BestKnownNumber, Is.EqualTo(pivotNumber + 1), "loaded tree"); - } + Assert.That(tree.BestKnownNumber, Is.EqualTo(pivotNumber + 1), "tree"); + Assert.That(tree.LowestInsertedHeader?.Number, Is.EqualTo(1), "loaded tree - lowest header"); + Assert.That(tree.LowestInsertedBodyNumber, Is.EqualTo(null), "loaded tree - lowest body"); + Assert.That(loadedTree.BestKnownNumber, Is.EqualTo(pivotNumber + 1), "loaded tree"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Loads_best_known_correctly_when_head_before_pivot() + [Test, MaxTime(Timeout.MaxTestTime)] + public void Loads_best_known_correctly_when_head_before_pivot() + { + int pivotNumber = 1000; + int head = 10; + SyncConfig syncConfig = new() { - int pivotNumber = 1000; - int head = 10; - SyncConfig syncConfig = new() - { - PivotNumber = pivotNumber.ToString() - }; + PivotNumber = pivotNumber.ToString() + }; - BlockTreeBuilder treeBuilder = Build.A.BlockTree().OfChainLength(head + 1); + BlockTreeBuilder treeBuilder = Build.A.BlockTree().OfChainLength(head + 1); - BlockTree loadedTree = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(treeBuilder) - .WithSyncConfig(syncConfig) - .TestObject; + BlockTree loadedTree = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(treeBuilder) + .WithSyncConfig(syncConfig) + .TestObject; - Assert.That(loadedTree.BestKnownNumber, Is.EqualTo(head), "loaded tree"); - } + Assert.That(loadedTree.BestKnownNumber, Is.EqualTo(head), "loaded tree"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Cannot_insert_genesis() + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cannot_insert_genesis() + { + long pivotNumber = 0L; + + SyncConfig syncConfig = new() { - long pivotNumber = 0L; + PivotNumber = pivotNumber.ToString(), + }; - SyncConfig syncConfig = new() - { - PivotNumber = pivotNumber.ToString(), - }; + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .WithSyncConfig(syncConfig) + .TestObject; - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .WithSyncConfig(syncConfig) - .TestObject; + Block genesis = Build.A.Block.Genesis.TestObject; + tree.SuggestBlock(genesis); + Assert.Throws(() => tree.Insert(genesis)); + Assert.Throws(() => tree.Insert(genesis.Header)); + } - Block genesis = Build.A.Block.Genesis.TestObject; - tree.SuggestBlock(genesis); - Assert.Throws(() => tree.Insert(genesis)); - Assert.Throws(() => tree.Insert(genesis.Header)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Should_set_zero_total_difficulty() + { + long pivotNumber = 0L; - [Test, Timeout(Timeout.MaxTestTime)] - public void Should_set_zero_total_difficulty() + SyncConfig syncConfig = new() { - long pivotNumber = 0L; + PivotNumber = pivotNumber.ToString(), + }; - SyncConfig syncConfig = new() - { - PivotNumber = pivotNumber.ToString(), - }; + CustomSpecProvider specProvider = new(((ForkActivation)0, London.Instance)); + specProvider.UpdateMergeTransitionInfo(null, 0); - CustomSpecProvider specProvider = new(((ForkActivation)0, London.Instance)); - specProvider.UpdateMergeTransitionInfo(null, 0); + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .WithSyncConfig(syncConfig) + .WithSpecProvider(specProvider) + .TestObject; - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .WithSyncConfig(syncConfig) - .WithSpecProvider(specProvider) - .TestObject; + Block genesis = Build.A.Block.WithDifficulty(0).TestObject; + tree.SuggestBlock(genesis).Should().Be(AddBlockResult.Added); + tree.FindBlock(genesis.Hash, BlockTreeLookupOptions.None)!.TotalDifficulty.Should().Be(UInt256.Zero); - Block genesis = Build.A.Block.WithDifficulty(0).TestObject; - tree.SuggestBlock(genesis).Should().Be(AddBlockResult.Added); - tree.FindBlock(genesis.Hash, BlockTreeLookupOptions.None)!.TotalDifficulty.Should().Be(UInt256.Zero); + Block A = Build.A.Block.WithParent(genesis).WithDifficulty(0).TestObject; + tree.SuggestBlock(A).Should().Be(AddBlockResult.Added); + tree.FindBlock(A.Hash, BlockTreeLookupOptions.None)!.TotalDifficulty.Should().Be(UInt256.Zero); + } - Block A = Build.A.Block.WithParent(genesis).WithDifficulty(0).TestObject; - tree.SuggestBlock(A).Should().Be(AddBlockResult.Added); - tree.FindBlock(A.Hash, BlockTreeLookupOptions.None)!.TotalDifficulty.Should().Be(UInt256.Zero); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Inserts_blooms() + { + long pivotNumber = 5L; - [Test, Timeout(Timeout.MaxTestTime)] - public void Inserts_blooms() + SyncConfig syncConfig = new() { - long pivotNumber = 5L; - - SyncConfig syncConfig = new() - { - PivotNumber = pivotNumber.ToString(), - }; + PivotNumber = pivotNumber.ToString(), + }; - IBloomStorage bloomStorage = Substitute.For(); - IChainLevelInfoRepository chainLevelInfoRepository = Substitute.For(); + IBloomStorage bloomStorage = Substitute.For(); + IChainLevelInfoRepository chainLevelInfoRepository = Substitute.For(); - BlockTree tree = Build.A.BlockTree() - .WithChainLevelInfoRepository(chainLevelInfoRepository) - .WithBloomStorage(bloomStorage) - .WithSyncConfig(syncConfig) - .TestObject; + BlockTree tree = Build.A.BlockTree() + .WithChainLevelInfoRepository(chainLevelInfoRepository) + .WithBloomStorage(bloomStorage) + .WithSyncConfig(syncConfig) + .TestObject; - tree.SuggestBlock(Build.A.Block.Genesis.TestObject); + tree.SuggestBlock(Build.A.Block.Genesis.TestObject); - for (long i = 5; i > 0; i--) + for (long i = 5; i > 0; i--) + { + Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(1L).TestObject; + tree.Insert(block.Header); + Received.InOrder(() => { - Block block = Build.A.Block.WithNumber(i).WithTotalDifficulty(1L).TestObject; - tree.Insert(block.Header); - Received.InOrder(() => - { - bloomStorage.Store(block.Header.Number, block.Bloom!); - chainLevelInfoRepository.PersistLevel(block.Header.Number, Arg.Any(), Arg.Any()); - }); - } + bloomStorage.Store(block.Header.Number, block.Bloom!); + chainLevelInfoRepository.PersistLevel(block.Header.Number, Arg.Any(), Arg.Any()); + }); } + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Block_loading_is_lazy() + [Test, MaxTime(Timeout.MaxTestTime)] + public void Block_loading_is_lazy() + { + SyncConfig syncConfig = new() { - SyncConfig syncConfig = new() - { - PivotNumber = 0L.ToString(), - }; - - BlockTreeBuilder builder = Build.A.BlockTree() - .WithSyncConfig(syncConfig); - BlockTree tree = builder - .TestObject; - - Block genesis = Build.A.Block.Genesis.TestObject; - tree.SuggestBlock(genesis); - - Block previousBlock = genesis; - for (int i = 1; i < 10; i++) - { - Block block = Build.A.Block.WithNumber(i).WithParent(previousBlock).TestObject; - tree.SuggestBlock(block); - previousBlock = block; - } + PivotNumber = 0L.ToString(), + }; - Block lastBlock = previousBlock; + BlockTreeBuilder builder = Build.A.BlockTree() + .WithSyncConfig(syncConfig); + BlockTree tree = builder + .TestObject; - BlockTree loadedTree = Build.A.BlockTree() - .WithoutSettingHead - .WithSyncConfig(syncConfig) - .WithDatabaseFrom(builder) - .TestObject; - loadedTree.FindHeader(lastBlock.Hash, BlockTreeLookupOptions.None); - } + Block genesis = Build.A.Block.Genesis.TestObject; + tree.SuggestBlock(genesis); - [Test, Timeout(Timeout.MaxTestTime)] - public void When_block_is_moved_to_main_blooms_are_stored() + Block previousBlock = genesis; + for (int i = 1; i < 10; i++) { - Transaction t1 = Build.A.Transaction.TestObject; - Transaction t2 = Build.A.Transaction.TestObject; - - IBloomStorage bloomStorage = Substitute.For(); - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithBloomStorage(bloomStorage) - .TestObject; - // new(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), OlympicSpecProvider.Instance, bloomStorage, LimboLogs.Instance); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1A = Build.A.Block.WithNumber(1).WithDifficulty(2).WithTransactions(t1).WithParent(block0).TestObject; - Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(3).WithTransactions(t2).WithParent(block0).TestObject; + Block block = Build.A.Block.WithNumber(i).WithParent(previousBlock).TestObject; + tree.SuggestBlock(block); + previousBlock = block; + } - AddToMain(blockTree, block0); + Block lastBlock = previousBlock; - blockTree.SuggestBlock(block1B); - blockTree.SuggestBlock(block1A); - blockTree.UpdateMainChain(block1A); + BlockTree loadedTree = Build.A.BlockTree() + .WithoutSettingHead + .WithSyncConfig(syncConfig) + .WithDatabaseFrom(builder) + .TestObject; + loadedTree.FindHeader(lastBlock.Hash, BlockTreeLookupOptions.None); + } - bloomStorage.Received().Store(block1A.Number, block1A.Bloom!); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_block_is_moved_to_main_blooms_are_stored() + { + Transaction t1 = Build.A.Transaction.TestObject; + Transaction t2 = Build.A.Transaction.TestObject; + + IBloomStorage bloomStorage = Substitute.For(); + BlockTree blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithBloomStorage(bloomStorage) + .TestObject; + // new(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), OlympicSpecProvider.Instance, bloomStorage, LimboLogs.Instance); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1A = Build.A.Block.WithNumber(1).WithDifficulty(2).WithTransactions(t1).WithParent(block0).TestObject; + Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(3).WithTransactions(t2).WithParent(block0).TestObject; + + AddToMain(blockTree, block0); + + blockTree.SuggestBlock(block1B); + blockTree.SuggestBlock(block1A); + blockTree.UpdateMainChain(block1A); + + bloomStorage.Received().Store(block1A.Number, block1A.Bloom!); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_find_genesis_level() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - ChainLevelInfo info = blockTree.FindLevel(0)!; - Assert.True(info.HasBlockOnMainChain); - Assert.That(info.BlockInfos.Length, Is.EqualTo(1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_find_genesis_level() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + ChainLevelInfo info = blockTree.FindLevel(0)!; + Assert.That(info.HasBlockOnMainChain, Is.True); + Assert.That(info.BlockInfos.Length, Is.EqualTo(1)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_find_some_level() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - ChainLevelInfo info = blockTree.FindLevel(1)!; - Assert.True(info.HasBlockOnMainChain); - Assert.That(info.BlockInfos.Length, Is.EqualTo(1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_find_some_level() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + ChainLevelInfo info = blockTree.FindLevel(1)!; + Assert.That(info.HasBlockOnMainChain, Is.True); + Assert.That(info.BlockInfos.Length, Is.EqualTo(1)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Cannot_find_future_level() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - ChainLevelInfo info = blockTree.FindLevel(1000)!; - Assert.IsNull(info); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cannot_find_future_level() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + ChainLevelInfo info = blockTree.FindLevel(1000)!; + Assert.That(info, Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_delete_a_future_slice() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.DeleteChainSlice(1000, 2000); - Assert.That(blockTree.Head!.Number, Is.EqualTo(2)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_delete_a_future_slice() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.DeleteChainSlice(1000, 2000); + Assert.That(blockTree.Head!.Number, Is.EqualTo(2)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_delete_slice() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.DeleteChainSlice(2, 2); - Assert.Null(blockTree.FindBlock(2, BlockTreeLookupOptions.None)); - Assert.Null(blockTree.FindHeader(2, BlockTreeLookupOptions.None)); - Assert.Null(blockTree.FindLevel(2)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_delete_slice() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.DeleteChainSlice(2, 2); + Assert.That(blockTree.FindBlock(2, BlockTreeLookupOptions.None), Is.Null); + Assert.That(blockTree.FindHeader(2, BlockTreeLookupOptions.None), Is.Null); + Assert.That(blockTree.FindLevel(2), Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Does_not_delete_outside_of_the_slice() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.DeleteChainSlice(2, 2); - Assert.NotNull(blockTree.FindBlock(1, BlockTreeLookupOptions.None)); - Assert.NotNull(blockTree.FindHeader(1, BlockTreeLookupOptions.None)); - Assert.NotNull(blockTree.FindLevel(1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Does_not_delete_outside_of_the_slice() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.DeleteChainSlice(2, 2); + Assert.That(blockTree.FindBlock(1, BlockTreeLookupOptions.None), Is.Not.Null); + Assert.That(blockTree.FindHeader(1, BlockTreeLookupOptions.None), Is.Not.Null); + Assert.That(blockTree.FindLevel(1), Is.Not.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_delete_one_block() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.DeleteChainSlice(2, 2); - Assert.That(blockTree.Head!.Number, Is.EqualTo(1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_delete_one_block() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.DeleteChainSlice(2, 2); + Assert.That(blockTree.Head!.Number, Is.EqualTo(1)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_delete_two_blocks() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.DeleteChainSlice(1, 2); - Assert.Null(blockTree.FindLevel(1)); - Assert.Null(blockTree.FindLevel(2)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_delete_two_blocks() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.DeleteChainSlice(1, 2); + Assert.That(blockTree.FindLevel(1), Is.Null); + Assert.That(blockTree.FindLevel(2), Is.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_delete_in_the_middle() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.DeleteChainSlice(1, 1); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_delete_in_the_middle() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.DeleteChainSlice(1, 1); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Throws_when_start_after_end() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - Assert.Throws(() => blockTree.DeleteChainSlice(2, 1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Throws_when_start_after_end() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + Assert.Throws(() => blockTree.DeleteChainSlice(2, 1)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Throws_when_start_at_zero() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - Assert.Throws(() => blockTree.DeleteChainSlice(0, 1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Throws_when_start_at_zero() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + Assert.Throws(() => blockTree.DeleteChainSlice(0, 1)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Throws_when_start_below_zero() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - Assert.Throws(() => blockTree.DeleteChainSlice(-1, 1)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Throws_when_start_below_zero() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + Assert.Throws(() => blockTree.DeleteChainSlice(-1, 1)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Cannot_delete_too_many() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - Assert.Throws(() => blockTree.DeleteChainSlice(1000, 52001)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cannot_delete_too_many() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + Assert.Throws(() => blockTree.DeleteChainSlice(1000, 52001)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Cannot_add_blocks_when_blocked() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.BlockAcceptingNewBlocks(); - blockTree.SuggestBlock(Build.A.Block.WithNumber(3).TestObject).Should().Be(AddBlockResult.CannotAccept); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cannot_add_blocks_when_blocked() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.BlockAcceptingNewBlocks(); + blockTree.SuggestBlock(Build.A.Block.WithNumber(3).TestObject).Should().Be(AddBlockResult.CannotAccept); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_block_cannot_insert_blocks() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.CanAcceptNewBlocks.Should().BeTrue(); - blockTree.BlockAcceptingNewBlocks(); - blockTree.CanAcceptNewBlocks.Should().BeFalse(); - Block newBlock = Build.A.Block.WithNumber(3).TestObject; - AddBlockResult result = blockTree.Insert(newBlock); - result.Should().Be(AddBlockResult.CannotAccept); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_block_cannot_insert_blocks() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.CanAcceptNewBlocks.Should().BeTrue(); + blockTree.BlockAcceptingNewBlocks(); + blockTree.CanAcceptNewBlocks.Should().BeFalse(); + Block newBlock = Build.A.Block.WithNumber(3).TestObject; + AddBlockResult result = blockTree.Insert(newBlock); + result.Should().Be(AddBlockResult.CannotAccept); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_skip_blocked_tree() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.CanAcceptNewBlocks.Should().BeTrue(); - blockTree.BlockAcceptingNewBlocks(); - blockTree.CanAcceptNewBlocks.Should().BeFalse(); - Block newBlock = Build.A.Block.WithNumber(3).TestObject; - AddBlockResult result = blockTree.Insert(newBlock, BlockTreeInsertBlockOptions.SkipCanAcceptNewBlocks); - result.Should().Be(AddBlockResult.Added); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_skip_blocked_tree() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.CanAcceptNewBlocks.Should().BeTrue(); + blockTree.BlockAcceptingNewBlocks(); + blockTree.CanAcceptNewBlocks.Should().BeFalse(); + Block newBlock = Build.A.Block.WithNumber(3).TestObject; + AddBlockResult result = blockTree.Insert(newBlock, BlockTreeInsertBlockOptions.SkipCanAcceptNewBlocks); + result.Should().Be(AddBlockResult.Added); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_block_and_unblock_adding_blocks() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.CanAcceptNewBlocks.Should().BeTrue(); - blockTree.BlockAcceptingNewBlocks(); - blockTree.CanAcceptNewBlocks.Should().BeFalse(); - blockTree.BlockAcceptingNewBlocks(); - blockTree.ReleaseAcceptingNewBlocks(); - blockTree.CanAcceptNewBlocks.Should().BeFalse(); - blockTree.ReleaseAcceptingNewBlocks(); - blockTree.CanAcceptNewBlocks.Should().BeTrue(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_block_and_unblock_adding_blocks() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.CanAcceptNewBlocks.Should().BeTrue(); + blockTree.BlockAcceptingNewBlocks(); + blockTree.CanAcceptNewBlocks.Should().BeFalse(); + blockTree.BlockAcceptingNewBlocks(); + blockTree.ReleaseAcceptingNewBlocks(); + blockTree.CanAcceptNewBlocks.Should().BeFalse(); + blockTree.ReleaseAcceptingNewBlocks(); + blockTree.CanAcceptNewBlocks.Should().BeTrue(); + } - [Timeout(Timeout.MaxTestTime)] - [TestCase(10, false, 10000000ul)] - [TestCase(4, false, 4000000ul)] - [TestCase(10, true, 10000000ul)] - public void Recovers_total_difficulty(int chainLength, bool deleteAllLevels, ulong expectedTotalDifficulty) + [MaxTime(Timeout.MaxTestTime)] + [TestCase(10, false, 10000000ul)] + [TestCase(4, false, 4000000ul)] + [TestCase(10, true, 10000000ul)] + public void Recovers_total_difficulty(int chainLength, bool deleteAllLevels, ulong expectedTotalDifficulty) + { + BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree().OfChainLength(chainLength); + BlockTree blockTree = blockTreeBuilder.TestObject; + int chainLeft = deleteAllLevels ? 0 : 1; + for (int i = chainLength - 1; i >= chainLeft; i--) { - BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree().OfChainLength(chainLength); - BlockTree blockTree = blockTreeBuilder.TestObject; - int chainLeft = deleteAllLevels ? 0 : 1; - for (int i = chainLength - 1; i >= chainLeft; i--) + ChainLevelInfo? level = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i); + if (level is not null) { - ChainLevelInfo? level = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i); - if (level is not null) + for (int j = 0; j < level.BlockInfos.Length; j++) { - for (int j = 0; j < level.BlockInfos.Length; j++) + Hash256 blockHash = level.BlockInfos[j].BlockHash; + BlockHeader? header = blockTree.FindHeader(blockHash, BlockTreeLookupOptions.None); + if (header is not null) { - Hash256 blockHash = level.BlockInfos[j].BlockHash; - BlockHeader? header = blockTree.FindHeader(blockHash, BlockTreeLookupOptions.None); - if (header is not null) - { - header.TotalDifficulty = null; - } + header.TotalDifficulty = null; } - - blockTreeBuilder.ChainLevelInfoRepository.Delete(i); } - } - - blockTree.FindBlock(blockTree.Head!.Hash, BlockTreeLookupOptions.None)!.TotalDifficulty.Should() - .Be(new UInt256(expectedTotalDifficulty)); - for (int i = chainLength - 1; i >= 0; i--) - { - ChainLevelInfo? level = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i); - - level.Should().NotBeNull(); - level!.BlockInfos.Should().HaveCount(1); + blockTreeBuilder.ChainLevelInfoRepository.Delete(i); } } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Visitor_can_block_adding_blocks() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - ManualResetEvent manualResetEvent = new ManualResetEvent(false); - Task acceptTask = blockTree.Accept(new TestBlockTreeVisitor(manualResetEvent), CancellationToken.None); - blockTree.CanAcceptNewBlocks.Should().BeFalse(); - manualResetEvent.Set(); - await acceptTask; - } + blockTree.FindBlock(blockTree.Head!.Hash, BlockTreeLookupOptions.None)!.TotalDifficulty.Should() + .Be(new UInt256(expectedTotalDifficulty)); - [Test, Timeout(Timeout.MaxTestTime)] - public async Task SuggestBlockAsync_should_wait_for_blockTree_unlock() + for (int i = chainLength - 1; i >= 0; i--) { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.BlockAcceptingNewBlocks(); - ValueTask suggest = blockTree.SuggestBlockAsync(Build.A.Block.WithNumber(3).TestObject); - suggest.IsCompleted.Should().Be(false); - blockTree.ReleaseAcceptingNewBlocks(); - await suggest; - suggest.IsCompleted.Should().Be(true); - } + ChainLevelInfo? level = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i); - [Test, Timeout(Timeout.MaxTestTime)] - public async Task SuggestBlockAsync_works_well_with_multiple_locks_and_unlocks() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - blockTree.BlockAcceptingNewBlocks(); // 1st blockade - blockTree.ReleaseAcceptingNewBlocks(); // release - access unlocked - blockTree.BlockAcceptingNewBlocks(); // 1st blockade - blockTree.BlockAcceptingNewBlocks(); // 2nd blockade - blockTree.BlockAcceptingNewBlocks(); // 3rd blockade - ValueTask suggest = blockTree.SuggestBlockAsync(Build.A.Block.WithNumber(3).TestObject); - suggest.IsCompleted.Should().Be(false); - blockTree.ReleaseAcceptingNewBlocks(); // 1st release - 2 blockades left - suggest.IsCompleted.Should().Be(false); - blockTree.ReleaseAcceptingNewBlocks(); // 2nd release - 1 blockade left - suggest.IsCompleted.Should().Be(false); - blockTree.BlockAcceptingNewBlocks(); // 1 more blockade - 2 blockades left - suggest.IsCompleted.Should().Be(false); - blockTree.ReleaseAcceptingNewBlocks(); // release - 1 blockade left - suggest.IsCompleted.Should().Be(false); - blockTree.ReleaseAcceptingNewBlocks(); // 3rd release - access unlocked - await suggest; - suggest.IsCompleted.Should().Be(true); + level.Should().NotBeNull(); + level!.BlockInfos.Should().HaveCount(1); } + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task SuggestBlockAsync_works_well_when_there_are_no_blockades() - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - ValueTask suggest = blockTree.SuggestBlockAsync(Build.A.Block.WithNumber(3).TestObject); - await suggest; - suggest.IsCompleted.Should().Be(true); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Visitor_can_block_adding_blocks() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + ManualResetEvent manualResetEvent = new ManualResetEvent(false); + Task acceptTask = blockTree.Accept(new TestBlockTreeVisitor(manualResetEvent), CancellationToken.None); + blockTree.CanAcceptNewBlocks.Should().BeFalse(); + manualResetEvent.Set(); + await acceptTask; + } - [Test, Timeout(Timeout.MaxTestTime)] - public void SuggestBlock_should_work_with_zero_difficulty() - { - Block genesisWithZeroDifficulty = Build.A.Block.WithDifficulty(0).WithNumber(0).TestObject; - CustomSpecProvider specProvider = new(((ForkActivation)0, GrayGlacier.Instance)); - specProvider.UpdateMergeTransitionInfo(null, 0); - BlockTree blockTree = Build.A.BlockTree(genesisWithZeroDifficulty, specProvider).OfChainLength(1).TestObject; - - Block block = Build.A.Block.WithDifficulty(0).WithParent(genesisWithZeroDifficulty).TestObject; - blockTree.SuggestBlock(block).Should().Be(AddBlockResult.Added); - blockTree.SuggestBlock(Build.A.Block.WithParent(block).WithDifficulty(0).TestObject).Should().Be(AddBlockResult.Added); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task SuggestBlockAsync_should_wait_for_blockTree_unlock() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.BlockAcceptingNewBlocks(); + ValueTask suggest = blockTree.SuggestBlockAsync(Build.A.Block.WithNumber(3).TestObject); + suggest.IsCompleted.Should().Be(false); + blockTree.ReleaseAcceptingNewBlocks(); + await suggest; + suggest.IsCompleted.Should().Be(true); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void BlockAddedToMain_should_have_updated_Head() - { - BlockTree blockTree = BuildBlockTree(); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - AddToMain(blockTree, block0); + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task SuggestBlockAsync_works_well_with_multiple_locks_and_unlocks() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + blockTree.BlockAcceptingNewBlocks(); // 1st blockade + blockTree.ReleaseAcceptingNewBlocks(); // release - access unlocked + blockTree.BlockAcceptingNewBlocks(); // 1st blockade + blockTree.BlockAcceptingNewBlocks(); // 2nd blockade + blockTree.BlockAcceptingNewBlocks(); // 3rd blockade + ValueTask suggest = blockTree.SuggestBlockAsync(Build.A.Block.WithNumber(3).TestObject); + suggest.IsCompleted.Should().Be(false); + blockTree.ReleaseAcceptingNewBlocks(); // 1st release - 2 blockades left + suggest.IsCompleted.Should().Be(false); + blockTree.ReleaseAcceptingNewBlocks(); // 2nd release - 1 blockade left + suggest.IsCompleted.Should().Be(false); + blockTree.BlockAcceptingNewBlocks(); // 1 more blockade - 2 blockades left + suggest.IsCompleted.Should().Be(false); + blockTree.ReleaseAcceptingNewBlocks(); // release - 1 blockade left + suggest.IsCompleted.Should().Be(false); + blockTree.ReleaseAcceptingNewBlocks(); // 3rd release - access unlocked + await suggest; + suggest.IsCompleted.Should().Be(true); + } - long blockAddedToMainHeadNumber = 0; - blockTree.BlockAddedToMain += (_, _) => { blockAddedToMainHeadNumber = blockTree.Head!.Header.Number; }; + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task SuggestBlockAsync_works_well_when_there_are_no_blockades() + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + ValueTask suggest = blockTree.SuggestBlockAsync(Build.A.Block.WithNumber(3).TestObject); + await suggest; + suggest.IsCompleted.Should().Be(true); + } - AddToMain(blockTree, block1); + [Test, MaxTime(Timeout.MaxTestTime)] + public void SuggestBlock_should_work_with_zero_difficulty() + { + Block genesisWithZeroDifficulty = Build.A.Block.WithDifficulty(0).WithNumber(0).TestObject; + CustomSpecProvider specProvider = new(((ForkActivation)0, GrayGlacier.Instance)); + specProvider.UpdateMergeTransitionInfo(null, 0); + BlockTree blockTree = Build.A.BlockTree(genesisWithZeroDifficulty, specProvider).OfChainLength(1).TestObject; + + Block block = Build.A.Block.WithDifficulty(0).WithParent(genesisWithZeroDifficulty).TestObject; + blockTree.SuggestBlock(block).Should().Be(AddBlockResult.Added); + blockTree.SuggestBlock(Build.A.Block.WithParent(block).WithDifficulty(0).TestObject).Should().Be(AddBlockResult.Added); + } - Assert.That(blockAddedToMainHeadNumber, Is.EqualTo(blockTree.Head!.Number)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void BlockAddedToMain_should_have_updated_Head() + { + BlockTree blockTree = BuildBlockTree(); + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + AddToMain(blockTree, block0); - public static IEnumerable InvalidBlockTestCases - { - get - { - BlockHeader? FindHeader(BlockTree b, Hash256? h, BlockTreeLookupOptions o) => b.FindHeader(h, o); - BlockHeader? FindBlock(BlockTree b, Hash256? h, BlockTreeLookupOptions o) => b.FindBlock(h, o)?.Header; + long blockAddedToMainHeadNumber = 0; + blockTree.BlockAddedToMain += (_, _) => { blockAddedToMainHeadNumber = blockTree.Head!.Header.Number; }; - IReadOnlyList valueCombinations = EnumExtensions.AllValuesCombinations(); - foreach (BlockTreeLookupOptions blockTreeLookupOptions in valueCombinations) - { - bool allowInvalid = (blockTreeLookupOptions & BlockTreeLookupOptions.AllowInvalid) == BlockTreeLookupOptions.AllowInvalid; - yield return new TestCaseData((Func)FindHeader, blockTreeLookupOptions, allowInvalid) - { - TestName = $"InvalidBlock_{nameof(FindHeader)}_({blockTreeLookupOptions})_{(allowInvalid ? "found" : "not_found")}" - }; - yield return new TestCaseData((Func)FindBlock, blockTreeLookupOptions, allowInvalid) - { - TestName = $"InvalidBlock_{nameof(FindBlock)}_({blockTreeLookupOptions})_{(allowInvalid ? "found" : "not_found")}" - }; - } - } - } + AddToMain(blockTree, block1); - [TestCaseSource(nameof(InvalidBlockTestCases))] - public void Find_handles_invalid_blocks(Func findFunction, BlockTreeLookupOptions lookupOptions, bool foundInvalid) - { - BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; - Block invalidBlock = Build.A.Block.WithNumber(4).WithParent(blockTree.Head!).TestObject; - blockTree.SuggestBlock(invalidBlock); - blockTree.DeleteInvalidBlock(invalidBlock); - findFunction(blockTree, invalidBlock.Hash, lookupOptions).Should().Be(foundInvalid ? invalidBlock.Header : null); - } + Assert.That(blockAddedToMainHeadNumber, Is.EqualTo(blockTree.Head!.Number)); + } - [TestCase(true)] - [TestCase(false)] - public void On_restart_loads_already_processed_genesis_block(bool wereProcessed) + public static IEnumerable InvalidBlockTestCases + { + get { - TestMemDb blocksDb = new(); - TestMemDb headersDb = new(); - TestMemDb blockNumberDb = new(); - TestMemDb blocksInfosDb = new(); - ChainLevelInfoRepository chainLevelInfoRepository = new(blocksInfosDb); + BlockHeader? FindHeader(BlockTree b, Hash256? h, BlockTreeLookupOptions o) => b.FindHeader(h, o); + BlockHeader? FindBlock(BlockTree b, Hash256? h, BlockTreeLookupOptions o) => b.FindBlock(h, o)?.Header; - // First run + IReadOnlyList valueCombinations = EnumExtensions.AllValuesCombinations(); + foreach (BlockTreeLookupOptions blockTreeLookupOptions in valueCombinations) { - Hash256 uncleHash = new("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); - BlockTree tree = Build.A.BlockTree(HoleskySpecProvider.Instance) - .WithBlockStore(new BlockStore(blocksDb)) - .WithBlocksNumberDb(blockNumberDb) - .WithHeadersDb(headersDb) - .WithChainLevelInfoRepository(chainLevelInfoRepository) - .WithoutSettingHead - .TestObject; - - // Holesky genesis - Block genesis = new(new( - parentHash: Keccak.Zero, - unclesHash: uncleHash, - beneficiary: new Address(Keccak.Zero), - difficulty: 1, - number: 0, - gasLimit: 25000000, - timestamp: 1695902100, - extraData: Array.Empty()) + bool allowInvalid = (blockTreeLookupOptions & BlockTreeLookupOptions.AllowInvalid) == BlockTreeLookupOptions.AllowInvalid; + yield return new TestCaseData((Func)FindHeader, blockTreeLookupOptions, allowInvalid) { - Hash = new Hash256("0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4"), - Bloom = Core.Bloom.Empty - }); - - // Second block - Block second = new(new( - parentHash: genesis.Header.Hash!, - unclesHash: uncleHash, - beneficiary: new Address(Keccak.Zero), - difficulty: 0, - number: genesis.Header.Number + 1, - gasLimit: 25000000, - timestamp: genesis.Header.Timestamp + 100, - extraData: Array.Empty()) + TestName = $"InvalidBlock_{nameof(FindHeader)}_({blockTreeLookupOptions})_{(allowInvalid ? "found" : "not_found")}" + }; + yield return new TestCaseData((Func)FindBlock, blockTreeLookupOptions, allowInvalid) { - Hash = new Hash256("0x1111111111111111111111111111111111111111111111111111111111111111"), - Bloom = Core.Bloom.Empty, - StateRoot = genesis.Header.Hash, - }); - - // Third block - Block third = new(new( - parentHash: second.Header.Hash!, - unclesHash: uncleHash, - beneficiary: new Address(Keccak.Zero), - difficulty: 0, - number: second.Header.Number + 1, - gasLimit: 25000000, - timestamp: second.Header.Timestamp + 100, - extraData: Array.Empty()) - { - Hash = new Hash256("0x2222222222222222222222222222222222222222222222222222222222222222"), - Bloom = Core.Bloom.Empty, - StateRoot = genesis.Header.Hash, - }); - - tree.SuggestBlock(genesis); - tree.Genesis.Should().NotBeNull(); + TestName = $"InvalidBlock_{nameof(FindBlock)}_({blockTreeLookupOptions})_{(allowInvalid ? "found" : "not_found")}" + }; + } + } + } - tree.UpdateMainChain(ImmutableList.Create(genesis), wereProcessed); + [TestCaseSource(nameof(InvalidBlockTestCases))] + public void Find_handles_invalid_blocks(Func findFunction, BlockTreeLookupOptions lookupOptions, bool foundInvalid) + { + BlockTree blockTree = Build.A.BlockTree().OfChainLength(3).TestObject; + Block invalidBlock = Build.A.Block.WithNumber(4).WithParent(blockTree.Head!).TestObject; + blockTree.SuggestBlock(invalidBlock); + blockTree.DeleteInvalidBlock(invalidBlock); + findFunction(blockTree, invalidBlock.Hash, lookupOptions).Should().Be(foundInvalid ? invalidBlock.Header : null); + } - tree.SuggestBlock(second); - tree.SuggestBlock(third); - } + [TestCase(true)] + [TestCase(false)] + public void On_restart_loads_already_processed_genesis_block(bool wereProcessed) + { + TestMemDb blocksDb = new(); + TestMemDb headersDb = new(); + TestMemDb blockNumberDb = new(); + TestMemDb blocksInfosDb = new(); + ChainLevelInfoRepository chainLevelInfoRepository = new(blocksInfosDb); + + // First run + { + Hash256 uncleHash = new("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); + BlockTree tree = Build.A.BlockTree(HoleskySpecProvider.Instance) + .WithBlockStore(new BlockStore(blocksDb)) + .WithBlocksNumberDb(blockNumberDb) + .WithHeadersDb(headersDb) + .WithChainLevelInfoRepository(chainLevelInfoRepository) + .WithoutSettingHead + .TestObject; - // Assume Nethermind got restarted + // Holesky genesis + Block genesis = new(new( + parentHash: Keccak.Zero, + unclesHash: uncleHash, + beneficiary: new Address(Keccak.Zero), + difficulty: 1, + number: 0, + gasLimit: 25000000, + timestamp: 1695902100, + extraData: Array.Empty()) { - BlockTree tree = Build.A.BlockTree(HoleskySpecProvider.Instance) - .WithBlockStore(new BlockStore(blocksDb)) - .WithBlocksNumberDb(blockNumberDb) - .WithHeadersDb(headersDb) - .WithChainLevelInfoRepository(chainLevelInfoRepository) - .WithoutSettingHead - .TestObject; - - tree.Genesis.Should().NotBeNull(); - } + Hash = new Hash256("0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4"), + Bloom = Core.Bloom.Empty + }); + + // Second block + Block second = new(new( + parentHash: genesis.Header.Hash!, + unclesHash: uncleHash, + beneficiary: new Address(Keccak.Zero), + difficulty: 0, + number: genesis.Header.Number + 1, + gasLimit: 25000000, + timestamp: genesis.Header.Timestamp + 100, + extraData: Array.Empty()) + { + Hash = new Hash256("0x1111111111111111111111111111111111111111111111111111111111111111"), + Bloom = Core.Bloom.Empty, + StateRoot = genesis.Header.Hash, + }); + + // Third block + Block third = new(new( + parentHash: second.Header.Hash!, + unclesHash: uncleHash, + beneficiary: new Address(Keccak.Zero), + difficulty: 0, + number: second.Header.Number + 1, + gasLimit: 25000000, + timestamp: second.Header.Timestamp + 100, + extraData: Array.Empty()) + { + Hash = new Hash256("0x2222222222222222222222222222222222222222222222222222222222222222"), + Bloom = Core.Bloom.Empty, + StateRoot = genesis.Header.Hash, + }); + + tree.SuggestBlock(genesis); + tree.Genesis.Should().NotBeNull(); + + tree.UpdateMainChain(ImmutableList.Create(genesis), wereProcessed); + + tree.SuggestBlock(second); + tree.SuggestBlock(third); } - private class TestBlockTreeVisitor : IBlockTreeVisitor + // Assume Nethermind got restarted { - private readonly ManualResetEvent _manualResetEvent; - private bool _wait = true; + BlockTree tree = Build.A.BlockTree(HoleskySpecProvider.Instance) + .WithBlockStore(new BlockStore(blocksDb)) + .WithBlocksNumberDb(blockNumberDb) + .WithHeadersDb(headersDb) + .WithChainLevelInfoRepository(chainLevelInfoRepository) + .WithoutSettingHead + .TestObject; - public TestBlockTreeVisitor(ManualResetEvent manualResetEvent) - { - _manualResetEvent = manualResetEvent; - } + tree.Genesis.Should().NotBeNull(); + } + } - public bool PreventsAcceptingNewBlocks => true; - public long StartLevelInclusive => 0; - public long EndLevelExclusive => 3; - public async Task VisitLevelStart(ChainLevelInfo chainLevelInfo, long levelNumber, CancellationToken cancellationToken) - { - if (_wait) - { - await _manualResetEvent.WaitOneAsync(cancellationToken); - _wait = false; - } + private class TestBlockTreeVisitor : IBlockTreeVisitor + { + private readonly ManualResetEvent _manualResetEvent; + private bool _wait = true; - return LevelVisitOutcome.None; - } + public TestBlockTreeVisitor(ManualResetEvent manualResetEvent) + { + _manualResetEvent = manualResetEvent; + } - public Task VisitMissing(Hash256 hash, CancellationToken cancellationToken) + public bool PreventsAcceptingNewBlocks => true; + public long StartLevelInclusive => 0; + public long EndLevelExclusive => 3; + public async Task VisitLevelStart(ChainLevelInfo chainLevelInfo, long levelNumber, CancellationToken cancellationToken) + { + if (_wait) { - return Task.FromResult(true); + await _manualResetEvent.WaitOneAsync(cancellationToken); + _wait = false; } - public Task VisitHeader(BlockHeader header, CancellationToken cancellationToken) - { - return Task.FromResult(HeaderVisitOutcome.None); - } + return LevelVisitOutcome.None; + } - public Task VisitBlock(Block block, CancellationToken cancellationToken) - { - return Task.FromResult(BlockVisitOutcome.None); - } + public Task VisitMissing(Hash256 hash, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } - public Task VisitLevelEnd(ChainLevelInfo chainLevelInfo, long levelNumber, CancellationToken cancellationToken) - { - return Task.FromResult(LevelVisitOutcome.None); - } + public Task VisitHeader(BlockHeader header, CancellationToken cancellationToken) + { + return Task.FromResult(HeaderVisitOutcome.None); + } + + public Task VisitBlock(Block block, CancellationToken cancellationToken) + { + return Task.FromResult(BlockVisitOutcome.None); + } + + public Task VisitLevelEnd(ChainLevelInfo chainLevelInfo, long levelNumber, CancellationToken cancellationToken) + { + return Task.FromResult(LevelVisitOutcome.None); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs index 41bc3472f20..b76b5822a8e 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs @@ -13,720 +13,714 @@ using Nethermind.Core.Attributes; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Blockchain; -using Nethermind.Specs; using Nethermind.Core.Test.Builders; -using Nethermind.Db; using Nethermind.Evm.Tracing; using Nethermind.Logging; -using Nethermind.State.Repositories; -using Nethermind.Db.Blooms; using Nethermind.State; using Nethermind.Trie; using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +[Parallelizable(ParallelScope.Self)] +public class BlockchainProcessorTests { - [TestFixture] - [Parallelizable(ParallelScope.Self)] - public class BlockchainProcessorTests + private class ProcessingTestContext { - private class ProcessingTestContext + private readonly ILogManager _logManager = LimboLogs.Instance; + + private class BlockProcessorMock : IBlockProcessor { - private readonly ILogManager _logManager = LimboLogs.Instance; + private readonly ILogger _logger; - private class BlockProcessorMock : IBlockProcessor - { - private readonly ILogger _logger; + private readonly HashSet _allowed = new(); - private readonly HashSet _allowed = new(); + private readonly HashSet _allowedToFail = new(); - private readonly HashSet _allowedToFail = new(); + private readonly HashSet _rootProcessed = new(); - private readonly HashSet _rootProcessed = new(); + public BlockProcessorMock(ILogManager logManager, IStateReader stateReader) + { + _logger = logManager.GetClassLogger(); + stateReader.When(it => + it.RunTreeVisitor(Arg.Any(), Arg.Any(), Arg.Any())) + .Do((info => + { + // Simulate state root check + ITreeVisitor visitor = (ITreeVisitor)info[0]; + Hash256 stateRoot = (Hash256)info[1]; + if (!_rootProcessed.Contains(stateRoot)) visitor.VisitMissingNode(stateRoot, new TrieVisitContext()); + })); - public BlockProcessorMock(ILogManager logManager, IStateReader stateReader) - { - _logger = logManager.GetClassLogger(); - stateReader.When(it => - it.RunTreeVisitor(Arg.Any(), Arg.Any(), Arg.Any())) - .Do((info => - { - // Simulate state root check - ITreeVisitor visitor = (ITreeVisitor)info[0]; - Hash256 stateRoot = (Hash256)info[1]; - if (!_rootProcessed.Contains(stateRoot)) visitor.VisitMissingNode(stateRoot, new TrieVisitContext()); - })); + stateReader.HasStateForRoot(Arg.Any()).Returns(x => _rootProcessed.Contains(x[0])); + } - stateReader.HasStateForRoot(Arg.Any()).Returns(x => _rootProcessed.Contains(x[0])); - } + public void Allow(Hash256 hash) + { + _logger.Info($"Allowing {hash} to process"); + _allowed.Add(hash); + } - public void Allow(Hash256 hash) - { - _logger.Info($"Allowing {hash} to process"); - _allowed.Add(hash); - } + public void AllowToFail(Hash256 hash) + { + _logger.Info($"Allowing {hash} to fail"); + _allowedToFail.Add(hash); + } - public void AllowToFail(Hash256 hash) + public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, ProcessingOptions processingOptions, IBlockTracer blockTracer) + { + if (blockTracer != NullBlockTracer.Instance) { - _logger.Info($"Allowing {hash} to fail"); - _allowedToFail.Add(hash); + // this is for block reruns on failure for diag tracing + throw new InvalidBlockException(suggestedBlocks[0], "wrong tracer"); } - public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, ProcessingOptions processingOptions, IBlockTracer blockTracer) + _logger.Info($"Processing {suggestedBlocks.Last().ToString(Block.Format.Short)}"); + while (true) { - if (blockTracer != NullBlockTracer.Instance) + bool notYet = false; + for (int i = 0; i < suggestedBlocks.Count; i++) { - // this is for block reruns on failure for diag tracing - throw new InvalidBlockException(suggestedBlocks[0], "wrong tracer"); - } - - _logger.Info($"Processing {suggestedBlocks.Last().ToString(Block.Format.Short)}"); - while (true) - { - bool notYet = false; - for (int i = 0; i < suggestedBlocks.Count; i++) + BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks)); + Block suggestedBlock = suggestedBlocks[i]; + BlockProcessing?.Invoke(this, new BlockEventArgs(suggestedBlock)); + Hash256 hash = suggestedBlock.Hash!; + if (!_allowed.Contains(hash)) { - BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks)); - Block suggestedBlock = suggestedBlocks[i]; - BlockProcessing?.Invoke(this, new BlockEventArgs(suggestedBlock)); - Hash256 hash = suggestedBlock.Hash!; - if (!_allowed.Contains(hash)) + if (_allowedToFail.Contains(hash)) { - if (_allowedToFail.Contains(hash)) - { - _allowedToFail.Remove(hash); - BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty())); - throw new InvalidBlockException(suggestedBlock, "allowed to fail"); - } - - notYet = true; - break; + _allowedToFail.Remove(hash); + BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty())); + throw new InvalidBlockException(suggestedBlock, "allowed to fail"); } - } - if (notYet) - { - Thread.Sleep(20); - } - else - { - _rootProcessed.Add(suggestedBlocks.Last().StateRoot!); - BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty())); - return suggestedBlocks.ToArray(); + notYet = true; + break; } } - } - - public event EventHandler? BlocksProcessing; - - public event EventHandler? BlockProcessing; - - public event EventHandler? BlockProcessed; - public event EventHandler? TransactionProcessed - { - add { } - remove { } - } - } - - private class RecoveryStepMock : IBlockPreprocessorStep - { - private readonly ILogger _logger; - private readonly ConcurrentDictionary _allowed = new(); - private readonly ConcurrentDictionary _allowedToFail = new(); - - public RecoveryStepMock(ILogManager logManager) - { - _logger = logManager.GetClassLogger(); - } - - public void Allow(Hash256 hash) - { - _logger.Info($"Allowing {hash} to recover"); - _allowed[hash] = new object(); - } - - public void RecoverData(Block block) - { - _logger.Info($"Recovering data for {block.ToString(Block.Format.Short)}"); - if (block.Author is not null) + if (notYet) { - _logger.Info($"Data was already there for {block.ToString(Block.Format.Short)}"); - return; + Thread.Sleep(20); } - - while (true) + else { - Hash256 blockHash = block.Hash!; - if (!_allowed.ContainsKey(blockHash)) - { - if (_allowedToFail.ContainsKey(blockHash)) - { - _allowedToFail.Remove(blockHash, out _); - throw new Exception(); - } - - Thread.Sleep(20); - continue; - } - - block.Header.Author = Address.Zero; - _allowed.Remove(blockHash, out _); - return; + _rootProcessed.Add(suggestedBlocks.Last().StateRoot!); + BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty())); + return suggestedBlocks.ToArray(); } } } - private readonly BlockTree _blockTree; - private readonly AutoResetEvent _resetEvent; - private readonly AutoResetEvent _queueEmptyResetEvent; - private readonly BlockProcessorMock _blockProcessor; - private readonly RecoveryStepMock _recoveryStep; - private readonly BlockchainProcessor _processor; - private readonly ILogger _logger; + public event EventHandler? BlocksProcessing; - private Hash256? _headBefore; - private int _processingQueueEmptyFired; - private const int ProcessingWait = 2000; + public event EventHandler? BlockProcessing; - public ProcessingTestContext(bool startProcessor) - { - _logger = _logManager.GetClassLogger(); - IStateReader stateReader = Substitute.For(); - - _blockTree = Build.A.BlockTree() - .WithoutSettingHead - .TestObject; - _blockProcessor = new BlockProcessorMock(_logManager, stateReader); - _recoveryStep = new RecoveryStepMock(_logManager); - _processor = new BlockchainProcessor(_blockTree, _blockProcessor, _recoveryStep, stateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); - _resetEvent = new AutoResetEvent(false); - _queueEmptyResetEvent = new AutoResetEvent(false); - - _processor.ProcessingQueueEmpty += (_, _) => - { - _processingQueueEmptyFired++; - _queueEmptyResetEvent.Set(); - }; - - _blockTree.NewHeadBlock += (_, args) => - { - _logger.Info($"Finished waiting for {args.Block.ToString(Block.Format.Short)} as block became the new head block"); - _resetEvent.Set(); - }; - - if (startProcessor) - _processor.Start(); - } + public event EventHandler? BlockProcessed; - public ProcessingTestContext IsProcessingBlocks(bool expectedIsProcessingBlocks, ulong maxInterval) + public event EventHandler? TransactionProcessed { - bool actual = _processor.IsProcessingBlocks(maxInterval); - Assert.That(actual, Is.EqualTo(expectedIsProcessingBlocks)); - return this; + add { } + remove { } } + } - public ProcessingTestContext AndRecoveryQueueLimitHasBeenReached() - { - _processor.SoftMaxRecoveryQueueSizeInTx = 0; - return this; - } + private class RecoveryStepMock : IBlockPreprocessorStep + { + private readonly ILogger _logger; + private readonly ConcurrentDictionary _allowed = new(); + private readonly ConcurrentDictionary _allowedToFail = new(); - public AfterBlock Processed(Block block) + public RecoveryStepMock(ILogManager logManager) { - _headBefore = _blockTree.Head?.Hash; - ManualResetEvent processedEvent = new(false); - bool wasProcessed = false; - _blockProcessor.BlockProcessed += (_, args) => - { - if (args.Block.Hash == block.Hash) - { - wasProcessed = true; - processedEvent.Set(); - } - }; - - _logger.Info($"Waiting for {block.ToString(Block.Format.Short)} to process"); - _blockProcessor.Allow(block.Hash!); - processedEvent.WaitOne(ProcessingWait); - Assert.True(wasProcessed, $"Expected this block to get processed but it was not: {block.ToString(Block.Format.Short)}"); - - return new AfterBlock(_logManager, this, block); + _logger = logManager.GetClassLogger(); } - public AfterBlock ProcessedSkipped(Block block) + public void Allow(Hash256 hash) { - _headBefore = _blockTree.Head?.Hash; - _logger.Info($"Waiting for {block.ToString(Block.Format.Short)} to be skipped"); - _blockProcessor.Allow(block.Hash!); - return new AfterBlock(_logManager, this, block); + _logger.Info($"Allowing {hash} to recover"); + _allowed[hash] = new object(); } - public AfterBlock ProcessedFail(Block block) + public void RecoverData(Block block) { - _headBefore = _blockTree.Head?.Hash; - ManualResetEvent processedEvent = new(false); - bool wasProcessed = false; - _blockProcessor.BlockProcessed += (_, args) => + _logger.Info($"Recovering data for {block.ToString(Block.Format.Short)}"); + if (block.Author is not null) { - if (args.Block.Hash == block.Hash) - { - wasProcessed = true; - processedEvent.Set(); - } - }; - - _logger.Info($"Waiting for {block.ToString(Block.Format.Short)} to fail processing"); - _blockProcessor.AllowToFail(block.Hash!); - processedEvent.WaitOne(ProcessingWait); - Assert.True(wasProcessed, $"Block was never processed {block.ToString(Block.Format.Short)}"); - Assert.That(_blockTree.Head?.Hash, Is.EqualTo(_headBefore), $"Processing did not fail - {block.ToString(Block.Format.Short)} became a new head block"); - _logger.Info($"Finished waiting for {block.ToString(Block.Format.Short)} to fail processing"); - return new AfterBlock(_logManager, this, block); - } - - public ProcessingTestContext Suggested(Block block) - { - AddBlockResult result = _blockTree.SuggestBlock(block); - if (result != AddBlockResult.Added) - { - _logger.Info($"Finished waiting for {block.ToString(Block.Format.Short)} as block was ignored"); - _resetEvent.Set(); + _logger.Info($"Data was already there for {block.ToString(Block.Format.Short)}"); + return; } - return this; - } - - public ProcessingTestContext SuggestedWithoutProcessingAndMoveToMain(Block block) - { - AddBlockResult result = _blockTree.SuggestBlock(block, BlockTreeSuggestOptions.None); - if (result != AddBlockResult.Added) + while (true) { - Assert.Fail($"Block {block} was expected to be added"); - } - - _blockTree.UpdateMainChain(new[] { block }, false); - _blockProcessor.Allow(block.Hash!); - _recoveryStep.Allow(block.Hash!); + Hash256 blockHash = block.Hash!; + if (!_allowed.ContainsKey(blockHash)) + { + if (_allowedToFail.ContainsKey(blockHash)) + { + _allowedToFail.Remove(blockHash, out _); + throw new Exception(); + } - return this; - } + Thread.Sleep(20); + continue; + } - public ProcessingTestContext Suggested(BlockHeader block) - { - AddBlockResult result = _blockTree.SuggestHeader(block); - if (result != AddBlockResult.Added) - { - _logger.Info($"Finished waiting for {block.ToString(BlockHeader.Format.Short)} as block was ignored"); - _resetEvent.Set(); + block.Header.Author = Address.Zero; + _allowed.Remove(blockHash, out _); + return; } - - return this; - } - - public ProcessingTestContext Recovered(Block block) - { - _recoveryStep.Allow(block.Hash!); - return this; - } - - public ProcessingTestContext CountIs(int expectedCount) - { - var count = ((IBlockProcessingQueue)_processor).Count; - Assert.That(expectedCount, Is.EqualTo(count)); - return this; } + } - public AfterBlock FullyProcessed(Block block) - { - return Suggested(block) - .Recovered(block) - .Processed(block); - } + private readonly BlockTree _blockTree; + private readonly AutoResetEvent _resetEvent; + private readonly AutoResetEvent _queueEmptyResetEvent; + private readonly BlockProcessorMock _blockProcessor; + private readonly RecoveryStepMock _recoveryStep; + private readonly BlockchainProcessor _processor; + private readonly ILogger _logger; - public AfterBlock FullyProcessedSkipped(Block block) - { - return Suggested(block) - .Recovered(block) - .ProcessedSkipped(block); - } + private Hash256? _headBefore; + private int _processingQueueEmptyFired; + private const int ProcessingWait = 2000; - public AfterBlock FullyProcessedFail(Block block) - { - return Suggested(block) - .Recovered(block) - .ProcessedFail(block); - } - - public ProcessingTestContext QueueIsEmpty(int count) + public ProcessingTestContext(bool startProcessor) + { + _logger = _logManager.GetClassLogger(); + IStateReader stateReader = Substitute.For(); + + _blockTree = Build.A.BlockTree() + .WithoutSettingHead + .TestObject; + _blockProcessor = new BlockProcessorMock(_logManager, stateReader); + _recoveryStep = new RecoveryStepMock(_logManager); + _processor = new BlockchainProcessor(_blockTree, _blockProcessor, _recoveryStep, stateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); + _resetEvent = new AutoResetEvent(false); + _queueEmptyResetEvent = new AutoResetEvent(false); + + _processor.ProcessingQueueEmpty += (_, _) => { - _queueEmptyResetEvent.WaitOne(ProcessingWait); - Assert.That(_processingQueueEmptyFired, Is.EqualTo(count), $"Processing queue fired {_processingQueueEmptyFired} times."); - return this; - } + _processingQueueEmptyFired++; + _queueEmptyResetEvent.Set(); + }; - public class AfterBlock + _blockTree.NewHeadBlock += (_, args) => { - public const int IgnoreWait = 200; + _logger.Info($"Finished waiting for {args.Block.ToString(Block.Format.Short)} as block became the new head block"); + _resetEvent.Set(); + }; - private readonly ILogger _logger; - private readonly Block _block; - private readonly ProcessingTestContext _processingTestContext; - - public AfterBlock(ILogManager logManager, ProcessingTestContext processingTestContext, Block block) - { - _logger = logManager.GetClassLogger(); - _processingTestContext = processingTestContext; - _block = block; - } + if (startProcessor) + _processor.Start(); + } - public ProcessingTestContext BecomesGenesis() - { - _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to become genesis block"); - _processingTestContext._resetEvent.WaitOne(ProcessingWait); - Assert.That(_processingTestContext._blockTree.Genesis!.Hash, Is.EqualTo(_block.Header.Hash), "genesis"); - return _processingTestContext; - } + public ProcessingTestContext IsProcessingBlocks(bool expectedIsProcessingBlocks, ulong maxInterval) + { + bool actual = _processor.IsProcessingBlocks(maxInterval); + Assert.That(actual, Is.EqualTo(expectedIsProcessingBlocks)); + return this; + } - public ProcessingTestContext BecomesNewHead() - { - _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to become the new head block"); - _processingTestContext._resetEvent.WaitOne(ProcessingWait); - Assert.That(() => _processingTestContext._blockTree.Head!.Hash, Is.EqualTo(_block.Header.Hash).After(1000, 100)); - return _processingTestContext; - } + public ProcessingTestContext AndRecoveryQueueLimitHasBeenReached() + { + _processor.SoftMaxRecoveryQueueSizeInTx = 0; + return this; + } - public ProcessingTestContext IsKeptOnBranch() + public AfterBlock Processed(Block block) + { + _headBefore = _blockTree.Head?.Hash; + ManualResetEvent processedEvent = new(false); + bool wasProcessed = false; + _blockProcessor.BlockProcessed += (_, args) => + { + if (args.Block.Hash == block.Hash) { - _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to be ignored"); - _processingTestContext._resetEvent.WaitOne(IgnoreWait); - Assert.That(_processingTestContext._blockTree.Head!.Hash, Is.EqualTo(_processingTestContext._headBefore), "head"); - _logger.Info($"Finished waiting for {_block.ToString(Block.Format.Short)} to be ignored"); - return _processingTestContext; + wasProcessed = true; + processedEvent.Set(); } + }; - public ProcessingTestContext IsDeletedAsInvalid() - { - _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to be deleted"); - _processingTestContext._resetEvent.WaitOne(IgnoreWait); - Assert.That(_processingTestContext._blockTree.Head!.Hash, Is.EqualTo(_processingTestContext._headBefore), "head"); - _logger.Info($"Finished waiting for {_block.ToString(Block.Format.Short)} to be deleted"); - Assert.Null(_processingTestContext._blockTree.FindBlock(_block.Hash, BlockTreeLookupOptions.None)); - return _processingTestContext; - } - } + _logger.Info($"Waiting for {block.ToString(Block.Format.Short)} to process"); + _blockProcessor.Allow(block.Hash!); + processedEvent.WaitOne(ProcessingWait); + Assert.That(wasProcessed, Is.True, $"Expected this block to get processed but it was not: {block.ToString(Block.Format.Short)}"); - public ProcessingTestContext Sleep(int milliseconds) - { - Thread.Sleep(milliseconds); - return this; - } + return new AfterBlock(_logManager, this, block); } - private static class When + public AfterBlock ProcessedSkipped(Block block) { - public static ProcessingTestContext ProcessingBlocks => new(true); - - public static ProcessingTestContext ProcessorIsNotStarted => new(false); + _headBefore = _blockTree.Head?.Hash; + _logger.Info($"Waiting for {block.ToString(Block.Format.Short)} to be skipped"); + _blockProcessor.Allow(block.Hash!); + return new AfterBlock(_logManager, this, block); } - private static readonly Block _block0 = Build.A.Block.WithNumber(0).WithNonce(0).WithDifficulty(0).TestObject; - private static readonly Block _block1D2 = Build.A.Block.WithNumber(1).WithNonce(1).WithParent(_block0).WithDifficulty(2).TestObject; - private static readonly Block _block2D4 = Build.A.Block.WithNumber(2).WithNonce(2).WithParent(_block1D2).WithDifficulty(2).TestObject; - private static readonly Block _block3D6 = Build.A.Block.WithNumber(3).WithNonce(3).WithParent(_block2D4).WithDifficulty(2).TestObject; - private static readonly Block _block4D8 = Build.A.Block.WithNumber(4).WithNonce(4).WithParent(_block3D6).WithDifficulty(2).TestObject; - private static readonly Block _block5D10 = Build.A.Block.WithNumber(5).WithNonce(5).WithParent(_block4D8).WithDifficulty(2).TestObject; - private static readonly Block _blockB2D4 = Build.A.Block.WithNumber(2).WithNonce(6).WithParent(_block1D2).WithDifficulty(2).TestObject; - private static readonly Block _blockB3D8 = Build.A.Block.WithNumber(3).WithNonce(7).WithParent(_blockB2D4).WithDifficulty(4).TestObject; - private static readonly Block _blockC2D100 = Build.A.Block.WithNumber(3).WithNonce(8).WithParent(_block1D2).WithDifficulty(98).TestObject; - private static readonly Block _blockD2D200 = Build.A.Block.WithNumber(3).WithNonce(8).WithParent(_block1D2).WithDifficulty(198).TestObject; - private static readonly Block _blockE2D300 = Build.A.Block.WithNumber(3).WithNonce(8).WithParent(_block1D2).WithDifficulty(298).TestObject; - - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_ignore_lower_difficulty() + public AfterBlock ProcessedFail(Block block) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_blockB2D4).BecomesNewHead() - .FullyProcessed(_blockB3D8).BecomesNewHead() - .FullyProcessedSkipped(_block2D4).IsKeptOnBranch() - .FullyProcessedSkipped(_block3D6).IsKeptOnBranch(); + _headBefore = _blockTree.Head?.Hash; + ManualResetEvent processedEvent = new(false); + bool wasProcessed = false; + _blockProcessor.BlockProcessed += (_, args) => + { + if (args.Block.Hash == block.Hash) + { + wasProcessed = true; + processedEvent.Set(); + } + }; + + _logger.Info($"Waiting for {block.ToString(Block.Format.Short)} to fail processing"); + _blockProcessor.AllowToFail(block.Hash!); + processedEvent.WaitOne(ProcessingWait); + Assert.That(wasProcessed, Is.True, $"Block was never processed {block.ToString(Block.Format.Short)}"); + Assert.That(_blockTree.Head?.Hash, Is.EqualTo(_headBefore), $"Processing did not fail - {block.ToString(Block.Format.Short)} became a new head block"); + _logger.Info($"Finished waiting for {block.ToString(Block.Format.Short)} to fail processing"); + return new AfterBlock(_logManager, this, block); } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_ignore_same_difficulty() + public ProcessingTestContext Suggested(Block block) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_block2D4).BecomesNewHead() - .FullyProcessedSkipped(_blockB2D4).IsKeptOnBranch(); - } + AddBlockResult result = _blockTree.SuggestBlock(block); + if (result != AddBlockResult.Added) + { + _logger.Info($"Finished waiting for {block.ToString(Block.Format.Short)} as block was ignored"); + _resetEvent.Set(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_process_sequence() - { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_block2D4).BecomesNewHead() - .FullyProcessed(_block3D6).BecomesNewHead() - .FullyProcessed(_block4D8).BecomesNewHead(); + return this; } - [Test, Timeout(Timeout.MaxTestTime)] - [Explicit("Does not work on CI")] - public void Will_update_metrics_on_processing() + public ProcessingTestContext SuggestedWithoutProcessingAndMoveToMain(Block block) { - long metricsBefore = Metrics.LastBlockProcessingTimeInMs; + AddBlockResult result = _blockTree.SuggestBlock(block, BlockTreeSuggestOptions.None); + if (result != AddBlockResult.Added) + { + Assert.Fail($"Block {block} was expected to be added"); + } - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis(); + _blockTree.UpdateMainChain(new[] { block }, false); + _blockProcessor.Allow(block.Hash!); + _recoveryStep.Allow(block.Hash!); - long metricsAfter = Metrics.LastBlockProcessingTimeInMs; - metricsAfter.Should().NotBe(metricsBefore); + return this; } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_process_fast_sync_transition() + public ProcessingTestContext Suggested(BlockHeader block) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_block2D4).BecomesNewHead() - .Suggested(_block3D6.Header) - .FullyProcessed(_block4D8).BecomesNewHead(); - } + AddBlockResult result = _blockTree.SuggestHeader(block); + if (result != AddBlockResult.Added) + { + _logger.Info($"Finished waiting for {block.ToString(BlockHeader.Format.Short)} as block was ignored"); + _resetEvent.Set(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Can_process_fast_sync() - { - BasicTestBlockchain testBlockchain = await BasicTestBlockchain.Create(); - await testBlockchain.BuildSomeBlocks(5); - - When.ProcessingBlocks - .FullyProcessed(testBlockchain.BlockTree.FindBlock(0)!).BecomesGenesis() - .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(1)!) - .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(2)!) - .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(3)!) - .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(4)!) - .FullyProcessed(testBlockchain.BlockTree.FindBlock(5)!).BecomesNewHead(); + return this; } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_reorganize_just_head_block_twice() + public ProcessingTestContext Recovered(Block block) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_block2D4).BecomesNewHead() - .FullyProcessed(_blockC2D100).BecomesNewHead() - .FullyProcessed(_blockD2D200).BecomesNewHead() - .FullyProcessed(_blockE2D300).BecomesNewHead(); + _recoveryStep.Allow(block.Hash!); + return this; } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_reorganize_there_and_back() + public ProcessingTestContext CountIs(int expectedCount) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_block2D4).BecomesNewHead() - .FullyProcessed(_block3D6).BecomesNewHead() - .FullyProcessedSkipped(_blockB2D4).IsKeptOnBranch() - .FullyProcessed(_blockB3D8).BecomesNewHead() - .FullyProcessedSkipped(_block4D8).IsKeptOnBranch() - .FullyProcessed(_block5D10).BecomesNewHead(); + var count = ((IBlockProcessingQueue)_processor).Count; + Assert.That(expectedCount, Is.EqualTo(count)); + return this; } - [Test, Timeout(Timeout.MaxTestTime), Retry(3)] - public void Can_reorganize_to_longer_path() + public AfterBlock FullyProcessed(Block block) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_blockB2D4).BecomesNewHead() - .FullyProcessed(_blockB3D8).BecomesNewHead() - .FullyProcessedSkipped(_block2D4).IsKeptOnBranch() - .FullyProcessedSkipped(_block3D6).IsKeptOnBranch() - .FullyProcessedSkipped(_block4D8).IsKeptOnBranch() - .FullyProcessed(_block5D10).BecomesNewHead(); + return Suggested(block) + .Recovered(block) + .Processed(block); } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_reorganize_to_same_length() + public AfterBlock FullyProcessedSkipped(Block block) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_block2D4).BecomesNewHead() - .FullyProcessed(_block3D6).BecomesNewHead() - .FullyProcessedSkipped(_blockB2D4).IsKeptOnBranch() - .FullyProcessed(_blockB3D8).BecomesNewHead(); + return Suggested(block) + .Recovered(block) + .ProcessedSkipped(block); } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_reorganize_to_shorter_path() + public AfterBlock FullyProcessedFail(Block block) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessed(_block2D4).BecomesNewHead() - .FullyProcessed(_block3D6).BecomesNewHead() - .FullyProcessed(_blockC2D100).BecomesNewHead(); + return Suggested(block) + .Recovered(block) + .ProcessedFail(block); } - [Test, Timeout(Timeout.MaxTestTime)] - [Retry(3)] // some flakiness - public void Can_change_branch_on_invalid_block() + public ProcessingTestContext QueueIsEmpty(int count) { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .FullyProcessedFail(_block2D4).IsDeletedAsInvalid() - .FullyProcessed(_blockB2D4).BecomesNewHead(); + _queueEmptyResetEvent.WaitOne(ProcessingWait); + Assert.That(_processingQueueEmptyFired, Is.EqualTo(count), $"Processing queue fired {_processingQueueEmptyFired} times."); + return this; } - [Test(Description = "Covering scenario when we have an invalid block followed by its descendants." + - "All the descandant blocks should get discarded and an alternative branch should get selected." + - "BRANCH A | BLOCK 2 | INVALID | DISCARD" + - "BRANCH A | BLOCK 3 | VALID | DISCARD" + - "BRANCH A | BLOCK 4 | VALID | DISCARD" + - "BRANCH B | BLOCK 2 | VALID | NEW HEAD"), Timeout(Timeout.MaxTestTime)] - public void Can_change_branch_on_invalid_block_when_invalid_branch_is_in_the_queue() + public class AfterBlock { - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .Suggested(_block1D2) - .Suggested(_block2D4) - .Suggested(_block3D6) - .Suggested(_block4D8) - .Recovered(_block1D2) - .Recovered(_block2D4) - .Recovered(_block3D6) - .Recovered(_block4D8) - .Processed(_block1D2).BecomesNewHead() - .ProcessedFail(_block2D4).IsDeletedAsInvalid() - .ProcessedSkipped(_block3D6).IsDeletedAsInvalid() - .ProcessedSkipped(_block4D8).IsDeletedAsInvalid() - .FullyProcessed(_blockB2D4).BecomesNewHead(); - } + public const int IgnoreWait = 200; - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_change_branch_on_invalid_block_when_invalid_branch_is_in_the_queue_and_recovery_queue_max_has_been_reached() - { - When.ProcessingBlocks - .AndRecoveryQueueLimitHasBeenReached() - .FullyProcessed(_block0).BecomesGenesis() - .Suggested(_block1D2) - .Suggested(_block2D4) - .Suggested(_block3D6) - .Suggested(_block4D8) - .Recovered(_block1D2) - .Recovered(_block2D4) - .Processed(_block1D2).BecomesNewHead() - .ProcessedFail(_block2D4).IsDeletedAsInvalid() - .Recovered(_block3D6) - .Recovered(_block4D8) - .ProcessedSkipped(_block3D6).IsDeletedAsInvalid() - .ProcessedSkipped(_block4D8).IsDeletedAsInvalid() - .FullyProcessed(_blockB2D4).BecomesNewHead(); - } + private readonly ILogger _logger; + private readonly Block _block; + private readonly ProcessingTestContext _processingTestContext; - [Test, Timeout(Timeout.MaxTestTime)] - [Ignore("Not implemented yet - scenario when from suggested blocks we can see that previously suggested will not be winning")] - [Todo(Improve.Performance, "We can skip processing losing branches by implementing code to pass this test")] - public void Never_process_branches_that_are_known_to_lose_in_the_future() - { - // this can be solved easily by resetting the hash to follow whenever suggesting a block that is not a child of the previously suggested block - When.ProcessingBlocks - .FullyProcessed(_block0).BecomesGenesis() - .Suggested(_block1D2) - .Suggested(_block2D4) - .Suggested(_block3D6) - .Suggested(_blockB2D4) - .Suggested(_blockB3D8) - .Recovered(_block1D2) - .Recovered(_block2D4) - .Recovered(_block3D6) - .Recovered(_blockB2D4) - .Recovered(_blockB3D8) - .Processed(_block1D2).BecomesNewHead() - .ProcessedSkipped(_block2D4).IsKeptOnBranch(); - } + public AfterBlock(ILogManager logManager, ProcessingTestContext processingTestContext, Block block) + { + _logger = logManager.GetClassLogger(); + _processingTestContext = processingTestContext; + _block = block; + } - [Test, Timeout(Timeout.MaxTestTime)] - public void IsProcessingBlocks_returns_true_when_processing_blocks() - { - When.ProcessingBlocks - .IsProcessingBlocks(true, 1) - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .IsProcessingBlocks(true, 1) - .FullyProcessed(_block2D4).BecomesNewHead() - .IsProcessingBlocks(true, 1) - .FullyProcessed(_block3D6).BecomesNewHead() - .IsProcessingBlocks(true, 1); - } + public ProcessingTestContext BecomesGenesis() + { + _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to become genesis block"); + _processingTestContext._resetEvent.WaitOne(ProcessingWait); + Assert.That(_processingTestContext._blockTree.Genesis!.Hash, Is.EqualTo(_block.Header.Hash), "genesis"); + return _processingTestContext; + } - [Test, Timeout(Timeout.MaxTestTime)] - public void IsProcessingBlocks_returns_false_when_max_interval_elapsed() - { - When.ProcessingBlocks - .IsProcessingBlocks(true, 1) - .FullyProcessed(_block0).BecomesGenesis() - .FullyProcessed(_block1D2).BecomesNewHead() - .IsProcessingBlocks(true, 1) - .FullyProcessed(_block2D4).BecomesNewHead() - .Sleep(2000) - .IsProcessingBlocks(false, 1) - .FullyProcessed(_block3D6).BecomesNewHead() - .IsProcessingBlocks(true, 1); - } + public ProcessingTestContext BecomesNewHead() + { + _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to become the new head block"); + _processingTestContext._resetEvent.WaitOne(ProcessingWait); + Assert.That(() => _processingTestContext._blockTree.Head!.Hash, Is.EqualTo(_block.Header.Hash).After(1000, 100)); + return _processingTestContext; + } - [Test, Timeout(Timeout.MaxTestTime)] - public void ProcessorIsNotStarted_returns_false() - { - When.ProcessorIsNotStarted - .IsProcessingBlocks(false, 10) - .Sleep(1000) - .IsProcessingBlocks(false, 10); + public ProcessingTestContext IsKeptOnBranch() + { + _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to be ignored"); + _processingTestContext._resetEvent.WaitOne(IgnoreWait); + Assert.That(_processingTestContext._blockTree.Head!.Hash, Is.EqualTo(_processingTestContext._headBefore), "head"); + _logger.Info($"Finished waiting for {_block.ToString(Block.Format.Short)} to be ignored"); + return _processingTestContext; + } + + public ProcessingTestContext IsDeletedAsInvalid() + { + _logger.Info($"Waiting for {_block.ToString(Block.Format.Short)} to be deleted"); + _processingTestContext._resetEvent.WaitOne(IgnoreWait); + Assert.That(_processingTestContext._blockTree.Head!.Hash, Is.EqualTo(_processingTestContext._headBefore), "head"); + _logger.Info($"Finished waiting for {_block.ToString(Block.Format.Short)} to be deleted"); + Assert.That(_processingTestContext._blockTree.FindBlock(_block.Hash, BlockTreeLookupOptions.None), Is.Null); + return _processingTestContext; + } } - [Test, Timeout(Timeout.MaxTestTime)] - public void QueueCount_returns_correctly() + public ProcessingTestContext Sleep(int milliseconds) { - When.ProcessingBlocks - .QueueIsEmpty(1) - .FullyProcessed(_block0) - .BecomesGenesis() - .QueueIsEmpty(2) - - - .Suggested(_block1D2) - .Recovered(_block1D2) - .CountIs(1) - - .Suggested(_block2D4) - .Suggested(_block3D6) - .Recovered(_block2D4) - .Recovered(_block3D6) - .CountIs(3) - - .Processed(_block1D2) - .BecomesNewHead() - .Sleep(10) - .CountIs(2) - .ProcessedFail(_block2D4) - .IsDeletedAsInvalid() - .ProcessedSkipped(_block3D6) - .IsDeletedAsInvalid() - .Sleep(10) - .CountIs(0) - .QueueIsEmpty(3); + Thread.Sleep(milliseconds); + return this; } } + + private static class When + { + public static ProcessingTestContext ProcessingBlocks => new(true); + + public static ProcessingTestContext ProcessorIsNotStarted => new(false); + } + + private static readonly Block _block0 = Build.A.Block.WithNumber(0).WithNonce(0).WithDifficulty(0).TestObject; + private static readonly Block _block1D2 = Build.A.Block.WithNumber(1).WithNonce(1).WithParent(_block0).WithDifficulty(2).TestObject; + private static readonly Block _block2D4 = Build.A.Block.WithNumber(2).WithNonce(2).WithParent(_block1D2).WithDifficulty(2).TestObject; + private static readonly Block _block3D6 = Build.A.Block.WithNumber(3).WithNonce(3).WithParent(_block2D4).WithDifficulty(2).TestObject; + private static readonly Block _block4D8 = Build.A.Block.WithNumber(4).WithNonce(4).WithParent(_block3D6).WithDifficulty(2).TestObject; + private static readonly Block _block5D10 = Build.A.Block.WithNumber(5).WithNonce(5).WithParent(_block4D8).WithDifficulty(2).TestObject; + private static readonly Block _blockB2D4 = Build.A.Block.WithNumber(2).WithNonce(6).WithParent(_block1D2).WithDifficulty(2).TestObject; + private static readonly Block _blockB3D8 = Build.A.Block.WithNumber(3).WithNonce(7).WithParent(_blockB2D4).WithDifficulty(4).TestObject; + private static readonly Block _blockC2D100 = Build.A.Block.WithNumber(3).WithNonce(8).WithParent(_block1D2).WithDifficulty(98).TestObject; + private static readonly Block _blockD2D200 = Build.A.Block.WithNumber(3).WithNonce(8).WithParent(_block1D2).WithDifficulty(198).TestObject; + private static readonly Block _blockE2D300 = Build.A.Block.WithNumber(3).WithNonce(8).WithParent(_block1D2).WithDifficulty(298).TestObject; + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_ignore_lower_difficulty() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_blockB2D4).BecomesNewHead() + .FullyProcessed(_blockB3D8).BecomesNewHead() + .FullyProcessedSkipped(_block2D4).IsKeptOnBranch() + .FullyProcessedSkipped(_block3D6).IsKeptOnBranch(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_ignore_same_difficulty() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_block2D4).BecomesNewHead() + .FullyProcessedSkipped(_blockB2D4).IsKeptOnBranch(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_process_sequence() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_block2D4).BecomesNewHead() + .FullyProcessed(_block3D6).BecomesNewHead() + .FullyProcessed(_block4D8).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + [Explicit("Does not work on CI")] + public void Will_update_metrics_on_processing() + { + long metricsBefore = Metrics.LastBlockProcessingTimeInMs; + + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis(); + + long metricsAfter = Metrics.LastBlockProcessingTimeInMs; + metricsAfter.Should().NotBe(metricsBefore); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_process_fast_sync_transition() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_block2D4).BecomesNewHead() + .Suggested(_block3D6.Header) + .FullyProcessed(_block4D8).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Can_process_fast_sync() + { + BasicTestBlockchain testBlockchain = await BasicTestBlockchain.Create(); + await testBlockchain.BuildSomeBlocks(5); + + When.ProcessingBlocks + .FullyProcessed(testBlockchain.BlockTree.FindBlock(0)!).BecomesGenesis() + .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(1)!) + .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(2)!) + .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(3)!) + .SuggestedWithoutProcessingAndMoveToMain(testBlockchain.BlockTree.FindBlock(4)!) + .FullyProcessed(testBlockchain.BlockTree.FindBlock(5)!).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_reorganize_just_head_block_twice() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_block2D4).BecomesNewHead() + .FullyProcessed(_blockC2D100).BecomesNewHead() + .FullyProcessed(_blockD2D200).BecomesNewHead() + .FullyProcessed(_blockE2D300).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_reorganize_there_and_back() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_block2D4).BecomesNewHead() + .FullyProcessed(_block3D6).BecomesNewHead() + .FullyProcessedSkipped(_blockB2D4).IsKeptOnBranch() + .FullyProcessed(_blockB3D8).BecomesNewHead() + .FullyProcessedSkipped(_block4D8).IsKeptOnBranch() + .FullyProcessed(_block5D10).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime), Retry(3)] + public void Can_reorganize_to_longer_path() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_blockB2D4).BecomesNewHead() + .FullyProcessed(_blockB3D8).BecomesNewHead() + .FullyProcessedSkipped(_block2D4).IsKeptOnBranch() + .FullyProcessedSkipped(_block3D6).IsKeptOnBranch() + .FullyProcessedSkipped(_block4D8).IsKeptOnBranch() + .FullyProcessed(_block5D10).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_reorganize_to_same_length() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_block2D4).BecomesNewHead() + .FullyProcessed(_block3D6).BecomesNewHead() + .FullyProcessedSkipped(_blockB2D4).IsKeptOnBranch() + .FullyProcessed(_blockB3D8).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_reorganize_to_shorter_path() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessed(_block2D4).BecomesNewHead() + .FullyProcessed(_block3D6).BecomesNewHead() + .FullyProcessed(_blockC2D100).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + [Retry(3)] // some flakiness + public void Can_change_branch_on_invalid_block() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .FullyProcessedFail(_block2D4).IsDeletedAsInvalid() + .FullyProcessed(_blockB2D4).BecomesNewHead(); + } + + [Test(Description = "Covering scenario when we have an invalid block followed by its descendants." + + "All the descandant blocks should get discarded and an alternative branch should get selected." + + "BRANCH A | BLOCK 2 | INVALID | DISCARD" + + "BRANCH A | BLOCK 3 | VALID | DISCARD" + + "BRANCH A | BLOCK 4 | VALID | DISCARD" + + "BRANCH B | BLOCK 2 | VALID | NEW HEAD"), MaxTime(Timeout.MaxTestTime)] + public void Can_change_branch_on_invalid_block_when_invalid_branch_is_in_the_queue() + { + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .Suggested(_block1D2) + .Suggested(_block2D4) + .Suggested(_block3D6) + .Suggested(_block4D8) + .Recovered(_block1D2) + .Recovered(_block2D4) + .Recovered(_block3D6) + .Recovered(_block4D8) + .Processed(_block1D2).BecomesNewHead() + .ProcessedFail(_block2D4).IsDeletedAsInvalid() + .ProcessedSkipped(_block3D6).IsDeletedAsInvalid() + .ProcessedSkipped(_block4D8).IsDeletedAsInvalid() + .FullyProcessed(_blockB2D4).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_change_branch_on_invalid_block_when_invalid_branch_is_in_the_queue_and_recovery_queue_max_has_been_reached() + { + When.ProcessingBlocks + .AndRecoveryQueueLimitHasBeenReached() + .FullyProcessed(_block0).BecomesGenesis() + .Suggested(_block1D2) + .Suggested(_block2D4) + .Suggested(_block3D6) + .Suggested(_block4D8) + .Recovered(_block1D2) + .Recovered(_block2D4) + .Processed(_block1D2).BecomesNewHead() + .ProcessedFail(_block2D4).IsDeletedAsInvalid() + .Recovered(_block3D6) + .Recovered(_block4D8) + .ProcessedSkipped(_block3D6).IsDeletedAsInvalid() + .ProcessedSkipped(_block4D8).IsDeletedAsInvalid() + .FullyProcessed(_blockB2D4).BecomesNewHead(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + [Ignore("Not implemented yet - scenario when from suggested blocks we can see that previously suggested will not be winning")] + [Todo(Improve.Performance, "We can skip processing losing branches by implementing code to pass this test")] + public void Never_process_branches_that_are_known_to_lose_in_the_future() + { + // this can be solved easily by resetting the hash to follow whenever suggesting a block that is not a child of the previously suggested block + When.ProcessingBlocks + .FullyProcessed(_block0).BecomesGenesis() + .Suggested(_block1D2) + .Suggested(_block2D4) + .Suggested(_block3D6) + .Suggested(_blockB2D4) + .Suggested(_blockB3D8) + .Recovered(_block1D2) + .Recovered(_block2D4) + .Recovered(_block3D6) + .Recovered(_blockB2D4) + .Recovered(_blockB3D8) + .Processed(_block1D2).BecomesNewHead() + .ProcessedSkipped(_block2D4).IsKeptOnBranch(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void IsProcessingBlocks_returns_true_when_processing_blocks() + { + When.ProcessingBlocks + .IsProcessingBlocks(true, 1) + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .IsProcessingBlocks(true, 1) + .FullyProcessed(_block2D4).BecomesNewHead() + .IsProcessingBlocks(true, 1) + .FullyProcessed(_block3D6).BecomesNewHead() + .IsProcessingBlocks(true, 1); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void IsProcessingBlocks_returns_false_when_max_interval_elapsed() + { + When.ProcessingBlocks + .IsProcessingBlocks(true, 1) + .FullyProcessed(_block0).BecomesGenesis() + .FullyProcessed(_block1D2).BecomesNewHead() + .IsProcessingBlocks(true, 1) + .FullyProcessed(_block2D4).BecomesNewHead() + .Sleep(2000) + .IsProcessingBlocks(false, 1) + .FullyProcessed(_block3D6).BecomesNewHead() + .IsProcessingBlocks(true, 1); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void ProcessorIsNotStarted_returns_false() + { + When.ProcessorIsNotStarted + .IsProcessingBlocks(false, 10) + .Sleep(1000) + .IsProcessingBlocks(false, 10); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void QueueCount_returns_correctly() + { + When.ProcessingBlocks + .QueueIsEmpty(1) + .FullyProcessed(_block0) + .BecomesGenesis() + .QueueIsEmpty(2) + + + .Suggested(_block1D2) + .Recovered(_block1D2) + .CountIs(1) + + .Suggested(_block2D4) + .Suggested(_block3D6) + .Recovered(_block2D4) + .Recovered(_block3D6) + .CountIs(3) + + .Processed(_block1D2) + .BecomesNewHead() + .Sleep(10) + .CountIs(2) + .ProcessedFail(_block2D4) + .IsDeletedAsInvalid() + .ProcessedSkipped(_block3D6) + .IsDeletedAsInvalid() + .Sleep(10) + .CountIs(0) + .QueueIsEmpty(3); + } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs index 3fe0bef5147..bdce81d8086 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs @@ -16,275 +16,274 @@ using Nethermind.Trie.Pruning; using NUnit.Framework; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +[Parallelizable(ParallelScope.All)] +public class BlockhashProviderTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class BlockhashProviderTests + private static IWorldState CreateWorldState() { - private static IWorldState CreateWorldState() - { - var trieStore = new TrieStore(new MemDb(), LimboLogs.Instance); - var worldState = new WorldState(trieStore, new MemDb(), LimboLogs.Instance); - worldState.CreateAccount(Eip2935Constants.BlockHashHistoryAddress, 0, 1); - worldState.Commit(Frontier.Instance); - return worldState; - } + var trieStore = new TrieStore(new MemDb(), LimboLogs.Instance); + var worldState = new WorldState(trieStore, new MemDb(), LimboLogs.Instance); + worldState.CreateAccount(Eip2935Constants.BlockHashHistoryAddress, 0, 1); + worldState.Commit(Frontier.Instance); + return worldState; + } - private static BlockhashProvider CreateBlockHashProvider(IBlockFinder tree, IReleaseSpec spec) - { - IWorldState worldState = CreateWorldState(); - BlockhashProvider provider = new(tree, new TestSpecProvider(spec), worldState, LimboLogs.Instance); - return provider; - } + private static BlockhashProvider CreateBlockHashProvider(IBlockFinder tree, IReleaseSpec spec) + { + IWorldState worldState = CreateWorldState(); + BlockhashProvider provider = new(tree, new TestSpecProvider(spec), worldState, LimboLogs.Instance); + return provider; + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_get_parent_only_headers() - { - const int chainLength = 512; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_get_parent_only_headers() + { + const int chainLength = 512; - Block genesis = Build.A.Block.Genesis.TestObject; + Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader? head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None); - Block current = Build.A.Block.WithParent(head!).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); - Assert.That(result, Is.EqualTo(head?.Hash)); - } + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader? head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None); + Block current = Build.A.Block.WithParent(head!).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); + Assert.That(result, Is.EqualTo(head?.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_lookup_up_to_256_before_with_headers_only() - { - const int chainLength = 512; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_lookup_up_to_256_before_with_headers_only() + { + const int chainLength = 512; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; - Block current = Build.A.Block.WithParent(head).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, chainLength - 256); - Assert.That(result, Is.EqualTo(tree.FindHeader(256, BlockTreeLookupOptions.None)!.Hash)); - } + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; + Block current = Build.A.Block.WithParent(head).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 256); + Assert.That(result, Is.EqualTo(tree.FindHeader(256, BlockTreeLookupOptions.None)!.Hash)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_lookup_up_to_256_before_with_headers_only_and_competing_branches() - { - const int chainLength = 512; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_lookup_up_to_256_before_with_headers_only_and_competing_branches() + { + const int chainLength = 512; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) - .OfChainLength(out Block _, chainLength, 1).TestObject; + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) + .OfChainLength(out Block _, chainLength, 1).TestObject; - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - Block current = Build.A.Block.WithParent(headBlock).TestObject; - long lookupNumber = chainLength - 256; - Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); - Assert.NotNull(result); - } + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + Block current = Build.A.Block.WithParent(headBlock).TestObject; + long lookupNumber = chainLength - 256; + Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); + Assert.That(result, Is.Not.Null); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_lookup_up_to_256_before_soon_after_fast_sync() - { - const int chainLength = 512; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_lookup_up_to_256_before_soon_after_fast_sync() + { + const int chainLength = 512; + + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) + .OfChainLength(out Block _, chainLength, 1).TestObject; + + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + Block current = Build.A.Block.WithParent(headBlock).TestObject; + tree.SuggestBlock(current); + tree.UpdateMainChain(current); + long lookupNumber = chainLength - 256; + Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); + Assert.That(result, Is.Not.Null); + } - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) - .OfChainLength(out Block _, chainLength, 1).TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_lookup_up_to_256_before_some_blocks_after_fast_sync() + { + const int chainLength = 512; + + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) + .OfChainLength(out Block _, chainLength, 1).TestObject; - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - Block current = Build.A.Block.WithParent(headBlock).TestObject; + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + + Block current = Build.A.Block.WithParent(headBlock).TestObject; + for (int i = 0; i < 6; i++) + { tree.SuggestBlock(current); tree.UpdateMainChain(current); - long lookupNumber = chainLength - 256; - Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); - Assert.NotNull(result); + current = Build.A.Block.WithParent(current).TestObject; } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_lookup_up_to_256_before_some_blocks_after_fast_sync() - { - const int chainLength = 512; - - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) - .OfChainLength(out Block _, chainLength, 1).TestObject; - - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - - Block current = Build.A.Block.WithParent(headBlock).TestObject; - for (int i = 0; i < 6; i++) - { - tree.SuggestBlock(current); - tree.UpdateMainChain(current); - current = Build.A.Block.WithParent(current).TestObject; - } + long lookupNumber = current.Number - 256; + Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); + Assert.That(result, Is.Not.Null); + } - long lookupNumber = current.Number - 256; - Hash256? result = provider.GetBlockhash(current.Header, lookupNumber); - Assert.NotNull(result); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_handle_non_main_chain_in_fast_sync() + { + const int chainLength = 512; - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_handle_non_main_chain_in_fast_sync() + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) + .OfChainLength(out Block _, chainLength, 1).TestObject; + Block current = Build.A.Block.WithParent(headBlock).TestObject; + for (int i = 0; i < 6; i++) { - const int chainLength = 512; - - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(out Block headBlock, chainLength) - .OfChainLength(out Block _, chainLength, 1).TestObject; - Block current = Build.A.Block.WithParent(headBlock).TestObject; - for (int i = 0; i < 6; i++) - { - tree.SuggestBlock(current); - tree.UpdateMainChain(current); - current = Build.A.Block.WithParent(current).TestObject; - } - - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - - Hash256? result = provider.GetBlockhash(current.Header, 509); - Assert.NotNull(result); + tree.SuggestBlock(current); + tree.UpdateMainChain(current); + current = Build.A.Block.WithParent(current).TestObject; } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_get_parent_hash() - { - const int chainLength = 512; + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - Block genesis = Build.A.Block.Genesis.TestObject; + Hash256? result = provider.GetBlockhash(current.Header, 509); + Assert.That(result, Is.Not.Null); + } - BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_get_parent_hash() + { + const int chainLength = 512; - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; - Block current = Build.A.Block.WithParent(head).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); - Assert.That(result, Is.EqualTo(head.Hash)); - } + Block genesis = Build.A.Block.Genesis.TestObject; - [Test, Timeout(Timeout.MaxTestTime)] - public void Cannot_ask_for_self() - { - const int chainLength = 512; + BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; + Block current = Build.A.Block.WithParent(head).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); + Assert.That(result, Is.EqualTo(head.Hash)); + } - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; - Block current = Build.A.Block.WithParent(head).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, chainLength); - Assert.Null(result); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cannot_ask_for_self() + { + const int chainLength = 512; - [Test, Timeout(Timeout.MaxTestTime)] - public void Cannot_ask_about_future() - { - const int chainLength = 512; + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; + Block current = Build.A.Block.WithParent(head).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, chainLength); + Assert.That(result, Is.Null); + } - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; - Block current = Build.A.Block.WithParent(head).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, chainLength + 1); - Assert.Null(result); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cannot_ask_about_future() + { + const int chainLength = 512; - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_lookup_up_to_256_before() - { - const int chainLength = 512; + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; + Block current = Build.A.Block.WithParent(head).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, chainLength + 1); + Assert.That(result, Is.Null); + } - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; - Block current = Build.A.Block.WithParent(head).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, chainLength - 256); - Assert.That(result, Is.EqualTo(tree.FindHeader(256, BlockTreeLookupOptions.None)!.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_lookup_up_to_256_before() + { + const int chainLength = 512; - [Test, Timeout(Timeout.MaxTestTime)] - public void No_lookup_more_than_256_before() - { - const int chainLength = 512; + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; + Block current = Build.A.Block.WithParent(head).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 256); + Assert.That(result, Is.EqualTo(tree.FindHeader(256, BlockTreeLookupOptions.None)!.Hash)); + } - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; - Block current = Build.A.Block.WithParent(head).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, chainLength - 257); - Assert.Null(result); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void No_lookup_more_than_256_before() + { + const int chainLength = 512; - [Test, Timeout(Timeout.MaxTestTime)] - public void UInt_256_overflow() - { - const int chainLength = 128; + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; + Block current = Build.A.Block.WithParent(head).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 257); + Assert.That(result, Is.Null); + } - BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); - BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; - Block current = Build.A.Block.WithParent(head).TestObject; - Hash256? result = provider.GetBlockhash(current.Header, 127); - Assert.That(result, Is.EqualTo(head.Hash)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void UInt_256_overflow() + { + const int chainLength = 128; - [Timeout(Timeout.MaxTestTime)] - [TestCase(1)] - [TestCase(512)] - [TestCase(8192)] - [TestCase(8193)] - public void Eip2935_enabled_Eip7709_disabled_and_then_get_hash(int chainLength) - { - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; - - BlockHeader? head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None); - // number = chainLength - Block current = Build.A.Block.WithParent(head!).TestObject; - tree.SuggestHeader(current.Header); - - IWorldState worldState = CreateWorldState(); - var specProvider = new CustomSpecProvider( - (new ForkActivation(0, genesis.Timestamp), Frontier.Instance), - (new ForkActivation(0, current.Timestamp), Prague.Instance)); - BlockhashProvider provider = new(tree, specProvider, worldState, LimboLogs.Instance); - BlockhashStore store = new(specProvider, worldState); - - Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); - Assert.That(result, Is.EqualTo(head?.Hash)); - AssertGenesisHash(Prague.Instance, provider, current.Header, genesis.Hash); - - head = current.Header; - // number = chainLength + 1 - current = Build.A.Block.WithParent(head!).TestObject; - tree.SuggestHeader(current.Header); - - store.ApplyBlockhashStateChanges(current.Header); - result = provider.GetBlockhash(current.Header, chainLength); - Assert.That(result, Is.EqualTo(head?.Hash)); - - AssertGenesisHash(Prague.Instance, provider, current.Header, genesis.Hash); - } + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfChainLength(chainLength).TestObject; - private static void AssertGenesisHash(IReleaseSpec spec, BlockhashProvider provider, BlockHeader currentHeader, - Hash256? genesisHash) - { - Hash256? result = provider.GetBlockhash(currentHeader, 0); - if ((spec.IsEip7709Enabled && currentHeader.Number > Eip2935Constants.RingBufferSize) || currentHeader.Number > 256) - Assert.That(result, Is.Null); - else - Assert.That(result, Is.EqualTo(genesisHash)); - } + BlockhashProvider provider = CreateBlockHashProvider(tree, Frontier.Instance); + BlockHeader head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None)!; + Block current = Build.A.Block.WithParent(head).TestObject; + Hash256? result = provider.GetBlockhash(current.Header, 127); + Assert.That(result, Is.EqualTo(head.Hash)); + } + + [MaxTime(Timeout.MaxTestTime)] + [TestCase(1)] + [TestCase(512)] + [TestCase(8192)] + [TestCase(8193)] + public void Eip2935_enabled_Eip7709_disabled_and_then_get_hash(int chainLength) + { + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; + + BlockHeader? head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None); + // number = chainLength + Block current = Build.A.Block.WithParent(head!).TestObject; + tree.SuggestHeader(current.Header); + + IWorldState worldState = CreateWorldState(); + var specProvider = new CustomSpecProvider( + (new ForkActivation(0, genesis.Timestamp), Frontier.Instance), + (new ForkActivation(0, current.Timestamp), Prague.Instance)); + BlockhashProvider provider = new(tree, specProvider, worldState, LimboLogs.Instance); + BlockhashStore store = new(specProvider, worldState); + + Hash256? result = provider.GetBlockhash(current.Header, chainLength - 1); + Assert.That(result, Is.EqualTo(head?.Hash)); + AssertGenesisHash(Prague.Instance, provider, current.Header, genesis.Hash); + + head = current.Header; + // number = chainLength + 1 + current = Build.A.Block.WithParent(head!).TestObject; + tree.SuggestHeader(current.Header); + + store.ApplyBlockhashStateChanges(current.Header); + result = provider.GetBlockhash(current.Header, chainLength); + Assert.That(result, Is.EqualTo(head?.Hash)); + + AssertGenesisHash(Prague.Instance, provider, current.Header, genesis.Hash); + } + + private static void AssertGenesisHash(IReleaseSpec spec, BlockhashProvider provider, BlockHeader currentHeader, + Hash256? genesisHash) + { + Hash256? result = provider.GetBlockhash(currentHeader, 0); + if ((spec.IsEip7709Enabled && currentHeader.Number > Eip2935Constants.RingBufferSize) || currentHeader.Number > 256) + Assert.That(result, Is.Null); + else + Assert.That(result, Is.EqualTo(genesisHash)); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Bloom/BloomStorageTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Bloom/BloomStorageTests.cs index 7522a0d0d31..75ef1f1cfa5 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Bloom/BloomStorageTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Bloom/BloomStorageTests.cs @@ -14,199 +14,198 @@ using Nethermind.Db.Blooms; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Bloom +namespace Nethermind.Blockchain.Test.Bloom; + +[Parallelizable(ParallelScope.All)] +public class BloomStorageTests { - [Parallelizable(ParallelScope.All)] - public class BloomStorageTests + [MaxTime(Timeout.MaxTestTime)] + [TestCase(0, 0)] + [TestCase(1, 1)] + [TestCase(0, 10)] + [TestCase(10, 12)] + public void Empty_storage_does_not_contain_blocks(long from, long to) { - [Timeout(Timeout.MaxTestTime)] - [TestCase(0, 0)] - [TestCase(1, 1)] - [TestCase(0, 10)] - [TestCase(10, 12)] - public void Empty_storage_does_not_contain_blocks(long from, long to) - { - BloomStorage storage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); - storage.ContainsRange(from, to).Should().BeFalse(); - } + BloomStorage storage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); + storage.ContainsRange(from, to).Should().BeFalse(); + } - [Timeout(Timeout.MaxTestTime)] - [TestCase(0, 0, ExpectedResult = false)] - [TestCase(1, 1, ExpectedResult = true)] - [TestCase(0, 10, ExpectedResult = false)] - [TestCase(1, 10, ExpectedResult = true)] - [TestCase(10, 12, ExpectedResult = false)] - public bool Initialized_storage_contain_blocks_as_db(long from, long to) - { - MemDb memColumnsDb = new(); - memColumnsDb.Set(BloomStorage.MinBlockNumberKey, 1L.ToBigEndianByteArrayWithoutLeadingZeros()); - memColumnsDb.Set(BloomStorage.MaxBlockNumberKey, 11L.ToBigEndianByteArrayWithoutLeadingZeros()); - BloomStorage storage = new(new BloomConfig(), memColumnsDb, new InMemoryDictionaryFileStoreFactory()); - return storage.ContainsRange(from, to); - } + [MaxTime(Timeout.MaxTestTime)] + [TestCase(0, 0, ExpectedResult = false)] + [TestCase(1, 1, ExpectedResult = true)] + [TestCase(0, 10, ExpectedResult = false)] + [TestCase(1, 10, ExpectedResult = true)] + [TestCase(10, 12, ExpectedResult = false)] + public bool Initialized_storage_contain_blocks_as_db(long from, long to) + { + MemDb memColumnsDb = new(); + memColumnsDb.Set(BloomStorage.MinBlockNumberKey, 1L.ToBigEndianByteArrayWithoutLeadingZeros()); + memColumnsDb.Set(BloomStorage.MaxBlockNumberKey, 11L.ToBigEndianByteArrayWithoutLeadingZeros()); + BloomStorage storage = new(new BloomConfig(), memColumnsDb, new InMemoryDictionaryFileStoreFactory()); + return storage.ContainsRange(from, to); + } + + [MaxTime(Timeout.MaxTestTime)] + [TestCase(0, 0, ExpectedResult = false)] + [TestCase(1, 1, ExpectedResult = true)] + [TestCase(0, 10, ExpectedResult = false)] + [TestCase(1, 10, ExpectedResult = true)] + [TestCase(10, 12, ExpectedResult = false)] + public bool Contain_blocks_after_store(long from, long to) + { + BloomStorage storage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); - [Timeout(Timeout.MaxTestTime)] - [TestCase(0, 0, ExpectedResult = false)] - [TestCase(1, 1, ExpectedResult = true)] - [TestCase(0, 10, ExpectedResult = false)] - [TestCase(1, 10, ExpectedResult = true)] - [TestCase(10, 12, ExpectedResult = false)] - public bool Contain_blocks_after_store(long from, long to) + for (long i = 1; i < 11; i++) { - BloomStorage storage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); + storage.Store(i, Core.Bloom.Empty); + } - for (long i = 1; i < 11; i++) - { - storage.Store(i, Core.Bloom.Empty); - } + return storage.ContainsRange(from, to); + } - return storage.ContainsRange(from, to); + public static IEnumerable GetBloomsTestCases + { + get + { + IEnumerable GetRange(long expectedFound, int offset = 0) => Enumerable.Range(offset, (int)expectedFound).Select(i => (long)i); + int searchesPerBucket = 1 + LevelMultiplier + LevelMultiplier * LevelMultiplier + LevelMultiplier * LevelMultiplier * LevelMultiplier; + + int bucketItems = new BloomStorage(new BloomConfig() { IndexLevelBucketSizes = new[] { LevelMultiplier, LevelMultiplier, LevelMultiplier } }, new MemDb(), new InMemoryDictionaryFileStoreFactory()).MaxBucketSize; + int count = bucketItems * Buckets; + int maxIndex = count - 1; + yield return new TestCaseData(0, maxIndex, false, Enumerable.Empty(), Buckets); + yield return new TestCaseData(0, maxIndex, true, GetRange(count), Buckets * searchesPerBucket); + yield return new TestCaseData(5, 49, true, GetRange(45, 5), 4 + 45); // 4 lookups at level one (16), 45 lookups at bottom level (49-5+1) + yield return new TestCaseData(0, LevelMultiplier * LevelMultiplier * LevelMultiplier - 1, true, GetRange(LevelMultiplier * LevelMultiplier * LevelMultiplier), searchesPerBucket - 1); // skips highest level + yield return new TestCaseData(0, LevelMultiplier * LevelMultiplier * LevelMultiplier * 2 - 1, true, GetRange(LevelMultiplier * LevelMultiplier * LevelMultiplier * 2), (searchesPerBucket - 1) * 2); // skips highest level + yield return new TestCaseData(0, LevelMultiplier * LevelMultiplier * LevelMultiplier * 3 - 1, true, GetRange(LevelMultiplier * LevelMultiplier * LevelMultiplier * 3), searchesPerBucket * 3); // doesn't skip highest level } + } + + [TestCaseSource(nameof(GetBloomsTestCases))] + public void Returns_proper_blooms_after_store(long from, long to, bool isMatch, IEnumerable expectedBlocks, long expectedBloomsChecked) + { + BloomStorage storage = CreateBloomStorage(new BloomConfig() { IndexLevelBucketSizes = new[] { LevelMultiplier, LevelMultiplier, LevelMultiplier } }); + long bloomsChecked = 0; - public static IEnumerable GetBloomsTestCases + IBloomEnumeration bloomEnumeration = storage.GetBlooms(from, to); + IList ranges = new List(); + foreach (Core.Bloom unused in bloomEnumeration) { - get + bloomsChecked++; + if (isMatch && bloomEnumeration.TryGetBlockNumber(out long blockNumber)) { - IEnumerable GetRange(long expectedFound, int offset = 0) => Enumerable.Range(offset, (int)expectedFound).Select(i => (long)i); - int searchesPerBucket = 1 + LevelMultiplier + LevelMultiplier * LevelMultiplier + LevelMultiplier * LevelMultiplier * LevelMultiplier; - - int bucketItems = new BloomStorage(new BloomConfig() { IndexLevelBucketSizes = new[] { LevelMultiplier, LevelMultiplier, LevelMultiplier } }, new MemDb(), new InMemoryDictionaryFileStoreFactory()).MaxBucketSize; - int count = bucketItems * Buckets; - int maxIndex = count - 1; - yield return new TestCaseData(0, maxIndex, false, Enumerable.Empty(), Buckets); - yield return new TestCaseData(0, maxIndex, true, GetRange(count), Buckets * searchesPerBucket); - yield return new TestCaseData(5, 49, true, GetRange(45, 5), 4 + 45); // 4 lookups at level one (16), 45 lookups at bottom level (49-5+1) - yield return new TestCaseData(0, LevelMultiplier * LevelMultiplier * LevelMultiplier - 1, true, GetRange(LevelMultiplier * LevelMultiplier * LevelMultiplier), searchesPerBucket - 1); // skips highest level - yield return new TestCaseData(0, LevelMultiplier * LevelMultiplier * LevelMultiplier * 2 - 1, true, GetRange(LevelMultiplier * LevelMultiplier * LevelMultiplier * 2), (searchesPerBucket - 1) * 2); // skips highest level - yield return new TestCaseData(0, LevelMultiplier * LevelMultiplier * LevelMultiplier * 3 - 1, true, GetRange(LevelMultiplier * LevelMultiplier * LevelMultiplier * 3), searchesPerBucket * 3); // doesn't skip highest level + ranges.Add(blockNumber); } } - [TestCaseSource(nameof(GetBloomsTestCases))] - public void Returns_proper_blooms_after_store(long from, long to, bool isMatch, IEnumerable expectedBlocks, long expectedBloomsChecked) - { - BloomStorage storage = CreateBloomStorage(new BloomConfig() { IndexLevelBucketSizes = new[] { LevelMultiplier, LevelMultiplier, LevelMultiplier } }); - long bloomsChecked = 0; + ranges.Should().BeEquivalentTo(expectedBlocks); + bloomsChecked.Should().Be(expectedBloomsChecked); + } - IBloomEnumeration bloomEnumeration = storage.GetBlooms(from, to); - IList ranges = new List(); - foreach (Core.Bloom unused in bloomEnumeration) + [MaxTime(Timeout.MaxTestTime)] + [TestCase(1, 10, new long[] { 4 }, new[] { 4 })] + [TestCase(0, 4, new long[] { 4 }, new[] { 4 })] + [TestCase(1, 10, new long[] { 1, 4, 6, 8 }, new[] { 4 })] + [TestCase(1, 10, new long[] { 4, 6, 8 }, new[] { 4, 4 })] + [TestCase(1, 10, new long[] { 4, 8, 16, 32 }, new[] { 4, 4 })] + [TestCase(1, 48, new long[] { 4, 8, 16, 32 }, new[] { 4, 4 })] + [TestCase(5, 60, new long[] { 4, 8, 49 }, new[] { 8, 3 })] + [TestCase(1, 120, new long[] { 4, 8, 64, 65 }, new[] { 4, 4, 4 })] + [TestCase(0, 120, new long[] { 0, 1, 2, 3, 5, 7, 11, 120 }, new[] { 9, 3 })] + public void Can_find_bloom_with_fromBlock_offset(long from, long to, long[] blocksSet, int[] levels) + { + BloomStorage storage = CreateBloomStorage(new BloomConfig { IndexLevelBucketSizes = levels }); + Core.Bloom bloom = new(); + byte[] bytes = { 1, 2, 3 }; + bloom.Set(bytes); + foreach (long blockNumber in blocksSet) + { + if (blockNumber > storage.MaxBlockNumber + 1) { - bloomsChecked++; - if (isMatch && bloomEnumeration.TryGetBlockNumber(out long blockNumber)) - { - ranges.Add(blockNumber); - } + // Assert.Fail($"Missing blocks. Trying inserting {blockNumber}, when current max block is {storage.MaxBlockNumber}."); } - - ranges.Should().BeEquivalentTo(expectedBlocks); - bloomsChecked.Should().Be(expectedBloomsChecked); + storage.Store(blockNumber, bloom); } - [Timeout(Timeout.MaxTestTime)] - [TestCase(1, 10, new long[] { 4 }, new[] { 4 })] - [TestCase(0, 4, new long[] { 4 }, new[] { 4 })] - [TestCase(1, 10, new long[] { 1, 4, 6, 8 }, new[] { 4 })] - [TestCase(1, 10, new long[] { 4, 6, 8 }, new[] { 4, 4 })] - [TestCase(1, 10, new long[] { 4, 8, 16, 32 }, new[] { 4, 4 })] - [TestCase(1, 48, new long[] { 4, 8, 16, 32 }, new[] { 4, 4 })] - [TestCase(5, 60, new long[] { 4, 8, 49 }, new[] { 8, 3 })] - [TestCase(1, 120, new long[] { 4, 8, 64, 65 }, new[] { 4, 4, 4 })] - [TestCase(0, 120, new long[] { 0, 1, 2, 3, 5, 7, 11, 120 }, new[] { 9, 3 })] - public void Can_find_bloom_with_fromBlock_offset(long from, long to, long[] blocksSet, int[] levels) + IBloomEnumeration bloomEnumeration = storage.GetBlooms(from, to); + IList foundBlocks = new List(blocksSet.Length); + foreach (Core.Bloom b in bloomEnumeration) { - BloomStorage storage = CreateBloomStorage(new BloomConfig { IndexLevelBucketSizes = levels }); - Core.Bloom bloom = new(); - byte[] bytes = { 1, 2, 3 }; - bloom.Set(bytes); - foreach (long blockNumber in blocksSet) + if (b.Matches(bytes) && bloomEnumeration.TryGetBlockNumber(out long block)) { - if (blockNumber > storage.MaxBlockNumber + 1) - { - // Assert.Fail($"Missing blocks. Trying inserting {blockNumber}, when current max block is {storage.MaxBlockNumber}."); - } - storage.Store(blockNumber, bloom); + foundBlocks.Add(block); } - - IBloomEnumeration bloomEnumeration = storage.GetBlooms(from, to); - IList foundBlocks = new List(blocksSet.Length); - foreach (Core.Bloom b in bloomEnumeration) - { - if (b.Matches(bytes) && bloomEnumeration.TryGetBlockNumber(out long block)) - { - foundBlocks.Add(block); - } - } - - long[] expectedFoundBlocks = blocksSet.Where(b => b >= from && b <= to).ToArray(); - TestContext.Out.WriteLine($"Expected found blocks: {string.Join(", ", expectedFoundBlocks)}"); - foundBlocks.Should().BeEquivalentTo(expectedFoundBlocks); } - private const int Buckets = 3; - private const int LevelMultiplier = 16; + long[] expectedFoundBlocks = blocksSet.Where(b => b >= from && b <= to).ToArray(); + TestContext.Out.WriteLine($"Expected found blocks: {string.Join(", ", expectedFoundBlocks)}"); + foundBlocks.Should().BeEquivalentTo(expectedFoundBlocks); + } - private static BloomStorage CreateBloomStorage(BloomConfig? bloomConfig = null) - { - BloomStorage storage = new(bloomConfig ?? new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); - int bucketItems = storage.MaxBucketSize * Buckets; + private const int Buckets = 3; + private const int LevelMultiplier = 16; - for (long i = 0; i < bucketItems; i++) - { - storage.Store(i, Core.Bloom.Empty); - } + private static BloomStorage CreateBloomStorage(BloomConfig? bloomConfig = null) + { + BloomStorage storage = new(bloomConfig ?? new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); + int bucketItems = storage.MaxBucketSize * Buckets; - return storage; + for (long i = 0; i < bucketItems; i++) + { + storage.Store(i, Core.Bloom.Empty); } - [Timeout(Timeout.MaxTestTime)] - [TestCase(byte.MaxValue)] - [TestCase(ushort.MaxValue / 4)] - [TestCase(ushort.MaxValue, Explicit = true)] - [TestCase(ushort.MaxValue * 8 + 7, Explicit = true)] - [TestCase(ushort.MaxValue * 128 + 127, Explicit = true)] - public void Can_safely_insert_concurrently(int maxBlock) + return storage; + } + + [MaxTime(Timeout.MaxTestTime)] + [TestCase(byte.MaxValue)] + [TestCase(ushort.MaxValue / 4)] + [TestCase(ushort.MaxValue, Explicit = true)] + [TestCase(ushort.MaxValue * 8 + 7, Explicit = true)] + [TestCase(ushort.MaxValue * 128 + 127, Explicit = true)] + public void Can_safely_insert_concurrently(int maxBlock) + { + BloomConfig config = new() { IndexLevelBucketSizes = new[] { 16, 16, 16 } }; + string basePath = Path.Combine(Path.GetTempPath(), DbNames.Bloom, maxBlock.ToString()); + try { - BloomConfig config = new() { IndexLevelBucketSizes = new[] { 16, 16, 16 } }; - string basePath = Path.Combine(Path.GetTempPath(), DbNames.Bloom, maxBlock.ToString()); - try + FixedSizeFileStoreFactory fileStorageFactory = new(basePath, DbNames.Bloom, Core.Bloom.ByteLength); + using BloomStorage storage = new(config, new MemDb(), fileStorageFactory); + + Parallel.For(0, maxBlock + 1, + new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 16 }, + i => + { + Core.Bloom bloom = new(); + bloom.Set(i % Core.Bloom.BitLength); + storage.Store(i, bloom); + }); + + IBloomEnumeration blooms = storage.GetBlooms(0, maxBlock); + int j = 0; + foreach (Core.Bloom bloom in blooms) { - FixedSizeFileStoreFactory fileStorageFactory = new(basePath, DbNames.Bloom, Core.Bloom.ByteLength); - using BloomStorage storage = new(config, new MemDb(), fileStorageFactory); - - Parallel.For(0, maxBlock + 1, - new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 16 }, - i => - { - Core.Bloom bloom = new(); - bloom.Set(i % Core.Bloom.BitLength); - storage.Store(i, bloom); - }); - - IBloomEnumeration blooms = storage.GetBlooms(0, maxBlock); - int j = 0; - foreach (Core.Bloom bloom in blooms) + j++; + (long FromBlock, long ToBlock) currentIndices = blooms.CurrentIndices; + int fromBlock = (int)(currentIndices.FromBlock % Core.Bloom.BitLength); + int toBlock = (int)(Math.Min(currentIndices.ToBlock, maxBlock) % Core.Bloom.BitLength); + Core.Bloom expectedBloom = new(); + for (int i = fromBlock; i <= toBlock; i++) { - j++; - (long FromBlock, long ToBlock) currentIndices = blooms.CurrentIndices; - int fromBlock = (int)(currentIndices.FromBlock % Core.Bloom.BitLength); - int toBlock = (int)(Math.Min(currentIndices.ToBlock, maxBlock) % Core.Bloom.BitLength); - Core.Bloom expectedBloom = new(); - for (int i = fromBlock; i <= toBlock; i++) - { - expectedBloom.Set(i); - } - - bloom.Should().Be(expectedBloom, $"blocks <{currentIndices.FromBlock}, {currentIndices.ToBlock}>"); - blooms.TryGetBlockNumber(out _); + expectedBloom.Set(i); } - TestContext.WriteLine($"Checked {j} blooms"); - } - finally - { - Directory.Delete(basePath, true); + bloom.Should().Be(expectedBloom, $"blocks <{currentIndices.FromBlock}, {currentIndices.ToBlock}>"); + blooms.TryGetBlockNumber(out _); } + + TestContext.Out.WriteLine($"Checked {j} blooms"); + } + finally + { + Directory.Delete(basePath, true); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/ChainHeadReadOnlyStateProviderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/ChainHeadReadOnlyStateProviderTests.cs index 4f63033347b..6711e128351 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/ChainHeadReadOnlyStateProviderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/ChainHeadReadOnlyStateProviderTests.cs @@ -7,16 +7,15 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +public class ChainHeadReadOnlyStateProviderTests { - public class ChainHeadReadOnlyStateProviderTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void uses_block_tree_head_state_root() { - [Test, Timeout(Timeout.MaxTestTime)] - public void uses_block_tree_head_state_root() - { - BlockTree blockTree = Build.A.BlockTree(Build.A.Block.WithStateRoot(TestItem.KeccakA).TestObject).OfChainLength(10).TestObject; - ChainHeadReadOnlyStateProvider chainHeadReadOnlyStateProvider = new(blockTree, Substitute.For()); - chainHeadReadOnlyStateProvider.StateRoot.Should().BeEquivalentTo(blockTree.Head!.StateRoot); - } + BlockTree blockTree = Build.A.BlockTree(Build.A.Block.WithStateRoot(TestItem.KeccakA).TestObject).OfChainLength(10).TestObject; + ChainHeadReadOnlyStateProvider chainHeadReadOnlyStateProvider = new(blockTree, Substitute.For()); + chainHeadReadOnlyStateProvider.StateRoot.Should().BeEquivalentTo(blockTree.Head!.StateRoot); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/CompositeTxSourceTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/CompositeTxSourceTests.cs index 7afd9c48398..7d1e8667359 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/CompositeTxSourceTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/CompositeTxSourceTests.cs @@ -12,66 +12,65 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Consensus +namespace Nethermind.Blockchain.Test.Consensus; + +public class CompositeTxSourceTests { - public class CompositeTxSourceTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void To_string_does_not_throw() { - [Test, Timeout(Timeout.MaxTestTime)] - public void To_string_does_not_throw() - { - ITxSource txSource = Substitute.For(); - CompositeTxSource selector = new(txSource); - _ = selector.ToString(); - } + ITxSource txSource = Substitute.For(); + CompositeTxSource selector = new(txSource); + _ = selector.ToString(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Throws_on_null_argument() - { - Assert.Throws(() => new CompositeTxSource(null!)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Throws_on_null_argument() + { + Assert.Throws(() => new CompositeTxSource(null!)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void selectTransactions_injects_transactions_from_ImmediateTransactionSources_in_front_of_block_transactions() + [Test, MaxTime(Timeout.MaxTestTime)] + public void selectTransactions_injects_transactions_from_ImmediateTransactionSources_in_front_of_block_transactions() + { + ITxSource CreateImmediateTransactionSource(BlockHeader header, Address address, List txs, bool createsTransaction) { - ITxSource CreateImmediateTransactionSource(BlockHeader header, Address address, List txs, bool createsTransaction) + var immediateTransactionSource = Substitute.For(); + immediateTransactionSource.GetTransactions(header, Arg.Any()).Returns(x => { - var immediateTransactionSource = Substitute.For(); - immediateTransactionSource.GetTransactions(header, Arg.Any()).Returns(x => + if (createsTransaction) { - if (createsTransaction) - { - var transaction = Build.A.GeneratedTransaction.To(address).WithGasPrice(UInt256.Zero).TestObject; - txs.Add(transaction); - return new[] { transaction }; - } - else - { - return Array.Empty(); - } - }); - return immediateTransactionSource; - } + var transaction = Build.A.GeneratedTransaction.To(address).WithGasPrice(UInt256.Zero).TestObject; + txs.Add(transaction); + return new[] { transaction }; + } + else + { + return Array.Empty(); + } + }); + return immediateTransactionSource; + } - var parentHeader = Build.A.BlockHeader.TestObject; - var gasLimit = 1000; - List expected = new(); + var parentHeader = Build.A.BlockHeader.TestObject; + var gasLimit = 1000; + List expected = new(); - var innerPendingTxSelector = Substitute.For(); + var innerPendingTxSelector = Substitute.For(); - var immediateTransactionSource1 = CreateImmediateTransactionSource(parentHeader, TestItem.AddressB, expected, true); - var immediateTransactionSource2 = CreateImmediateTransactionSource(parentHeader, TestItem.AddressC, expected, false); - var immediateTransactionSource3 = CreateImmediateTransactionSource(parentHeader, TestItem.AddressD, expected, true); + var immediateTransactionSource1 = CreateImmediateTransactionSource(parentHeader, TestItem.AddressB, expected, true); + var immediateTransactionSource2 = CreateImmediateTransactionSource(parentHeader, TestItem.AddressC, expected, false); + var immediateTransactionSource3 = CreateImmediateTransactionSource(parentHeader, TestItem.AddressD, expected, true); - var originalTxs = Build.A.Transaction.TestObjectNTimes(5); - innerPendingTxSelector.GetTransactions(parentHeader, Arg.Any()).Returns(originalTxs); + var originalTxs = Build.A.Transaction.TestObjectNTimes(5); + innerPendingTxSelector.GetTransactions(parentHeader, Arg.Any()).Returns(originalTxs); - var compositeTxSource = new CompositeTxSource( - immediateTransactionSource1, immediateTransactionSource2, immediateTransactionSource3, innerPendingTxSelector); + var compositeTxSource = new CompositeTxSource( + immediateTransactionSource1, immediateTransactionSource2, immediateTransactionSource3, innerPendingTxSelector); - var transactions = compositeTxSource.GetTransactions(parentHeader, gasLimit).ToArray(); - expected.AddRange(originalTxs); + var transactions = compositeTxSource.GetTransactions(parentHeader, gasLimit).ToArray(); + expected.AddRange(originalTxs); - transactions.Should().BeEquivalentTo(expected); - } + transactions.Should().BeEquivalentTo(expected); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NethDevSealEngineTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NethDevSealEngineTests.cs index 4d4405e8cc6..d9f0704c516 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NethDevSealEngineTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NethDevSealEngineTests.cs @@ -14,7 +14,7 @@ namespace Nethermind.Blockchain.Test.Consensus [TestFixture] public class NethDevSealEngineTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Defaults_are_fine() { NethDevSealEngine nethDevSealEngine = new(); @@ -22,14 +22,14 @@ public void Defaults_are_fine() nethDevSealEngine.CanSeal(1, Keccak.Zero).Should().BeTrue(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_seal_returns_true() { NethDevSealEngine nethDevSealEngine = new(); nethDevSealEngine.CanSeal(1, Keccak.Zero).Should().BeTrue(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Validations_return_true() { NethDevSealEngine nethDevSealEngine = new(); @@ -38,7 +38,7 @@ public void Validations_return_true() nethDevSealEngine.ValidateSeal(null, true).Should().Be(true); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Block_sealing_sets_the_hash() { Block block = Build.A.Block.TestObject; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSealEngineTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSealEngineTests.cs index 8a6dfc3002f..dcf4bf71310 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSealEngineTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSealEngineTests.cs @@ -13,14 +13,14 @@ namespace Nethermind.Blockchain.Test.Consensus [TestFixture] public class NullSealEngineTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Default_hints() { ISealValidator sealValidator = NullSealEngine.Instance; sealValidator.HintValidationRange(Guid.Empty, 0, 0); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Test() { NullSealEngine engine = NullSealEngine.Instance; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs index e070c064c71..cfac44513dd 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs @@ -14,7 +14,7 @@ namespace Nethermind.Blockchain.Test.Consensus [TestFixture] public class NullSignerTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Test() { NullSigner signer = NullSigner.Instance; @@ -22,7 +22,7 @@ public void Test() signer.CanSign.Should().BeTrue(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public async Task Test_signing() { NullSigner signer = NullSigner.Instance; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/OneByOneTxSourceTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/OneByOneTxSourceTests.cs index 1ba45176618..35484810836 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/OneByOneTxSourceTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/OneByOneTxSourceTests.cs @@ -13,7 +13,7 @@ namespace Nethermind.Blockchain.Test.Consensus [TestFixture] public class OneByOneTxSourceTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_serve_one_by_one() { ITxSource source = Substitute.For(); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SealEngineExceptionTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SealEngineExceptionTests.cs index 5fdd029e1b3..5d5fcb9602c 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SealEngineExceptionTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SealEngineExceptionTests.cs @@ -10,7 +10,7 @@ namespace Nethermind.Blockchain.Test.Consensus [TestFixture] public class SealEngineExceptionTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Test() { SealEngineException exception = new("message"); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs index 43c3e511ace..23957d53a0c 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs @@ -18,7 +18,7 @@ namespace Nethermind.Blockchain.Test.Consensus [TestFixture] public class SignerTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Address_is_zero_when_key_is_null() { // not a great fan of using Address.Zero like a null value but let us show in test @@ -27,14 +27,14 @@ public void Address_is_zero_when_key_is_null() signer.Address.Should().Be(Address.Zero); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Cannot_sign_when_null_key() { Signer signer = new(1, (PrivateKey?)null, LimboLogs.Instance); signer.CanSign.Should().BeFalse(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_set_signer_to_null() { Signer signer = new(1, TestItem.PrivateKeyA, LimboLogs.Instance); @@ -43,7 +43,7 @@ public void Can_set_signer_to_null() signer.CanSign.Should().BeFalse(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_set_signer_to_protected_null() { Signer signer = new(1, TestItem.PrivateKeyA, LimboLogs.Instance); @@ -52,14 +52,14 @@ public void Can_set_signer_to_protected_null() signer.CanSign.Should().BeFalse(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Throws_when_trying_to_sign_with_a_null_key() { Signer signer = new(1, (PrivateKey?)null, LimboLogs.Instance); Assert.Throws(() => signer.Sign(Keccak.Zero)); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public async Task Test_signing() { Signer signer = new(1, TestItem.PrivateKeyA, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SinglePendingTxSelectorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SinglePendingTxSelectorTests.cs index de48f000265..4bc0c890d50 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SinglePendingTxSelectorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SinglePendingTxSelectorTests.cs @@ -16,7 +16,7 @@ public class SinglePendingTxSelectorTests { private readonly BlockHeader _anyParent = Build.A.BlockHeader.TestObject; - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void To_string_does_not_throw() { ITxSource txSource = Substitute.For(); @@ -24,7 +24,7 @@ public void To_string_does_not_throw() _ = selector.ToString(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void When_no_transactions_returns_empty_list() { ITxSource txSource = Substitute.For(); @@ -32,7 +32,7 @@ public void When_no_transactions_returns_empty_list() selector.GetTransactions(_anyParent, 1000000).Should().HaveCount(0); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void When_many_transactions_returns_one_with_lowest_nonce_and_highest_timestamp() { ITxSource txSource = Substitute.For(); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/DaoDataTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/DaoDataTests.cs index 3d8f0dda65f..b7483603e60 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/DaoDataTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/DaoDataTests.cs @@ -5,17 +5,15 @@ using Nethermind.Core; using NUnit.Framework; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +public class DaoDataTests { - [TestFixture] - public class DaoDataTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void Test() { - [Test, Timeout(Timeout.MaxTestTime)] - public void Test() - { - DaoData.DaoAccounts.Should().HaveCount(116); - DaoData.DaoWithdrawalAccount.Should().Be( - new Address("bf4ed7b27f1d666546e30d74d50d173d20bca754")); - } + DaoData.DaoAccounts.Should().HaveCount(116); + DaoData.DaoWithdrawalAccount.Should().Be( + new Address("bf4ed7b27f1d666546e30d74d50d173d20bca754")); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Data/FileLocalDataSourceTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Data/FileLocalDataSourceTests.cs index 2114a7fb98e..0046ba3748d 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Data/FileLocalDataSourceTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Data/FileLocalDataSourceTests.cs @@ -18,7 +18,7 @@ namespace Nethermind.Blockchain.Test.Data { public class FileLocalDataSourceTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void correctly_reads_existing_file() { using (var tempFile = TempPath.GetTempFile()) @@ -31,7 +31,7 @@ public void correctly_reads_existing_file() } [Ignore("flaky")] - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public async Task correctly_updates_from_existing_file() { using (var tempFile = TempPath.GetTempFile()) @@ -60,7 +60,7 @@ public async Task correctly_updates_from_existing_file() } } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] [Ignore("flaky test")] public async Task correctly_updates_from_new_file() { @@ -83,7 +83,7 @@ public async Task correctly_updates_from_new_file() private static string GenerateStringJson(params string[] items) => $"[{string.Join(", ", items.Select(i => $"\"{i}\""))}]"; - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void loads_default_when_failed_loading_file() { using var tempFile = TempPath.GetTempFile(); @@ -94,7 +94,7 @@ public void loads_default_when_failed_loading_file() } } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] [Retry(10)] [Ignore("Causing repeated pains on GitHub actions.")] public async Task retries_loading_file() @@ -123,7 +123,7 @@ public async Task retries_loading_file() } [Ignore("flaky test")] - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public async Task loads_default_when_deleted_file() { using (var tempFile = TempPath.GetTempFile()) diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterManagerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterManagerTests.cs index 3c4b3e05ff3..28f2ba1a791 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterManagerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterManagerTests.cs @@ -17,306 +17,305 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Filters +namespace Nethermind.Blockchain.Test.Filters; + +public class FilterManagerTests { - public class FilterManagerTests + private IFilterStore _filterStore = null!; + private IBlockProcessor _blockProcessor = null!; + private ITxPool _txPool = null!; + private ILogManager _logManager = null!; + private FilterManager _filterManager = null!; + + private int _currentFilterId; + + [SetUp] + public void Setup() { - private IFilterStore _filterStore = null!; - private IBlockProcessor _blockProcessor = null!; - private ITxPool _txPool = null!; - private ILogManager _logManager = null!; - private FilterManager _filterManager = null!; + _currentFilterId = 0; + _filterStore = Substitute.For(); + _blockProcessor = Substitute.For(); + _txPool = Substitute.For(); + _logManager = LimboLogs.Instance; + } - private int _currentFilterId; + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_default_filter_parameters() + => LogsShouldNotBeEmpty(_ => { }, _ => { }); - [SetUp] - public void Setup() - { - _currentFilterId = 0; - _filterStore = Substitute.For(); - _blockProcessor = Substitute.For(); - _txPool = Substitute.For(); - _logManager = LimboLogs.Instance; - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void many_logs_should_not_be_empty_for_default_filters_parameters() + => LogsShouldNotBeEmpty(new Action[] { _ => { }, _ => { }, _ => { } }, + new Action[] { _ => { }, _ => { }, _ => { } }); - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_default_filter_parameters() - => LogsShouldNotBeEmpty(_ => { }, _ => { }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void many_logs_should_not_be_empty_for_default_filters_parameters() - => LogsShouldNotBeEmpty(new Action[] { _ => { }, _ => { }, _ => { } }, - new Action[] { _ => { }, _ => { }, _ => { } }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_from_block_earliest_type() - => LogsShouldNotBeEmpty(filter => filter.FromEarliestBlock(), _ => { }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_from_block_pending_type() - => LogsShouldNotBeEmpty(filter => filter.FromPendingBlock(), _ => { }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_from_block_latest_type() - => LogsShouldNotBeEmpty(filter => filter.FromLatestBlock(), _ => { }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_to_block_earliest_type() - => LogsShouldNotBeEmpty(filter => filter.ToEarliestBlock(), _ => { }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_to_block_pending_type() - => LogsShouldNotBeEmpty(filter => filter.ToPendingBlock(), _ => { }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_to_block_latest_type() - => LogsShouldNotBeEmpty(filter => filter.ToLatestBlock(), _ => { }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_from_block_number_in_range() - => LogsShouldNotBeEmpty(filter => filter.FromBlock(1L), - receipt => receipt.WithBlockNumber(2L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void many_logs_should_not_be_empty_for_from_blocks_numbers_in_range() - => LogsShouldNotBeEmpty( - new Action[] - { - filter => filter.FromBlock(1L), - filter => filter.FromBlock(2L), - filter => filter.FromBlock(3L) - }, - new Action[] - { - receipt => receipt.WithBlockNumber(1L), - receipt => receipt.WithBlockNumber(5L), - receipt => receipt.WithBlockNumber(10L) - }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_from_block_number_not_in_range() - => LogsShouldBeEmpty(filter => filter.FromBlock(1L), - receipt => receipt.WithBlockNumber(0L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_to_block_number_in_range() - => LogsShouldNotBeEmpty(filter => filter.ToBlock(2L), - receipt => receipt.WithBlockNumber(1L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void many_logs_should_not_be_empty_for_to_blocks_numbers_in_range() - => LogsShouldNotBeEmpty( - new Action[] - { - filter => filter.ToBlock(1L), - filter => filter.ToBlock(5L), - filter => filter.ToBlock(10L) - }, - new Action[] - { - receipt => receipt.WithBlockNumber(1L), - receipt => receipt.WithBlockNumber(2L), - receipt => receipt.WithBlockNumber(3L) - }); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_to_block_number_not_in_range() - => LogsShouldBeEmpty(filter => filter.ToBlock(1L), - receipt => receipt.WithBlockNumber(2L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_from_block_number_in_range_and_to_block_number_in_range() - => LogsShouldNotBeEmpty(filter => filter.FromBlock(2L).ToBlock(6L), - receipt => receipt.WithBlockNumber(4L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_from_block_number_in_range_and_to_block_number_not_in_range() - => LogsShouldBeEmpty(filter => filter.FromBlock(2L).ToBlock(3L), - receipt => receipt.WithBlockNumber(4L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_from_block_number_not_in_range_and_to_block_number_in_range() - => LogsShouldBeEmpty(filter => filter.FromBlock(5L).ToBlock(7L), - receipt => receipt.WithBlockNumber(4L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_from_block_number_not_in_range_and_to_block_number_not_in_range() - => LogsShouldBeEmpty(filter => filter.FromBlock(2L).ToBlock(3L), - receipt => receipt.WithBlockNumber(4L)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_existing_address() - => LogsShouldNotBeEmpty(filter => filter.WithAddress(TestItem.AddressA), - receipt => receipt.WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_non_existing_address() - => LogsShouldBeEmpty(filter => filter.WithAddress(TestItem.AddressA), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressB).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_existing_addresses() - => LogsShouldNotBeEmpty(filter => filter.WithAddresses(TestItem.AddressA, TestItem.AddressB), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressB).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_non_existing_addresses() - => LogsShouldBeEmpty(filter => filter.WithAddresses(TestItem.AddressA, TestItem.AddressB), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressC).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_existing_specific_topic() - => LogsShouldNotBeEmpty(filter => filter - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA)), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_non_existing_specific_topic() - => LogsShouldBeEmpty(filter => filter - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA)), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_existing_any_topic() - => LogsShouldNotBeEmpty(filter => filter - .WithTopicExpressions(TestTopicExpressions.Any), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_existing_or_topic() - => LogsShouldNotBeEmpty(filter => filter - .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakD))), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_non_existing_or_topic() - => LogsShouldBeEmpty(filter => filter - .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakD))), - receipt => receipt - .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_existing_block_and_address_and_topics() - => LogsShouldNotBeEmpty(filter => filter - .FromBlock(1L) - .ToBlock(10L) - .WithAddress(TestItem.AddressA) - .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakD))), - receipt => receipt - .WithBlockNumber(6L) - .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA) - .WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_not_be_empty_for_existing_block_and_addresses_and_topics() - => LogsShouldNotBeEmpty(filter => filter - .FromBlock(1L) - .ToBlock(10L) - .WithAddresses(TestItem.AddressA, TestItem.AddressB) - .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakD))), - receipt => receipt - .WithBlockNumber(6L) - .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA) - .WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); - - [Test, Timeout(Timeout.MaxTestTime)] - public void logs_should_be_empty_for_existing_block_and_addresses_and_non_existing_topic() - => LogsShouldBeEmpty(filter => filter - .FromBlock(1L) - .ToBlock(10L) - .WithAddresses(TestItem.AddressA, TestItem.AddressB) - .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakC), TestTopicExpressions.Specific(TestItem.KeccakD))), - receipt => receipt - .WithBlockNumber(6L) - .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA) - .WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); - - - private void LogsShouldNotBeEmpty(Action filterBuilder, - Action receiptBuilder) - => LogsShouldNotBeEmpty(new[] { filterBuilder }, new[] { receiptBuilder }); - - private void LogsShouldBeEmpty(Action filterBuilder, - Action receiptBuilder) - => LogsShouldBeEmpty(new[] { filterBuilder }, new[] { receiptBuilder }); - - private void LogsShouldNotBeEmpty(IEnumerable> filterBuilders, - IEnumerable> receiptBuilders) - => Assert(filterBuilders, receiptBuilders, logs => logs.Should().NotBeEmpty()); - - private void LogsShouldBeEmpty(IEnumerable> filterBuilders, - IEnumerable> receiptBuilders) - => Assert(filterBuilders, receiptBuilders, logs => logs.Should().BeEmpty()); - - private void Assert(IEnumerable> filterBuilders, - IEnumerable> receiptBuilders, - Action> logsAssertion) - { - List filters = new List(); - List receipts = new List(); - foreach (Action filterBuilder in filterBuilders) - { - filters.Add(BuildFilter(filterBuilder)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_from_block_earliest_type() + => LogsShouldNotBeEmpty(filter => filter.FromEarliestBlock(), _ => { }); - foreach (Action receiptBuilder in receiptBuilders) - { - receipts.Add(BuildReceipt(receiptBuilder)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_from_block_pending_type() + => LogsShouldNotBeEmpty(filter => filter.FromPendingBlock(), _ => { }); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_from_block_latest_type() + => LogsShouldNotBeEmpty(filter => filter.FromLatestBlock(), _ => { }); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_to_block_earliest_type() + => LogsShouldNotBeEmpty(filter => filter.ToEarliestBlock(), _ => { }); - // adding always a simple block filter and test - Block block = Build.A.Block.TestObject; - BlockFilter blockFilter = new(_currentFilterId++, 0); - filters.Add(blockFilter); + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_to_block_pending_type() + => LogsShouldNotBeEmpty(filter => filter.ToPendingBlock(), _ => { }); - _filterStore.GetFilters().Returns(filters.OfType().ToArray()); - _filterStore.GetFilters().Returns(filters.OfType().ToArray()); - _filterManager = new FilterManager(_filterStore, _blockProcessor, _txPool, _logManager); + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_to_block_latest_type() + => LogsShouldNotBeEmpty(filter => filter.ToLatestBlock(), _ => { }); - _blockProcessor.BlockProcessed += Raise.EventWith(_blockProcessor, new BlockProcessedEventArgs(block, Array.Empty())); + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_from_block_number_in_range() + => LogsShouldNotBeEmpty(filter => filter.FromBlock(1L), + receipt => receipt.WithBlockNumber(2L)); - int index = 1; - foreach (TxReceipt receipt in receipts) + [Test, MaxTime(Timeout.MaxTestTime)] + public void many_logs_should_not_be_empty_for_from_blocks_numbers_in_range() + => LogsShouldNotBeEmpty( + new Action[] { - _blockProcessor.TransactionProcessed += Raise.EventWith(_blockProcessor, - new TxProcessedEventArgs(index, Build.A.Transaction.TestObject, receipt)); - index++; - } + filter => filter.FromBlock(1L), + filter => filter.FromBlock(2L), + filter => filter.FromBlock(3L) + }, + new Action[] + { + receipt => receipt.WithBlockNumber(1L), + receipt => receipt.WithBlockNumber(5L), + receipt => receipt.WithBlockNumber(10L) + }); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_from_block_number_not_in_range() + => LogsShouldBeEmpty(filter => filter.FromBlock(1L), + receipt => receipt.WithBlockNumber(0L)); - NUnit.Framework.Assert.Multiple(() => + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_to_block_number_in_range() + => LogsShouldNotBeEmpty(filter => filter.ToBlock(2L), + receipt => receipt.WithBlockNumber(1L)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void many_logs_should_not_be_empty_for_to_blocks_numbers_in_range() + => LogsShouldNotBeEmpty( + new Action[] + { + filter => filter.ToBlock(1L), + filter => filter.ToBlock(5L), + filter => filter.ToBlock(10L) + }, + new Action[] { - foreach (LogFilter filter in filters.OfType()) - { - FilterLog[] logs = _filterManager.GetLogs(filter.Id); - logsAssertion(logs); - } - - Hash256[] hashes = _filterManager.GetBlocksHashes(blockFilter.Id); - NUnit.Framework.Assert.That(hashes.Length, Is.EqualTo(1)); + receipt => receipt.WithBlockNumber(1L), + receipt => receipt.WithBlockNumber(2L), + receipt => receipt.WithBlockNumber(3L) }); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_to_block_number_not_in_range() + => LogsShouldBeEmpty(filter => filter.ToBlock(1L), + receipt => receipt.WithBlockNumber(2L)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_from_block_number_in_range_and_to_block_number_in_range() + => LogsShouldNotBeEmpty(filter => filter.FromBlock(2L).ToBlock(6L), + receipt => receipt.WithBlockNumber(4L)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_from_block_number_in_range_and_to_block_number_not_in_range() + => LogsShouldBeEmpty(filter => filter.FromBlock(2L).ToBlock(3L), + receipt => receipt.WithBlockNumber(4L)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_from_block_number_not_in_range_and_to_block_number_in_range() + => LogsShouldBeEmpty(filter => filter.FromBlock(5L).ToBlock(7L), + receipt => receipt.WithBlockNumber(4L)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_from_block_number_not_in_range_and_to_block_number_not_in_range() + => LogsShouldBeEmpty(filter => filter.FromBlock(2L).ToBlock(3L), + receipt => receipt.WithBlockNumber(4L)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_existing_address() + => LogsShouldNotBeEmpty(filter => filter.WithAddress(TestItem.AddressA), + receipt => receipt.WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_non_existing_address() + => LogsShouldBeEmpty(filter => filter.WithAddress(TestItem.AddressA), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressB).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_existing_addresses() + => LogsShouldNotBeEmpty(filter => filter.WithAddresses(TestItem.AddressA, TestItem.AddressB), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressB).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_non_existing_addresses() + => LogsShouldBeEmpty(filter => filter.WithAddresses(TestItem.AddressA, TestItem.AddressB), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressC).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_existing_specific_topic() + => LogsShouldNotBeEmpty(filter => filter + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA)), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_non_existing_specific_topic() + => LogsShouldBeEmpty(filter => filter + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA)), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_existing_any_topic() + => LogsShouldNotBeEmpty(filter => filter + .WithTopicExpressions(TestTopicExpressions.Any), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_existing_or_topic() + => LogsShouldNotBeEmpty(filter => filter + .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakD))), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_non_existing_or_topic() + => LogsShouldBeEmpty(filter => filter + .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakD))), + receipt => receipt + .WithLogs(Build.A.LogEntry.WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_existing_block_and_address_and_topics() + => LogsShouldNotBeEmpty(filter => filter + .FromBlock(1L) + .ToBlock(10L) + .WithAddress(TestItem.AddressA) + .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakD))), + receipt => receipt + .WithBlockNumber(6L) + .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA) + .WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_not_be_empty_for_existing_block_and_addresses_and_topics() + => LogsShouldNotBeEmpty(filter => filter + .FromBlock(1L) + .ToBlock(10L) + .WithAddresses(TestItem.AddressA, TestItem.AddressB) + .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakD))), + receipt => receipt + .WithBlockNumber(6L) + .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA) + .WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); + + [Test, MaxTime(Timeout.MaxTestTime)] + public void logs_should_be_empty_for_existing_block_and_addresses_and_non_existing_topic() + => LogsShouldBeEmpty(filter => filter + .FromBlock(1L) + .ToBlock(10L) + .WithAddresses(TestItem.AddressA, TestItem.AddressB) + .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakC), TestTopicExpressions.Specific(TestItem.KeccakD))), + receipt => receipt + .WithBlockNumber(6L) + .WithLogs(Build.A.LogEntry.WithAddress(TestItem.AddressA) + .WithTopics(TestItem.KeccakB, TestItem.KeccakC).TestObject)); + + + private void LogsShouldNotBeEmpty(Action filterBuilder, + Action receiptBuilder) + => LogsShouldNotBeEmpty(new[] { filterBuilder }, new[] { receiptBuilder }); + + private void LogsShouldBeEmpty(Action filterBuilder, + Action receiptBuilder) + => LogsShouldBeEmpty(new[] { filterBuilder }, new[] { receiptBuilder }); + + private void LogsShouldNotBeEmpty(IEnumerable> filterBuilders, + IEnumerable> receiptBuilders) + => Assert(filterBuilders, receiptBuilders, logs => logs.Should().NotBeEmpty()); + + private void LogsShouldBeEmpty(IEnumerable> filterBuilders, + IEnumerable> receiptBuilders) + => Assert(filterBuilders, receiptBuilders, logs => logs.Should().BeEmpty()); + + private void Assert(IEnumerable> filterBuilders, + IEnumerable> receiptBuilders, + Action> logsAssertion) + { + List filters = new List(); + List receipts = new List(); + foreach (Action filterBuilder in filterBuilders) + { + filters.Add(BuildFilter(filterBuilder)); } - private LogFilter BuildFilter(Action builder) + foreach (Action receiptBuilder in receiptBuilders) { - FilterBuilder builderInstance = FilterBuilder.New(ref _currentFilterId); - builder(builderInstance); + receipts.Add(BuildReceipt(receiptBuilder)); + } + + // adding always a simple block filter and test + Block block = Build.A.Block.TestObject; + BlockFilter blockFilter = new(_currentFilterId++, 0); + filters.Add(blockFilter); - return builderInstance.Build(); + _filterStore.GetFilters().Returns(filters.OfType().ToArray()); + _filterStore.GetFilters().Returns(filters.OfType().ToArray()); + _filterManager = new FilterManager(_filterStore, _blockProcessor, _txPool, _logManager); + + _blockProcessor.BlockProcessed += Raise.EventWith(_blockProcessor, new BlockProcessedEventArgs(block, Array.Empty())); + + int index = 1; + foreach (TxReceipt receipt in receipts) + { + _blockProcessor.TransactionProcessed += Raise.EventWith(_blockProcessor, + new TxProcessedEventArgs(index, Build.A.Transaction.TestObject, receipt)); + index++; } - private static TxReceipt BuildReceipt(Action builder) + NUnit.Framework.Assert.Multiple(() => { - ReceiptBuilder builderInstance = new(); - builder(builderInstance); + foreach (LogFilter filter in filters.OfType()) + { + FilterLog[] logs = _filterManager.GetLogs(filter.Id); + logsAssertion(logs); + } - return builderInstance.TestObject; - } + Hash256[] hashes = _filterManager.GetBlocksHashes(blockFilter.Id); + NUnit.Framework.Assert.That(hashes.Length, Is.EqualTo(1)); + }); + } + + private LogFilter BuildFilter(Action builder) + { + FilterBuilder builderInstance = FilterBuilder.New(ref _currentFilterId); + builder(builderInstance); + + return builderInstance.Build(); + } + + private static TxReceipt BuildReceipt(Action builder) + { + ReceiptBuilder builderInstance = new(); + builder(builderInstance); + + return builderInstance.TestObject; } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs index bf58f99f3db..80b054978b5 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs @@ -13,137 +13,135 @@ using Nethermind.Core.Test.Builders; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Filters +namespace Nethermind.Blockchain.Test.Filters; + +public class FilterStoreTests { - [TestFixture] - public class FilterStoreTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_save_and_load_block_filter() { - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_save_and_load_block_filter() - { - FilterStore store = new(); - BlockFilter filter = store.CreateBlockFilter(1); - store.SaveFilter(filter); - Assert.True(store.FilterExists(0), "exists"); - Assert.That(store.GetFilterType(filter.Id), Is.EqualTo(FilterType.BlockFilter), "type"); - } + FilterStore store = new(); + BlockFilter filter = store.CreateBlockFilter(1); + store.SaveFilter(filter); + Assert.That(store.FilterExists(0), Is.True, "exists"); + Assert.That(store.GetFilterType(filter.Id), Is.EqualTo(FilterType.BlockFilter), "type"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_save_and_load_log_filter() - { - FilterStore store = new(); - LogFilter filter = store.CreateLogFilter(new BlockParameter(1), new BlockParameter(2)); - store.SaveFilter(filter); - Assert.True(store.FilterExists(0), "exists"); - Assert.That(store.GetFilterType(filter.Id), Is.EqualTo(FilterType.LogFilter), "type"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_save_and_load_log_filter() + { + FilterStore store = new(); + LogFilter filter = store.CreateLogFilter(new BlockParameter(1), new BlockParameter(2)); + store.SaveFilter(filter); + Assert.That(store.FilterExists(0), Is.True, "exists"); + Assert.That(store.GetFilterType(filter.Id), Is.EqualTo(FilterType.LogFilter), "type"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Cannot_overwrite_filters() - { - FilterStore store = new(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Cannot_overwrite_filters() + { + FilterStore store = new(); - BlockFilter externalFilter = new(100, 1); - store.SaveFilter(externalFilter); - Assert.Throws(() => store.SaveFilter(externalFilter)); - } + BlockFilter externalFilter = new(100, 1); + store.SaveFilter(externalFilter); + Assert.Throws(() => store.SaveFilter(externalFilter)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Ids_are_incremented_when_storing_externally_created_filter() - { - FilterStore store = new(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Ids_are_incremented_when_storing_externally_created_filter() + { + FilterStore store = new(); - BlockFilter externalFilter = new(100, 1); - store.SaveFilter(externalFilter); - LogFilter filter = store.CreateLogFilter(new BlockParameter(1), new BlockParameter(2)); - store.SaveFilter(filter); + BlockFilter externalFilter = new(100, 1); + store.SaveFilter(externalFilter); + LogFilter filter = store.CreateLogFilter(new BlockParameter(1), new BlockParameter(2)); + store.SaveFilter(filter); - Assert.True(store.FilterExists(100), "exists 100"); - Assert.True(store.FilterExists(101), "exists 101"); - Assert.That(store.GetFilterType(filter.Id), Is.EqualTo(FilterType.LogFilter), "type"); - } + Assert.That(store.FilterExists(100), Is.True, "exists 100"); + Assert.That(store.FilterExists(101), Is.True, "exists 101"); + Assert.That(store.GetFilterType(filter.Id), Is.EqualTo(FilterType.LogFilter), "type"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Remove_filter_removes_and_notifies() - { - FilterStore store = new(); - BlockFilter filter = store.CreateBlockFilter(1); - store.SaveFilter(filter); - bool hasNotified = false; - store.FilterRemoved += (s, e) => hasNotified = true; - store.RemoveFilter(0); - - Assert.True(hasNotified, "notied"); - Assert.False(store.FilterExists(0), "exists"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Remove_filter_removes_and_notifies() + { + FilterStore store = new(); + BlockFilter filter = store.CreateBlockFilter(1); + store.SaveFilter(filter); + bool hasNotified = false; + store.FilterRemoved += (s, e) => hasNotified = true; + store.RemoveFilter(0); + + Assert.That(hasNotified, Is.True, "notied"); + Assert.That(store.FilterExists(0), Is.False, "exists"); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_get_filters_by_type() - { - FilterStore store = new(); - BlockFilter filter1 = store.CreateBlockFilter(1); - store.SaveFilter(filter1); - LogFilter filter2 = store.CreateLogFilter(new BlockParameter(1), new BlockParameter(2)); - store.SaveFilter(filter2); - - LogFilter[] logFilters = store.GetFilters().ToArray(); - BlockFilter[] blockFilters = store.GetFilters().ToArray(); - - Assert.That(logFilters.Length, Is.EqualTo(1), "log filters length"); - Assert.That(logFilters[0].Id, Is.EqualTo(1), "log filters ids"); - Assert.That(blockFilters.Length, Is.EqualTo(1), "block Filters length"); - Assert.That(blockFilters[0].Id, Is.EqualTo(0), "block filters ids"); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_get_filters_by_type() + { + FilterStore store = new(); + BlockFilter filter1 = store.CreateBlockFilter(1); + store.SaveFilter(filter1); + LogFilter filter2 = store.CreateLogFilter(new BlockParameter(1), new BlockParameter(2)); + store.SaveFilter(filter2); + + LogFilter[] logFilters = store.GetFilters().ToArray(); + BlockFilter[] blockFilters = store.GetFilters().ToArray(); + + Assert.That(logFilters.Length, Is.EqualTo(1), "log filters length"); + Assert.That(logFilters[0].Id, Is.EqualTo(1), "log filters ids"); + Assert.That(blockFilters.Length, Is.EqualTo(1), "block Filters length"); + Assert.That(blockFilters[0].Id, Is.EqualTo(0), "block filters ids"); + } - public static IEnumerable CorrectlyCreatesAddressFilterTestCases + public static IEnumerable CorrectlyCreatesAddressFilterTestCases + { + get { - get - { - yield return new TestCaseData(null, AddressFilter.AnyAddress); - yield return new TestCaseData(TestItem.AddressA.ToString(), new AddressFilter(TestItem.AddressA)); - yield return new TestCaseData(new[] { TestItem.AddressA.ToString(), TestItem.AddressB.ToString() }, - new AddressFilter(new HashSet() { TestItem.AddressA, TestItem.AddressB })); - } + yield return new TestCaseData(null, AddressFilter.AnyAddress); + yield return new TestCaseData(TestItem.AddressA.ToString(), new AddressFilter(TestItem.AddressA)); + yield return new TestCaseData(new[] { TestItem.AddressA.ToString(), TestItem.AddressB.ToString() }, + new AddressFilter(new HashSet() { TestItem.AddressA, TestItem.AddressB })); } + } - [TestCaseSource(nameof(CorrectlyCreatesAddressFilterTestCases))] - public void Correctly_creates_address_filter(object address, AddressFilter expected) - { - BlockParameter from = new(100); - BlockParameter to = new(BlockParameterType.Latest); - FilterStore store = new(); - LogFilter filter = store.CreateLogFilter(from, to, address); - filter.AddressFilter.Should().BeEquivalentTo(expected); - } + [TestCaseSource(nameof(CorrectlyCreatesAddressFilterTestCases))] + public void Correctly_creates_address_filter(object address, AddressFilter expected) + { + BlockParameter from = new(100); + BlockParameter to = new(BlockParameterType.Latest); + FilterStore store = new(); + LogFilter filter = store.CreateLogFilter(from, to, address); + filter.AddressFilter.Should().BeEquivalentTo(expected); + } - public static IEnumerable CorrectlyCreatesTopicsFilterTestCases + public static IEnumerable CorrectlyCreatesTopicsFilterTestCases + { + get { - get - { - yield return new TestCaseData(null, SequenceTopicsFilter.AnyTopic); + yield return new TestCaseData(null, SequenceTopicsFilter.AnyTopic); - yield return new TestCaseData(new[] { TestItem.KeccakA.ToString() }, - new SequenceTopicsFilter(new SpecificTopic(TestItem.KeccakA))); + yield return new TestCaseData(new[] { TestItem.KeccakA.ToString() }, + new SequenceTopicsFilter(new SpecificTopic(TestItem.KeccakA))); - yield return new TestCaseData(new[] { TestItem.KeccakA.ToString(), TestItem.KeccakB.ToString() }, - new SequenceTopicsFilter(new SpecificTopic(TestItem.KeccakA), new SpecificTopic(TestItem.KeccakB))); + yield return new TestCaseData(new[] { TestItem.KeccakA.ToString(), TestItem.KeccakB.ToString() }, + new SequenceTopicsFilter(new SpecificTopic(TestItem.KeccakA), new SpecificTopic(TestItem.KeccakB))); - yield return new TestCaseData(new[] { null, TestItem.KeccakB.ToString() }, - new SequenceTopicsFilter(AnyTopic.Instance, new SpecificTopic(TestItem.KeccakB))); + yield return new TestCaseData(new[] { null, TestItem.KeccakB.ToString() }, + new SequenceTopicsFilter(AnyTopic.Instance, new SpecificTopic(TestItem.KeccakB))); - yield return new TestCaseData(new object[] { new[] { TestItem.KeccakA.ToString(), TestItem.KeccakB.ToString(), TestItem.KeccakC.ToString() }, TestItem.KeccakD.ToString() }, - new SequenceTopicsFilter(new OrExpression(new SpecificTopic(TestItem.KeccakA), new SpecificTopic(TestItem.KeccakB), new SpecificTopic(TestItem.KeccakC)), new SpecificTopic(TestItem.KeccakD))); - } + yield return new TestCaseData(new object[] { new[] { TestItem.KeccakA.ToString(), TestItem.KeccakB.ToString(), TestItem.KeccakC.ToString() }, TestItem.KeccakD.ToString() }, + new SequenceTopicsFilter(new OrExpression(new SpecificTopic(TestItem.KeccakA), new SpecificTopic(TestItem.KeccakB), new SpecificTopic(TestItem.KeccakC)), new SpecificTopic(TestItem.KeccakD))); } + } - [TestCaseSource(nameof(CorrectlyCreatesTopicsFilterTestCases))] - public void Correctly_creates_topics_filter(IEnumerable topics, TopicsFilter expected) - { - BlockParameter from = new(100); - BlockParameter to = new(BlockParameterType.Latest); - FilterStore store = new(); - LogFilter filter = store.CreateLogFilter(from, to, null, topics); - filter.TopicsFilter.Should().BeEquivalentTo(expected, c => c.ComparingByValue()); - } + [TestCaseSource(nameof(CorrectlyCreatesTopicsFilterTestCases))] + public void Correctly_creates_topics_filter(IEnumerable topics, TopicsFilter expected) + { + BlockParameter from = new(100); + BlockParameter to = new(BlockParameterType.Latest); + FilterStore store = new(); + LogFilter filter = store.CreateLogFilter(from, to, null, topics); + filter.TopicsFilter.Should().BeEquivalentTo(expected, c => c.ComparingByValue()); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Filters/LogFilterTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Filters/LogFilterTests.cs index ab9bbeff4f9..fdceb6b1839 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Filters/LogFilterTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Filters/LogFilterTests.cs @@ -10,209 +10,208 @@ using Nethermind.Core.Test.Builders; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Filters +namespace Nethermind.Blockchain.Test.Filters; + +public class LogFilterTests { - public class LogFilterTests - { - private int _filterCounter; - - [Test, Timeout(Timeout.MaxTestTime)] - public void any_address_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithAnyAddress() - .Build(); + private int _filterCounter; - filter.Matches(Core.Bloom.Empty).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void address_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithAddress(TestItem.AddressA) - .Build(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void any_address_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithAnyAddress() + .Build(); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA)); + filter.Matches(Core.Bloom.Empty).Should().BeTrue(); + } - filter.Matches(bloom).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void addresses_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithAddresses(TestItem.AddressA, TestItem.AddressB, TestItem.AddressC) - .Build(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void address_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithAddress(TestItem.AddressA) + .Build(); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB)); + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA)); - filter.Matches(bloom).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void any_topics_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Any) - .Build(); + filter.Matches(bloom).Should().BeTrue(); + } - filter.Matches(Core.Bloom.Empty).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void specific_topics_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA)) - .Build(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void addresses_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithAddresses(TestItem.AddressA, TestItem.AddressB, TestItem.AddressC) + .Build(); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakA, TestItem.KeccakB)); + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB)); - filter.Matches(bloom).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void multiple_specific_topics_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakB)) - .Build(); + filter.Matches(bloom).Should().BeTrue(); + } - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakA, TestItem.KeccakB)); + [Test, MaxTime(Timeout.MaxTestTime)] + public void any_topics_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Any) + .Build(); - filter.Matches(bloom).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void or_topics_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) - .Build(); + filter.Matches(Core.Bloom.Empty).Should().BeTrue(); + } - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakB)); + [Test, MaxTime(Timeout.MaxTestTime)] + public void specific_topics_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA)) + .Build(); - filter.Matches(bloom).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void complex_topics_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) - .Build(); + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakA, TestItem.KeccakB)); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakA)); - - filter.Matches(bloom).Should().BeTrue(); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void complex_filter_matches_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakC))) - .WithAddress(TestItem.AddressD) - .Build(); - - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressD, TestItem.KeccakA, TestItem.KeccakC)); - - filter.Matches(bloom).Should().BeTrue(); - } + filter.Matches(bloom).Should().BeTrue(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void address_filter_doesnt_match_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithAddress(TestItem.AddressA) - .Build(); - - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressD), GetLogEntry(TestItem.AddressC)); + [Test, MaxTime(Timeout.MaxTestTime)] + public void multiple_specific_topics_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakB)) + .Build(); - filter.Matches(bloom).Should().BeFalse(); - } + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakA, TestItem.KeccakB)); - [Test, Timeout(Timeout.MaxTestTime)] - public void addresses_filter_doesnt_match_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithAddresses(TestItem.AddressA, TestItem.AddressB, TestItem.AddressC) - .Build(); - - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressD)); + filter.Matches(bloom).Should().BeTrue(); + } - filter.Matches(bloom).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void or_topics_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) + .Build(); + + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakB)); - [Test, Timeout(Timeout.MaxTestTime)] - public void specific_topics_filter_doesnt_match_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakC)) - .Build(); - - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakA, TestItem.KeccakB)); + filter.Matches(bloom).Should().BeTrue(); + } - filter.Matches(bloom).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void complex_topics_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) + .Build(); - [Test, Timeout(Timeout.MaxTestTime)] - public void multiple_specific_topics_filter_doesnt_match_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakB)) - .Build(); + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakA)); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakC)); + filter.Matches(bloom).Should().BeTrue(); + } - filter.Matches(bloom).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void complex_filter_matches_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakC))) + .WithAddress(TestItem.AddressD) + .Build(); - [Test, Timeout(Timeout.MaxTestTime)] - public void or_topics_filter_doesnt_match_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) - .Build(); + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressD, TestItem.KeccakA, TestItem.KeccakC)); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakC)); + filter.Matches(bloom).Should().BeTrue(); + } - filter.Matches(bloom).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void address_filter_doesnt_match_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithAddress(TestItem.AddressA) + .Build(); - [Test, Timeout(Timeout.MaxTestTime)] - public void complex_topics_filter_doesnt_match_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) - .Build(); + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressD), GetLogEntry(TestItem.AddressC)); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakC)); + filter.Matches(bloom).Should().BeFalse(); + } - filter.Matches(bloom).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void addresses_filter_doesnt_match_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithAddresses(TestItem.AddressA, TestItem.AddressB, TestItem.AddressC) + .Build(); - [Test, Timeout(Timeout.MaxTestTime)] - public void complex_filter_doesnt_match_bloom() - { - LogFilter filter = FilterBuilder.New(ref _filterCounter) - .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakC))) - .WithAddress(TestItem.AddressD) - .Build(); + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressD)); - Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakA, TestItem.KeccakD)); + filter.Matches(bloom).Should().BeFalse(); + } - filter.Matches(bloom).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void specific_topics_filter_doesnt_match_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakC)) + .Build(); - private Core.Bloom GetBloom(params LogEntry[] logEntries) - { - Core.Bloom bloom = new Core.Bloom(); - bloom.Add(logEntries); - return bloom; - } + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakA, TestItem.KeccakB)); - private static LogEntry GetLogEntry(Address address, params Hash256[] topics) => new(address, Array.Empty(), topics); + filter.Matches(bloom).Should().BeFalse(); } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void multiple_specific_topics_filter_doesnt_match_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Specific(TestItem.KeccakB)) + .Build(); + + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakC)); + + filter.Matches(bloom).Should().BeFalse(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void or_topics_filter_doesnt_match_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) + .Build(); + + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressB, TestItem.KeccakC)); + + filter.Matches(bloom).Should().BeFalse(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void complex_topics_filter_doesnt_match_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA))) + .Build(); + + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakC)); + + filter.Matches(bloom).Should().BeFalse(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void complex_filter_doesnt_match_bloom() + { + LogFilter filter = FilterBuilder.New(ref _filterCounter) + .WithTopicExpressions(TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Or(TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakC))) + .WithAddress(TestItem.AddressD) + .Build(); + + Core.Bloom bloom = GetBloom(GetLogEntry(TestItem.AddressA, TestItem.KeccakA, TestItem.KeccakD)); + + filter.Matches(bloom).Should().BeFalse(); + } + + private Core.Bloom GetBloom(params LogEntry[] logEntries) + { + Core.Bloom bloom = new Core.Bloom(); + bloom.Add(logEntries); + return bloom; + } + + private static LogEntry GetLogEntry(Address address, params Hash256[] topics) => new(address, Array.Empty(), topics); } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs index 2d7ea7a3ae4..a270e0c9d2c 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs @@ -23,335 +23,334 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Find +namespace Nethermind.Blockchain.Test.Find; + +public class LogFinderTests { - public class LogFinderTests + private IBlockTree _blockTree = null!; + private BlockTree _rawBlockTree = null!; + private IReceiptStorage _receiptStorage = null!; + private LogFinder _logFinder = null!; + private IBloomStorage _bloomStorage = null!; + private IReceiptsRecovery _receiptsRecovery = null!; + private Block _headTestBlock = null!; + + [SetUp] + public void SetUp() { - private IBlockTree _blockTree = null!; - private BlockTree _rawBlockTree = null!; - private IReceiptStorage _receiptStorage = null!; - private LogFinder _logFinder = null!; - private IBloomStorage _bloomStorage = null!; - private IReceiptsRecovery _receiptsRecovery = null!; - private Block _headTestBlock = null!; - - [SetUp] - public void SetUp() - { - SetUp(true); - } + SetUp(true); + } - [TearDown] - public void TearDown() => _bloomStorage?.Dispose(); + [TearDown] + public void TearDown() => _bloomStorage?.Dispose(); - private void SetUp(bool allowReceiptIterator) - { - var specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any()).IsEip155Enabled.Returns(true); - _receiptStorage = new InMemoryReceiptStorage(allowReceiptIterator); - _rawBlockTree = Build.A.BlockTree() - .WithTransactions(_receiptStorage, LogsForBlockBuilder) - .OfChainLength(out _headTestBlock, 5) - .TestObject; - _blockTree = _rawBlockTree; - _bloomStorage = new BloomStorage(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); - _receiptsRecovery = Substitute.For(); - _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); - } + private void SetUp(bool allowReceiptIterator) + { + var specProvider = Substitute.For(); + specProvider.GetSpec(Arg.Any()).IsEip155Enabled.Returns(true); + _receiptStorage = new InMemoryReceiptStorage(allowReceiptIterator); + _rawBlockTree = Build.A.BlockTree() + .WithTransactions(_receiptStorage, LogsForBlockBuilder) + .OfChainLength(out _headTestBlock, 5) + .TestObject; + _blockTree = _rawBlockTree; + _bloomStorage = new BloomStorage(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); + _receiptsRecovery = Substitute.For(); + _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); + } - private void SetupHeadWithNoTransaction() - { - Block blockWithNoTransaction = Build.A.Block - .WithParent(_headTestBlock) - .TestObject; - _rawBlockTree.SuggestBlock(blockWithNoTransaction) - .Should().Be(AddBlockResult.Added); - _rawBlockTree.UpdateMainChain(blockWithNoTransaction); - } + private void SetupHeadWithNoTransaction() + { + Block blockWithNoTransaction = Build.A.Block + .WithParent(_headTestBlock) + .TestObject; + _rawBlockTree.SuggestBlock(blockWithNoTransaction) + .Should().Be(AddBlockResult.Added); + _rawBlockTree.UpdateMainChain(blockWithNoTransaction); + } - private IEnumerable LogsForBlockBuilder(Block block, Transaction transaction) + private IEnumerable LogsForBlockBuilder(Block block, Transaction transaction) + { + if (block.Number == 1) { - if (block.Number == 1) + if (transaction.Value == 1) { - if (transaction.Value == 1) - { - yield return Build.A.LogEntry.WithAddress(TestItem.AddressA).WithTopics(TestItem.KeccakA).TestObject; - } - else if (transaction.Value == 2) - { - yield return Build.A.LogEntry.WithAddress(TestItem.AddressA).WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject; - } + yield return Build.A.LogEntry.WithAddress(TestItem.AddressA).WithTopics(TestItem.KeccakA).TestObject; } - else if (block.Number == 4) + else if (transaction.Value == 2) { - if (transaction.Value == 1) - { - yield return Build.A.LogEntry.WithAddress(TestItem.AddressB).WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject; - } - else if (transaction.Value == 2) - { - yield return Build.A.LogEntry.WithAddress(TestItem.AddressC).WithTopics(TestItem.KeccakB, TestItem.KeccakA, TestItem.KeccakE).TestObject; - yield return Build.A.LogEntry.WithAddress(TestItem.AddressD).WithTopics(TestItem.KeccakD, TestItem.KeccakA).TestObject; - } + yield return Build.A.LogEntry.WithAddress(TestItem.AddressA).WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject; } } - - public static IEnumerable WithBloomValues + else if (block.Number == 4) { - get + if (transaction.Value == 1) { - yield return false; - yield return true; + yield return Build.A.LogEntry.WithAddress(TestItem.AddressB).WithTopics(TestItem.KeccakA, TestItem.KeccakB).TestObject; + } + else if (transaction.Value == 2) + { + yield return Build.A.LogEntry.WithAddress(TestItem.AddressC).WithTopics(TestItem.KeccakB, TestItem.KeccakA, TestItem.KeccakE).TestObject; + yield return Build.A.LogEntry.WithAddress(TestItem.AddressD).WithTopics(TestItem.KeccakD, TestItem.KeccakA).TestObject; } } + } - [Test, Timeout(Timeout.MaxTestTime)] - public void filter_all_logs([ValueSource(nameof(WithBloomValues))] bool withBloomDb, [Values(false, true)] bool allowReceiptIterator) + public static IEnumerable WithBloomValues + { + get { - SetUp(allowReceiptIterator); - StoreTreeBlooms(withBloomDb); - var logFilter = AllBlockFilter().Build(); - var logs = _logFinder.FindLogs(logFilter).ToArray(); - logs.Length.Should().Be(5); - var indexes = logs.Select(l => (int)l.LogIndex).ToArray(); - // indexes[0].Should().Be(0); - // indexes[1].Should().Be(1); - // indexes[2].Should().Be(0); - // indexes[3].Should().Be(1); - // indexes[4].Should().Be(2); - indexes.Should().BeEquivalentTo(new[] { 0, 1, 0, 1, 2 }); + yield return false; + yield return true; } + } - [Test, Timeout(Timeout.MaxTestTime)] - public void filter_all_logs_iteratively([ValueSource(nameof(WithBloomValues))] bool withBloomDb, [Values(false, true)] bool allowReceiptIterator) - { - SetUp(allowReceiptIterator); - LogFilter logFilter = AllBlockFilter().Build(); - FilterLog[] logs = _logFinder.FindLogs(logFilter).ToArray(); - logs.Length.Should().Be(5); - var indexes = logs.Select(l => (int)l.LogIndex).ToArray(); - // indexes[0].Should().Be(0); - // indexes[1].Should().Be(1); - // indexes[2].Should().Be(0); - // indexes[3].Should().Be(1); - // indexes[4].Should().Be(2); - // BeEquivalentTo does not check the ordering!!! :O - indexes.Should().BeEquivalentTo(new[] { 0, 1, 0, 1, 2 }); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void filter_all_logs([ValueSource(nameof(WithBloomValues))] bool withBloomDb, [Values(false, true)] bool allowReceiptIterator) + { + SetUp(allowReceiptIterator); + StoreTreeBlooms(withBloomDb); + var logFilter = AllBlockFilter().Build(); + var logs = _logFinder.FindLogs(logFilter).ToArray(); + logs.Length.Should().Be(5); + var indexes = logs.Select(l => (int)l.LogIndex).ToArray(); + // indexes[0].Should().Be(0); + // indexes[1].Should().Be(1); + // indexes[2].Should().Be(0); + // indexes[3].Should().Be(1); + // indexes[4].Should().Be(2); + indexes.Should().BeEquivalentTo(new[] { 0, 1, 0, 1, 2 }); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void throw_exception_when_receipts_are_missing([ValueSource(nameof(WithBloomValues))] bool withBloomDb) - { - StoreTreeBlooms(withBloomDb); - _receiptStorage = NullReceiptStorage.Instance; - _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); + [Test, MaxTime(Timeout.MaxTestTime)] + public void filter_all_logs_iteratively([ValueSource(nameof(WithBloomValues))] bool withBloomDb, [Values(false, true)] bool allowReceiptIterator) + { + SetUp(allowReceiptIterator); + LogFilter logFilter = AllBlockFilter().Build(); + FilterLog[] logs = _logFinder.FindLogs(logFilter).ToArray(); + logs.Length.Should().Be(5); + var indexes = logs.Select(l => (int)l.LogIndex).ToArray(); + // indexes[0].Should().Be(0); + // indexes[1].Should().Be(1); + // indexes[2].Should().Be(0); + // indexes[3].Should().Be(1); + // indexes[4].Should().Be(2); + // BeEquivalentTo does not check the ordering!!! :O + indexes.Should().BeEquivalentTo(new[] { 0, 1, 0, 1, 2 }); + } - var logFilter = AllBlockFilter().Build(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void throw_exception_when_receipts_are_missing([ValueSource(nameof(WithBloomValues))] bool withBloomDb) + { + StoreTreeBlooms(withBloomDb); + _receiptStorage = NullReceiptStorage.Instance; + _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); - _logFinder.Invoking(it => it.FindLogs(logFilter)) - .Should() - .Throw(); - } + var logFilter = AllBlockFilter().Build(); - [Test, Timeout(Timeout.MaxTestTime)] - public void when_receipts_are_missing_and_header_has_no_receipt_root_do_not_throw_exception_() - { - _receiptStorage = NullReceiptStorage.Instance; - _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); + _logFinder.Invoking(it => it.FindLogs(logFilter)) + .Should() + .Throw(); + } - SetupHeadWithNoTransaction(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void when_receipts_are_missing_and_header_has_no_receipt_root_do_not_throw_exception_() + { + _receiptStorage = NullReceiptStorage.Instance; + _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); - var logFilter = AllBlockFilter().Build(); + SetupHeadWithNoTransaction(); - _logFinder.Invoking(it => it.FindLogs(logFilter)) - .Should() - .NotThrow(); - } + var logFilter = AllBlockFilter().Build(); - [Test, Timeout(Timeout.MaxTestTime)] - public void filter_all_logs_should_throw_when_to_block_is_not_found([ValueSource(nameof(WithBloomValues))] bool withBloomDb) - { - StoreTreeBlooms(withBloomDb); - var blockFinder = Substitute.For(); - _logFinder = new LogFinder(blockFinder, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); - var logFilter = AllBlockFilter().Build(); - var action = new Func>(() => _logFinder.FindLogs(logFilter)); - action.Should().Throw(); - blockFinder.Received().FindHeader(logFilter.ToBlock, false); - blockFinder.DidNotReceive().FindHeader(logFilter.FromBlock); - } + _logFinder.Invoking(it => it.FindLogs(logFilter)) + .Should() + .NotThrow(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void filter_all_logs_should_throw_when_to_block_is_not_found([ValueSource(nameof(WithBloomValues))] bool withBloomDb) + { + StoreTreeBlooms(withBloomDb); + var blockFinder = Substitute.For(); + _logFinder = new LogFinder(blockFinder, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); + var logFilter = AllBlockFilter().Build(); + var action = new Func>(() => _logFinder.FindLogs(logFilter)); + action.Should().Throw(); + blockFinder.Received().FindHeader(logFilter.ToBlock, false); + blockFinder.DidNotReceive().FindHeader(logFilter.FromBlock); + } - public static IEnumerable FilterByAddressTestsData + public static IEnumerable FilterByAddressTestsData + { + get { - get - { - yield return new TestCaseData(new[] { TestItem.AddressA }, 2, false); - yield return new TestCaseData(new[] { TestItem.AddressB }, 1, false); - yield return new TestCaseData(new[] { TestItem.AddressC }, 1, false); - yield return new TestCaseData(new[] { TestItem.AddressD }, 1, false); - yield return new TestCaseData(new[] { TestItem.AddressA, TestItem.AddressC, TestItem.AddressD }, 4, false); - - yield return new TestCaseData(new[] { TestItem.AddressA }, 2, true); - yield return new TestCaseData(new[] { TestItem.AddressB }, 1, true); - yield return new TestCaseData(new[] { TestItem.AddressC }, 1, true); - yield return new TestCaseData(new[] { TestItem.AddressD }, 1, true); - yield return new TestCaseData(new[] { TestItem.AddressA, TestItem.AddressC, TestItem.AddressD }, 4, true); - } + yield return new TestCaseData(new[] { TestItem.AddressA }, 2, false); + yield return new TestCaseData(new[] { TestItem.AddressB }, 1, false); + yield return new TestCaseData(new[] { TestItem.AddressC }, 1, false); + yield return new TestCaseData(new[] { TestItem.AddressD }, 1, false); + yield return new TestCaseData(new[] { TestItem.AddressA, TestItem.AddressC, TestItem.AddressD }, 4, false); + + yield return new TestCaseData(new[] { TestItem.AddressA }, 2, true); + yield return new TestCaseData(new[] { TestItem.AddressB }, 1, true); + yield return new TestCaseData(new[] { TestItem.AddressC }, 1, true); + yield return new TestCaseData(new[] { TestItem.AddressD }, 1, true); + yield return new TestCaseData(new[] { TestItem.AddressA, TestItem.AddressC, TestItem.AddressD }, 4, true); } + } - [TestCaseSource(nameof(FilterByAddressTestsData))] - public void filter_by_address(Address[] addresses, int expectedCount, bool withBloomDb) - { - StoreTreeBlooms(withBloomDb); - var filterBuilder = AllBlockFilter(); - filterBuilder = addresses.Length == 1 ? filterBuilder.WithAddress(addresses[0]) : filterBuilder.WithAddresses(addresses); - var logFilter = filterBuilder.Build(); + [TestCaseSource(nameof(FilterByAddressTestsData))] + public void filter_by_address(Address[] addresses, int expectedCount, bool withBloomDb) + { + StoreTreeBlooms(withBloomDb); + var filterBuilder = AllBlockFilter(); + filterBuilder = addresses.Length == 1 ? filterBuilder.WithAddress(addresses[0]) : filterBuilder.WithAddresses(addresses); + var logFilter = filterBuilder.Build(); - var logs = _logFinder.FindLogs(logFilter).ToArray(); + var logs = _logFinder.FindLogs(logFilter).ToArray(); - logs.Length.Should().Be(expectedCount); - } + logs.Length.Should().Be(expectedCount); + } - public static IEnumerable FilterByTopicsTestsData + public static IEnumerable FilterByTopicsTestsData + { + get { - get - { - yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakA) }, false, new long[] { 1, 1, 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakB) }, false, new long[] { 1, 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Any }, false, new long[] { 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakE) }, false, new long[] { 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB) }, false, new long[] { 1, 1, 4, 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakB) }, false, new long[] { 1, 4 }); - - yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakA) }, true, new long[] { 1, 1, 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakB) }, true, new long[] { 1, 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Any }, true, new long[] { 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakE) }, true, new long[] { 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB) }, true, new long[] { 1, 1, 4, 4 }); - yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakB) }, true, new long[] { 1, 4 }); - } + yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakA) }, false, new long[] { 1, 1, 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakB) }, false, new long[] { 1, 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Any }, false, new long[] { 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakE) }, false, new long[] { 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB) }, false, new long[] { 1, 1, 4, 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakB) }, false, new long[] { 1, 4 }); + + yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakA) }, true, new long[] { 1, 1, 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakB) }, true, new long[] { 1, 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakA), TestTopicExpressions.Any }, true, new long[] { 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Specific(TestItem.KeccakB), TestTopicExpressions.Any, TestTopicExpressions.Specific(TestItem.KeccakE) }, true, new long[] { 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB) }, true, new long[] { 1, 1, 4, 4 }); + yield return new TestCaseData(new[] { TestTopicExpressions.Or(TestItem.KeccakA, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakB) }, true, new long[] { 1, 4 }); } + } - [TestCaseSource(nameof(FilterByTopicsTestsData))] - public void filter_by_topics_and_return_logs_in_order(TopicExpression[] topics, bool withBloomDb, long[] expectedBlockNumbers) - { - StoreTreeBlooms(withBloomDb); - var logFilter = AllBlockFilter().WithTopicExpressions(topics).Build(); + [TestCaseSource(nameof(FilterByTopicsTestsData))] + public void filter_by_topics_and_return_logs_in_order(TopicExpression[] topics, bool withBloomDb, long[] expectedBlockNumbers) + { + StoreTreeBlooms(withBloomDb); + var logFilter = AllBlockFilter().WithTopicExpressions(topics).Build(); - var logs = _logFinder.FindLogs(logFilter).ToArray(); + var logs = _logFinder.FindLogs(logFilter).ToArray(); - var blockNumbers = logs.Select((log) => log.BlockNumber).ToArray(); - Assert.That(expectedBlockNumbers, Is.EqualTo(blockNumbers)); - } + var blockNumbers = logs.Select((log) => log.BlockNumber).ToArray(); + Assert.That(expectedBlockNumbers, Is.EqualTo(blockNumbers)); + } - public static IEnumerable FilterByBlocksTestsData + public static IEnumerable FilterByBlocksTestsData + { + get { - get - { - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock().Build(), 3, false); - yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToLatestBlock().Build(), 5, false); - yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToPendingBlock().Build(), 5, false); - yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToEarliestBlock().Build(), 0, false); - yield return new TestCaseData(FilterBuilder.New().FromBlock(1).ToBlock(1).Build(), 2, false); - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToEarliestBlock().Build(), 0, false); //wrong order test - - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock().Build(), 3, true); - yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToLatestBlock().Build(), 5, true); - yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToPendingBlock().Build(), 5, true); - yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToEarliestBlock().Build(), 0, true); - yield return new TestCaseData(FilterBuilder.New().FromBlock(1).ToBlock(1).Build(), 2, true); - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToEarliestBlock().Build(), 0, true); //wrong order test - } + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock().Build(), 3, false); + yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToLatestBlock().Build(), 5, false); + yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToPendingBlock().Build(), 5, false); + yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToEarliestBlock().Build(), 0, false); + yield return new TestCaseData(FilterBuilder.New().FromBlock(1).ToBlock(1).Build(), 2, false); + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToEarliestBlock().Build(), 0, false); //wrong order test + + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock().Build(), 3, true); + yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToLatestBlock().Build(), 5, true); + yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToPendingBlock().Build(), 5, true); + yield return new TestCaseData(FilterBuilder.New().FromEarliestBlock().ToEarliestBlock().Build(), 0, true); + yield return new TestCaseData(FilterBuilder.New().FromBlock(1).ToBlock(1).Build(), 2, true); + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToEarliestBlock().Build(), 0, true); //wrong order test } + } - [TestCaseSource(nameof(FilterByBlocksTestsData))] - public void filter_by_blocks(LogFilter filter, int expectedCount, bool withBloomDb) - { - StoreTreeBlooms(withBloomDb); - var logs = _logFinder.FindLogs(filter).ToArray(); - logs.Length.Should().Be(expectedCount); - } + [TestCaseSource(nameof(FilterByBlocksTestsData))] + public void filter_by_blocks(LogFilter filter, int expectedCount, bool withBloomDb) + { + StoreTreeBlooms(withBloomDb); + var logs = _logFinder.FindLogs(filter).ToArray(); + logs.Length.Should().Be(expectedCount); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void filter_by_blocks_with_limit([ValueSource(nameof(WithBloomValues))] bool withBloomDb) - { - StoreTreeBlooms(withBloomDb); - _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery, 2); - var filter = FilterBuilder.New().FromLatestBlock().ToLatestBlock().Build(); - var logs = _logFinder.FindLogs(filter).ToArray(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void filter_by_blocks_with_limit([ValueSource(nameof(WithBloomValues))] bool withBloomDb) + { + StoreTreeBlooms(withBloomDb); + _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery, 2); + var filter = FilterBuilder.New().FromLatestBlock().ToLatestBlock().Build(); + var logs = _logFinder.FindLogs(filter).ToArray(); - logs.Length.Should().Be(3); - } + logs.Length.Should().Be(3); + } - public static IEnumerable ComplexFilterTestsData + public static IEnumerable ComplexFilterTestsData + { + get { - get - { - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() - .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) - .WithAddresses(TestItem.AddressC, TestItem.AddressD).Build(), 2, false); + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() + .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) + .WithAddresses(TestItem.AddressC, TestItem.AddressD).Build(), 2, false); - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() - .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) - .WithAddresses(TestItem.AddressC).Build(), 1, false); + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() + .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) + .WithAddresses(TestItem.AddressC).Build(), 1, false); - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() - .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) - .WithAddresses(TestItem.AddressC, TestItem.AddressD).Build(), 2, true); + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() + .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) + .WithAddresses(TestItem.AddressC, TestItem.AddressD).Build(), 2, true); - yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() - .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) - .WithAddresses(TestItem.AddressC).Build(), 1, true); - } + yield return new TestCaseData(FilterBuilder.New().FromLatestBlock().ToLatestBlock() + .WithTopicExpressions(TestTopicExpressions.Or(TestItem.KeccakD, TestItem.KeccakB), TestTopicExpressions.Specific(TestItem.KeccakA)) + .WithAddresses(TestItem.AddressC).Build(), 1, true); } + } - [TestCaseSource(nameof(ComplexFilterTestsData))] - public void complex_filter(LogFilter filter, int expectedCount, bool withBloomDb) - { - StoreTreeBlooms(withBloomDb); - var logs = _logFinder.FindLogs(filter).ToArray(); - logs.Length.Should().Be(expectedCount); - } + [TestCaseSource(nameof(ComplexFilterTestsData))] + public void complex_filter(LogFilter filter, int expectedCount, bool withBloomDb) + { + StoreTreeBlooms(withBloomDb); + var logs = _logFinder.FindLogs(filter).ToArray(); + logs.Length.Should().Be(expectedCount); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Throw_log_finder_operation_canceled_after_given_timeout([Values(2, 0.01)] double waitTime) - { - var timeout = TimeSpan.FromMilliseconds(Timeout.MaxWaitTime); - using CancellationTokenSource cancellationTokenSource = new(timeout); - CancellationToken cancellationToken = cancellationTokenSource.Token; + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Throw_log_finder_operation_canceled_after_given_timeout([Values(2, 0.01)] double waitTime) + { + var timeout = TimeSpan.FromMilliseconds(Timeout.MaxWaitTime); + using CancellationTokenSource cancellationTokenSource = new(timeout); + CancellationToken cancellationToken = cancellationTokenSource.Token; - StoreTreeBlooms(true); - _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); - var logFilter = AllBlockFilter().Build(); - var logs = _logFinder.FindLogs(logFilter, cancellationToken); + StoreTreeBlooms(true); + _logFinder = new LogFinder(_blockTree, _receiptStorage, _receiptStorage, _bloomStorage, LimboLogs.Instance, _receiptsRecovery); + var logFilter = AllBlockFilter().Build(); + var logs = _logFinder.FindLogs(logFilter, cancellationToken); - await Task.Delay(timeout * waitTime); + await Task.Delay(timeout * waitTime); - Func action = () => logs.ToArray(); + Func action = () => logs.ToArray(); - if (waitTime > 1) - { - action.Should().Throw().WithInnerException(); - } - else - { - action.Should().NotThrow(); - } + if (waitTime > 1) + { + action.Should().Throw().WithInnerException(); + } + else + { + action.Should().NotThrow(); } + } - private static FilterBuilder AllBlockFilter() => FilterBuilder.New().FromEarliestBlock().ToPendingBlock(); + private static FilterBuilder AllBlockFilter() => FilterBuilder.New().FromEarliestBlock().ToPendingBlock(); - private void StoreTreeBlooms(bool withBloomDb) + private void StoreTreeBlooms(bool withBloomDb) + { + if (withBloomDb) { - if (withBloomDb) + for (int i = 0; i <= _blockTree.Head!.Number; i++) { - for (int i = 0; i <= _blockTree.Head!.Number; i++) - { - _bloomStorage.Store(i, _blockTree.FindHeader(i)!.Bloom!); - } + _bloomStorage.Store(i, _blockTree.FindHeader(i)!.Bloom!); } } - } + } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/CopyTreeVisitorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/CopyTreeVisitorTests.cs index eb99ee1c310..37e267645f2 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/CopyTreeVisitorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/CopyTreeVisitorTests.cs @@ -1,11 +1,9 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; using FluentAssertions; using Nethermind.Blockchain.FullPruning; using Nethermind.Core; @@ -19,102 +17,100 @@ using Nethermind.Trie; using Nethermind.Trie.Pruning; using NSubstitute; -using NSubstitute.ExceptionExtensions; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.FullPruning +namespace Nethermind.Blockchain.Test.FullPruning; + +[Parallelizable(ParallelScope.Self)] +[TestFixture(INodeStorage.KeyScheme.HalfPath)] +[TestFixture(INodeStorage.KeyScheme.Hash)] +public class CopyTreeVisitorTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture(INodeStorage.KeyScheme.HalfPath)] - [TestFixture(INodeStorage.KeyScheme.Hash)] - public class CopyTreeVisitorTests + private readonly INodeStorage.KeyScheme _keyScheme; + + public CopyTreeVisitorTests(INodeStorage.KeyScheme scheme) { - private readonly INodeStorage.KeyScheme _keyScheme; + _keyScheme = scheme; + } - public CopyTreeVisitorTests(INodeStorage.KeyScheme scheme) - { - _keyScheme = scheme; - } + [TestCase(0, 1)] + [TestCase(0, 8)] + [TestCase(1, 1)] + [TestCase(1, 8)] + [MaxTime(Timeout.MaxTestTime)] + public void copies_state_between_dbs(int fullPruningMemoryBudgetMb, int maxDegreeOfParallelism) + { + TestMemDb trieDb = new(); + TestMemDb clonedDb = new(); - [TestCase(0, 1)] - [TestCase(0, 8)] - [TestCase(1, 1)] - [TestCase(1, 8)] - [Timeout(Timeout.MaxTestTime)] - public void copies_state_between_dbs(int fullPruningMemoryBudgetMb, int maxDegreeOfParallelism) + VisitingOptions visitingOptions = new() { - TestMemDb trieDb = new(); - TestMemDb clonedDb = new(); + MaxDegreeOfParallelism = maxDegreeOfParallelism, + FullScanMemoryBudget = fullPruningMemoryBudgetMb.MiB(), + }; - VisitingOptions visitingOptions = new() - { - MaxDegreeOfParallelism = maxDegreeOfParallelism, - FullScanMemoryBudget = fullPruningMemoryBudgetMb.MiB(), - }; + IPruningContext ctx = StartPruning(trieDb, clonedDb); + CopyDb(ctx, CancellationToken.None, trieDb, visitingOptions, writeFlags: WriteFlags.LowPriority); - IPruningContext ctx = StartPruning(trieDb, clonedDb); - CopyDb(ctx, CancellationToken.None, trieDb, visitingOptions, writeFlags: WriteFlags.LowPriority); + List keys = trieDb.Keys.ToList(); + List values = trieDb.Values.ToList(); - List keys = trieDb.Keys.ToList(); - List values = trieDb.Values.ToList(); + ctx.Commit(); - ctx.Commit(); + clonedDb.Count.Should().Be(132); + clonedDb.Keys.Should().BeEquivalentTo(keys); + clonedDb.Values.Should().BeEquivalentTo(values); - clonedDb.Count.Should().Be(132); - clonedDb.Keys.Should().BeEquivalentTo(keys); - clonedDb.Values.Should().BeEquivalentTo(values); + clonedDb.KeyWasWrittenWithFlags(keys[0], WriteFlags.LowPriority); + trieDb.KeyWasReadWithFlags(keys[0], ReadFlags.SkipDuplicateRead | ReadFlags.HintReadAhead); + } - clonedDb.KeyWasWrittenWithFlags(keys[0], WriteFlags.LowPriority); - trieDb.KeyWasReadWithFlags(keys[0], ReadFlags.SkipDuplicateRead | ReadFlags.HintReadAhead); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void cancel_coping_state_between_dbs() + { + MemDb trieDb = new(); + MemDb clonedDb = new(); + IPruningContext pruningContext = StartPruning(trieDb, clonedDb); - [Test, Timeout(Timeout.MaxTestTime)] - public void cancel_coping_state_between_dbs() - { - MemDb trieDb = new(); - MemDb clonedDb = new(); - IPruningContext pruningContext = StartPruning(trieDb, clonedDb); + CancellationTokenSource cts = new CancellationTokenSource(); + cts.Cancel(); - CancellationTokenSource cts = new CancellationTokenSource(); - cts.Cancel(); + CopyDb(pruningContext, cts.Token, trieDb); - CopyDb(pruningContext, cts.Token, trieDb); + clonedDb.Count.Should().BeLessThan(trieDb.Count); + } - clonedDb.Count.Should().BeLessThan(trieDb.Count); - } + private IPruningContext CopyDb(IPruningContext pruningContext, CancellationToken cancellationToken, MemDb trieDb, VisitingOptions? visitingOptions = null, WriteFlags writeFlags = WriteFlags.None) + { + LimboLogs logManager = LimboLogs.Instance; + PatriciaTree trie = Build.A.Trie(new NodeStorage(trieDb, _keyScheme)).WithAccountsByIndex(0, 100).TestObject; + IStateReader stateReader = new StateReader(new TrieStore(trieDb, logManager), new MemDb(), logManager); - private IPruningContext CopyDb(IPruningContext pruningContext, CancellationToken cancellationToken, MemDb trieDb, VisitingOptions? visitingOptions = null, WriteFlags writeFlags = WriteFlags.None) + if (_keyScheme == INodeStorage.KeyScheme.Hash) { - LimboLogs logManager = LimboLogs.Instance; - PatriciaTree trie = Build.A.Trie(new NodeStorage(trieDb, _keyScheme)).WithAccountsByIndex(0, 100).TestObject; - IStateReader stateReader = new StateReader(new TrieStore(trieDb, logManager), new MemDb(), logManager); - - if (_keyScheme == INodeStorage.KeyScheme.Hash) - { - NodeStorage nodeStorage = new NodeStorage(pruningContext, _keyScheme); - using CopyTreeVisitor copyTreeVisitor = new(nodeStorage, writeFlags, logManager, cancellationToken); - stateReader.RunTreeVisitor(copyTreeVisitor, trie.RootHash, visitingOptions); - copyTreeVisitor.Finish(); - } - else - { - NodeStorage nodeStorage = new NodeStorage(pruningContext, _keyScheme); - using CopyTreeVisitor copyTreeVisitor = new(nodeStorage, writeFlags, logManager, cancellationToken); - stateReader.RunTreeVisitor(copyTreeVisitor, trie.RootHash, visitingOptions); - copyTreeVisitor.Finish(); - } - - return pruningContext; + NodeStorage nodeStorage = new NodeStorage(pruningContext, _keyScheme); + using CopyTreeVisitor copyTreeVisitor = new(nodeStorage, writeFlags, logManager, cancellationToken); + stateReader.RunTreeVisitor(copyTreeVisitor, trie.RootHash, visitingOptions); + copyTreeVisitor.Finish(); } - - private static IPruningContext StartPruning(MemDb trieDb, MemDb clonedDb) + else { - IDbFactory dbFactory = Substitute.For(); - dbFactory.CreateDb(Arg.Any()).Returns(trieDb, clonedDb); - - FullPruningDb fullPruningDb = new(new DbSettings("test", "test"), dbFactory); - fullPruningDb.TryStartPruning(out IPruningContext pruningContext); - return pruningContext; + NodeStorage nodeStorage = new NodeStorage(pruningContext, _keyScheme); + using CopyTreeVisitor copyTreeVisitor = new(nodeStorage, writeFlags, logManager, cancellationToken); + stateReader.RunTreeVisitor(copyTreeVisitor, trie.RootHash, visitingOptions); + copyTreeVisitor.Finish(); } + + return pruningContext; + } + + private static IPruningContext StartPruning(MemDb trieDb, MemDb clonedDb) + { + IDbFactory dbFactory = Substitute.For(); + dbFactory.CreateDb(Arg.Any()).Returns(trieDb, clonedDb); + + FullPruningDb fullPruningDb = new(new DbSettings("test", "test"), dbFactory); + fullPruningDb.TryStartPruning(out IPruningContext pruningContext); + return pruningContext; } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/DiskFreeSpacePruningTriggerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/DiskFreeSpacePruningTriggerTests.cs index e0303d41ae8..1e7023164ab 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/DiskFreeSpacePruningTriggerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/DiskFreeSpacePruningTriggerTests.cs @@ -8,32 +8,31 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.FullPruning +namespace Nethermind.Blockchain.Test.FullPruning; + +[Parallelizable(ParallelScope.All)] +public class DiskFreeSpacePruningTriggerTests { - [Parallelizable(ParallelScope.All)] - public class DiskFreeSpacePruningTriggerTests + [MaxTime(Timeout.MaxTestTime)] + [TestCase(999, ExpectedResult = true)] + [TestCase(1000, ExpectedResult = false)] + public bool triggers_on_low_free_space(int availableFreeSpace) { - [Timeout(Timeout.MaxTestTime)] - [TestCase(999, ExpectedResult = true)] - [TestCase(1000, ExpectedResult = false)] - public bool triggers_on_low_free_space(int availableFreeSpace) - { - ITimerFactory timerFactory = Substitute.For(); - ITimer timer = Substitute.For(); - timerFactory.CreateTimer(Arg.Any()).Returns(timer); + ITimerFactory timerFactory = Substitute.For(); + ITimer timer = Substitute.For(); + timerFactory.CreateTimer(Arg.Any()).Returns(timer); - string path = "path"; - IFileSystem fileSystem = Substitute.For(); - fileSystem.Path.GetFullPath(path).Returns(path); - fileSystem.DriveInfo.New(path).AvailableFreeSpace.Returns(availableFreeSpace); + string path = "path"; + IFileSystem fileSystem = Substitute.For(); + fileSystem.Path.GetFullPath(path).Returns(path); + fileSystem.DriveInfo.New(path).AvailableFreeSpace.Returns(availableFreeSpace); - bool triggered = false; + bool triggered = false; - DiskFreeSpacePruningTrigger trigger = new(path, 1000, timerFactory, fileSystem); - trigger.Prune += (o, e) => triggered = true; + DiskFreeSpacePruningTrigger trigger = new(path, 1000, timerFactory, fileSystem); + trigger.Prune += (o, e) => triggered = true; - timer.Elapsed += Raise.Event(); - return triggered; - } + timer.Elapsed += Raise.Event(); + return triggered; } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs index 0af8ccef6ad..a06cc8ed80a 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs @@ -23,451 +23,450 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.FullPruning +namespace Nethermind.Blockchain.Test.FullPruning; + + +[TestFixture(0, 1)] +[TestFixture(0, 4)] +[TestFixture(1, 1)] +[TestFixture(1, 4)] +[Parallelizable(ParallelScope.Children)] +public class FullPrunerTests { + private readonly int _fullPrunerMemoryBudgetMb; + private readonly int _degreeOfParallelism; + + public FullPrunerTests(int fullPrunerMemoryBudgetMb, int degreeOfParallelism) + { + _fullPrunerMemoryBudgetMb = fullPrunerMemoryBudgetMb; + _degreeOfParallelism = degreeOfParallelism; + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task can_prune() + { + TestContext test = CreateTest(); + await test.RunFullPruning(); + test.ShouldCopyAllValues(); + } + + [MaxTime(Timeout.MaxTestTime * 2)] // this is particular long test + [TestCase(INodeStorage.KeyScheme.Hash, INodeStorage.KeyScheme.Current, INodeStorage.KeyScheme.Hash)] + [TestCase(INodeStorage.KeyScheme.HalfPath, INodeStorage.KeyScheme.Current, INodeStorage.KeyScheme.HalfPath)] + [TestCase(INodeStorage.KeyScheme.Hash, INodeStorage.KeyScheme.HalfPath, INodeStorage.KeyScheme.HalfPath)] + [TestCase(INodeStorage.KeyScheme.HalfPath, INodeStorage.KeyScheme.Hash, INodeStorage.KeyScheme.HalfPath)] + public async Task can_prune_and_switch_key_scheme(INodeStorage.KeyScheme currentKeyScheme, INodeStorage.KeyScheme newKeyScheme, INodeStorage.KeyScheme expectedNewScheme) + { + TestContext test = new( + true, + false, + FullPruningCompletionBehavior.None, + _fullPrunerMemoryBudgetMb, + _degreeOfParallelism, + currentKeyScheme: currentKeyScheme, + preferredKeyScheme: newKeyScheme); + + test.NodeStorage.Scheme.Should().Be(currentKeyScheme); + await test.RunFullPruning(); + test.ShouldCopyAllValuesWhenVisitingTrie(); + test.NodeStorage.Scheme.Should().Be(expectedNewScheme); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task pruning_deletes_old_db_on_success() + { + TestContext test = CreateTest(clearPrunedDb: true); + await test.RunFullPruning(); + test.TrieDb.Count.Should().Be(0); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task pruning_keeps_old_db_on_fail() + { + TestContext test = CreateTest(false); + int count = test.TrieDb.Count; + await test.RunFullPruning(); + test.TrieDb.Count.Should().Be(count); + } - [TestFixture(0, 1)] - [TestFixture(0, 4)] - [TestFixture(1, 1)] - [TestFixture(1, 4)] - [Parallelizable(ParallelScope.Children)] - public class FullPrunerTests + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task pruning_deletes_new_db_on_fail() { - private readonly int _fullPrunerMemoryBudgetMb; - private readonly int _degreeOfParallelism; + TestContext test = CreateTest(false); + await test.RunFullPruning(); + test.CopyDb.Count.Should().Be(0); + } - public FullPrunerTests(int fullPrunerMemoryBudgetMb, int degreeOfParallelism) + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task pruning_keeps_new_db_on_success() + { + TestContext test = CreateTest(); + int count = test.TrieDb.Count; + await test.RunFullPruning(); + test.CopyDb.Count.Should().Be(count); + } + + [MaxTime(Timeout.MaxTestTime)] + [TestCase(true, FullPruningCompletionBehavior.None, false)] + [TestCase(true, FullPruningCompletionBehavior.ShutdownOnSuccess, true)] + [TestCase(true, FullPruningCompletionBehavior.AlwaysShutdown, true)] + [TestCase(false, FullPruningCompletionBehavior.None, false)] + [TestCase(false, FullPruningCompletionBehavior.ShutdownOnSuccess, false)] + [TestCase(false, FullPruningCompletionBehavior.AlwaysShutdown, true)] + [Retry(10)] + public async Task pruning_shuts_down_node(bool success, FullPruningCompletionBehavior behavior, bool expectedShutdown) + { + TestContext test = CreateTest(successfulPruning: success, completionBehavior: behavior); + await test.RunFullPruning(); + + if (expectedShutdown) { - _fullPrunerMemoryBudgetMb = fullPrunerMemoryBudgetMb; - _degreeOfParallelism = degreeOfParallelism; + test.ProcessExitSource.Received(1).Exit(ExitCodes.Ok); } - - [Test, Timeout(Timeout.MaxTestTime)] - public async Task can_prune() + else { - TestContext test = CreateTest(); - await test.RunFullPruning(); - test.ShouldCopyAllValues(); + test.ProcessExitSource.DidNotReceiveWithAnyArgs().Exit(ExitCodes.Ok); } + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task can_not_start_pruning_when_other_is_in_progress() + { + TestContext test = CreateTest(); + test.FullPruningDb.CanStartPruning.Should().BeTrue(); + + test.TriggerPruningViaEvent(); + TestFullPruningDb.TestPruningContext pruningContext = await test.WaitForPruningStart(); + test.FullPruningDb.CanStartPruning.Should().BeFalse(); + await test.WaitForPruningEnd(pruningContext); + + test.FullPruningDb.CanStartPruning.Should().BeTrue(); + } - [Timeout(Timeout.MaxTestTime * 2)] // this is particular long test - [TestCase(INodeStorage.KeyScheme.Hash, INodeStorage.KeyScheme.Current, INodeStorage.KeyScheme.Hash)] - [TestCase(INodeStorage.KeyScheme.HalfPath, INodeStorage.KeyScheme.Current, INodeStorage.KeyScheme.HalfPath)] - [TestCase(INodeStorage.KeyScheme.Hash, INodeStorage.KeyScheme.HalfPath, INodeStorage.KeyScheme.HalfPath)] - [TestCase(INodeStorage.KeyScheme.HalfPath, INodeStorage.KeyScheme.Hash, INodeStorage.KeyScheme.HalfPath)] - public async Task can_prune_and_switch_key_scheme(INodeStorage.KeyScheme currentKeyScheme, INodeStorage.KeyScheme newKeyScheme, INodeStorage.KeyScheme expectedNewScheme) + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task should_not_start_multiple_pruning() + { + TestContext test = CreateTest(); + test.TriggerPruningViaEvent(); + TestFullPruningDb.TestPruningContext ctx = await test.WaitForPruningStart(); + test.TriggerPruningViaEvent(); + await test.WaitForPruningEnd(ctx); + test.FullPruningDb.PruningStarted.Should().Be(1); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task should_duplicate_writes_while_pruning() + { + TestContext test = CreateTest(); + TestFullPruningDb.TestPruningContext ctx = await test.WaitForPruningStart(); + byte[] key = { 1, 2, 3 }; + test.FullPruningDb[key] = key; + test.FullPruningDb.Context.WaitForFinish.Set(); + + await test.WaitForPruningEnd(ctx); + test.FullPruningDb[key].Should().BeEquivalentTo(key); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task should_duplicate_writes_to_batches_while_pruning() + { + TestContext test = CreateTest(); + byte[] key = { 0, 1, 2 }; + TestFullPruningDb.TestPruningContext context = await test.WaitForPruningStart(); + + using (IWriteBatch writeBatch = test.FullPruningDb.StartWriteBatch()) { - TestContext test = new( - true, - false, - FullPruningCompletionBehavior.None, - _fullPrunerMemoryBudgetMb, - _degreeOfParallelism, - currentKeyScheme: currentKeyScheme, - preferredKeyScheme: newKeyScheme); - - test.NodeStorage.Scheme.Should().Be(currentKeyScheme); - await test.RunFullPruning(); - test.ShouldCopyAllValuesWhenVisitingTrie(); - test.NodeStorage.Scheme.Should().Be(expectedNewScheme); + writeBatch[key] = key; } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task pruning_deletes_old_db_on_success() + await test.WaitForPruningEnd(context); + + test.FullPruningDb[key].Should().BeEquivalentTo(key); + } + + private TestContext CreateTest( + bool successfulPruning = true, + bool clearPrunedDb = false, + FullPruningCompletionBehavior completionBehavior = FullPruningCompletionBehavior.None) => + new( + successfulPruning, + clearPrunedDb, + completionBehavior, + _fullPrunerMemoryBudgetMb, + _degreeOfParallelism); + + private class TestContext + { + private readonly bool _clearPrunedDb; + private readonly Hash256 _stateRoot; + private long _head; + public TestFullPruningDb FullPruningDb { get; } + public IPruningTrigger PruningTrigger { get; } = Substitute.For(); + public IBlockTree BlockTree { get; } = Substitute.For(); + public IStateReader StateReader { get; } + public FullPruner Pruner { get; } + public MemDb TrieDb { get; } + public INodeStorage NodeStorage { get; } + public TestMemDb CopyDb { get; } + public IDriveInfo DriveInfo { get; set; } = Substitute.For(); + public IChainEstimations _chainEstimations = ChainSizes.UnknownChain.Instance; + + public IProcessExitSource ProcessExitSource { get; } = Substitute.For(); + + public TestContext( + bool successfulPruning, + bool clearPrunedDb = false, + FullPruningCompletionBehavior completionBehavior = FullPruningCompletionBehavior.None, + int fullScanMemoryBudgetMb = 0, + int degreeOfParallelism = 0, + INodeStorage.KeyScheme currentKeyScheme = INodeStorage.KeyScheme.HalfPath, + INodeStorage.KeyScheme preferredKeyScheme = INodeStorage.KeyScheme.Current) { - TestContext test = CreateTest(clearPrunedDb: true); - await test.RunFullPruning(); - test.TrieDb.Count.Should().Be(0); + BlockTree.OnUpdateMainChain += (_, e) => _head = e.Blocks[^1].Number; + _clearPrunedDb = clearPrunedDb; + TrieDb = new TestMemDb(); + CopyDb = new TestMemDb(); + IDbFactory dbFactory = Substitute.For(); + dbFactory.CreateDb(Arg.Any()).Returns(TrieDb, CopyDb); + + NodeStorage storageForWrite = new NodeStorage(TrieDb, currentKeyScheme); + PatriciaTree trie = Build.A.Trie(storageForWrite).WithAccountsByIndex(0, 100).TestObject; + _stateRoot = trie.RootHash; + FullPruningDb = new TestFullPruningDb(new DbSettings("test", "test"), dbFactory, successfulPruning, clearPrunedDb); + NodeStorageFactory nodeStorageFactory = new NodeStorageFactory(preferredKeyScheme, LimboLogs.Instance); + nodeStorageFactory.DetectCurrentKeySchemeFrom(TrieDb); + NodeStorage = nodeStorageFactory.WrapKeyValueStore(FullPruningDb); + StateReader = new StateReader(new TrieStore(NodeStorage, LimboLogs.Instance), new TestMemDb(), LimboLogs.Instance); + + Pruner = new( + FullPruningDb, + nodeStorageFactory, + NodeStorage, + PruningTrigger, + new PruningConfig() + { + FullPruningMaxDegreeOfParallelism = degreeOfParallelism, + FullPruningMemoryBudgetMb = fullScanMemoryBudgetMb, + FullPruningCompletionBehavior = completionBehavior + }, BlockTree, StateReader, ProcessExitSource, _chainEstimations, DriveInfo, Substitute.For(), LimboLogs.Instance); } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task pruning_keeps_old_db_on_fail() + public async Task RunFullPruning() { - TestContext test = CreateTest(false); - int count = test.TrieDb.Count; - await test.RunFullPruning(); - test.TrieDb.Count.Should().Be(count); + TestFullPruningDb.TestPruningContext ctx = await WaitForPruningStart(); + await WaitForPruningEnd(ctx); } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task pruning_deletes_new_db_on_fail() + public void TriggerPruningViaEvent() { - TestContext test = CreateTest(false); - await test.RunFullPruning(); - test.CopyDb.Count.Should().Be(0); + PruningTrigger.Prune += Raise.Event>(); } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task pruning_keeps_new_db_on_success() + public async Task WaitForPruningEnd(TestFullPruningDb.TestPruningContext context) { - TestContext test = CreateTest(); - int count = test.TrieDb.Count; - await test.RunFullPruning(); - test.CopyDb.Count.Should().Be(count); + while (!await context.WaitForFinish.WaitOneAsync(TimeSpan.FromMilliseconds(1), CancellationToken.None)) + { + AddBlocks(1); + } + AddBlocks(1); + return await context.DisposeEvent.WaitOneAsync(TimeSpan.FromMilliseconds(Timeout.MaxWaitTime * 5), CancellationToken.None); } - [Timeout(Timeout.MaxTestTime)] - [TestCase(true, FullPruningCompletionBehavior.None, false)] - [TestCase(true, FullPruningCompletionBehavior.ShutdownOnSuccess, true)] - [TestCase(true, FullPruningCompletionBehavior.AlwaysShutdown, true)] - [TestCase(false, FullPruningCompletionBehavior.None, false)] - [TestCase(false, FullPruningCompletionBehavior.ShutdownOnSuccess, false)] - [TestCase(false, FullPruningCompletionBehavior.AlwaysShutdown, true)] - [Retry(10)] - public async Task pruning_shuts_down_node(bool success, FullPruningCompletionBehavior behavior, bool expectedShutdown) + public async Task WaitForPruningStart() { - TestContext test = CreateTest(successfulPruning: success, completionBehavior: behavior); - await test.RunFullPruning(); + TriggerPruningViaEvent(); + using CancellationTokenSource cts = new CancellationTokenSource(); + Task addBlockTasks = Task.Run(() => + { + while (!cts.IsCancellationRequested) + { + AddBlocks(1); + } + }); - if (expectedShutdown) + try { - test.ProcessExitSource.Received(1).Exit(ExitCodes.Ok); + Assert.That(() => FullPruningDb.Context, Is.Not.Null.After(Timeout.MaxTestTime, 1)); } - else + finally { - test.ProcessExitSource.DidNotReceiveWithAnyArgs().Exit(ExitCodes.Ok); + await cts.CancelAsync(); + await addBlockTasks; } - } - - [Test, Timeout(Timeout.MaxTestTime)] - public async Task can_not_start_pruning_when_other_is_in_progress() - { - TestContext test = CreateTest(); - test.FullPruningDb.CanStartPruning.Should().BeTrue(); - test.TriggerPruningViaEvent(); - TestFullPruningDb.TestPruningContext pruningContext = await test.WaitForPruningStart(); - test.FullPruningDb.CanStartPruning.Should().BeFalse(); - await test.WaitForPruningEnd(pruningContext); - - test.FullPruningDb.CanStartPruning.Should().BeTrue(); + TestFullPruningDb.TestPruningContext context = FullPruningDb.Context; + return context; } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task should_not_start_multiple_pruning() + public void AddBlocks(long count) { - TestContext test = CreateTest(); - test.TriggerPruningViaEvent(); - TestFullPruningDb.TestPruningContext ctx = await test.WaitForPruningStart(); - test.TriggerPruningViaEvent(); - await test.WaitForPruningEnd(ctx); - test.FullPruningDb.PruningStarted.Should().Be(1); + for (int i = 0; i < count; i++) + { + long number = _head + 1; + BlockTree.BestPersistedState.Returns(_head); + Block head = Build.A.Block.WithStateRoot(_stateRoot).WithNumber(number).TestObject; + BlockTree.Head.Returns(head); + BlockTree.FindHeader(number).Returns(head.Header); + BlockTree.OnUpdateMainChain += Raise.EventWith(new OnUpdateMainChainArgs(new List() { head }, true)); + Thread.Sleep(1); // Need to add a little sleep as the wait for event in full pruner is async. + } } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task should_duplicate_writes_while_pruning() + public void ShouldCopyAllValuesWhenVisitingTrie() { - TestContext test = CreateTest(); - TestFullPruningDb.TestPruningContext ctx = await test.WaitForPruningStart(); - byte[] key = { 1, 2, 3 }; - test.FullPruningDb[key] = key; - test.FullPruningDb.Context.WaitForFinish.Set(); - - await test.WaitForPruningEnd(ctx); - test.FullPruningDb[key].Should().BeEquivalentTo(key); + PatriciaTree trie = new PatriciaTree(new TrieStore(new NodeStorage(TrieDb), LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + TrieCopiedNodeVisitor visitor = new TrieCopiedNodeVisitor(new NodeStorage(CopyDb)); + trie.Accept(visitor, BlockTree.Head!.StateRoot!); } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task should_duplicate_writes_to_batches_while_pruning() + public void ShouldCopyAllValues() { - TestContext test = CreateTest(); - byte[] key = { 0, 1, 2 }; - TestFullPruningDb.TestPruningContext context = await test.WaitForPruningStart(); - - using (IWriteBatch writeBatch = test.FullPruningDb.StartWriteBatch()) + foreach (KeyValuePair keyValuePair in TrieDb.GetAll()) { - writeBatch[key] = key; + CopyDb[keyValuePair.Key].Should().BeEquivalentTo(keyValuePair.Value); + CopyDb.KeyWasWrittenWithFlags(keyValuePair.Key, WriteFlags.LowPriority | WriteFlags.DisableWAL); } + } + } + + private class TestFullPruningDb : FullPruningDb + { + private readonly bool _successfulPruning; + private readonly bool _clearPrunedDb; - await test.WaitForPruningEnd(context); + public TestPruningContext Context { get; set; } = null!; + public new int PruningStarted { get; private set; } + public ManualResetEvent WaitForClearDb { get; } = new(false); - test.FullPruningDb[key].Should().BeEquivalentTo(key); + public TestFullPruningDb(DbSettings settings, IDbFactory dbFactory, bool successfulPruning, bool clearPrunedDb = false) + : base(settings, dbFactory) + { + _successfulPruning = successfulPruning; + _clearPrunedDb = clearPrunedDb; } - private TestContext CreateTest( - bool successfulPruning = true, - bool clearPrunedDb = false, - FullPruningCompletionBehavior completionBehavior = FullPruningCompletionBehavior.None) => - new( - successfulPruning, - clearPrunedDb, - completionBehavior, - _fullPrunerMemoryBudgetMb, - _degreeOfParallelism); - - private class TestContext + protected override void ClearOldDb(IDb oldDb) { - private readonly bool _clearPrunedDb; - private readonly Hash256 _stateRoot; - private long _head; - public TestFullPruningDb FullPruningDb { get; } - public IPruningTrigger PruningTrigger { get; } = Substitute.For(); - public IBlockTree BlockTree { get; } = Substitute.For(); - public IStateReader StateReader { get; } - public FullPruner Pruner { get; } - public MemDb TrieDb { get; } - public INodeStorage NodeStorage { get; } - public TestMemDb CopyDb { get; } - public IDriveInfo DriveInfo { get; set; } = Substitute.For(); - public IChainEstimations _chainEstimations = ChainSizes.UnknownChain.Instance; - - public IProcessExitSource ProcessExitSource { get; } = Substitute.For(); - - public TestContext( - bool successfulPruning, - bool clearPrunedDb = false, - FullPruningCompletionBehavior completionBehavior = FullPruningCompletionBehavior.None, - int fullScanMemoryBudgetMb = 0, - int degreeOfParallelism = 0, - INodeStorage.KeyScheme currentKeyScheme = INodeStorage.KeyScheme.HalfPath, - INodeStorage.KeyScheme preferredKeyScheme = INodeStorage.KeyScheme.Current) + if (_clearPrunedDb) { - BlockTree.OnUpdateMainChain += (_, e) => _head = e.Blocks[^1].Number; - _clearPrunedDb = clearPrunedDb; - TrieDb = new TestMemDb(); - CopyDb = new TestMemDb(); - IDbFactory dbFactory = Substitute.For(); - dbFactory.CreateDb(Arg.Any()).Returns(TrieDb, CopyDb); - - NodeStorage storageForWrite = new NodeStorage(TrieDb, currentKeyScheme); - PatriciaTree trie = Build.A.Trie(storageForWrite).WithAccountsByIndex(0, 100).TestObject; - _stateRoot = trie.RootHash; - FullPruningDb = new TestFullPruningDb(new DbSettings("test", "test"), dbFactory, successfulPruning, clearPrunedDb); - NodeStorageFactory nodeStorageFactory = new NodeStorageFactory(preferredKeyScheme, LimboLogs.Instance); - nodeStorageFactory.DetectCurrentKeySchemeFrom(TrieDb); - NodeStorage = nodeStorageFactory.WrapKeyValueStore(FullPruningDb); - StateReader = new StateReader(new TrieStore(NodeStorage, LimboLogs.Instance), new TestMemDb(), LimboLogs.Instance); - - Pruner = new( - FullPruningDb, - nodeStorageFactory, - NodeStorage, - PruningTrigger, - new PruningConfig() - { - FullPruningMaxDegreeOfParallelism = degreeOfParallelism, - FullPruningMemoryBudgetMb = fullScanMemoryBudgetMb, - FullPruningCompletionBehavior = completionBehavior - }, BlockTree, StateReader, ProcessExitSource, _chainEstimations, DriveInfo, Substitute.For(), LimboLogs.Instance); + base.ClearOldDb(oldDb); + WaitForClearDb.Set(); } + } - public async Task RunFullPruning() + public override bool TryStartPruning(bool duplicateReads, out IPruningContext context) + { + if (base.TryStartPruning(duplicateReads, out context)) { - TestFullPruningDb.TestPruningContext ctx = await WaitForPruningStart(); - await WaitForPruningEnd(ctx); + context = Context = new TestPruningContext(context, _successfulPruning); + PruningStarted++; + return true; } + return false; + } - public void TriggerPruningViaEvent() - { - PruningTrigger.Prune += Raise.Event>(); - } + internal class TestPruningContext : IPruningContext + { + private readonly IPruningContext _context; + private readonly bool _successfulPruning; - public async Task WaitForPruningEnd(TestFullPruningDb.TestPruningContext context) - { - while (!await context.WaitForFinish.WaitOneAsync(TimeSpan.FromMilliseconds(1), CancellationToken.None)) - { - AddBlocks(1); - } - AddBlocks(1); - return await context.DisposeEvent.WaitOneAsync(TimeSpan.FromMilliseconds(Timeout.MaxWaitTime * 5), CancellationToken.None); - } + public ManualResetEvent DisposeEvent { get; } = new(false); + public ManualResetEvent WaitForFinish { get; } = new(false); - public async Task WaitForPruningStart() + public TestPruningContext(IPruningContext context, bool successfulPruning) { - TriggerPruningViaEvent(); - using CancellationTokenSource cts = new CancellationTokenSource(); - Task addBlockTasks = Task.Run(() => - { - while (!cts.IsCancellationRequested) - { - AddBlocks(1); - } - }); - - try - { - Assert.That(() => FullPruningDb.Context, Is.Not.Null.After(Timeout.MaxTestTime, 1)); - } - finally - { - await cts.CancelAsync(); - await addBlockTasks; - } - - TestFullPruningDb.TestPruningContext context = FullPruningDb.Context; - return context; + _context = context; + _successfulPruning = successfulPruning; } - public void AddBlocks(long count) + public void Dispose() { - for (int i = 0; i < count; i++) - { - long number = _head + 1; - BlockTree.BestPersistedState.Returns(_head); - Block head = Build.A.Block.WithStateRoot(_stateRoot).WithNumber(number).TestObject; - BlockTree.Head.Returns(head); - BlockTree.FindHeader(number).Returns(head.Header); - BlockTree.OnUpdateMainChain += Raise.EventWith(new OnUpdateMainChainArgs(new List() { head }, true)); - Thread.Sleep(1); // Need to add a little sleep as the wait for event in full pruner is async. - } + _context.Dispose(); + DisposeEvent.Set(); + CancellationTokenSource.Dispose(); } - public void ShouldCopyAllValuesWhenVisitingTrie() + public byte[]? this[ReadOnlySpan key] { - PatriciaTree trie = new PatriciaTree(new TrieStore(new NodeStorage(TrieDb), LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - TrieCopiedNodeVisitor visitor = new TrieCopiedNodeVisitor(new NodeStorage(CopyDb)); - trie.Accept(visitor, BlockTree.Head!.StateRoot!); + get => _context[key]; + set => _context[key] = value; } - public void ShouldCopyAllValues() + public IWriteBatch StartWriteBatch() { - foreach (KeyValuePair keyValuePair in TrieDb.GetAll()) - { - CopyDb[keyValuePair.Key].Should().BeEquivalentTo(keyValuePair.Value); - CopyDb.KeyWasWrittenWithFlags(keyValuePair.Key, WriteFlags.LowPriority | WriteFlags.DisableWAL); - } + return _context.StartWriteBatch(); } - } - - private class TestFullPruningDb : FullPruningDb - { - private readonly bool _successfulPruning; - private readonly bool _clearPrunedDb; - public TestPruningContext Context { get; set; } = null!; - public new int PruningStarted { get; private set; } - public ManualResetEvent WaitForClearDb { get; } = new(false); - - public TestFullPruningDb(DbSettings settings, IDbFactory dbFactory, bool successfulPruning, bool clearPrunedDb = false) - : base(settings, dbFactory) + public void Set(ReadOnlySpan key, byte[]? value, WriteFlags flags = WriteFlags.None) { - _successfulPruning = successfulPruning; - _clearPrunedDb = clearPrunedDb; + _context.Set(key, value, flags); } - protected override void ClearOldDb(IDb oldDb) + public byte[]? Get(ReadOnlySpan key, ReadFlags flags = ReadFlags.None) { - if (_clearPrunedDb) - { - base.ClearOldDb(oldDb); - WaitForClearDb.Set(); - } + return _context.Get(key, flags); } - public override bool TryStartPruning(bool duplicateReads, out IPruningContext context) + public void Commit() { - if (base.TryStartPruning(duplicateReads, out context)) + WaitForFinish.Set(); + if (_successfulPruning) { - context = Context = new TestPruningContext(context, _successfulPruning); - PruningStarted++; - return true; + _context.Commit(); } - return false; } - internal class TestPruningContext : IPruningContext + public void MarkStart() { - private readonly IPruningContext _context; - private readonly bool _successfulPruning; - - public ManualResetEvent DisposeEvent { get; } = new(false); - public ManualResetEvent WaitForFinish { get; } = new(false); - - public TestPruningContext(IPruningContext context, bool successfulPruning) - { - _context = context; - _successfulPruning = successfulPruning; - } - - public void Dispose() - { - _context.Dispose(); - DisposeEvent.Set(); - CancellationTokenSource.Dispose(); - } - - public byte[]? this[ReadOnlySpan key] - { - get => _context[key]; - set => _context[key] = value; - } - - public IWriteBatch StartWriteBatch() - { - return _context.StartWriteBatch(); - } - - public void Set(ReadOnlySpan key, byte[]? value, WriteFlags flags = WriteFlags.None) - { - _context.Set(key, value, flags); - } - - public byte[]? Get(ReadOnlySpan key, ReadFlags flags = ReadFlags.None) - { - return _context.Get(key, flags); - } + _context.MarkStart(); + } - public void Commit() - { - WaitForFinish.Set(); - if (_successfulPruning) - { - _context.Commit(); - } - } + public CancellationTokenSource CancellationTokenSource { get; } = new(); + } + } - public void MarkStart() - { - _context.MarkStart(); - } + class TrieCopiedNodeVisitor : ITreeVisitor + { + private INodeStorage _nodeStorageToCompareTo; - public CancellationTokenSource CancellationTokenSource { get; } = new(); - } + public TrieCopiedNodeVisitor(INodeStorage nodeStorage) + { + _nodeStorageToCompareTo = nodeStorage; } - class TrieCopiedNodeVisitor : ITreeVisitor + private void CheckNode(Hash256? storage, in TreePath path, TrieNode node) { - private INodeStorage _nodeStorageToCompareTo; - - public TrieCopiedNodeVisitor(INodeStorage nodeStorage) - { - _nodeStorageToCompareTo = nodeStorage; - } - - private void CheckNode(Hash256? storage, in TreePath path, TrieNode node) - { - _nodeStorageToCompareTo.KeyExists(storage, path, node.Keccak).Should().BeTrue(); - } + _nodeStorageToCompareTo.KeyExists(storage, path, node.Keccak).Should().BeTrue(); + } - public bool IsFullDbScan => true; - public bool ShouldVisit(in TreePathContextWithStorage ctx, Hash256 nextNode) => true; + public bool IsFullDbScan => true; + public bool ShouldVisit(in TreePathContextWithStorage ctx, Hash256 nextNode) => true; - public void VisitTree(in TreePathContextWithStorage ctx, Hash256 rootHash, TrieVisitContext trieVisitContext) - { - } + public void VisitTree(in TreePathContextWithStorage ctx, Hash256 rootHash, TrieVisitContext trieVisitContext) + { + } - public void VisitMissingNode(in TreePathContextWithStorage ctx, Hash256 nodeHash, TrieVisitContext trieVisitContext) - { - } + public void VisitMissingNode(in TreePathContextWithStorage ctx, Hash256 nodeHash, TrieVisitContext trieVisitContext) + { + } - public void VisitBranch(in TreePathContextWithStorage ctx, TrieNode node, TrieVisitContext trieVisitContext) - { - CheckNode(ctx.Storage, ctx.Path, node); - } + public void VisitBranch(in TreePathContextWithStorage ctx, TrieNode node, TrieVisitContext trieVisitContext) + { + CheckNode(ctx.Storage, ctx.Path, node); + } - public void VisitExtension(in TreePathContextWithStorage ctx, TrieNode node, TrieVisitContext trieVisitContext) - { - CheckNode(ctx.Storage, ctx.Path, node); - } + public void VisitExtension(in TreePathContextWithStorage ctx, TrieNode node, TrieVisitContext trieVisitContext) + { + CheckNode(ctx.Storage, ctx.Path, node); + } - public void VisitLeaf(in TreePathContextWithStorage ctx, TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) - { - CheckNode(ctx.Storage, ctx.Path, node); - } + public void VisitLeaf(in TreePathContextWithStorage ctx, TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) + { + CheckNode(ctx.Storage, ctx.Path, node); + } - public void VisitCode(in TreePathContextWithStorage ctx, Hash256 codeHash, TrieVisitContext trieVisitContext) - { - } + public void VisitCode(in TreePathContextWithStorage ctx, Hash256 codeHash, TrieVisitContext trieVisitContext) + { } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs index 08a83248f7a..3f6e5e8b7f2 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs @@ -12,7 +12,6 @@ using Nethermind.Blockchain.FullPruning; using Nethermind.Config; using Nethermind.Core; -using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test.Blockchain; @@ -29,192 +28,191 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.FullPruning +namespace Nethermind.Blockchain.Test.FullPruning; + +public class FullPruningDiskTest { - public class FullPruningDiskTest + public class PruningTestBlockchain : TestBlockchain { - public class PruningTestBlockchain : TestBlockchain + public FullPruningDb PruningDb { get; private set; } = null!; + public INodeStorage MainNodeStorage { get; private set; } = null!; + public TempPath TempDirectory { get; } + public IPruningTrigger PruningTrigger { get; } = Substitute.For(); + public FullTestPruner FullPruner { get; private set; } = null!; + public IPruningConfig PruningConfig { get; set; } = new PruningConfig(); + public IDriveInfo DriveInfo { get; set; } = Substitute.For(); + public IChainEstimations _chainEstimations = Substitute.For(); + public IProcessExitSource ProcessExitSource { get; } = Substitute.For(); + + public PruningTestBlockchain() { - public FullPruningDb PruningDb { get; private set; } = null!; - public INodeStorage MainNodeStorage { get; private set; } = null!; - public TempPath TempDirectory { get; } - public IPruningTrigger PruningTrigger { get; } = Substitute.For(); - public FullTestPruner FullPruner { get; private set; } = null!; - public IPruningConfig PruningConfig { get; set; } = new PruningConfig(); - public IDriveInfo DriveInfo { get; set; } = Substitute.For(); - public IChainEstimations _chainEstimations = Substitute.For(); - public IProcessExitSource ProcessExitSource { get; } = Substitute.For(); - - public PruningTestBlockchain() - { - TempDirectory = TempPath.GetTempDirectory(); - } + TempDirectory = TempPath.GetTempDirectory(); + } - protected override async Task Build( - ISpecProvider? specProvider = null, - UInt256? initialValues = null, - bool addBlockOnStart = true - ) - { - TestBlockchain chain = await base.Build(specProvider, initialValues, addBlockOnStart); - PruningDb = (FullPruningDb)DbProvider.StateDb; - DriveInfo.AvailableFreeSpace.Returns(long.MaxValue); - _chainEstimations.StateSize.Returns((long?)null); - - NodeStorageFactory nodeStorageFactory = new NodeStorageFactory(INodeStorage.KeyScheme.Current, LimboLogs.Instance); - MainNodeStorage = nodeStorageFactory.WrapKeyValueStore(PruningDb); - - FullPruner = new FullTestPruner( - PruningDb, - nodeStorageFactory, - MainNodeStorage, - PruningTrigger, - PruningConfig, - BlockTree, - StateReader, - ProcessExitSource, - DriveInfo, - chain.TrieStore, - _chainEstimations, - LogManager); - return chain; - } + protected override async Task Build( + ISpecProvider? specProvider = null, + UInt256? initialValues = null, + bool addBlockOnStart = true + ) + { + TestBlockchain chain = await base.Build(specProvider, initialValues, addBlockOnStart); + PruningDb = (FullPruningDb)DbProvider.StateDb; + DriveInfo.AvailableFreeSpace.Returns(long.MaxValue); + _chainEstimations.StateSize.Returns((long?)null); + + NodeStorageFactory nodeStorageFactory = new NodeStorageFactory(INodeStorage.KeyScheme.Current, LimboLogs.Instance); + MainNodeStorage = nodeStorageFactory.WrapKeyValueStore(PruningDb); + + FullPruner = new FullTestPruner( + PruningDb, + nodeStorageFactory, + MainNodeStorage, + PruningTrigger, + PruningConfig, + BlockTree, + StateReader, + ProcessExitSource, + DriveInfo, + chain.TrieStore, + _chainEstimations, + LogManager); + return chain; + } - protected override async Task CreateDbProvider() - { - IDbProvider dbProvider = new DbProvider(); - RocksDbFactory rocksDbFactory = new(new DbConfig(), LogManager, TempDirectory.Path); - StandardDbInitializer standardDbInitializer = new(dbProvider, rocksDbFactory, new FileSystem()); - await standardDbInitializer.InitStandardDbsAsync(true); - return dbProvider; - } + protected override async Task CreateDbProvider() + { + IDbProvider dbProvider = new DbProvider(); + RocksDbFactory rocksDbFactory = new(new DbConfig(), LogManager, TempDirectory.Path); + StandardDbInitializer standardDbInitializer = new(dbProvider, rocksDbFactory, new FileSystem()); + await standardDbInitializer.InitStandardDbsAsync(true); + return dbProvider; + } - public override void Dispose() - { - base.Dispose(); - TempDirectory.Dispose(); - } + public override void Dispose() + { + base.Dispose(); + TempDirectory.Dispose(); + } - protected override Task AddBlocksOnStart() => Task.CompletedTask; + protected override Task AddBlocksOnStart() => Task.CompletedTask; + + public static async Task Create(IPruningConfig? pruningConfig = null) + { + PruningTestBlockchain chain = new() { PruningConfig = pruningConfig ?? new PruningConfig() }; + await chain.Build(); + return chain; + } - public static async Task Create(IPruningConfig? pruningConfig = null) + public class FullTestPruner : FullPruner + { + public EventWaitHandle WaitHandle { get; } = new ManualResetEvent(false); + + public FullTestPruner( + IFullPruningDb pruningDb, + INodeStorageFactory nodeStorageFactory, + INodeStorage mainNodeStorage, + IPruningTrigger pruningTrigger, + IPruningConfig pruningConfig, + IBlockTree blockTree, + IStateReader stateReader, + IProcessExitSource processExitSource, + IDriveInfo driveInfo, + IPruningTrieStore trieStore, + IChainEstimations chainEstimations, + ILogManager logManager) + : base(pruningDb, nodeStorageFactory, mainNodeStorage, pruningTrigger, pruningConfig, blockTree, stateReader, processExitSource, chainEstimations, driveInfo, trieStore, logManager) { - PruningTestBlockchain chain = new() { PruningConfig = pruningConfig ?? new PruningConfig() }; - await chain.Build(); - return chain; } - public class FullTestPruner : FullPruner + protected override async Task RunFullPruning(CancellationToken cancellationToken) { - public EventWaitHandle WaitHandle { get; } = new ManualResetEvent(false); - - public FullTestPruner( - IFullPruningDb pruningDb, - INodeStorageFactory nodeStorageFactory, - INodeStorage mainNodeStorage, - IPruningTrigger pruningTrigger, - IPruningConfig pruningConfig, - IBlockTree blockTree, - IStateReader stateReader, - IProcessExitSource processExitSource, - IDriveInfo driveInfo, - IPruningTrieStore trieStore, - IChainEstimations chainEstimations, - ILogManager logManager) - : base(pruningDb, nodeStorageFactory, mainNodeStorage, pruningTrigger, pruningConfig, blockTree, stateReader, processExitSource, chainEstimations, driveInfo, trieStore, logManager) - { - } - - protected override async Task RunFullPruning(CancellationToken cancellationToken) - { - await base.RunFullPruning(cancellationToken); - WaitHandle.Set(); - } + await base.RunFullPruning(cancellationToken); + WaitHandle.Set(); } } + } - [Test, Timeout(Timeout.MaxTestTime), Retry(5)] - public async Task prune_on_disk_multiple_times() + [Test, MaxTime(Timeout.MaxTestTime), Retry(5)] + public async Task prune_on_disk_multiple_times() + { + using PruningTestBlockchain chain = await PruningTestBlockchain.Create(new PruningConfig { FullPruningMinimumDelayHours = 0 }); + for (int i = 0; i < 3; i++) { - using PruningTestBlockchain chain = await PruningTestBlockchain.Create(new PruningConfig { FullPruningMinimumDelayHours = 0 }); - for (int i = 0; i < 3; i++) - { - await RunPruning(chain, i, false); - } + await RunPruning(chain, i, false); } + } - [Test, Timeout(Timeout.MaxTestTime), Retry(5)] - public async Task prune_on_disk_only_once() + [Test, MaxTime(Timeout.MaxTestTime), Retry(5)] + public async Task prune_on_disk_only_once() + { + using PruningTestBlockchain chain = await PruningTestBlockchain.Create(new PruningConfig { FullPruningMinimumDelayHours = 10 }); + for (int i = 0; i < 3; i++) { - using PruningTestBlockchain chain = await PruningTestBlockchain.Create(new PruningConfig { FullPruningMinimumDelayHours = 10 }); - for (int i = 0; i < 3; i++) - { - await RunPruning(chain, i, true); - } + await RunPruning(chain, i, true); } + } + + [TestCase(100, 150, false)] + [TestCase(200, 100, true)] + [TestCase(130, 100, true)] + [TestCase(130, 101, false)] + public async Task should_check_available_space_before_running(long availableSpace, long requiredSpace, bool isEnoughSpace) + { + using PruningTestBlockchain chain = await PruningTestBlockchain.Create(); + chain._chainEstimations.PruningSize.Returns(requiredSpace); + chain.DriveInfo.AvailableFreeSpace.Returns(availableSpace); + PruningTriggerEventArgs args = new(); + chain.PruningTrigger.Prune += Raise.Event>(args); + args.Status.Should().Be(isEnoughSpace ? PruningStatus.Starting : PruningStatus.NotEnoughDiskSpace); + } - [TestCase(100, 150, false)] - [TestCase(200, 100, true)] - [TestCase(130, 100, true)] - [TestCase(130, 101, false)] - public async Task should_check_available_space_before_running(long availableSpace, long requiredSpace, bool isEnoughSpace) + private static async Task RunPruning(PruningTestBlockchain chain, int time, bool onlyFirstRuns) + { + chain.FullPruner.WaitHandle.Reset(); + PruningTriggerEventArgs args = new(); + chain.PruningTrigger.Prune += Raise.Event>(args); + if (args.Status != PruningStatus.Starting) return; + for (int i = 0; i < Reorganization.MaxDepth + 2; i++) { - using PruningTestBlockchain chain = await PruningTestBlockchain.Create(); - chain._chainEstimations.PruningSize.Returns(requiredSpace); - chain.DriveInfo.AvailableFreeSpace.Returns(availableSpace); - PruningTriggerEventArgs args = new(); - chain.PruningTrigger.Prune += Raise.Event>(args); - args.Status.Should().Be(isEnoughSpace ? PruningStatus.Starting : PruningStatus.NotEnoughDiskSpace); + await chain.AddBlock(true); } - private static async Task RunPruning(PruningTestBlockchain chain, int time, bool onlyFirstRuns) + HashSet allItems = chain.DbProvider.StateDb.GetAllValues().ToHashSet(Bytes.EqualityComparer); + bool pruningFinished = false; + for (int i = 0; i < 100 && !pruningFinished; i++) { - chain.FullPruner.WaitHandle.Reset(); - PruningTriggerEventArgs args = new(); - chain.PruningTrigger.Prune += Raise.Event>(args); - if (args.Status != PruningStatus.Starting) return; - for (int i = 0; i < Reorganization.MaxDepth + 2; i++) - { - await chain.AddBlock(true); - } - - HashSet allItems = chain.DbProvider.StateDb.GetAllValues().ToHashSet(Bytes.EqualityComparer); - bool pruningFinished = false; - for (int i = 0; i < 100 && !pruningFinished; i++) - { - pruningFinished = chain.FullPruner.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(100)); - await chain.AddBlock(true); - } + pruningFinished = chain.FullPruner.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(100)); + await chain.AddBlock(true); + } - if (!onlyFirstRuns || time == 0) - { - pruningFinished.Should().BeTrue(); + if (!onlyFirstRuns || time == 0) + { + pruningFinished.Should().BeTrue(); - await WriteFileStructure(chain); + await WriteFileStructure(chain); - Assert.That( - () => chain.PruningDb.InnerDbName, - Is.EqualTo($"State{time + 1}").After(500, 100) - ); + Assert.That( + () => chain.PruningDb.InnerDbName, + Is.EqualTo($"State{time + 1}").After(500, 100) + ); - HashSet currentItems = chain.DbProvider.StateDb.GetAllValues().ToHashSet(Bytes.EqualityComparer); - currentItems.IsSubsetOf(allItems).Should().BeTrue(); - currentItems.Count.Should().BeGreaterThan(0); - } + HashSet currentItems = chain.DbProvider.StateDb.GetAllValues().ToHashSet(Bytes.EqualityComparer); + currentItems.IsSubsetOf(allItems).Should().BeTrue(); + currentItems.Count.Should().BeGreaterThan(0); } + } - private static async Task WriteFileStructure(PruningTestBlockchain chain) + private static async Task WriteFileStructure(PruningTestBlockchain chain) + { + string stateDbPath = Path.Combine(chain.TempDirectory.Path, "state"); + foreach (string directory in Directory.EnumerateDirectories(stateDbPath)) { - string stateDbPath = Path.Combine(chain.TempDirectory.Path, "state"); - foreach (string directory in Directory.EnumerateDirectories(stateDbPath)) - { - await TestContext.Out.WriteLineAsync(directory); - } + await TestContext.Out.WriteLineAsync(directory); + } - foreach (string file in Directory.EnumerateFiles(stateDbPath)) - { - await TestContext.Out.WriteLineAsync(file); - } + foreach (string file in Directory.EnumerateFiles(stateDbPath)) + { + await TestContext.Out.WriteLineAsync(file); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/PathSizePruningTriggerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/PathSizePruningTriggerTests.cs index b95e0a9328a..afd9472e16f 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/PathSizePruningTriggerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/PathSizePruningTriggerTests.cs @@ -9,52 +9,51 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.FullPruning +namespace Nethermind.Blockchain.Test.FullPruning; + +[Parallelizable(ParallelScope.All)] +public class PathSizePruningTriggerTests { - [Parallelizable(ParallelScope.All)] - public class PathSizePruningTriggerTests + [MaxTime(Timeout.MaxTestTime)] + [TestCase(300, ExpectedResult = true)] + [TestCase(400, ExpectedResult = false)] + public bool triggers_on_path_too_big(int threshold) { - [Timeout(Timeout.MaxTestTime)] - [TestCase(300, ExpectedResult = true)] - [TestCase(400, ExpectedResult = false)] - public bool triggers_on_path_too_big(int threshold) - { - ITimerFactory timerFactory = Substitute.For(); - ITimer timer = Substitute.For(); - timerFactory.CreateTimer(Arg.Any()).Returns(timer); - - string path = "path"; - IFileSystem fileSystem = Substitute.For(); - IFileInfo[] files = new[] - { - GetFile(10), - GetFile(100), - GetFile(200) - }; - fileSystem.Directory.Exists(path).Returns(true); - fileSystem.DirectoryInfo.New(path).EnumerateFiles().Returns(files); - - bool triggered = false; - - PathSizePruningTrigger trigger = new(path, threshold, timerFactory, fileSystem); - trigger.Prune += (o, e) => triggered = true; - - timer.Elapsed += Raise.Event(); - return triggered; - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void throws_on_nonexisting_path() - { - Action action = () => new PathSizePruningTrigger("path", 5, null!, Substitute.For()); - action.Should().Throw(); - } + ITimerFactory timerFactory = Substitute.For(); + ITimer timer = Substitute.For(); + timerFactory.CreateTimer(Arg.Any()).Returns(timer); - private static IFileInfo GetFile(long length) + string path = "path"; + IFileSystem fileSystem = Substitute.For(); + IFileInfo[] files = new[] { - IFileInfo fileInfo = Substitute.For(); - fileInfo.Length.Returns(length); - return fileInfo; - } + GetFile(10), + GetFile(100), + GetFile(200) + }; + fileSystem.Directory.Exists(path).Returns(true); + fileSystem.DirectoryInfo.New(path).EnumerateFiles().Returns(files); + + bool triggered = false; + + PathSizePruningTrigger trigger = new(path, threshold, timerFactory, fileSystem); + trigger.Prune += (o, e) => triggered = true; + + timer.Elapsed += Raise.Event(); + return triggered; + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void throws_on_nonexisting_path() + { + Action action = () => new PathSizePruningTrigger("path", 5, null!, Substitute.For()); + action.Should().Throw(); + } + + private static IFileInfo GetFile(long length) + { + IFileInfo fileInfo = Substitute.For(); + fileInfo.Length.Returns(length); + return fileInfo; } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs index 47f983dcbab..1acac6d7b4a 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs @@ -18,28 +18,27 @@ namespace Nethermind.Blockchain.Test; [Parallelizable(ParallelScope.All)] -[TestFixture] public class GenesisLoaderTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_load_genesis_with_emtpy_accounts_and_storage() { AssertBlockHash("0x61b2253366eab37849d21ac066b96c9de133b8c58a9a38652deae1dd7ec22e7b", "Specs/empty_accounts_and_storages.json"); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_load_genesis_with_emtpy_accounts_and_code() { AssertBlockHash("0xfa3da895e1c2a4d2673f60dd885b867d60fb6d823abaf1e5276a899d7e2feca5", "Specs/empty_accounts_and_codes.json"); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_load_genesis_with_precompile_that_has_zero_balance() { AssertBlockHash("0x62839401df8970ec70785f62e9e9d559b256a9a10b343baf6c064747b094de09", "Specs/hive_zero_balance_test.json"); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Can_load_withdrawals_with_empty_root() { Block block = GetGenesisBlock("Specs/shanghai_from_genesis.json"); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs index 988136b6896..18ca8be5352 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs @@ -15,335 +15,334 @@ using Nethermind.TxPool; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public partial class BlockProducerBaseTests { - public partial class BlockProducerBaseTests + public static class BadContract { - public static class BadContract - { - public static AbiSignature Divide { get; } = new("divide"); // divide - } + public static AbiSignature Divide { get; } = new("divide"); // divide + } - public static partial class BaseFeeTestScenario + public static partial class BaseFeeTestScenario + { + public partial class ScenarioBuilder { - public partial class ScenarioBuilder - { - private readonly Address _address = TestItem.Addresses[0]; - private readonly IAbiEncoder _abiEncoder = new AbiEncoder(); + private readonly Address _address = TestItem.Addresses[0]; + private readonly IAbiEncoder _abiEncoder = new AbiEncoder(); - private Address _contractAddress = null!; - private TestRpcBlockchain _testRpcBlockchain = null!; + private Address _contractAddress = null!; + private TestRpcBlockchain _testRpcBlockchain = null!; - private long _eip1559TransitionBlock; - private bool _eip1559Enabled; - private Task? _antecedent; - private UInt256 _currentNonce = 1; + private long _eip1559TransitionBlock; + private bool _eip1559Enabled; + private Task? _antecedent; + private UInt256 _currentNonce = 1; - public ScenarioBuilder WithEip1559TransitionBlock(long transitionBlock) - { - _eip1559Enabled = true; - _eip1559TransitionBlock = transitionBlock; - return this; - } + public ScenarioBuilder WithEip1559TransitionBlock(long transitionBlock) + { + _eip1559Enabled = true; + _eip1559TransitionBlock = transitionBlock; + return this; + } - private async Task CreateTestBlockchainAsync(long gasLimit) - { - await ExecuteAntecedentIfNeeded(); - TestSingleReleaseSpecProvider spec = new( - new ReleaseSpec() - { - IsEip1559Enabled = _eip1559Enabled, - Eip1559TransitionBlock = _eip1559TransitionBlock, - Eip1559FeeCollector = _eip1559FeeCollector, - IsEip155Enabled = true - }); - BlockBuilder blockBuilder = Build.A.Block.Genesis.WithGasLimit(gasLimit); - _testRpcBlockchain = await TestRpcBlockchain.ForTest(SealEngineType.NethDev) - .WithGenesisBlockBuilder(blockBuilder) - .Build(spec); - _testRpcBlockchain.TestWallet.UnlockAccount(_address, new SecureString()); - await _testRpcBlockchain.AddFunds(_address, 1.Ether()); - return this; - } + private async Task CreateTestBlockchainAsync(long gasLimit) + { + await ExecuteAntecedentIfNeeded(); + TestSingleReleaseSpecProvider spec = new( + new ReleaseSpec() + { + IsEip1559Enabled = _eip1559Enabled, + Eip1559TransitionBlock = _eip1559TransitionBlock, + Eip1559FeeCollector = _eip1559FeeCollector, + IsEip155Enabled = true + }); + BlockBuilder blockBuilder = Build.A.Block.Genesis.WithGasLimit(gasLimit); + _testRpcBlockchain = await TestRpcBlockchain.ForTest(SealEngineType.NethDev) + .WithGenesisBlockBuilder(blockBuilder) + .Build(spec); + _testRpcBlockchain.TestWallet.UnlockAccount(_address, new SecureString()); + await _testRpcBlockchain.AddFunds(_address, 1.Ether()); + return this; + } - public ScenarioBuilder CreateTestBlockchain(long gasLimit = 10000000000) - { - _antecedent = CreateTestBlockchainAsync(gasLimit); - return this; - } + public ScenarioBuilder CreateTestBlockchain(long gasLimit = 10000000000) + { + _antecedent = CreateTestBlockchainAsync(gasLimit); + return this; + } - public ScenarioBuilder DeployContract() - { - _antecedent = DeployContractAsync(); - return this; - } + public ScenarioBuilder DeployContract() + { + _antecedent = DeployContractAsync(); + return this; + } - private async Task DeployContractAsync() + private async Task DeployContractAsync() + { + await ExecuteAntecedentIfNeeded(); + _contractAddress = ContractAddress.From(_address, 0L); + byte[] bytecode = await GetContractBytecode("BadContract"); + Transaction tx = new() { - await ExecuteAntecedentIfNeeded(); - _contractAddress = ContractAddress.From(_address, 0L); - byte[] bytecode = await GetContractBytecode("BadContract"); - Transaction tx = new() - { - Value = 0, - Data = bytecode, - GasLimit = 1000000, - GasPrice = 20.GWei(), - SenderAddress = _address, - }; - await _testRpcBlockchain.TxSender.SendTransaction(tx, TxHandlingOptions.ManagedNonce | TxHandlingOptions.PersistentBroadcast); - return this; - } + Value = 0, + Data = bytecode, + GasLimit = 1000000, + GasPrice = 20.GWei(), + SenderAddress = _address, + }; + await _testRpcBlockchain.TxSender.SendTransaction(tx, TxHandlingOptions.ManagedNonce | TxHandlingOptions.PersistentBroadcast); + return this; + } - public ScenarioBuilder SendEip1559Transaction(long gasLimit = 1000000, UInt256? gasPremium = null, UInt256? feeCap = null, bool serviceTransaction = false) - { - _antecedent = SendTransactionAsync(gasLimit, gasPremium ?? 20.GWei(), feeCap ?? UInt256.Zero, serviceTransaction); - return this; - } + public ScenarioBuilder SendEip1559Transaction(long gasLimit = 1000000, UInt256? gasPremium = null, UInt256? feeCap = null, bool serviceTransaction = false) + { + _antecedent = SendTransactionAsync(gasLimit, gasPremium ?? 20.GWei(), feeCap ?? UInt256.Zero, serviceTransaction); + return this; + } - public ScenarioBuilder SendLegacyTransaction(long gasLimit = 1000000, UInt256? gasPremium = null, bool serviceTransaction = false, UInt256? nonce = null) - { - _antecedent = SendTransactionAsync(gasLimit, gasPremium ?? 20.GWei(), UInt256.Zero, serviceTransaction, nonce); - return this; - } - private async Task SendTransactionAsync(long gasLimit, UInt256 gasPrice, UInt256 feeCap, bool serviceTransaction, UInt256? nonce = null) + public ScenarioBuilder SendLegacyTransaction(long gasLimit = 1000000, UInt256? gasPremium = null, bool serviceTransaction = false, UInt256? nonce = null) + { + _antecedent = SendTransactionAsync(gasLimit, gasPremium ?? 20.GWei(), UInt256.Zero, serviceTransaction, nonce); + return this; + } + private async Task SendTransactionAsync(long gasLimit, UInt256 gasPrice, UInt256 feeCap, bool serviceTransaction, UInt256? nonce = null) + { + await ExecuteAntecedentIfNeeded(); + byte[] txData = _abiEncoder.Encode( + AbiEncodingStyle.IncludeSignature, + BadContract.Divide); + Transaction tx = new() { - await ExecuteAntecedentIfNeeded(); - byte[] txData = _abiEncoder.Encode( - AbiEncodingStyle.IncludeSignature, - BadContract.Divide); - Transaction tx = new() - { - Value = 0, - Data = txData, - To = _contractAddress, - SenderAddress = _address, - GasLimit = gasLimit, - GasPrice = gasPrice, - DecodedMaxFeePerGas = feeCap, - Nonce = nonce ?? _currentNonce++, - IsServiceTransaction = serviceTransaction - }; - - var (_, result) = await _testRpcBlockchain.TxSender.SendTransaction(tx, TxHandlingOptions.None); - Assert.That(result, Is.EqualTo(AcceptTxResult.Accepted)); - return this; - } + Value = 0, + Data = txData, + To = _contractAddress, + SenderAddress = _address, + GasLimit = gasLimit, + GasPrice = gasPrice, + DecodedMaxFeePerGas = feeCap, + Nonce = nonce ?? _currentNonce++, + IsServiceTransaction = serviceTransaction + }; + + var (_, result) = await _testRpcBlockchain.TxSender.SendTransaction(tx, TxHandlingOptions.None); + Assert.That(result, Is.EqualTo(AcceptTxResult.Accepted)); + return this; + } - public ScenarioBuilder BlocksBeforeTransitionShouldHaveZeroBaseFee() - { - _antecedent = BlocksBeforeTransitionShouldHaveZeroBaseFeeAsync(); - return this; - } + public ScenarioBuilder BlocksBeforeTransitionShouldHaveZeroBaseFee() + { + _antecedent = BlocksBeforeTransitionShouldHaveZeroBaseFeeAsync(); + return this; + } - public ScenarioBuilder AssertNewBlock(UInt256 expectedBaseFee, params Transaction[] transactions) - { - _antecedent = AssertNewBlockAsync(expectedBaseFee, transactions); - return this; - } + public ScenarioBuilder AssertNewBlock(UInt256 expectedBaseFee, params Transaction[] transactions) + { + _antecedent = AssertNewBlockAsync(expectedBaseFee, transactions); + return this; + } - public ScenarioBuilder AssertNewBlockWithDecreasedBaseFee() - { - _antecedent = AssertNewBlockWithDecreasedBaseFeeAsync(); - return this; - } + public ScenarioBuilder AssertNewBlockWithDecreasedBaseFee() + { + _antecedent = AssertNewBlockWithDecreasedBaseFeeAsync(); + return this; + } - public ScenarioBuilder AssertNewBlockWithIncreasedBaseFee() - { - _antecedent = AssertNewBlockWithIncreasedBaseFeeAsync(); - return this; - } + public ScenarioBuilder AssertNewBlockWithIncreasedBaseFee() + { + _antecedent = AssertNewBlockWithIncreasedBaseFeeAsync(); + return this; + } - private async Task BlocksBeforeTransitionShouldHaveZeroBaseFeeAsync() + private async Task BlocksBeforeTransitionShouldHaveZeroBaseFeeAsync() + { + await ExecuteAntecedentIfNeeded(); + IBlockTree blockTree = _testRpcBlockchain.BlockTree; + Block startingBlock = blockTree.Head!; + Assert.That(startingBlock.Header.BaseFeePerGas, Is.EqualTo(UInt256.Zero)); + for (long i = startingBlock.Number; i < _eip1559TransitionBlock - 1; ++i) { - await ExecuteAntecedentIfNeeded(); - IBlockTree blockTree = _testRpcBlockchain.BlockTree; - Block startingBlock = blockTree.Head!; - Assert.That(startingBlock.Header.BaseFeePerGas, Is.EqualTo(UInt256.Zero)); - for (long i = startingBlock.Number; i < _eip1559TransitionBlock - 1; ++i) - { - await _testRpcBlockchain.AddBlock(); - Block currentBlock = blockTree.Head!; - Assert.That(currentBlock.Header.BaseFeePerGas, Is.EqualTo(UInt256.Zero)); - } - - return this; + await _testRpcBlockchain.AddBlock(); + Block currentBlock = blockTree.Head!; + Assert.That(currentBlock.Header.BaseFeePerGas, Is.EqualTo(UInt256.Zero)); } - private async Task AssertNewBlockAsync(UInt256 expectedBaseFee, - params Transaction[] transactions) - { - await ExecuteAntecedentIfNeeded(); - await _testRpcBlockchain.AddBlock(transactions); - IBlockTree blockTree = _testRpcBlockchain.BlockTree; - Block headBlock = blockTree.Head!; - Assert.That(headBlock.Header.BaseFeePerGas, Is.EqualTo(expectedBaseFee)); - - return this; - } + return this; + } - private async Task AssertNewBlockWithDecreasedBaseFeeAsync() - { - await ExecuteAntecedentIfNeeded(); + private async Task AssertNewBlockAsync(UInt256 expectedBaseFee, + params Transaction[] transactions) + { + await ExecuteAntecedentIfNeeded(); + await _testRpcBlockchain.AddBlock(transactions); + IBlockTree blockTree = _testRpcBlockchain.BlockTree; + Block headBlock = blockTree.Head!; + Assert.That(headBlock.Header.BaseFeePerGas, Is.EqualTo(expectedBaseFee)); - IBlockTree blockTree = _testRpcBlockchain.BlockTree; - Block startingBlock = blockTree.Head!; - await _testRpcBlockchain.AddBlock(); - Block newBlock = blockTree.Head!; - Assert.Less(newBlock.Header.BaseFeePerGas, startingBlock.Header.BaseFeePerGas); + return this; + } - return this; - } + private async Task AssertNewBlockWithDecreasedBaseFeeAsync() + { + await ExecuteAntecedentIfNeeded(); - private async Task AssertNewBlockWithIncreasedBaseFeeAsync() - { - await ExecuteAntecedentIfNeeded(); + IBlockTree blockTree = _testRpcBlockchain.BlockTree; + Block startingBlock = blockTree.Head!; + await _testRpcBlockchain.AddBlock(); + Block newBlock = blockTree.Head!; + Assert.That(newBlock.Header.BaseFeePerGas, Is.LessThan(startingBlock.Header.BaseFeePerGas)); - IBlockTree blockTree = _testRpcBlockchain.BlockTree; - Block startingBlock = blockTree.Head!; - await _testRpcBlockchain.AddBlock(); - Block newBlock = blockTree.Head!; - Assert.Less(startingBlock.Header.BaseFeePerGas, newBlock.Header.BaseFeePerGas); + return this; + } - return this; - } + private async Task AssertNewBlockWithIncreasedBaseFeeAsync() + { + await ExecuteAntecedentIfNeeded(); - private async Task ExecuteAntecedentIfNeeded() - { - if (_antecedent is not null) - await _antecedent; - } + IBlockTree blockTree = _testRpcBlockchain.BlockTree; + Block startingBlock = blockTree.Head!; + await _testRpcBlockchain.AddBlock(); + Block newBlock = blockTree.Head!; + Assert.That(startingBlock.Header.BaseFeePerGas, Is.LessThan(newBlock.Header.BaseFeePerGas)); - public async Task Finish() - { - await ExecuteAntecedentIfNeeded(); - } + return this; + } - private async Task GetContractBytecode(string contract) - { - string[] contractBytecode = await File.ReadAllLinesAsync($"contracts/{contract}.bin"); - if (contractBytecode.Length < 4) - { - throw new IOException("Bytecode not found"); - } + private async Task ExecuteAntecedentIfNeeded() + { + if (_antecedent is not null) + await _antecedent; + } - string bytecodeHex = contractBytecode[3]; - return Bytes.FromHexString(bytecodeHex); - } + public async Task Finish() + { + await ExecuteAntecedentIfNeeded(); } - public static ScenarioBuilder GoesLikeThis() + private async Task GetContractBytecode(string contract) { - return new(); + string[] contractBytecode = await File.ReadAllLinesAsync($"contracts/{contract}.bin"); + if (contractBytecode.Length < 4) + { + throw new IOException("Bytecode not found"); + } + + string bytecodeHex = contractBytecode[3]; + return Bytes.FromHexString(bytecodeHex); } } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task BlockProducer_has_blocks_with_zero_base_fee_before_fork() + public static ScenarioBuilder GoesLikeThis() { - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(5) - .CreateTestBlockchain() - .BlocksBeforeTransitionShouldHaveZeroBaseFee(); - await scenario.Finish(); + return new(); } + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task BlockProducer_returns_correct_fork_base_fee() - { - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(7) - .CreateTestBlockchain() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task BlockProducer_has_blocks_with_zero_base_fee_before_fork() + { + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(5) + .CreateTestBlockchain() + .BlocksBeforeTransitionShouldHaveZeroBaseFee(); + await scenario.Finish(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task BlockProducer_returns_correctly_decreases_base_fee_on_empty_blocks() - { - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(6) - .CreateTestBlockchain() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) - .AssertNewBlock(875000000) - .AssertNewBlock(765625000) - .AssertNewBlock(669921875) - .AssertNewBlock(586181641); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task BlockProducer_returns_correct_fork_base_fee() + { + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(7) + .CreateTestBlockchain() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee); + await scenario.Finish(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task BaseFee_should_decrease_when_we_send_transactions_below_gas_target() - { - long gasLimit = 3000000; - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(6) - .CreateTestBlockchain(gasLimit) - .DeployContract() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) - .SendLegacyTransaction(gasLimit / 3, 20.GWei()) - .SendEip1559Transaction(gasLimit / 3, 1.GWei(), 20.GWei()) - .AssertNewBlock(875000000) - .AssertNewBlockWithDecreasedBaseFee() - .AssertNewBlockWithDecreasedBaseFee(); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task BlockProducer_returns_correctly_decreases_base_fee_on_empty_blocks() + { + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(6) + .CreateTestBlockchain() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) + .AssertNewBlock(875000000) + .AssertNewBlock(765625000) + .AssertNewBlock(669921875) + .AssertNewBlock(586181641); + await scenario.Finish(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task BaseFee_should_not_change_when_we_send_transactions_equal_gas_target() - { - long gasTarget = 3000000; - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(6) - .CreateTestBlockchain(gasTarget) - .DeployContract() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) - .SendLegacyTransaction(gasTarget / 2, 20.GWei()) - .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) - .AssertNewBlock(875000000) - .AssertNewBlock(875000000) - .AssertNewBlockWithDecreasedBaseFee(); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task BaseFee_should_decrease_when_we_send_transactions_below_gas_target() + { + long gasLimit = 3000000; + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(6) + .CreateTestBlockchain(gasLimit) + .DeployContract() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) + .SendLegacyTransaction(gasLimit / 3, 20.GWei()) + .SendEip1559Transaction(gasLimit / 3, 1.GWei(), 20.GWei()) + .AssertNewBlock(875000000) + .AssertNewBlockWithDecreasedBaseFee() + .AssertNewBlockWithDecreasedBaseFee(); + await scenario.Finish(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task BaseFee_should_increase_when_we_send_transactions_above_gas_target() - { - long gasTarget = 3000000; - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(6) - .CreateTestBlockchain(gasTarget) - .DeployContract() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) - .SendLegacyTransaction(gasTarget / 2, 20.GWei()) - .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) - .SendLegacyTransaction(gasTarget / 2, 20.GWei()) - .AssertNewBlock(875000000) - .AssertNewBlockWithIncreasedBaseFee() - .AssertNewBlockWithDecreasedBaseFee(); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task BaseFee_should_not_change_when_we_send_transactions_equal_gas_target() + { + long gasTarget = 3000000; + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(6) + .CreateTestBlockchain(gasTarget) + .DeployContract() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) + .SendLegacyTransaction(gasTarget / 2, 20.GWei()) + .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) + .AssertNewBlock(875000000) + .AssertNewBlock(875000000) + .AssertNewBlockWithDecreasedBaseFee(); + await scenario.Finish(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task When_base_fee_decreases_previously_fee_too_low_transaction_is_included() - { - long gasTarget = 3000000; - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(6) - .CreateTestBlockchain(gasTarget) - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) - .SendLegacyTransaction(gasTarget / 2, 7.GWei() / 10, nonce: UInt256.Zero) - .AssertNewBlock(875000000) - .AssertNewBlock(765625000) - .AssertNewBlock(669921875) // added tx in 9th block - .AssertNewBlock(628051758); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task BaseFee_should_increase_when_we_send_transactions_above_gas_target() + { + long gasTarget = 3000000; + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(6) + .CreateTestBlockchain(gasTarget) + .DeployContract() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) + .SendLegacyTransaction(gasTarget / 2, 20.GWei()) + .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) + .SendLegacyTransaction(gasTarget / 2, 20.GWei()) + .AssertNewBlock(875000000) + .AssertNewBlockWithIncreasedBaseFee() + .AssertNewBlockWithDecreasedBaseFee(); + await scenario.Finish(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task When_base_fee_decreases_previously_fee_too_low_transaction_is_included() + { + long gasTarget = 3000000; + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(6) + .CreateTestBlockchain(gasTarget) + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) + .SendLegacyTransaction(gasTarget / 2, 7.GWei() / 10, nonce: UInt256.Zero) + .AssertNewBlock(875000000) + .AssertNewBlock(765625000) + .AssertNewBlock(669921875) // added tx in 9th block + .AssertNewBlock(628051758); + await scenario.Finish(); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.FeeCollector.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.FeeCollector.cs index acd93014c43..7d688f7875e 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.FeeCollector.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.FeeCollector.cs @@ -4,94 +4,92 @@ using System.Threading.Tasks; using Nethermind.Core; using Nethermind.Core.Extensions; -using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Int256; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public partial class BlockProducerBaseTests { - public partial class BlockProducerBaseTests + public static partial class BaseFeeTestScenario { - public static partial class BaseFeeTestScenario + public partial class ScenarioBuilder { - public partial class ScenarioBuilder - { - private Address _eip1559FeeCollector = null!; + private Address _eip1559FeeCollector = null!; - public ScenarioBuilder WithEip1559FeeCollector(Address address) - { - _eip1559FeeCollector = address; - return this; - } + public ScenarioBuilder WithEip1559FeeCollector(Address address) + { + _eip1559FeeCollector = address; + return this; + } - public ScenarioBuilder AssertNewBlockFeeCollected(UInt256 expectedFeeCollected, params Transaction[] transactions) - { - _antecedent = AssertNewBlockFeeCollectedAsync(expectedFeeCollected, transactions); - return this; - } + public ScenarioBuilder AssertNewBlockFeeCollected(UInt256 expectedFeeCollected, params Transaction[] transactions) + { + _antecedent = AssertNewBlockFeeCollectedAsync(expectedFeeCollected, transactions); + return this; + } - private async Task AssertNewBlockFeeCollectedAsync(UInt256 expectedFeeCollected, params Transaction[] transactions) - { - await ExecuteAntecedentIfNeeded(); - UInt256 balanceBefore = _testRpcBlockchain.State.GetBalance(_eip1559FeeCollector); - await _testRpcBlockchain.AddBlock(transactions); - UInt256 balanceAfter = _testRpcBlockchain.State.GetBalance(_eip1559FeeCollector); - Assert.That(balanceAfter - balanceBefore, Is.EqualTo(expectedFeeCollected)); + private async Task AssertNewBlockFeeCollectedAsync(UInt256 expectedFeeCollected, params Transaction[] transactions) + { + await ExecuteAntecedentIfNeeded(); + UInt256 balanceBefore = _testRpcBlockchain.State.GetBalance(_eip1559FeeCollector); + await _testRpcBlockchain.AddBlock(transactions); + UInt256 balanceAfter = _testRpcBlockchain.State.GetBalance(_eip1559FeeCollector); + Assert.That(balanceAfter - balanceBefore, Is.EqualTo(expectedFeeCollected)); - return this; - } + return this; } } + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task FeeCollector_should_collect_burned_fees_when_eip1559_and_fee_collector_are_set() - { - long gasTarget = 3000000; - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(6) - .WithEip1559FeeCollector(TestItem.AddressE) - .CreateTestBlockchain(gasTarget) - .DeployContract() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .SendLegacyTransaction(gasTarget / 2, 20.GWei()) - .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) - .SendLegacyTransaction(gasTarget / 2, 20.GWei()) - .AssertNewBlockFeeCollected(4500000.GWei()); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task FeeCollector_should_collect_burned_fees_when_eip1559_and_fee_collector_are_set() + { + long gasTarget = 3000000; + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(6) + .WithEip1559FeeCollector(TestItem.AddressE) + .CreateTestBlockchain(gasTarget) + .DeployContract() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .SendLegacyTransaction(gasTarget / 2, 20.GWei()) + .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) + .SendLegacyTransaction(gasTarget / 2, 20.GWei()) + .AssertNewBlockFeeCollected(4500000.GWei()); + await scenario.Finish(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task FeeCollector_should_not_collect_burned_fees_when_eip1559_is_not_set() - { - long gasTarget = 3000000; - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559FeeCollector(TestItem.AddressE) - .CreateTestBlockchain(gasTarget) - .DeployContract() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .SendLegacyTransaction(gasTarget / 2, 20.GWei()) - .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) - .SendLegacyTransaction(gasTarget / 2, 20.GWei()) - .AssertNewBlockFeeCollected(0); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task FeeCollector_should_not_collect_burned_fees_when_eip1559_is_not_set() + { + long gasTarget = 3000000; + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559FeeCollector(TestItem.AddressE) + .CreateTestBlockchain(gasTarget) + .DeployContract() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .SendLegacyTransaction(gasTarget / 2, 20.GWei()) + .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) + .SendLegacyTransaction(gasTarget / 2, 20.GWei()) + .AssertNewBlockFeeCollected(0); + await scenario.Finish(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task FeeCollector_should_not_collect_burned_fees_when_transaction_is_free() - { - long gasTarget = 3000000; - BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() - .WithEip1559TransitionBlock(6) - .WithEip1559FeeCollector(TestItem.AddressE) - .CreateTestBlockchain(gasTarget) - .DeployContract() - .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .SendLegacyTransaction(gasTarget / 2, 20.GWei(), true) - .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei(), true) - .SendLegacyTransaction(gasTarget / 2, 20.GWei(), true) - .AssertNewBlockFeeCollected(0); - await scenario.Finish(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task FeeCollector_should_not_collect_burned_fees_when_transaction_is_free() + { + long gasTarget = 3000000; + BaseFeeTestScenario.ScenarioBuilder scenario = BaseFeeTestScenario.GoesLikeThis() + .WithEip1559TransitionBlock(6) + .WithEip1559FeeCollector(TestItem.AddressE) + .CreateTestBlockchain(gasTarget) + .DeployContract() + .BlocksBeforeTransitionShouldHaveZeroBaseFee() + .SendLegacyTransaction(gasTarget / 2, 20.GWei(), true) + .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei(), true) + .SendLegacyTransaction(gasTarget / 2, 20.GWei(), true) + .AssertNewBlockFeeCollected(0); + await scenario.Finish(); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs index 3735ff1bc1b..0bb6554aca4 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs @@ -28,145 +28,144 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +[Parallelizable(ParallelScope.All)] +public partial class BlockProducerBaseTests { - [Parallelizable(ParallelScope.All)] - public partial class BlockProducerBaseTests + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task DevBlockProducer_IsProducingBlocks_returns_expected_results() { - [Test, Timeout(Timeout.MaxTestTime)] - public async Task DevBlockProducer_IsProducingBlocks_returns_expected_results() - { - TestRpcBlockchain testRpc = await CreateTestRpc(); - DevBlockProducer blockProducer = new( - Substitute.For(), - testRpc.BlockchainProcessor, - testRpc.State, - testRpc.BlockTree, - testRpc.Timestamper, - testRpc.SpecProvider, - new BlocksConfig(), - LimboLogs.Instance); - StandardBlockProducerRunner runner = new StandardBlockProducerRunner( - Substitute.For(), testRpc.BlockTree, blockProducer); - await AssertIsProducingBlocks(runner); - } + TestRpcBlockchain testRpc = await CreateTestRpc(); + DevBlockProducer blockProducer = new( + Substitute.For(), + testRpc.BlockchainProcessor, + testRpc.State, + testRpc.BlockTree, + testRpc.Timestamper, + testRpc.SpecProvider, + new BlocksConfig(), + LimboLogs.Instance); + StandardBlockProducerRunner runner = new StandardBlockProducerRunner( + Substitute.For(), testRpc.BlockTree, blockProducer); + await AssertIsProducingBlocks(runner); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task TestBlockProducer_IsProducingBlocks_returns_expected_results() - { - TestRpcBlockchain testRpc = await CreateTestRpc(); - IBlocksConfig blocksConfig = new BlocksConfig(); - TestBlockProducer blockProducer = new( - Substitute.For(), - testRpc.BlockchainProcessor, - testRpc.State, - Substitute.For(), - testRpc.BlockTree, - testRpc.Timestamper, - testRpc.SpecProvider, - LimboLogs.Instance, - blocksConfig); - StandardBlockProducerRunner runner = new StandardBlockProducerRunner( - Substitute.For(), testRpc.BlockTree, blockProducer); - await AssertIsProducingBlocks(runner); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task TestBlockProducer_IsProducingBlocks_returns_expected_results() + { + TestRpcBlockchain testRpc = await CreateTestRpc(); + IBlocksConfig blocksConfig = new BlocksConfig(); + TestBlockProducer blockProducer = new( + Substitute.For(), + testRpc.BlockchainProcessor, + testRpc.State, + Substitute.For(), + testRpc.BlockTree, + testRpc.Timestamper, + testRpc.SpecProvider, + LimboLogs.Instance, + blocksConfig); + StandardBlockProducerRunner runner = new StandardBlockProducerRunner( + Substitute.For(), testRpc.BlockTree, blockProducer); + await AssertIsProducingBlocks(runner); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task MinedBlockProducer_IsProducingBlocks_returns_expected_results() - { - TestRpcBlockchain testRpc = await CreateTestRpc(); - IBlocksConfig blocksConfig = new BlocksConfig(); - MinedBlockProducer blockProducer = new( - Substitute.For(), - testRpc.BlockchainProcessor, - Substitute.For(), - testRpc.BlockTree, - testRpc.State, - Substitute.For(), - testRpc.Timestamper, - testRpc.SpecProvider, - LimboLogs.Instance, - blocksConfig); - StandardBlockProducerRunner runner = new StandardBlockProducerRunner( - Substitute.For(), testRpc.BlockTree, blockProducer); - await AssertIsProducingBlocks(runner); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task MinedBlockProducer_IsProducingBlocks_returns_expected_results() + { + TestRpcBlockchain testRpc = await CreateTestRpc(); + IBlocksConfig blocksConfig = new BlocksConfig(); + MinedBlockProducer blockProducer = new( + Substitute.For(), + testRpc.BlockchainProcessor, + Substitute.For(), + testRpc.BlockTree, + testRpc.State, + Substitute.For(), + testRpc.Timestamper, + testRpc.SpecProvider, + LimboLogs.Instance, + blocksConfig); + StandardBlockProducerRunner runner = new StandardBlockProducerRunner( + Substitute.For(), testRpc.BlockTree, blockProducer); + await AssertIsProducingBlocks(runner); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task AuraTestBlockProducer_IsProducingBlocks_returns_expected_results() - { - IBlockProcessingQueue blockProcessingQueue = Substitute.For(); - blockProcessingQueue.IsEmpty.Returns(true); - AuRaBlockProducer blockProducer = new( - Substitute.For(), - Substitute.For(), - Substitute.For(), - Substitute.For(), - Substitute.For(), - Substitute.For(), - Substitute.For(), - Substitute.For(), - new AuRaConfig(), - Substitute.For(), - Substitute.For(), - LimboLogs.Instance, - Substitute.For()); - StandardBlockProducerRunner runner = new StandardBlockProducerRunner( - Substitute.For(), Substitute.For(), blockProducer); - await AssertIsProducingBlocks(runner); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task AuraTestBlockProducer_IsProducingBlocks_returns_expected_results() + { + IBlockProcessingQueue blockProcessingQueue = Substitute.For(); + blockProcessingQueue.IsEmpty.Returns(true); + AuRaBlockProducer blockProducer = new( + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For(), + new AuRaConfig(), + Substitute.For(), + Substitute.For(), + LimboLogs.Instance, + Substitute.For()); + StandardBlockProducerRunner runner = new StandardBlockProducerRunner( + Substitute.For(), Substitute.For(), blockProducer); + await AssertIsProducingBlocks(runner); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task CliqueBlockProducer_IsProducingBlocks_returns_expected_results() - { - TestRpcBlockchain testRpc = await CreateTestRpc(); - CliqueBlockProducer blockProducer = new( - Substitute.For(), - testRpc.BlockchainProcessor, - testRpc.State, - testRpc.Timestamper, - Substitute.For(), - Substitute.For(), - Substitute.For(), - Substitute.For(), - Substitute.For(), - new CliqueConfig(), - LimboLogs.Instance); + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task CliqueBlockProducer_IsProducingBlocks_returns_expected_results() + { + TestRpcBlockchain testRpc = await CreateTestRpc(); + CliqueBlockProducer blockProducer = new( + Substitute.For(), + testRpc.BlockchainProcessor, + testRpc.State, + testRpc.Timestamper, + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For(), + new CliqueConfig(), + LimboLogs.Instance); - CliqueBlockProducerRunner runner = new CliqueBlockProducerRunner( - testRpc.BlockTree, - testRpc.Timestamper, - Substitute.For(), - Substitute.For(), - blockProducer, - new CliqueConfig(), - LimboLogs.Instance); + CliqueBlockProducerRunner runner = new CliqueBlockProducerRunner( + testRpc.BlockTree, + testRpc.Timestamper, + Substitute.For(), + Substitute.For(), + blockProducer, + new CliqueConfig(), + LimboLogs.Instance); - await AssertIsProducingBlocks(runner); - } + await AssertIsProducingBlocks(runner); + } - private async Task CreateTestRpc() - { - Address address = TestItem.Addresses[0]; - TestSingleReleaseSpecProvider spec = new(ConstantinopleFix.Instance); - TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev) - .Build(spec); - testRpc.TestWallet.UnlockAccount(address, new SecureString()); - await testRpc.AddFunds(address, 1.Ether()); - return testRpc; - } + private async Task CreateTestRpc() + { + Address address = TestItem.Addresses[0]; + TestSingleReleaseSpecProvider spec = new(ConstantinopleFix.Instance); + TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev) + .Build(spec); + testRpc.TestWallet.UnlockAccount(address, new SecureString()); + await testRpc.AddFunds(address, 1.Ether()); + return testRpc; + } - private async Task AssertIsProducingBlocks(IBlockProducerRunner blockProducer) - { - Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(false)); - blockProducer.Start(); - Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); - Thread.Sleep(5000); - Assert.That(blockProducer.IsProducingBlocks(1), Is.EqualTo(false)); - Assert.That(blockProducer.IsProducingBlocks(1000), Is.EqualTo(true)); - Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); - await blockProducer.StopAsync(); - Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(false)); - } + private async Task AssertIsProducingBlocks(IBlockProducerRunner blockProducer) + { + Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(false)); + blockProducer.Start(); + Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); + Thread.Sleep(5000); + Assert.That(blockProducer.IsProducingBlocks(1), Is.EqualTo(false)); + Assert.That(blockProducer.IsProducingBlocks(1000), Is.EqualTo(true)); + Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); + await blockProducer.StopAsync(); + Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(false)); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs index e4edbe07823..e2ca4466712 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs @@ -17,89 +17,87 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public partial class BlockProducerBaseTests { - [TestFixture] - public partial class BlockProducerBaseTests + private class ProducerUnderTest : BlockProducerBase { - private class ProducerUnderTest : BlockProducerBase + public ProducerUnderTest( + ITxSource txSource, + IBlockchainProcessor processor, + ISealer sealer, + IBlockTree blockTree, + IWorldState stateProvider, + IGasLimitCalculator gasLimitCalculator, + ITimestamper timestamper, + ILogManager logManager, + IBlocksConfig blocksConfig) + : base( + txSource, + processor, + sealer, + blockTree, + stateProvider, + gasLimitCalculator, + timestamper, + MainnetSpecProvider.Instance, + logManager, + new TimestampDifficultyCalculator(), + blocksConfig) { - public ProducerUnderTest( - ITxSource txSource, - IBlockchainProcessor processor, - ISealer sealer, - IBlockTree blockTree, - IWorldState stateProvider, - IGasLimitCalculator gasLimitCalculator, - ITimestamper timestamper, - ILogManager logManager, - IBlocksConfig blocksConfig) - : base( - txSource, - processor, - sealer, - blockTree, - stateProvider, - gasLimitCalculator, - timestamper, - MainnetSpecProvider.Instance, - logManager, - new TimestampDifficultyCalculator(), - blocksConfig) - { - } + } - public Block Prepare() => PrepareBlock(Build.A.BlockHeader.TestObject); + public Block Prepare() => PrepareBlock(Build.A.BlockHeader.TestObject); - public Block Prepare(BlockHeader header) => PrepareBlock(header); + public Block Prepare(BlockHeader header) => PrepareBlock(header); - private class TimestampDifficultyCalculator : IDifficultyCalculator - { - public UInt256 Calculate(BlockHeader header, BlockHeader parent) => header.Timestamp; - } + private class TimestampDifficultyCalculator : IDifficultyCalculator + { + public UInt256 Calculate(BlockHeader header, BlockHeader parent) => header.Timestamp; } + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Time_passing_does_not_break_the_block() - { - ITimestamper timestamper = new IncrementalTimestamper(); - IBlocksConfig blocksConfig = new BlocksConfig(); - ProducerUnderTest producerUnderTest = new( - EmptyTxSource.Instance, - Substitute.For(), - NullSealEngine.Instance, - Build.A.BlockTree().TestObject, - Substitute.For(), - Substitute.For(), - timestamper, - LimboLogs.Instance, - blocksConfig - ); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Time_passing_does_not_break_the_block() + { + ITimestamper timestamper = new IncrementalTimestamper(); + IBlocksConfig blocksConfig = new BlocksConfig(); + ProducerUnderTest producerUnderTest = new( + EmptyTxSource.Instance, + Substitute.For(), + NullSealEngine.Instance, + Build.A.BlockTree().TestObject, + Substitute.For(), + Substitute.For(), + timestamper, + LimboLogs.Instance, + blocksConfig + ); - Block block = producerUnderTest.Prepare(); - new UInt256(block.Timestamp).Should().BeEquivalentTo(block.Difficulty); - } + Block block = producerUnderTest.Prepare(); + new UInt256(block.Timestamp).Should().BeEquivalentTo(block.Difficulty); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Parent_timestamp_is_used_consistently() - { - ITimestamper timestamper = new IncrementalTimestamper(DateTime.UnixEpoch, TimeSpan.FromSeconds(1)); - IBlocksConfig blocksConfig = new BlocksConfig(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Parent_timestamp_is_used_consistently() + { + ITimestamper timestamper = new IncrementalTimestamper(DateTime.UnixEpoch, TimeSpan.FromSeconds(1)); + IBlocksConfig blocksConfig = new BlocksConfig(); - ProducerUnderTest producerUnderTest = new( - EmptyTxSource.Instance, - Substitute.For(), - NullSealEngine.Instance, - Build.A.BlockTree().TestObject, - Substitute.For(), - Substitute.For(), - timestamper, - LimboLogs.Instance, - blocksConfig); + ProducerUnderTest producerUnderTest = new( + EmptyTxSource.Instance, + Substitute.For(), + NullSealEngine.Instance, + Build.A.BlockTree().TestObject, + Substitute.For(), + Substitute.For(), + timestamper, + LimboLogs.Instance, + blocksConfig); - ulong futureTime = UnixTime.FromSeconds(TimeSpan.FromDays(1).TotalSeconds).Seconds; - Block block = producerUnderTest.Prepare(Build.A.BlockHeader.WithTimestamp(futureTime).TestObject); - new UInt256(block.Timestamp).Should().BeEquivalentTo(block.Difficulty); - } + ulong futureTime = UnixTime.FromSeconds(TimeSpan.FromDays(1).TotalSeconds).Seconds; + Block block = producerUnderTest.Prepare(Build.A.BlockHeader.WithTimestamp(futureTime).TestObject); + new UInt256(block.Timestamp).Should().BeEquivalentTo(block.Difficulty); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockOnEachPendingTxTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockOnEachPendingTxTests.cs index 24df75462ea..fb7dcde6abf 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockOnEachPendingTxTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockOnEachPendingTxTests.cs @@ -8,24 +8,22 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public class BuildBlockOnEachPendingTxTests { - [TestFixture] - public class BuildBlockOnEachPendingTxTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void On_pending_trigger_works() { - [Test, Timeout(Timeout.MaxTestTime)] - public void On_pending_trigger_works() + int triggered = 0; + ITxPool txPool = Substitute.For(); + BuildBlockOnEachPendingTx trigger = new(txPool); + trigger.TriggerBlockProduction += (s, e) => triggered++; + for (int i = 0; i < 2; i++) { - int triggered = 0; - ITxPool txPool = Substitute.For(); - BuildBlockOnEachPendingTx trigger = new(txPool); - trigger.TriggerBlockProduction += (s, e) => triggered++; - for (int i = 0; i < 2; i++) - { - txPool.NewPending += Raise.EventWith(new TxEventArgs(Build.A.Transaction.TestObject)); - } - - triggered.Should().Be(2); + txPool.NewPending += Raise.EventWith(new TxEventArgs(Build.A.Transaction.TestObject)); } + + triggered.Should().Be(2); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockRegularlyTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockRegularlyTests.cs index cde66f555c0..4aa9dac4cbb 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockRegularlyTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlockRegularlyTests.cs @@ -7,20 +7,18 @@ using Nethermind.Consensus.Producers; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public class BuildBlockRegularlyTests { - [TestFixture] - public class BuildBlockRegularlyTests + [Test, MaxTime(Timeout.MaxTestTime), Retry(3)] + public async Task Regular_trigger_works() { - [Test, Timeout(Timeout.MaxTestTime), Retry(3)] - public async Task Regular_trigger_works() - { - int triggered = 0; - BuildBlocksRegularly trigger = new(TimeSpan.FromMilliseconds(5)); - trigger.TriggerBlockProduction += (s, e) => triggered++; - await Task.Delay(50); + int triggered = 0; + BuildBlocksRegularly trigger = new(TimeSpan.FromMilliseconds(5)); + trigger.TriggerBlockProduction += (s, e) => triggered++; + await Task.Delay(50); - triggered.Should().BeInRange(1, 20); - } + triggered.Should().BeInRange(1, 20); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs index a3574121765..fda6ddbe27a 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs @@ -13,79 +13,78 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +[Parallelizable(ParallelScope.All)] +public class BuildBlocksOnlyWhenNotProcessingTests { - [Parallelizable(ParallelScope.All)] - public class BuildBlocksOnlyWhenNotProcessingTests + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task should_trigger_block_production_on_empty_queue() { - [Test, Timeout(Timeout.MaxTestTime)] - public async Task should_trigger_block_production_on_empty_queue() - { - Context context = new(); - context.BlockProcessingQueue.IsEmpty.Returns(true); - Block block = (await context.MainBlockProductionTrigger.BuildBlock())!; - block.Should().Be(context.DefaultBlock); - context.TriggeredCount.Should().Be(1); - } + Context context = new(); + context.BlockProcessingQueue.IsEmpty.Returns(true); + Block block = (await context.MainBlockProductionTrigger.BuildBlock())!; + block.Should().Be(context.DefaultBlock); + context.TriggeredCount.Should().Be(1); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task should_trigger_block_production_when_queue_empties() - { - Context context = new(); - context.BlockProcessingQueue.IsEmpty.Returns(false); - Task buildTask = context.MainBlockProductionTrigger.BuildBlock(); + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task should_trigger_block_production_when_queue_empties() + { + Context context = new(); + context.BlockProcessingQueue.IsEmpty.Returns(false); + Task buildTask = context.MainBlockProductionTrigger.BuildBlock(); - await Task.Delay(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2); - buildTask.IsCanceled.Should().BeFalse(); + await Task.Delay(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2); + buildTask.IsCanceled.Should().BeFalse(); - context.BlockProcessingQueue.IsEmpty.Returns(true); - Block? block = await buildTask; - block.Should().Be(context.DefaultBlock); - context.TriggeredCount.Should().Be(1); - } + context.BlockProcessingQueue.IsEmpty.Returns(true); + Block? block = await buildTask; + block.Should().Be(context.DefaultBlock); + context.TriggeredCount.Should().Be(1); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task should_cancel_triggering_block_production() - { - Context context = new(); - context.BlockProcessingQueue.IsEmpty.Returns(false); - using CancellationTokenSource cancellationTokenSource = new(); - Task buildTask = context.MainBlockProductionTrigger.BuildBlock(cancellationToken: cancellationTokenSource.Token); + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task should_cancel_triggering_block_production() + { + Context context = new(); + context.BlockProcessingQueue.IsEmpty.Returns(false); + using CancellationTokenSource cancellationTokenSource = new(); + Task buildTask = context.MainBlockProductionTrigger.BuildBlock(cancellationToken: cancellationTokenSource.Token); - await Task.Delay(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2); - buildTask.IsCanceled.Should().BeFalse(); + await Task.Delay(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2); + buildTask.IsCanceled.Should().BeFalse(); - cancellationTokenSource.Cancel(); + cancellationTokenSource.Cancel(); - Func f = async () => { await buildTask; }; - await f.Should().ThrowAsync(); - } + Func f = async () => { await buildTask; }; + await f.Should().ThrowAsync(); + } - private class Context + private class Context + { + public Context() { - public Context() - { - MainBlockProductionTrigger = new BuildBlocksWhenRequested(); - BlockProcessingQueue = Substitute.For(); - BlockTree = Substitute.For(); - Trigger = new BuildBlocksOnlyWhenNotProcessing(MainBlockProductionTrigger, BlockProcessingQueue, BlockTree, LimboLogs.Instance, false); - DefaultBlock = Build.A.Block.TestObject; - Trigger.TriggerBlockProduction += OnTriggerBlockProduction; - } - - public Block DefaultBlock { get; } - public int TriggeredCount { get; private set; } + MainBlockProductionTrigger = new BuildBlocksWhenRequested(); + BlockProcessingQueue = Substitute.For(); + BlockTree = Substitute.For(); + Trigger = new BuildBlocksOnlyWhenNotProcessing(MainBlockProductionTrigger, BlockProcessingQueue, BlockTree, LimboLogs.Instance, false); + DefaultBlock = Build.A.Block.TestObject; + Trigger.TriggerBlockProduction += OnTriggerBlockProduction; + } - private void OnTriggerBlockProduction(object? sender, BlockProductionEventArgs e) - { - TriggeredCount++; - e.BlockProductionTask = Task.FromResult(DefaultBlock); - } + public Block DefaultBlock { get; } + public int TriggeredCount { get; private set; } - public BuildBlocksOnlyWhenNotProcessing Trigger { get; } - public IBlockTree BlockTree { get; } - public IBlockProcessingQueue BlockProcessingQueue { get; } - public IManualBlockProductionTrigger MainBlockProductionTrigger { get; } + private void OnTriggerBlockProduction(object? sender, BlockProductionEventArgs e) + { + TriggeredCount++; + e.BlockProductionTask = Task.FromResult(DefaultBlock); } + + public BuildBlocksOnlyWhenNotProcessing Trigger { get; } + public IBlockTree BlockTree { get; } + public IBlockProcessingQueue BlockProcessingQueue { get; } + public IManualBlockProductionTrigger MainBlockProductionTrigger { get; } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksWhenRequestedTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksWhenRequestedTests.cs index 86d96c4271e..a244c84aacb 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksWhenRequestedTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksWhenRequestedTests.cs @@ -5,19 +5,17 @@ using Nethermind.Consensus.Producers; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public class BuildBlocksWhenRequestedTests { - [TestFixture] - public class BuildBlocksWhenRequestedTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void Manual_trigger_works() { - [Test, Timeout(Timeout.MaxTestTime)] - public void Manual_trigger_works() - { - bool triggered = false; - BuildBlocksWhenRequested trigger = new(); - trigger.TriggerBlockProduction += (s, e) => triggered = true; - trigger.BuildBlock(); - triggered.Should().BeTrue(); - } + bool triggered = false; + BuildBlocksWhenRequested trigger = new(); + trigger.TriggerBlockProduction += (s, e) => triggered = true; + trigger.BuildBlock(); + triggered.Should().BeTrue(); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/CompositeBlockProductionTriggerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/CompositeBlockProductionTriggerTests.cs index 969708c8f6a..478c37bbebc 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/CompositeBlockProductionTriggerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/CompositeBlockProductionTriggerTests.cs @@ -5,25 +5,23 @@ using Nethermind.Consensus.Producers; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public class CompositeBlockProductionTriggerTests { - [TestFixture] - public class CompositeBlockProductionTriggerTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void On_pending_trigger_works() { - [Test, Timeout(Timeout.MaxTestTime)] - public void On_pending_trigger_works() - { - int triggered = 0; - BuildBlocksWhenRequested trigger1 = new(); - BuildBlocksWhenRequested trigger2 = new(); - IBlockProductionTrigger composite = trigger1.Or(trigger2); - composite.TriggerBlockProduction += (s, e) => triggered++; - trigger1.BuildBlock(); - trigger2.BuildBlock(); - trigger1.BuildBlock(); - trigger2.BuildBlock(); + int triggered = 0; + BuildBlocksWhenRequested trigger1 = new(); + BuildBlocksWhenRequested trigger2 = new(); + IBlockProductionTrigger composite = trigger1.Or(trigger2); + composite.TriggerBlockProduction += (s, e) => triggered++; + trigger1.BuildBlock(); + trigger2.BuildBlock(); + trigger1.BuildBlock(); + trigger2.BuildBlock(); - triggered.Should().Be(4); - } + triggered.Should().Be(4); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs index e3cf1c589bd..096dcd6db9a 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs @@ -17,106 +17,102 @@ using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Db; -using Nethermind.Db.Blooms; using Nethermind.Evm; using Nethermind.Evm.TransactionProcessing; using Nethermind.Logging; using Nethermind.Specs; using Nethermind.State; -using Nethermind.State.Repositories; using Nethermind.Trie.Pruning; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public class DevBlockProducerTests { - [TestFixture] - public class DevBlockProducerTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void Test() { - [Test, Timeout(Timeout.MaxTestTime)] - public void Test() - { - ISpecProvider specProvider = MainnetSpecProvider.Instance; - DbProvider dbProvider = new(); - dbProvider.RegisterDb(DbNames.BlockInfos, new MemDb()); - dbProvider.RegisterDb(DbNames.Blocks, new MemDb()); - dbProvider.RegisterDb(DbNames.Headers, new MemDb()); - dbProvider.RegisterDb(DbNames.State, new MemDb()); - dbProvider.RegisterDb(DbNames.Code, new MemDb()); - dbProvider.RegisterDb(DbNames.Metadata, new MemDb()); + ISpecProvider specProvider = MainnetSpecProvider.Instance; + DbProvider dbProvider = new(); + dbProvider.RegisterDb(DbNames.BlockInfos, new MemDb()); + dbProvider.RegisterDb(DbNames.Blocks, new MemDb()); + dbProvider.RegisterDb(DbNames.Headers, new MemDb()); + dbProvider.RegisterDb(DbNames.State, new MemDb()); + dbProvider.RegisterDb(DbNames.Code, new MemDb()); + dbProvider.RegisterDb(DbNames.Metadata, new MemDb()); - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .TestObject; + BlockTree blockTree = Build.A.BlockTree() + .WithoutSettingHead + .TestObject; - TrieStore trieStore = new( - dbProvider.RegisteredDbs[DbNames.State], - NoPruning.Instance, - Archive.Instance, - LimboLogs.Instance); - WorldState stateProvider = new( - trieStore, - dbProvider.RegisteredDbs[DbNames.Code], - LimboLogs.Instance); - StateReader stateReader = new(trieStore, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); - BlockhashProvider blockhashProvider = new(blockTree, specProvider, stateProvider, LimboLogs.Instance); - CodeInfoRepository codeInfoRepository = new(); - VirtualMachine virtualMachine = new( - blockhashProvider, - specProvider, - codeInfoRepository, - LimboLogs.Instance); - TransactionProcessor txProcessor = new( - specProvider, - stateProvider, - virtualMachine, - codeInfoRepository, - LimboLogs.Instance); - BlockProcessor blockProcessor = new( - specProvider, - Always.Valid, - NoBlockRewards.Instance, - new BlockProcessor.BlockValidationTransactionsExecutor(txProcessor, stateProvider), - stateProvider, - NullReceiptStorage.Instance, - txProcessor, - new BeaconBlockRootHandler(txProcessor), - new BlockhashStore(specProvider, stateProvider), - LimboLogs.Instance); - BlockchainProcessor blockchainProcessor = new( - blockTree, - blockProcessor, - NullRecoveryStep.Instance, - stateReader, - LimboLogs.Instance, - BlockchainProcessor.Options.Default); - BuildBlocksWhenRequested trigger = new(); - ManualTimestamper timestamper = new ManualTimestamper(); - DevBlockProducer devBlockProducer = new( - EmptyTxSource.Instance, - blockchainProcessor, - stateProvider, - blockTree, - timestamper, - specProvider, - new BlocksConfig(), - LimboLogs.Instance); + TrieStore trieStore = new( + dbProvider.RegisteredDbs[DbNames.State], + NoPruning.Instance, + Archive.Instance, + LimboLogs.Instance); + WorldState stateProvider = new( + trieStore, + dbProvider.RegisteredDbs[DbNames.Code], + LimboLogs.Instance); + StateReader stateReader = new(trieStore, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); + BlockhashProvider blockhashProvider = new(blockTree, specProvider, stateProvider, LimboLogs.Instance); + CodeInfoRepository codeInfoRepository = new(); + VirtualMachine virtualMachine = new( + blockhashProvider, + specProvider, + codeInfoRepository, + LimboLogs.Instance); + TransactionProcessor txProcessor = new( + specProvider, + stateProvider, + virtualMachine, + codeInfoRepository, + LimboLogs.Instance); + BlockProcessor blockProcessor = new( + specProvider, + Always.Valid, + NoBlockRewards.Instance, + new BlockProcessor.BlockValidationTransactionsExecutor(txProcessor, stateProvider), + stateProvider, + NullReceiptStorage.Instance, + txProcessor, + new BeaconBlockRootHandler(txProcessor), + new BlockhashStore(specProvider, stateProvider), + LimboLogs.Instance); + BlockchainProcessor blockchainProcessor = new( + blockTree, + blockProcessor, + NullRecoveryStep.Instance, + stateReader, + LimboLogs.Instance, + BlockchainProcessor.Options.Default); + BuildBlocksWhenRequested trigger = new(); + ManualTimestamper timestamper = new ManualTimestamper(); + DevBlockProducer devBlockProducer = new( + EmptyTxSource.Instance, + blockchainProcessor, + stateProvider, + blockTree, + timestamper, + specProvider, + new BlocksConfig(), + LimboLogs.Instance); - StandardBlockProducerRunner blockProducerRunner = new StandardBlockProducerRunner(trigger, blockTree, devBlockProducer); + StandardBlockProducerRunner blockProducerRunner = new StandardBlockProducerRunner(trigger, blockTree, devBlockProducer); - blockchainProcessor.Start(); - blockProducerRunner.Start(); - ProducedBlockSuggester _ = new ProducedBlockSuggester(blockTree, blockProducerRunner); + blockchainProcessor.Start(); + blockProducerRunner.Start(); + ProducedBlockSuggester _ = new ProducedBlockSuggester(blockTree, blockProducerRunner); - AutoResetEvent autoResetEvent = new(false); + AutoResetEvent autoResetEvent = new(false); - blockTree.NewHeadBlock += (_, _) => autoResetEvent.Set(); - blockTree.SuggestBlock(Build.A.Block.Genesis.TestObject); + blockTree.NewHeadBlock += (_, _) => autoResetEvent.Set(); + blockTree.SuggestBlock(Build.A.Block.Genesis.TestObject); - autoResetEvent.WaitOne(1000).Should().BeTrue("genesis"); + autoResetEvent.WaitOne(1000).Should().BeTrue("genesis"); - trigger.BuildBlock(); - autoResetEvent.WaitOne(1000).Should().BeTrue("1"); - blockTree.Head!.Number.Should().Be(1); - } + trigger.BuildBlock(); + autoResetEvent.WaitOne(1000).Should().BeTrue("1"); + blockTree.Head!.Number.Should().Be(1); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/IfPoolIsNotEmptyTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/IfPoolIsNotEmptyTests.cs index 1b01f73280b..3f2d97ac18b 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/IfPoolIsNotEmptyTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/IfPoolIsNotEmptyTests.cs @@ -7,23 +7,22 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Producers +namespace Nethermind.Blockchain.Test.Producers; + +public class IfPoolIsNotEmptyTests { - public class IfPoolIsNotEmptyTests + [MaxTime(Timeout.MaxTestTime)] + [TestCase(0, false)] + [TestCase(1, true)] + public void Does_not_trigger_when_empty(int txCount, bool shouldTrigger) { - [Timeout(Timeout.MaxTestTime)] - [TestCase(0, false)] - [TestCase(1, true)] - public void Does_not_trigger_when_empty(int txCount, bool shouldTrigger) - { - var pool = Substitute.For(); - pool.GetPendingTransactionsCount().Returns(txCount); - bool triggered = false; - BuildBlocksWhenRequested trigger = new(); - IBlockProductionTrigger withCondition = trigger.IfPoolIsNotEmpty(pool); - withCondition.TriggerBlockProduction += (s, e) => triggered = true; - trigger.BuildBlock(); - triggered.Should().Be(shouldTrigger); - } + var pool = Substitute.For(); + pool.GetPendingTransactionsCount().Returns(txCount); + bool triggered = false; + BuildBlocksWhenRequested trigger = new(); + IBlockProductionTrigger withCondition = trigger.IfPoolIsNotEmpty(pool); + withCondition.TriggerBlockProduction += (s, e) => triggered = true; + trigger.BuildBlock(); + triggered.Should().Be(shouldTrigger); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs index 6ee424c6b38..941b80e2217 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs @@ -15,69 +15,68 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Proofs +namespace Nethermind.Blockchain.Test.Proofs; + +public class ReceiptTrieTests { - public class ReceiptTrieTests + private static readonly IRlpStreamDecoder _decoder = Rlp.GetStreamDecoder()!; + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_calculate_root_no_eip_658() { - private static readonly IRlpStreamDecoder _decoder = Rlp.GetStreamDecoder()!; + TxReceipt receipt = Build.A.Receipt.WithAllFieldsFilled.TestObject; + Hash256 rootHash = ReceiptTrie.CalculateRoot(MainnetSpecProvider.Instance.GetSpec((1, null)), + [receipt], _decoder); + Assert.That(rootHash.ToString(), + Is.EqualTo("0xe51a2d9f986d68628990c9d65e45c36128ec7bb697bd426b0bb4d18a3f3321be")); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_calculate_root_no_eip_658() - { - TxReceipt receipt = Build.A.Receipt.WithAllFieldsFilled.TestObject; - Hash256 rootHash = ReceiptTrie.CalculateRoot(MainnetSpecProvider.Instance.GetSpec((1, null)), - [receipt], _decoder); - Assert.That(rootHash.ToString(), - Is.EqualTo("0xe51a2d9f986d68628990c9d65e45c36128ec7bb697bd426b0bb4d18a3f3321be")); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_calculate_root() + { + TxReceipt receipt = Build.A.Receipt.WithAllFieldsFilled.TestObject; + Hash256 rootHash = ReceiptTrie.CalculateRoot( + MainnetSpecProvider.Instance.GetSpec((MainnetSpecProvider.MuirGlacierBlockNumber, null)), + [receipt], _decoder); + Assert.That(rootHash.ToString(), + Is.EqualTo("0x2e6d89c5b539e72409f2e587730643986c2ef33db5e817a4223aa1bb996476d5")); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_calculate_root() - { - TxReceipt receipt = Build.A.Receipt.WithAllFieldsFilled.TestObject; - Hash256 rootHash = ReceiptTrie.CalculateRoot( - MainnetSpecProvider.Instance.GetSpec((MainnetSpecProvider.MuirGlacierBlockNumber, null)), - [receipt], _decoder); - Assert.That(rootHash.ToString(), - Is.EqualTo("0x2e6d89c5b539e72409f2e587730643986c2ef33db5e817a4223aa1bb996476d5")); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_collect_proof_with_branch() + { + TxReceipt receipt1 = Build.A.Receipt.WithAllFieldsFilled.TestObject; + TxReceipt receipt2 = Build.A.Receipt.WithAllFieldsFilled.TestObject; + ReceiptTrie trie = new(MainnetSpecProvider.Instance.GetSpec((ForkActivation)1), + [receipt1, receipt2], _decoder, true); + byte[][] proof = trie.BuildProof(0); + Assert.That(proof.Length, Is.EqualTo(2)); - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_collect_proof_with_branch() - { - TxReceipt receipt1 = Build.A.Receipt.WithAllFieldsFilled.TestObject; - TxReceipt receipt2 = Build.A.Receipt.WithAllFieldsFilled.TestObject; - ReceiptTrie trie = new(MainnetSpecProvider.Instance.GetSpec((ForkActivation)1), - [receipt1, receipt2], _decoder, true); - byte[][] proof = trie.BuildProof(0); - Assert.That(proof.Length, Is.EqualTo(2)); + trie.UpdateRootHash(); + VerifyProof(proof, trie.RootHash); + } - trie.UpdateRootHash(); - VerifyProof(proof, trie.RootHash); - } + private void VerifyProof(byte[][] proof, Hash256 receiptRoot) + { + TrieNode node = new(NodeType.Unknown, proof.Last()); + node.ResolveNode(Substitute.For(), TreePath.Empty); + TxReceipt receipt = _decoder.Decode(node.Value.AsRlpStream()); + Assert.That(receipt.Bloom, Is.Not.Null); - private void VerifyProof(byte[][] proof, Hash256 receiptRoot) + for (int i = proof.Length; i > 0; i--) { - TrieNode node = new(NodeType.Unknown, proof.Last()); - node.ResolveNode(Substitute.For(), TreePath.Empty); - TxReceipt receipt = _decoder.Decode(node.Value.AsRlpStream()); - Assert.NotNull(receipt.Bloom); - - for (int i = proof.Length; i > 0; i--) + Hash256 proofHash = Keccak.Compute(proof[i - 1]); + if (i > 1) { - Hash256 proofHash = Keccak.Compute(proof[i - 1]); - if (i > 1) - { - if (!new Rlp(proof[i - 2]).ToString(false).Contains(proofHash.ToString(false))) - { - throw new InvalidDataException(); - } - } - else if (proofHash != receiptRoot) + if (!new Rlp(proof[i - 2]).ToString(false).Contains(proofHash.ToString(false))) { throw new InvalidDataException(); } } + else if (proofHash != receiptRoot) + { + throw new InvalidDataException(); + } } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/TxTrieTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/TxTrieTests.cs index 0ae7483ce71..2966a72fe1d 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/TxTrieTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/TxTrieTests.cs @@ -12,90 +12,89 @@ using Nethermind.State.Proofs; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Proofs +namespace Nethermind.Blockchain.Test.Proofs; + +[TestFixture(true)] +[TestFixture(false)] +public class TxTrieTests { - [TestFixture(true)] - [TestFixture(false)] - public class TxTrieTests + private readonly IReleaseSpec _releaseSpec; + + public TxTrieTests(bool useEip2718) + { + _releaseSpec = useEip2718 ? Berlin.Instance : MuirGlacier.Instance; + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_calculate_root() { - private readonly IReleaseSpec _releaseSpec; + Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject; + Hash256 rootHash = TxTrie.CalculateRoot(block.Transactions); - public TxTrieTests(bool useEip2718) + if (_releaseSpec == Berlin.Instance) { - _releaseSpec = useEip2718 ? Berlin.Instance : MuirGlacier.Instance; + Assert.That(rootHash.ToString(), Is.EqualTo("0x29cc403075ed3d1d6af940d577125cc378ee5a26f7746cbaf87f1cf4a38258b5")); } - - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_calculate_root() + else { - Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject; - Hash256 rootHash = TxTrie.CalculateRoot(block.Transactions); - - if (_releaseSpec == Berlin.Instance) - { - Assert.That(rootHash.ToString(), Is.EqualTo("0x29cc403075ed3d1d6af940d577125cc378ee5a26f7746cbaf87f1cf4a38258b5")); - } - else - { - Assert.That(rootHash.ToString(), Is.EqualTo("0x29cc403075ed3d1d6af940d577125cc378ee5a26f7746cbaf87f1cf4a38258b5")); - } + Assert.That(rootHash.ToString(), Is.EqualTo("0x29cc403075ed3d1d6af940d577125cc378ee5a26f7746cbaf87f1cf4a38258b5")); } + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_collect_proof_trie_case_1() - { - Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject; - TxTrie txTrie = new(block.Transactions, true); - byte[][] proof = txTrie.BuildProof(0); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_collect_proof_trie_case_1() + { + Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject; + TxTrie txTrie = new(block.Transactions, true); + byte[][] proof = txTrie.BuildProof(0); - txTrie.UpdateRootHash(); - VerifyProof(proof, txTrie.RootHash); - } + txTrie.UpdateRootHash(); + VerifyProof(proof, txTrie.RootHash); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_collect_proof_with_trie_case_2() - { - Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject, Build.A.Transaction.TestObject).TestObject; - TxTrie txTrie = new(block.Transactions, true); - byte[][] proof = txTrie.BuildProof(0); - Assert.That(proof.Length, Is.EqualTo(2)); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_collect_proof_with_trie_case_2() + { + Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject, Build.A.Transaction.TestObject).TestObject; + TxTrie txTrie = new(block.Transactions, true); + byte[][] proof = txTrie.BuildProof(0); + Assert.That(proof.Length, Is.EqualTo(2)); - txTrie.UpdateRootHash(); - VerifyProof(proof, txTrie.RootHash); - } + txTrie.UpdateRootHash(); + VerifyProof(proof, txTrie.RootHash); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Can_collect_proof_with_trie_case_3_modified() - { - Block block = Build.A.Block.WithTransactions(Enumerable.Repeat(Build.A.Transaction.TestObject, 1000).ToArray()).TestObject; - TxTrie txTrie = new(block.Transactions, true); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Can_collect_proof_with_trie_case_3_modified() + { + Block block = Build.A.Block.WithTransactions(Enumerable.Repeat(Build.A.Transaction.TestObject, 1000).ToArray()).TestObject; + TxTrie txTrie = new(block.Transactions, true); - txTrie.UpdateRootHash(); - for (int i = 0; i < 1000; i++) - { - byte[][] proof = txTrie.BuildProof(i); - VerifyProof(proof, txTrie.RootHash); - } + txTrie.UpdateRootHash(); + for (int i = 0; i < 1000; i++) + { + byte[][] proof = txTrie.BuildProof(i); + VerifyProof(proof, txTrie.RootHash); } + } - private static void VerifyProof(byte[][] proof, Hash256 txRoot) + private static void VerifyProof(byte[][] proof, Hash256 txRoot) + { + for (int i = proof.Length; i > 0; i--) { - for (int i = proof.Length; i > 0; i--) + Hash256 proofHash = Keccak.Compute(proof[i - 1]); + if (i > 1) { - Hash256 proofHash = Keccak.Compute(proof[i - 1]); - if (i > 1) + if (!new Rlp(proof[i - 2]).ToString(false).Contains(proofHash.ToString(false))) { - if (!new Rlp(proof[i - 2]).ToString(false).Contains(proofHash.ToString(false))) - { - throw new InvalidDataException(); - } + throw new InvalidDataException(); } - else + } + else + { + if (proofHash != txRoot) { - if (proofHash != txRoot) - { - throw new InvalidDataException(); - } + throw new InvalidDataException(); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/WithdrawalTrieTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/WithdrawalTrieTests.cs index 8848ba9787b..4dada95cceb 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/WithdrawalTrieTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/WithdrawalTrieTests.cs @@ -13,7 +13,7 @@ namespace Nethermind.Blockchain.Test.Proofs; public class WithdrawalTrieTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Should_compute_hash_root() { var block = Build.A.Block.WithWithdrawals(10).TestObject; @@ -23,7 +23,7 @@ public void Should_compute_hash_root() trie.RootHash.ToString(), Is.EqualTo("0xf3a83e722a656f6d1813498178b7c9490a7488de8c576144f8bd473c61c3239f")); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Should_verify_proof() { var count = 10; @@ -32,7 +32,7 @@ public void Should_verify_proof() for (int i = 0; i < count; i++) { - Assert.IsTrue(VerifyProof(trie.BuildProof(i), trie.RootHash)); + Assert.That(VerifyProof(trie.BuildProof(i), trie.RootHash), Is.True); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/ReadOnlyBlockTreeTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/ReadOnlyBlockTreeTests.cs index ebd926724cf..2a85fb94a0e 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/ReadOnlyBlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/ReadOnlyBlockTreeTests.cs @@ -7,57 +7,56 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +public class ReadOnlyBlockTreeTests { - public class ReadOnlyBlockTreeTests + private IBlockTree _innerBlockTree = null!; + private ReadOnlyBlockTree _blockTree = null!; + + [SetUp] + public void SetUp() { - private IBlockTree _innerBlockTree = null!; - private ReadOnlyBlockTree _blockTree = null!; + _innerBlockTree = Substitute.For(); + _blockTree = new ReadOnlyBlockTree(_innerBlockTree); + } - [SetUp] - public void SetUp() - { - _innerBlockTree = Substitute.For(); - _blockTree = new ReadOnlyBlockTree(_innerBlockTree); - } + [TestCase] + public void DeleteChainSlice_throws_when_endNumber_other_than_bestKnownNumber() + { + Action action = () => _blockTree.DeleteChainSlice(0, 10); + action.Should().Throw(); + } + + [MaxTime(Timeout.MaxTestTime)] + [TestCase(10, 20, 15, null, false, true, TestName = "No corrupted block.")] + [TestCase(10, 20, 15, 19, false, true, TestName = "Corrupted block too far.")] + [TestCase(10, 20, 5, 19, false, true, TestName = "Start before head.")] + [TestCase(0, 20, 5, 19, false, true, TestName = "Head genesis.")] + [TestCase(null, 20, 5, 19, false, true, TestName = "Head null.")] + [TestCase(10, 20, 15, 16, false, false, TestName = "Allow deletion.")] + + [TestCase(10, 20, 15, null, true, false, TestName = "Force - No corrupted block.")] + [TestCase(10, 20, 15, 19, true, false, TestName = "Force - Corrupted block too far.")] + [TestCase(10, 20, 5, 19, true, true, TestName = "Force - Start before head.")] + [TestCase(0, 20, 5, 19, true, true, TestName = "Force - Head genesis.")] + [TestCase(null, 20, 5, 19, true, true, TestName = "Force - Head null.")] + public void DeleteChainSlice_throws_when_corrupted_blocks_not_found(long? head, long bestKnown, long start, long? corruptedBlock, bool force, bool throws) + { + _innerBlockTree.Head.Returns(head is null ? null : Build.A.Block.WithHeader(Build.A.BlockHeader.WithNumber(head.Value).TestObject).TestObject); + _innerBlockTree.BestKnownNumber.Returns(bestKnown); + _innerBlockTree.FindHeader(Arg.Any(), Arg.Any()) + .Returns(c => c.Arg() == corruptedBlock ? null : Build.A.BlockHeader.WithNumber(c.Arg()).TestObject); - [TestCase] - public void DeleteChainSlice_throws_when_endNumber_other_than_bestKnownNumber() + Action action = () => _blockTree.DeleteChainSlice(start, force: force); + + if (throws) { - Action action = () => _blockTree.DeleteChainSlice(0, 10); action.Should().Throw(); } - - [Timeout(Timeout.MaxTestTime)] - [TestCase(10, 20, 15, null, false, true, TestName = "No corrupted block.")] - [TestCase(10, 20, 15, 19, false, true, TestName = "Corrupted block too far.")] - [TestCase(10, 20, 5, 19, false, true, TestName = "Start before head.")] - [TestCase(0, 20, 5, 19, false, true, TestName = "Head genesis.")] - [TestCase(null, 20, 5, 19, false, true, TestName = "Head null.")] - [TestCase(10, 20, 15, 16, false, false, TestName = "Allow deletion.")] - - [TestCase(10, 20, 15, null, true, false, TestName = "Force - No corrupted block.")] - [TestCase(10, 20, 15, 19, true, false, TestName = "Force - Corrupted block too far.")] - [TestCase(10, 20, 5, 19, true, true, TestName = "Force - Start before head.")] - [TestCase(0, 20, 5, 19, true, true, TestName = "Force - Head genesis.")] - [TestCase(null, 20, 5, 19, true, true, TestName = "Force - Head null.")] - public void DeleteChainSlice_throws_when_corrupted_blocks_not_found(long? head, long bestKnown, long start, long? corruptedBlock, bool force, bool throws) + else { - _innerBlockTree.Head.Returns(head is null ? null : Build.A.Block.WithHeader(Build.A.BlockHeader.WithNumber(head.Value).TestObject).TestObject); - _innerBlockTree.BestKnownNumber.Returns(bestKnown); - _innerBlockTree.FindHeader(Arg.Any(), Arg.Any()) - .Returns(c => c.Arg() == corruptedBlock ? null : Build.A.BlockHeader.WithNumber(c.Arg()).TestObject); - - Action action = () => _blockTree.DeleteChainSlice(start, force: force); - - if (throws) - { - action.Should().Throw(); - } - else - { - action.Should().NotThrow(); - } + action.Should().NotThrow(); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs index 5fc64104e58..b4e21bae898 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs @@ -16,453 +16,451 @@ using Nethermind.Core.Test.Builders; using Nethermind.Crypto; using Nethermind.Db; -using Nethermind.Logging; using Nethermind.Serialization.Rlp; using Nethermind.Specs; using NSubstitute; using NSubstitute.Core; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Receipts +namespace Nethermind.Blockchain.Test.Receipts; + + +[TestFixture(true)] +[TestFixture(false)] +public class PersistentReceiptStorageTests { + private TestMemColumnsDb _receiptsDb = null!; + private ReceiptsRecovery _receiptsRecovery = null!; + private IBlockTree _blockTree = null!; + private IBlockStore _blockStore = null!; + private readonly bool _useCompactReceipts; + private ReceiptConfig _receiptConfig = null!; + private PersistentReceiptStorage _storage = null!; + private ReceiptArrayStorageDecoder _decoder = null!; + + public PersistentReceiptStorageTests(bool useCompactReceipts) + { + _useCompactReceipts = useCompactReceipts; + } - [TestFixture(true)] - [TestFixture(false)] - public class PersistentReceiptStorageTests + [SetUp] + public void SetUp() { - private TestMemColumnsDb _receiptsDb = null!; - private ReceiptsRecovery _receiptsRecovery = null!; - private IBlockTree _blockTree = null!; - private IBlockStore _blockStore = null!; - private readonly bool _useCompactReceipts; - private ReceiptConfig _receiptConfig = null!; - private PersistentReceiptStorage _storage = null!; - private ReceiptArrayStorageDecoder _decoder = null!; - - public PersistentReceiptStorageTests(bool useCompactReceipts) - { - _useCompactReceipts = useCompactReceipts; - } + MainnetSpecProvider specProvider = MainnetSpecProvider.Instance; + EthereumEcdsa ethereumEcdsa = new(specProvider.ChainId); + _receiptConfig = new ReceiptConfig(); + _receiptsRecovery = new(ethereumEcdsa, specProvider); + _receiptsDb = new TestMemColumnsDb(); + _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks).Set(Keccak.Zero, Array.Empty()); + _blockTree = Substitute.For(); + _blockStore = Substitute.For(); + CreateStorage(); + } - [SetUp] - public void SetUp() - { - MainnetSpecProvider specProvider = MainnetSpecProvider.Instance; - EthereumEcdsa ethereumEcdsa = new(specProvider.ChainId); - _receiptConfig = new ReceiptConfig(); - _receiptsRecovery = new(ethereumEcdsa, specProvider); - _receiptsDb = new TestMemColumnsDb(); - _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks).Set(Keccak.Zero, Array.Empty()); - _blockTree = Substitute.For(); - _blockStore = Substitute.For(); - CreateStorage(); - } + [TearDown] + public void TearDown() + { + _receiptsDb.Dispose(); + } - [TearDown] - public void TearDown() - { - _receiptsDb.Dispose(); - } + private void CreateStorage() + { + _decoder = new ReceiptArrayStorageDecoder(_useCompactReceipts); + _storage = new PersistentReceiptStorage( + _receiptsDb, + MainnetSpecProvider.Instance, + _receiptsRecovery, + _blockTree, + _blockStore, + _receiptConfig, + _decoder + ) + { MigratedBlockNumber = 0 }; + } - private void CreateStorage() - { - _decoder = new ReceiptArrayStorageDecoder(_useCompactReceipts); - _storage = new PersistentReceiptStorage( - _receiptsDb, - MainnetSpecProvider.Instance, - _receiptsRecovery, - _blockTree, - _blockStore, - _receiptConfig, - _decoder - ) - { MigratedBlockNumber = 0 }; - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Returns_null_for_missing_tx() + { + Hash256 blockHash = _storage.FindBlockHash(Keccak.Zero); + blockHash.Should().BeNull(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Returns_null_for_missing_tx() - { - Hash256 blockHash = _storage.FindBlockHash(Keccak.Zero); - blockHash.Should().BeNull(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void ReceiptsIterator_doesnt_throw_on_empty_span() + { + _storage.TryGetReceiptsIterator(1, Keccak.Zero, out ReceiptsIterator iterator); + iterator.TryGetNext(out _).Should().BeFalse(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void ReceiptsIterator_doesnt_throw_on_empty_span() - { - _storage.TryGetReceiptsIterator(1, Keccak.Zero, out ReceiptsIterator iterator); - iterator.TryGetNext(out _).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void ReceiptsIterator_doesnt_throw_on_null() + { + _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks).Set(Keccak.Zero, null!); + _storage.TryGetReceiptsIterator(1, Keccak.Zero, out ReceiptsIterator iterator); + iterator.TryGetNext(out _).Should().BeFalse(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void ReceiptsIterator_doesnt_throw_on_null() - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks).Set(Keccak.Zero, null!); - _storage.TryGetReceiptsIterator(1, Keccak.Zero, out ReceiptsIterator iterator); - iterator.TryGetNext(out _).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Get_returns_empty_on_empty_span() + { + _storage.Get(Keccak.Zero).Should().BeEquivalentTo(Array.Empty()); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Get_returns_empty_on_empty_span() - { - _storage.Get(Keccak.Zero).Should().BeEquivalentTo(Array.Empty()); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Adds_and_retrieves_receipts_for_block() + { + var (block, receipts) = InsertBlock(); - [Test, Timeout(Timeout.MaxTestTime)] - public void Adds_and_retrieves_receipts_for_block() - { - var (block, receipts) = InsertBlock(); + _storage.Get(block).Should().BeEquivalentTo(receipts); + // second should be from cache + _storage.Get(block).Should().BeEquivalentTo(receipts); + } - _storage.Get(block).Should().BeEquivalentTo(receipts); - // second should be from cache - _storage.Get(block).Should().BeEquivalentTo(receipts); - } + [Test] + public void Adds_should_prefix_key_with_blockNumber() + { + (Block block, _) = InsertBlock(); - [Test] - public void Adds_should_prefix_key_with_blockNumber() - { - (Block block, _) = InsertBlock(); + Span blockNumPrefixed = stackalloc byte[40]; + block.Number.ToBigEndianByteArray().CopyTo(blockNumPrefixed); // TODO: We don't need to create an array here... + block.Hash!.Bytes.CopyTo(blockNumPrefixed[8..]); - Span blockNumPrefixed = stackalloc byte[40]; - block.Number.ToBigEndianByteArray().CopyTo(blockNumPrefixed); // TODO: We don't need to create an array here... - block.Hash!.Bytes.CopyTo(blockNumPrefixed[8..]); + _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks)[blockNumPrefixed].Should().NotBeNull(); + } - _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks)[blockNumPrefixed].Should().NotBeNull(); - } + [Test] + public void Adds_should_attempt_hash_key_first_if_inserted_with_hashkey() + { + (Block block, TxReceipt[] receipts) = PrepareBlock(); - [Test] - public void Adds_should_attempt_hash_key_first_if_inserted_with_hashkey() - { - (Block block, TxReceipt[] receipts) = PrepareBlock(); + using NettyRlpStream rlpStream = _decoder.EncodeToNewNettyStream(receipts, RlpBehaviors.Storage); + _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks)[block.Hash!.Bytes] = rlpStream.AsSpan().ToArray(); - using NettyRlpStream rlpStream = _decoder.EncodeToNewNettyStream(receipts, RlpBehaviors.Storage); - _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks)[block.Hash!.Bytes] = rlpStream.AsSpan().ToArray(); + CreateStorage(); + _storage.Get(block); - CreateStorage(); - _storage.Get(block); + Span blockNumPrefixed = stackalloc byte[40]; + block.Number.ToBigEndianByteArray().CopyTo(blockNumPrefixed); // TODO: We don't need to create an array here... + block.Hash!.Bytes.CopyTo(blockNumPrefixed[8..]); - Span blockNumPrefixed = stackalloc byte[40]; - block.Number.ToBigEndianByteArray().CopyTo(blockNumPrefixed); // TODO: We don't need to create an array here... - block.Hash!.Bytes.CopyTo(blockNumPrefixed[8..]); + TestMemDb blocksDb = (TestMemDb)_receiptsDb.GetColumnDb(ReceiptsColumns.Blocks); + blocksDb.KeyWasRead(blockNumPrefixed.ToArray(), times: 0); + blocksDb.KeyWasRead(block.Hash.BytesToArray(), times: 1); + } - TestMemDb blocksDb = (TestMemDb)_receiptsDb.GetColumnDb(ReceiptsColumns.Blocks); - blocksDb.KeyWasRead(blockNumPrefixed.ToArray(), times: 0); - blocksDb.KeyWasRead(block.Hash.BytesToArray(), times: 1); - } + [Test] + public void Should_be_able_to_get_block_with_hash_address() + { + (Block block, TxReceipt[] receipts) = PrepareBlock(); - [Test] - public void Should_be_able_to_get_block_with_hash_address() - { - (Block block, TxReceipt[] receipts) = PrepareBlock(); + Span blockNumPrefixed = stackalloc byte[40]; + block.Number.ToBigEndianByteArray().CopyTo(blockNumPrefixed); // TODO: We don't need to create an array here... + block.Hash!.Bytes.CopyTo(blockNumPrefixed[8..]); - Span blockNumPrefixed = stackalloc byte[40]; - block.Number.ToBigEndianByteArray().CopyTo(blockNumPrefixed); // TODO: We don't need to create an array here... - block.Hash!.Bytes.CopyTo(blockNumPrefixed[8..]); + using NettyRlpStream rlpStream = _decoder.EncodeToNewNettyStream(receipts, RlpBehaviors.Storage); + _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks)[block.Hash.Bytes] = rlpStream.AsSpan().ToArray(); - using NettyRlpStream rlpStream = _decoder.EncodeToNewNettyStream(receipts, RlpBehaviors.Storage); - _receiptsDb.GetColumnDb(ReceiptsColumns.Blocks)[block.Hash.Bytes] = rlpStream.AsSpan().ToArray(); + _storage.Get(block).Length.Should().Be(receipts.Length); + } - _storage.Get(block).Length.Should().Be(receipts.Length); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void Should_not_cache_empty_non_processed_blocks() + { + Block block = Build.A.Block + .WithTransactions(Build.A.Transaction.SignedAndResolved().TestObject) + .WithReceiptsRoot(TestItem.KeccakA) + .TestObject; + + TxReceipt[] emptyReceipts = Array.Empty(); + _storage.Get(block).Should().BeEquivalentTo(emptyReceipts); + // can be from cache: + _storage.Get(block).Should().BeEquivalentTo(emptyReceipts); + (_, TxReceipt[] receipts) = InsertBlock(block); + // before should not be cached + _storage.Get(block).Should().BeEquivalentTo(receipts); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Should_not_cache_empty_non_processed_blocks() - { - Block block = Build.A.Block - .WithTransactions(Build.A.Transaction.SignedAndResolved().TestObject) - .WithReceiptsRoot(TestItem.KeccakA) - .TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Adds_and_retrieves_receipts_for_block_with_iterator_from_cache_after_insert() + { + var (block, receipts) = InsertBlock(); - TxReceipt[] emptyReceipts = Array.Empty(); - _storage.Get(block).Should().BeEquivalentTo(emptyReceipts); - // can be from cache: - _storage.Get(block).Should().BeEquivalentTo(emptyReceipts); - (_, TxReceipt[] receipts) = InsertBlock(block); - // before should not be cached - _storage.Get(block).Should().BeEquivalentTo(receipts); - } + _storage.TryGetReceiptsIterator(0, block.Hash!, out ReceiptsIterator iterator).Should().BeTrue(); + iterator.TryGetNext(out TxReceiptStructRef receiptStructRef).Should().BeTrue(); + receiptStructRef.LogsRlp.ToArray().Should().BeEmpty(); + receiptStructRef.Logs.Should().BeEquivalentTo(receipts.First().Logs); + iterator.TryGetNext(out receiptStructRef).Should().BeFalse(); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Adds_and_retrieves_receipts_for_block_with_iterator_from_cache_after_insert() - { - var (block, receipts) = InsertBlock(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Adds_and_retrieves_receipts_for_block_with_iterator() + { + var (block, _) = InsertBlock(); - _storage.TryGetReceiptsIterator(0, block.Hash!, out ReceiptsIterator iterator).Should().BeTrue(); - iterator.TryGetNext(out TxReceiptStructRef receiptStructRef).Should().BeTrue(); - receiptStructRef.LogsRlp.ToArray().Should().BeEmpty(); - receiptStructRef.Logs.Should().BeEquivalentTo(receipts.First().Logs); - iterator.TryGetNext(out receiptStructRef).Should().BeFalse(); - } + _storage.ClearCache(); + _storage.TryGetReceiptsIterator(block.Number, block.Hash!, out ReceiptsIterator iterator).Should().BeTrue(); + iterator.TryGetNext(out TxReceiptStructRef receiptStructRef).Should().BeTrue(); + receiptStructRef.LogsRlp.ToArray().Should().NotBeEmpty(); + receiptStructRef.Logs.Should().BeNullOrEmpty(); - [Test, Timeout(Timeout.MaxTestTime)] - public void Adds_and_retrieves_receipts_for_block_with_iterator() - { - var (block, _) = InsertBlock(); + iterator.TryGetNext(out receiptStructRef).Should().BeFalse(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Adds_and_retrieves_receipts_for_block_with_iterator_from_cache_after_get() + { + var (block, receipts) = InsertBlock(); + + _storage.ClearCache(); + _storage.Get(block); + _storage.TryGetReceiptsIterator(0, block.Hash!, out ReceiptsIterator iterator).Should().BeTrue(); + iterator.TryGetNext(out TxReceiptStructRef receiptStructRef).Should().BeTrue(); + receiptStructRef.LogsRlp.ToArray().Should().BeEmpty(); + receiptStructRef.Logs.Should().BeEquivalentTo(receipts.First().Logs); + iterator.TryGetNext(out receiptStructRef).Should().BeFalse(); + } - _storage.ClearCache(); - _storage.TryGetReceiptsIterator(block.Number, block.Hash!, out ReceiptsIterator iterator).Should().BeTrue(); - iterator.TryGetNext(out TxReceiptStructRef receiptStructRef).Should().BeTrue(); - receiptStructRef.LogsRlp.ToArray().Should().NotBeEmpty(); - receiptStructRef.Logs.Should().BeNullOrEmpty(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Should_handle_inserting_null_receipts() + { + Block block = Build.A.Block.WithReceiptsRoot(TestItem.KeccakA).TestObject; + _storage.Insert(block, null); + } - iterator.TryGetNext(out receiptStructRef).Should().BeFalse(); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void HasBlock_should_returnFalseForMissingHash() + { + _storage.HasBlock(0, Keccak.Compute("missing-value")).Should().BeFalse(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void HasBlock_should_returnTrueForKnownHash() + { + var (block, _) = InsertBlock(); + _storage.HasBlock(block.Number, block.Hash!).Should().BeTrue(); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void EnsureCanonical_should_change_tx_blockhash( + [Values(false, true)] bool ensureCanonical, + [Values(false, true)] bool isFinalized) + { + (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: isFinalized); + _storage.FindBlockHash(receipts[0].TxHash!).Should().Be(block.Hash!); - [Test, Timeout(Timeout.MaxTestTime)] - public void Adds_and_retrieves_receipts_for_block_with_iterator_from_cache_after_get() + Block anotherBlock = Build.A.Block + .WithTransactions(block.Transactions) + .WithReceiptsRoot(TestItem.KeccakA) + .WithExtraData(new byte[] { 1 }) + .TestObject; + + anotherBlock.Hash.Should().NotBe(block.Hash!); + _storage.Insert(anotherBlock, new[] { Build.A.Receipt.TestObject }, ensureCanonical); + _blockTree.FindBlockHash(anotherBlock.Number).Returns(anotherBlock.Hash); + + Hash256 findBlockHash = _storage.FindBlockHash(receipts[0].TxHash!); + if (ensureCanonical) { - var (block, receipts) = InsertBlock(); - - _storage.ClearCache(); - _storage.Get(block); - _storage.TryGetReceiptsIterator(0, block.Hash!, out ReceiptsIterator iterator).Should().BeTrue(); - iterator.TryGetNext(out TxReceiptStructRef receiptStructRef).Should().BeTrue(); - receiptStructRef.LogsRlp.ToArray().Should().BeEmpty(); - receiptStructRef.Logs.Should().BeEquivalentTo(receipts.First().Logs); - iterator.TryGetNext(out receiptStructRef).Should().BeFalse(); + findBlockHash.Should().Be(anotherBlock.Hash!); } - - [Test, Timeout(Timeout.MaxTestTime)] - public void Should_handle_inserting_null_receipts() + else { - Block block = Build.A.Block.WithReceiptsRoot(TestItem.KeccakA).TestObject; - _storage.Insert(block, null); + findBlockHash.Should().NotBe(anotherBlock.Hash!); } + } - [Test, Timeout(Timeout.MaxTestTime)] - public void HasBlock_should_returnFalseForMissingHash() + [Test] + public void EnsureCanonical_should_use_blockNumber_if_finalized() + { + (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true); + Span txHashBytes = receipts[0].TxHash!.Bytes; + if (_receiptConfig.CompactTxIndex) { - _storage.HasBlock(0, Keccak.Compute("missing-value")).Should().BeFalse(); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); } - - [Test, Timeout(Timeout.MaxTestTime)] - public void HasBlock_should_returnTrueForKnownHash() + else { - var (block, _) = InsertBlock(); - _storage.HasBlock(block.Number, block.Hash!).Should().BeTrue(); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().NotBeNull(); } + } - [Test, Timeout(Timeout.MaxTestTime)] - public void EnsureCanonical_should_change_tx_blockhash( - [Values(false, true)] bool ensureCanonical, - [Values(false, true)] bool isFinalized) - { - (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: isFinalized); - _storage.FindBlockHash(receipts[0].TxHash!).Should().Be(block.Hash!); + [Test] + public void When_TxLookupLimitIs_NegativeOne_DoNotIndexTxHash() + { + _receiptConfig.TxLookupLimit = -1; + CreateStorage(); + (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block)); + Thread.Sleep(100); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeNull(); + } - Block anotherBlock = Build.A.Block - .WithTransactions(block.Transactions) - .WithReceiptsRoot(TestItem.KeccakA) - .WithExtraData(new byte[] { 1 }) - .TestObject; + [TestCase(1L, false)] + [TestCase(10L, false)] + [TestCase(11L, true)] + public void Should_only_prune_index_tx_hashes_if_blockNumber_is_bigger_than_lookupLimit(long blockNumber, bool WillPruneOldIndicies) + { + _receiptConfig.TxLookupLimit = 10; + CreateStorage(); + _blockTree.BlockAddedToMain += + Raise.EventWith(new BlockReplacementEventArgs(Build.A.Block.WithNumber(blockNumber).TestObject)); + Thread.Sleep(100); + IEnumerable calls = _blockTree.ReceivedCalls() + .Where(call => call.GetMethodInfo().Name.EndsWith(nameof(_blockTree.FindBlock))); + if (WillPruneOldIndicies) + calls.Should().NotBeEmpty(); + else + calls.Should().BeEmpty(); + } - anotherBlock.Hash.Should().NotBe(block.Hash!); - _storage.Insert(anotherBlock, new[] { Build.A.Receipt.TestObject }, ensureCanonical); - _blockTree.FindBlockHash(anotherBlock.Number).Returns(anotherBlock.Hash); - - Hash256 findBlockHash = _storage.FindBlockHash(receipts[0].TxHash!); - if (ensureCanonical) - { - findBlockHash.Should().Be(anotherBlock.Hash!); - } - else - { - findBlockHash.Should().NotBe(anotherBlock.Hash!); - } - } + [Test] + public void When_HeadBlockIsFarAhead_DoNotIndexTxHash() + { + _receiptConfig.TxLookupLimit = 1000; + CreateStorage(); + (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true, headNumber: 1001); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block)); + Thread.Sleep(100); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeNull(); + } + + [Test] + public void When_NewHeadBlock_Remove_TxIndex_OfRemovedBlock() + { + CreateStorage(); + (Block block, TxReceipt[] receipts) = InsertBlock(); - [Test] - public void EnsureCanonical_should_use_blockNumber_if_finalized() + if (_receiptConfig.CompactTxIndex) { - (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true); - Span txHashBytes = receipts[0].TxHash!.Bytes; - if (_receiptConfig.CompactTxIndex) - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); - } - else - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().NotBeNull(); - } + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); } - - [Test] - public void When_TxLookupLimitIs_NegativeOne_DoNotIndexTxHash() + else { - _receiptConfig.TxLookupLimit = -1; - CreateStorage(); - (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block)); - Thread.Sleep(100); - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeNull(); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().NotBeNull(); } - [TestCase(1L, false)] - [TestCase(10L, false)] - [TestCase(11L, true)] - public void Should_only_prune_index_tx_hashes_if_blockNumber_is_bigger_than_lookupLimit(long blockNumber, bool WillPruneOldIndicies) + Block newHead = Build.A.Block.WithNumber(1).TestObject; + _blockTree.FindBestSuggestedHeader().Returns(newHead.Header); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(newHead, block)); + + Assert.That( + () => _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes], + Is.Null.After(1000, 100) + ); + } + + [Test] + public async Task When_NewHeadBlock_Remove_TxIndex_OfRemovedBlock_Unless_ItsAlsoInNewBlock() + { + _receiptConfig.CompactTxIndex = _useCompactReceipts; + CreateStorage(); + (Block block, TxReceipt[] receipts) = InsertBlock(); + Block block2 = Build.A.Block + .WithParent(block) + .WithNumber(2) + .WithTransactions(Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyC).TestObject) + .TestObject; + _blockTree.FindBestSuggestedHeader().Returns(block2.Header); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block2)); + + if (_receiptConfig.CompactTxIndex) { - _receiptConfig.TxLookupLimit = 10; - CreateStorage(); - _blockTree.BlockAddedToMain += - Raise.EventWith(new BlockReplacementEventArgs(Build.A.Block.WithNumber(blockNumber).TestObject)); - Thread.Sleep(100); - IEnumerable calls = _blockTree.ReceivedCalls() - .Where(call => call.GetMethodInfo().Name.EndsWith(nameof(_blockTree.FindBlock))); - if (WillPruneOldIndicies) - calls.Should().NotBeEmpty(); - else - calls.Should().BeEmpty(); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); } - - [Test] - public void When_HeadBlockIsFarAhead_DoNotIndexTxHash() + else { - _receiptConfig.TxLookupLimit = 1000; - CreateStorage(); - (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true, headNumber: 1001); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block)); - Thread.Sleep(100); - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeNull(); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(block.Hash!.Bytes.ToArray()); } - [Test] - public void When_NewHeadBlock_Remove_TxIndex_OfRemovedBlock() + Block block3 = Build.A.Block + .WithNumber(1) + .WithTransactions(block2.Transactions) + .WithExtraData(new byte[1]) + .TestObject; + Block block4 = Build.A.Block + .WithNumber(2) + .WithTransactions(block.Transactions) + .WithExtraData(new byte[1]) + .TestObject; + _blockTree.FindBestSuggestedHeader().Returns(block4.Header); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block3, block)); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block4, block2)); + + await Task.Delay(100); + if (_receiptConfig.CompactTxIndex) { - CreateStorage(); - (Block block, TxReceipt[] receipts) = InsertBlock(); - - if (_receiptConfig.CompactTxIndex) - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); - } - else - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().NotBeNull(); - } - - Block newHead = Build.A.Block.WithNumber(1).TestObject; - _blockTree.FindBestSuggestedHeader().Returns(newHead.Header); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(newHead, block)); - - Assert.That( - () => _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes], - Is.Null.After(1000, 100) - ); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block4.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block4.Number).Bytes); } - - [Test] - public async Task When_NewHeadBlock_Remove_TxIndex_OfRemovedBlock_Unless_ItsAlsoInNewBlock() + else { - _receiptConfig.CompactTxIndex = _useCompactReceipts; - CreateStorage(); - (Block block, TxReceipt[] receipts) = InsertBlock(); - Block block2 = Build.A.Block - .WithParent(block) - .WithNumber(2) - .WithTransactions(Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyC).TestObject) - .TestObject; - _blockTree.FindBestSuggestedHeader().Returns(block2.Header); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block2)); - - if (_receiptConfig.CompactTxIndex) - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); - } - else - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(block.Hash!.Bytes.ToArray()); - } - - Block block3 = Build.A.Block - .WithNumber(1) - .WithTransactions(block2.Transactions) - .WithExtraData(new byte[1]) - .TestObject; - Block block4 = Build.A.Block - .WithNumber(2) - .WithTransactions(block.Transactions) - .WithExtraData(new byte[1]) - .TestObject; - _blockTree.FindBestSuggestedHeader().Returns(block4.Header); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block3, block)); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block4, block2)); - - await Task.Delay(100); - if (_receiptConfig.CompactTxIndex) - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block4.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block4.Number).Bytes); - } - else - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block4.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(block4.Hash!.Bytes.ToArray()); - } + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block4.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(block4.Hash!.Bytes.ToArray()); } + } - [Test] - public void When_NewHeadBlock_ClearOldTxIndex() + [Test] + public void When_NewHeadBlock_ClearOldTxIndex() + { + _receiptConfig.TxLookupLimit = 1000; + CreateStorage(); + (Block block, TxReceipt[] receipts) = InsertBlock(); + + Span txHashBytes = receipts[0].TxHash!.Bytes; + if (_receiptConfig.CompactTxIndex) + { + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); + } + else { - _receiptConfig.TxLookupLimit = 1000; - CreateStorage(); - (Block block, TxReceipt[] receipts) = InsertBlock(); - - Span txHashBytes = receipts[0].TxHash!.Bytes; - if (_receiptConfig.CompactTxIndex) - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); - } - else - { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().NotBeNull(); - } - - Block newHead = Build.A.Block.WithNumber(_receiptConfig.TxLookupLimit.Value + 1).TestObject; - _blockTree.FindBestSuggestedHeader().Returns(newHead.Header); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(newHead)); - - Assert.That( - () => _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes], - Is.Null.After(1000, 100) - ); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[txHashBytes].Should().NotBeNull(); } - private (Block block, TxReceipt[] receipts) PrepareBlock(Block? block = null, bool isFinalized = false, long? headNumber = null) + Block newHead = Build.A.Block.WithNumber(_receiptConfig.TxLookupLimit.Value + 1).TestObject; + _blockTree.FindBestSuggestedHeader().Returns(newHead.Header); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(newHead)); + + Assert.That( + () => _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes], + Is.Null.After(1000, 100) + ); + } + + private (Block block, TxReceipt[] receipts) PrepareBlock(Block? block = null, bool isFinalized = false, long? headNumber = null) + { + block ??= Build.A.Block + .WithNumber(1) + .WithTransactions(Build.A.Transaction.SignedAndResolved().TestObject) + .WithReceiptsRoot(TestItem.KeccakA) + .TestObject; + + _blockTree.FindBlock(block.Hash!).Returns(block); + _blockTree.FindBlock(block.Number).Returns(block); + _blockTree.FindHeader(block.Number).Returns(block.Header); + _blockTree.FindBlockHash(block.Number).Returns(block.Hash); + if (isFinalized) { - block ??= Build.A.Block - .WithNumber(1) - .WithTransactions(Build.A.Transaction.SignedAndResolved().TestObject) - .WithReceiptsRoot(TestItem.KeccakA) + BlockHeader farHead = Build.A.BlockHeader + .WithNumber(Reorganization.MaxDepth + 5) .TestObject; - - _blockTree.FindBlock(block.Hash!).Returns(block); - _blockTree.FindBlock(block.Number).Returns(block); - _blockTree.FindHeader(block.Number).Returns(block.Header); - _blockTree.FindBlockHash(block.Number).Returns(block.Hash); - if (isFinalized) - { - BlockHeader farHead = Build.A.BlockHeader - .WithNumber(Reorganization.MaxDepth + 5) - .TestObject; - _blockTree.FindBestSuggestedHeader().Returns(farHead); - } - - if (headNumber is not null) - { - BlockHeader farHead = Build.A.BlockHeader - .WithNumber(headNumber.Value) - .TestObject; - _blockTree.FindBestSuggestedHeader().Returns(farHead); - } - TxReceipt[] receipts = { Build.A.Receipt.WithCalculatedBloom().TestObject }; - return (block, receipts); + _blockTree.FindBestSuggestedHeader().Returns(farHead); } - private (Block block, TxReceipt[] receipts) InsertBlock(Block? block = null, bool isFinalized = false, long? headNumber = null) + if (headNumber is not null) { - (block, TxReceipt[] receipts) = PrepareBlock(block, isFinalized, headNumber); - _storage.Insert(block, receipts); - _receiptsRecovery.TryRecover(new ReceiptRecoveryBlock(block), receipts); - - return (block, receipts); + BlockHeader farHead = Build.A.BlockHeader + .WithNumber(headNumber.Value) + .TestObject; + _blockTree.FindBestSuggestedHeader().Returns(farHead); } + TxReceipt[] receipts = { Build.A.Receipt.WithCalculatedBloom().TestObject }; + return (block, receipts); + } + + private (Block block, TxReceipt[] receipts) InsertBlock(Block? block = null, bool isFinalized = false, long? headNumber = null) + { + (block, TxReceipt[] receipts) = PrepareBlock(block, isFinalized, headNumber); + _storage.Insert(block, receipts); + _receiptsRecovery.TryRecover(new ReceiptRecoveryBlock(block), receipts); + + return (block, receipts); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsRecoveryTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsRecoveryTests.cs index 6d72e44f4f9..7cd1b0ec129 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsRecoveryTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsRecoveryTests.cs @@ -6,7 +6,6 @@ using Nethermind.Core; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; -using Nethermind.Logging; using Nethermind.Specs; using NUnit.Framework; @@ -25,7 +24,7 @@ public void Setup() _receiptsRecovery = new ReceiptsRecovery(ethereumEcdsa, specProvider); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(5, 5, true, ReceiptsRecoveryResult.NeedReinsert)] [TestCase(5, 5, false, ReceiptsRecoveryResult.Skipped)] [TestCase(0, 0, true, ReceiptsRecoveryResult.Skipped)] diff --git a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs index d8feb71c460..840c63e6f9f 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs @@ -26,7 +26,6 @@ namespace Nethermind.Blockchain.Test; -[TestFixture] public class ReorgTests { private BlockchainProcessor _blockchainProcessor = null!; @@ -97,7 +96,7 @@ public void Setup() [OneTimeTearDown] public void TearDown() => _blockchainProcessor?.Dispose(); - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] [Retry(3)] public void Test() { diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Rewards/NoBlockRewardsTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Rewards/NoBlockRewardsTests.cs index ce38a2ce14a..1dc26401128 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Rewards/NoBlockRewardsTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Rewards/NoBlockRewardsTests.cs @@ -6,17 +6,16 @@ using Nethermind.Core.Test.Builders; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Rewards +namespace Nethermind.Blockchain.Test.Rewards; + +public class NoBlockRewardsTests { - public class NoBlockRewardsTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void No_rewards() { - [Test, Timeout(Timeout.MaxTestTime)] - public void No_rewards() - { - Block block = Build.A.Block.WithNumber(10).WithUncles(Build.A.Block.WithNumber(9).TestObject).TestObject; - NoBlockRewards calculator = NoBlockRewards.Instance; - var rewards = calculator.CalculateRewards(block); - Assert.IsEmpty(rewards); - } + Block block = Build.A.Block.WithNumber(10).WithUncles(Build.A.Block.WithNumber(9).TestObject).TestObject; + NoBlockRewards calculator = NoBlockRewards.Instance; + var rewards = calculator.CalculateRewards(block); + Assert.That(rewards, Is.Empty); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Rewards/RewardCalculatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Rewards/RewardCalculatorTests.cs index 041676676af..d4225963be5 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Rewards/RewardCalculatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Rewards/RewardCalculatorTests.cs @@ -7,84 +7,83 @@ using Nethermind.Specs; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Rewards +namespace Nethermind.Blockchain.Test.Rewards; + +public class RewardCalculatorTests { - public class RewardCalculatorTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void Two_uncles_from_the_same_coinbase() + { + Block uncle = Build.A.Block.WithNumber(1).TestObject; + Block uncle2 = Build.A.Block.WithNumber(1).TestObject; + Block block = Build.A.Block.WithNumber(3).WithUncles(uncle, uncle2).TestObject; + + RewardCalculator calculator = new(MainnetSpecProvider.Instance); + BlockReward[] rewards = calculator.CalculateRewards(block); + + Assert.That(rewards.Length, Is.EqualTo(3)); + Assert.That((long)rewards[0].Value, Is.EqualTo(5312500000000000000), "miner"); + Assert.That((long)rewards[1].Value, Is.EqualTo(3750000000000000000), "uncle1"); + Assert.That((long)rewards[2].Value, Is.EqualTo(3750000000000000000), "uncle2"); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void One_uncle() + { + Block uncle = Build.A.Block.WithNumber(1).TestObject; + Block block = Build.A.Block.WithNumber(3).WithUncles(uncle).TestObject; + + RewardCalculator calculator = new(MainnetSpecProvider.Instance); + BlockReward[] rewards = calculator.CalculateRewards(block); + + Assert.That(rewards.Length, Is.EqualTo(2)); + Assert.That((long)rewards[0].Value, Is.EqualTo(5156250000000000000), "miner"); + Assert.That((long)rewards[1].Value, Is.EqualTo(3750000000000000000), "uncle1"); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void No_uncles() + { + Block block = Build.A.Block.WithNumber(3).TestObject; + + RewardCalculator calculator = new(MainnetSpecProvider.Instance); + BlockReward[] rewards = calculator.CalculateRewards(block); + + Assert.That(rewards.Length, Is.EqualTo(1)); + Assert.That((long)rewards[0].Value, Is.EqualTo(5000000000000000000), "miner"); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Byzantium_reward_two_uncles() + { + long blockNumber = MainnetSpecProvider.ByzantiumBlockNumber; + Block uncle = Build.A.Block.WithNumber(blockNumber - 2).TestObject; + Block uncle2 = Build.A.Block.WithNumber(blockNumber - 2).TestObject; + Block block = Build.A.Block.WithNumber(blockNumber).WithUncles(uncle, uncle2).TestObject; + + RewardCalculator calculator = new(MainnetSpecProvider.Instance); + BlockReward[] rewards = calculator.CalculateRewards(block); + + Assert.That(rewards.Length, Is.EqualTo(3)); + Assert.That((long)rewards[0].Value, Is.EqualTo(3187500000000000000), "miner"); + Assert.That((long)rewards[1].Value, Is.EqualTo(2250000000000000000), "uncle1"); + Assert.That((long)rewards[2].Value, Is.EqualTo(2250000000000000000), "uncle2"); + } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void Constantinople_reward_two_uncles() { - [Test, Timeout(Timeout.MaxTestTime)] - public void Two_uncles_from_the_same_coinbase() - { - Block uncle = Build.A.Block.WithNumber(1).TestObject; - Block uncle2 = Build.A.Block.WithNumber(1).TestObject; - Block block = Build.A.Block.WithNumber(3).WithUncles(uncle, uncle2).TestObject; - - RewardCalculator calculator = new(MainnetSpecProvider.Instance); - BlockReward[] rewards = calculator.CalculateRewards(block); - - Assert.That(rewards.Length, Is.EqualTo(3)); - Assert.That((long)rewards[0].Value, Is.EqualTo(5312500000000000000), "miner"); - Assert.That((long)rewards[1].Value, Is.EqualTo(3750000000000000000), "uncle1"); - Assert.That((long)rewards[2].Value, Is.EqualTo(3750000000000000000), "uncle2"); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void One_uncle() - { - Block uncle = Build.A.Block.WithNumber(1).TestObject; - Block block = Build.A.Block.WithNumber(3).WithUncles(uncle).TestObject; - - RewardCalculator calculator = new(MainnetSpecProvider.Instance); - BlockReward[] rewards = calculator.CalculateRewards(block); - - Assert.That(rewards.Length, Is.EqualTo(2)); - Assert.That((long)rewards[0].Value, Is.EqualTo(5156250000000000000), "miner"); - Assert.That((long)rewards[1].Value, Is.EqualTo(3750000000000000000), "uncle1"); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void No_uncles() - { - Block block = Build.A.Block.WithNumber(3).TestObject; - - RewardCalculator calculator = new(MainnetSpecProvider.Instance); - BlockReward[] rewards = calculator.CalculateRewards(block); - - Assert.That(rewards.Length, Is.EqualTo(1)); - Assert.That((long)rewards[0].Value, Is.EqualTo(5000000000000000000), "miner"); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void Byzantium_reward_two_uncles() - { - long blockNumber = MainnetSpecProvider.ByzantiumBlockNumber; - Block uncle = Build.A.Block.WithNumber(blockNumber - 2).TestObject; - Block uncle2 = Build.A.Block.WithNumber(blockNumber - 2).TestObject; - Block block = Build.A.Block.WithNumber(blockNumber).WithUncles(uncle, uncle2).TestObject; - - RewardCalculator calculator = new(MainnetSpecProvider.Instance); - BlockReward[] rewards = calculator.CalculateRewards(block); - - Assert.That(rewards.Length, Is.EqualTo(3)); - Assert.That((long)rewards[0].Value, Is.EqualTo(3187500000000000000), "miner"); - Assert.That((long)rewards[1].Value, Is.EqualTo(2250000000000000000), "uncle1"); - Assert.That((long)rewards[2].Value, Is.EqualTo(2250000000000000000), "uncle2"); - } - - [Test, Timeout(Timeout.MaxTestTime)] - public void Constantinople_reward_two_uncles() - { - long blockNumber = MainnetSpecProvider.ConstantinopleFixBlockNumber; - Block uncle = Build.A.Block.WithNumber(blockNumber - 2).TestObject; - Block uncle2 = Build.A.Block.WithNumber(blockNumber - 2).TestObject; - Block block = Build.A.Block.WithNumber(blockNumber).WithUncles(uncle, uncle2).TestObject; - - RewardCalculator calculator = new(MainnetSpecProvider.Instance); - BlockReward[] rewards = calculator.CalculateRewards(block); - - Assert.That(rewards.Length, Is.EqualTo(3)); - Assert.That((long)rewards[0].Value, Is.EqualTo(2125000000000000000), "miner"); - Assert.That((long)rewards[1].Value, Is.EqualTo(1500000000000000000), "uncle1"); - Assert.That((long)rewards[2].Value, Is.EqualTo(1500000000000000000), "uncle2"); - } + long blockNumber = MainnetSpecProvider.ConstantinopleFixBlockNumber; + Block uncle = Build.A.Block.WithNumber(blockNumber - 2).TestObject; + Block uncle2 = Build.A.Block.WithNumber(blockNumber - 2).TestObject; + Block block = Build.A.Block.WithNumber(blockNumber).WithUncles(uncle, uncle2).TestObject; + + RewardCalculator calculator = new(MainnetSpecProvider.Instance); + BlockReward[] rewards = calculator.CalculateRewards(block); + + Assert.That(rewards.Length, Is.EqualTo(3)); + Assert.That((long)rewards[0].Value, Is.EqualTo(2125000000000000000), "miner"); + Assert.That((long)rewards[1].Value, Is.EqualTo(1500000000000000000), "uncle1"); + Assert.That((long)rewards[2].Value, Is.EqualTo(1500000000000000000), "uncle2"); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs index e9c3ecc2280..aee9e3a4df5 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs @@ -7,54 +7,53 @@ using Nethermind.Specs.ChainSpecStyle; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Services +namespace Nethermind.Blockchain.Test.Services; + +public class HealthHintServiceTests { - public class HealthHintServiceTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void GetBlockProcessorAndProducerIntervalHint_returns_expected_result( + [ValueSource(nameof(BlockProcessorIntervalHintTestCases))] + BlockProcessorIntervalHint test) { - [Test, Timeout(Timeout.MaxTestTime)] - public void GetBlockProcessorAndProducerIntervalHint_returns_expected_result( - [ValueSource(nameof(BlockProcessorIntervalHintTestCases))] - BlockProcessorIntervalHint test) - { - IHealthHintService healthHintService = new HealthHintService(test.ChainSpec); - ulong? actualProcessing = healthHintService.MaxSecondsIntervalForProcessingBlocksHint(); - ulong? actualProducing = healthHintService.MaxSecondsIntervalForProducingBlocksHint(); - Assert.That(actualProcessing, Is.EqualTo(test.ExpectedProcessingHint)); - Assert.That(actualProducing, Is.EqualTo(test.ExpectedProducingHint)); - } + IHealthHintService healthHintService = new HealthHintService(test.ChainSpec); + ulong? actualProcessing = healthHintService.MaxSecondsIntervalForProcessingBlocksHint(); + ulong? actualProducing = healthHintService.MaxSecondsIntervalForProducingBlocksHint(); + Assert.That(actualProcessing, Is.EqualTo(test.ExpectedProcessingHint)); + Assert.That(actualProducing, Is.EqualTo(test.ExpectedProducingHint)); + } - public class BlockProcessorIntervalHint - { - public required ChainSpec ChainSpec { get; init; } - public ulong? ExpectedProcessingHint { get; init; } - public ulong? ExpectedProducingHint { get => null; } + public class BlockProcessorIntervalHint + { + public required ChainSpec ChainSpec { get; init; } + public ulong? ExpectedProcessingHint { get; init; } + public ulong? ExpectedProducingHint { get => null; } - public override string ToString() => - $"SealEngineType: {ChainSpec.SealEngineType}, ExpectedProcessingHint: {ExpectedProcessingHint}, ExpectedProducingHint: {ExpectedProducingHint}"; - } + public override string ToString() => + $"SealEngineType: {ChainSpec.SealEngineType}, ExpectedProcessingHint: {ExpectedProcessingHint}, ExpectedProducingHint: {ExpectedProducingHint}"; + } - public static IEnumerable BlockProcessorIntervalHintTestCases + public static IEnumerable BlockProcessorIntervalHintTestCases + { + get { - get + yield return new BlockProcessorIntervalHint + { + ChainSpec = new ChainSpec { SealEngineType = SealEngineType.NethDev, } + }; + yield return new BlockProcessorIntervalHint + { + ChainSpec = new ChainSpec { SealEngineType = SealEngineType.Ethash }, + ExpectedProcessingHint = 180 + }; + yield return new BlockProcessorIntervalHint + { + ChainSpec = new ChainSpec { SealEngineType = "Interval" } + }; + yield return new BlockProcessorIntervalHint { - yield return new BlockProcessorIntervalHint - { - ChainSpec = new ChainSpec { SealEngineType = SealEngineType.NethDev, } - }; - yield return new BlockProcessorIntervalHint - { - ChainSpec = new ChainSpec { SealEngineType = SealEngineType.Ethash }, - ExpectedProcessingHint = 180 - }; - yield return new BlockProcessorIntervalHint - { - ChainSpec = new ChainSpec { SealEngineType = "Interval" } - }; - yield return new BlockProcessorIntervalHint - { - ChainSpec = new ChainSpec { SealEngineType = SealEngineType.None } - }; - } + ChainSpec = new ChainSpec { SealEngineType = SealEngineType.None } + }; } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs index ca342190624..f247ffb1e15 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs @@ -5,7 +5,6 @@ using Nethermind.Consensus; using Nethermind.Consensus.Comparers; using Nethermind.Core; -using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Int256; @@ -13,189 +12,188 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test +namespace Nethermind.Blockchain.Test; + +public class TransactionComparisonTests { - public class TransactionComparisonTests + [MaxTime(Timeout.MaxTestTime)] + [TestCase(10, 10, 0)] + [TestCase(15, 10, -1)] + [TestCase(2, 3, 1)] + public void GasPriceComparer_for_legacy_transactions(int gasPriceX, int gasPriceY, int expectedResult) { - [Timeout(Timeout.MaxTestTime)] - [TestCase(10, 10, 0)] - [TestCase(15, 10, -1)] - [TestCase(2, 3, 1)] - public void GasPriceComparer_for_legacy_transactions(int gasPriceX, int gasPriceY, int expectedResult) - { - TestingContext context = new(); - IComparer comparer = context.DefaultComparer; - AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); - } + TestingContext context = new(); + IComparer comparer = context.DefaultComparer; + AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); + } - [Timeout(Timeout.MaxTestTime)] - [TestCase(10, 10, 0)] - [TestCase(15, 10, -1)] - [TestCase(2, 3, 1)] - public void ProducerGasPriceComparer_for_legacy_transactions(int gasPriceX, int gasPriceY, int expectedResult) - { - TestingContext context = new(); - IComparer comparer = context.GetProducerComparer(new BlockPreparationContext(0, 0)); - AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); - } + [MaxTime(Timeout.MaxTestTime)] + [TestCase(10, 10, 0)] + [TestCase(15, 10, -1)] + [TestCase(2, 3, 1)] + public void ProducerGasPriceComparer_for_legacy_transactions(int gasPriceX, int gasPriceY, int expectedResult) + { + TestingContext context = new(); + IComparer comparer = context.GetProducerComparer(new BlockPreparationContext(0, 0)); + AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); + } - [Timeout(Timeout.MaxTestTime)] - // head block number before eip 1559 transition - [TestCase(10, 10, 0, 0, 0)] - [TestCase(15, 10, 10, 1, -1)] - [TestCase(2, 3, 20, 0, 1)] - // head block number after eip 1559 transition - [TestCase(10, 10, 16, 5, 0)] - [TestCase(15, 10, 11, 6, -1)] - [TestCase(2, 3, 33, 7, 1)] - public void GasPriceComparer_for_legacy_transactions_1559(int gasPriceX, int gasPriceY, int headBaseFee, long headBlockNumber, int expectedResult) - { - long eip1559Transition = 5; - TestingContext context = new TestingContext(true, eip1559Transition) - .WithHeadBaseFeeNumber((UInt256)headBaseFee) - .WithHeadBlockNumber(headBlockNumber); - IComparer comparer = context.DefaultComparer; - AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); - } + [MaxTime(Timeout.MaxTestTime)] + // head block number before eip 1559 transition + [TestCase(10, 10, 0, 0, 0)] + [TestCase(15, 10, 10, 1, -1)] + [TestCase(2, 3, 20, 0, 1)] + // head block number after eip 1559 transition + [TestCase(10, 10, 16, 5, 0)] + [TestCase(15, 10, 11, 6, -1)] + [TestCase(2, 3, 33, 7, 1)] + public void GasPriceComparer_for_legacy_transactions_1559(int gasPriceX, int gasPriceY, int headBaseFee, long headBlockNumber, int expectedResult) + { + long eip1559Transition = 5; + TestingContext context = new TestingContext(true, eip1559Transition) + .WithHeadBaseFeeNumber((UInt256)headBaseFee) + .WithHeadBlockNumber(headBlockNumber); + IComparer comparer = context.DefaultComparer; + AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); + } - [Timeout(Timeout.MaxTestTime)] - // head block number before eip 1559 transition - [TestCase(10, 10, 0, 0, 0)] - [TestCase(15, 10, 10, 1, -1)] - [TestCase(2, 3, 20, 0, 1)] - // head block number after eip 1559 transition - [TestCase(10, 10, 16, 5, 0)] - [TestCase(15, 10, 11, 6, -1)] - [TestCase(2, 3, 33, 7, 1)] - public void ProducerGasPriceComparer_for_legacy_transactions_1559(int gasPriceX, int gasPriceY, int headBaseFee, long headBlockNumber, int expectedResult) - { - long eip1559Transition = 5; - TestingContext context = new(true, eip1559Transition); - IComparer comparer = context.GetProducerComparer(new BlockPreparationContext(0, 0)); - AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); - } + [MaxTime(Timeout.MaxTestTime)] + // head block number before eip 1559 transition + [TestCase(10, 10, 0, 0, 0)] + [TestCase(15, 10, 10, 1, -1)] + [TestCase(2, 3, 20, 0, 1)] + // head block number after eip 1559 transition + [TestCase(10, 10, 16, 5, 0)] + [TestCase(15, 10, 11, 6, -1)] + [TestCase(2, 3, 33, 7, 1)] + public void ProducerGasPriceComparer_for_legacy_transactions_1559(int gasPriceX, int gasPriceY, int headBaseFee, long headBlockNumber, int expectedResult) + { + long eip1559Transition = 5; + TestingContext context = new(true, eip1559Transition); + IComparer comparer = context.GetProducerComparer(new BlockPreparationContext(0, 0)); + AssertLegacyTransactions(comparer, gasPriceX, gasPriceY, expectedResult); + } - private void AssertLegacyTransactions(IComparer comparer, int gasPriceX, int gasPriceY, int expectedResult) - { - Transaction x = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) - .WithGasPrice((UInt256)gasPriceX).TestObject; - Transaction y = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) - .WithGasPrice((UInt256)gasPriceY).TestObject; - int result = comparer.Compare(x, y); - Assert.That(result, Is.EqualTo(expectedResult)); - } + private void AssertLegacyTransactions(IComparer comparer, int gasPriceX, int gasPriceY, int expectedResult) + { + Transaction x = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) + .WithGasPrice((UInt256)gasPriceX).TestObject; + Transaction y = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) + .WithGasPrice((UInt256)gasPriceY).TestObject; + int result = comparer.Compare(x, y); + Assert.That(result, Is.EqualTo(expectedResult)); + } + + [MaxTime(Timeout.MaxTestTime)] + [TestCase(10, 5, 12, 4, 4, 6, -1)] + [TestCase(10, 5, 12, 4, 10, 6, 1)] + [TestCase(10, 4, 12, 4, 4, 6, 1)] + [TestCase(12, 4, 12, 4, 4, 6, 0)] + [TestCase(10, 5, 12, 4, 4, 3, -1)] + [TestCase(10, 5, 12, 4, 10, 3, -1)] + public void GasPriceComparer_for_eip1559_transactions(int feeCapX, int gasPremiumX, int feeCapY, int gasPremiumY, int headBaseFee, long headBlockNumber, int expectedResult) + { + long eip1559Transition = 5; + TestingContext context = new TestingContext(true, eip1559Transition) + .WithHeadBaseFeeNumber((UInt256)headBaseFee) + .WithHeadBlockNumber(headBlockNumber); + IComparer comparer = context.DefaultComparer; + Assert1559Transactions(comparer, feeCapX, gasPremiumX, feeCapY, gasPremiumY, expectedResult); + } - [Timeout(Timeout.MaxTestTime)] - [TestCase(10, 5, 12, 4, 4, 6, -1)] - [TestCase(10, 5, 12, 4, 10, 6, 1)] - [TestCase(10, 4, 12, 4, 4, 6, 1)] - [TestCase(12, 4, 12, 4, 4, 6, 0)] - [TestCase(10, 5, 12, 4, 4, 3, -1)] - [TestCase(10, 5, 12, 4, 10, 3, -1)] - public void GasPriceComparer_for_eip1559_transactions(int feeCapX, int gasPremiumX, int feeCapY, int gasPremiumY, int headBaseFee, long headBlockNumber, int expectedResult) + [MaxTime(Timeout.MaxTestTime)] + [TestCase(4, 3, 1, 3, 1)] + [TestCase(4, 3, 3, 1, -1)] + [TestCase(4, 3, 0, 0, 0)] + public void GasPriceComparer_use_gas_bottleneck_when_it_is_not_null(int gasPriceX, int gasPriceY, int gasBottleneckX, int gasBottleneckY, int expectedResult) + { + long eip1559Transition = long.MaxValue; + TestingContext context = new TestingContext(false, eip1559Transition) + .WithHeadBaseFeeNumber((UInt256)0) + .WithHeadBlockNumber(1); + IComparer comparer = context.DefaultComparer; + Transaction x = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) + .WithGasPrice((UInt256)gasPriceX).WithGasBottleneck((UInt256)gasBottleneckX).TestObject; + Transaction y = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) + .WithGasPrice((UInt256)gasPriceY).WithGasBottleneck((UInt256)gasBottleneckY).TestObject; + int result = comparer.Compare(x, y); + Assert.That(result, Is.EqualTo(expectedResult)); + } + + [MaxTime(Timeout.MaxTestTime)] + [TestCase(10, 5, 12, 4, 4, 6, -1)] + [TestCase(10, 5, 12, 4, 10, 6, 1)] + [TestCase(10, 4, 12, 4, 4, 6, 1)] + [TestCase(12, 4, 12, 4, 4, 6, 0)] + [TestCase(10, 5, 12, 4, 4, 3, -1)] + [TestCase(10, 5, 12, 4, 10, 3, -1)] + public void ProducerGasPriceComparer_for_eip1559_transactions_1559(int feeCapX, int gasPremiumX, int feeCapY, int gasPremiumY, int headBaseFee, long headBlockNumber, int expectedResult) + { + long eip1559Transition = 5; + TestingContext context = new(true, eip1559Transition); + IComparer comparer = context.GetProducerComparer(new BlockPreparationContext((UInt256)headBaseFee, headBlockNumber)); + Assert1559Transactions(comparer, feeCapX, gasPremiumX, feeCapY, gasPremiumY, expectedResult); + } + + private void Assert1559Transactions(IComparer comparer, int feeCapX, int gasPremiumX, int feeCapY, int gasPremiumY, int expectedResult) + { + Transaction x = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) + .WithMaxFeePerGas((UInt256)feeCapX).WithMaxPriorityFeePerGas((UInt256)gasPremiumX) + .WithType(TxType.EIP1559).TestObject; + Transaction y = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) + .WithMaxFeePerGas((UInt256)feeCapY).WithMaxPriorityFeePerGas((UInt256)gasPremiumY) + .WithType(TxType.EIP1559).TestObject; + int result = comparer.Compare(x, y); + Assert.That(result, Is.EqualTo(expectedResult)); + } + + private class TestingContext + { + private readonly IBlockTree _blockTree; + private readonly ITransactionComparerProvider _transactionComparerProvider; + private long _blockNumber; + private UInt256 _baseFee; + + public TestingContext(bool isEip1559Enabled = false, long eip1559TransitionBlock = 0) { - long eip1559Transition = 5; - TestingContext context = new TestingContext(true, eip1559Transition) - .WithHeadBaseFeeNumber((UInt256)headBaseFee) - .WithHeadBlockNumber(headBlockNumber); - IComparer comparer = context.DefaultComparer; - Assert1559Transactions(comparer, feeCapX, gasPremiumX, feeCapY, gasPremiumY, expectedResult); + ReleaseSpec releaseSpec = new(); + ReleaseSpec eip1559ReleaseSpec = new() { IsEip1559Enabled = isEip1559Enabled, Eip1559TransitionBlock = eip1559TransitionBlock }; + ISpecProvider specProvider = Substitute.For(); + specProvider.GetSpec(Arg.Is(x => x.BlockNumber >= eip1559TransitionBlock)).Returns(eip1559ReleaseSpec); + specProvider.GetSpec(Arg.Is(x => x.BlockNumber < eip1559TransitionBlock)).Returns(releaseSpec); + _blockTree = Substitute.For(); + UpdateBlockTreeHead(); + _transactionComparerProvider = + new TransactionComparerProvider(specProvider, _blockTree); } - [Timeout(Timeout.MaxTestTime)] - [TestCase(4, 3, 1, 3, 1)] - [TestCase(4, 3, 3, 1, -1)] - [TestCase(4, 3, 0, 0, 0)] - public void GasPriceComparer_use_gas_bottleneck_when_it_is_not_null(int gasPriceX, int gasPriceY, int gasBottleneckX, int gasBottleneckY, int expectedResult) + public IComparer DefaultComparer => _transactionComparerProvider.GetDefaultComparer(); + + public IComparer GetProducerComparer(BlockPreparationContext blockPreparationContext) { - long eip1559Transition = long.MaxValue; - TestingContext context = new TestingContext(false, eip1559Transition) - .WithHeadBaseFeeNumber((UInt256)0) - .WithHeadBlockNumber(1); - IComparer comparer = context.DefaultComparer; - Transaction x = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) - .WithGasPrice((UInt256)gasPriceX).WithGasBottleneck((UInt256)gasBottleneckX).TestObject; - Transaction y = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) - .WithGasPrice((UInt256)gasPriceY).WithGasBottleneck((UInt256)gasBottleneckY).TestObject; - int result = comparer.Compare(x, y); - Assert.That(result, Is.EqualTo(expectedResult)); + return _transactionComparerProvider.GetDefaultProducerComparer(blockPreparationContext); } - [Timeout(Timeout.MaxTestTime)] - [TestCase(10, 5, 12, 4, 4, 6, -1)] - [TestCase(10, 5, 12, 4, 10, 6, 1)] - [TestCase(10, 4, 12, 4, 4, 6, 1)] - [TestCase(12, 4, 12, 4, 4, 6, 0)] - [TestCase(10, 5, 12, 4, 4, 3, -1)] - [TestCase(10, 5, 12, 4, 10, 3, -1)] - public void ProducerGasPriceComparer_for_eip1559_transactions_1559(int feeCapX, int gasPremiumX, int feeCapY, int gasPremiumY, int headBaseFee, long headBlockNumber, int expectedResult) + public TestingContext WithHeadBlockNumber(long headBlockNumber) { - long eip1559Transition = 5; - TestingContext context = new(true, eip1559Transition); - IComparer comparer = context.GetProducerComparer(new BlockPreparationContext((UInt256)headBaseFee, headBlockNumber)); - Assert1559Transactions(comparer, feeCapX, gasPremiumX, feeCapY, gasPremiumY, expectedResult); + _blockNumber = headBlockNumber; + UpdateBlockTreeHead(); + return this; } - private void Assert1559Transactions(IComparer comparer, int feeCapX, int gasPremiumX, int feeCapY, int gasPremiumY, int expectedResult) + public TestingContext WithHeadBaseFeeNumber(UInt256 headBaseFee) { - Transaction x = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) - .WithMaxFeePerGas((UInt256)feeCapX).WithMaxPriorityFeePerGas((UInt256)gasPremiumX) - .WithType(TxType.EIP1559).TestObject; - Transaction y = Build.A.Transaction.WithSenderAddress(TestItem.AddressA) - .WithMaxFeePerGas((UInt256)feeCapY).WithMaxPriorityFeePerGas((UInt256)gasPremiumY) - .WithType(TxType.EIP1559).TestObject; - int result = comparer.Compare(x, y); - Assert.That(result, Is.EqualTo(expectedResult)); + _baseFee = headBaseFee; + UpdateBlockTreeHead(); + return this; } - private class TestingContext + private void UpdateBlockTreeHead() { - private readonly IBlockTree _blockTree; - private readonly ITransactionComparerProvider _transactionComparerProvider; - private long _blockNumber; - private UInt256 _baseFee; - - public TestingContext(bool isEip1559Enabled = false, long eip1559TransitionBlock = 0) - { - ReleaseSpec releaseSpec = new(); - ReleaseSpec eip1559ReleaseSpec = new() { IsEip1559Enabled = isEip1559Enabled, Eip1559TransitionBlock = eip1559TransitionBlock }; - ISpecProvider specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Is(x => x.BlockNumber >= eip1559TransitionBlock)).Returns(eip1559ReleaseSpec); - specProvider.GetSpec(Arg.Is(x => x.BlockNumber < eip1559TransitionBlock)).Returns(releaseSpec); - _blockTree = Substitute.For(); - UpdateBlockTreeHead(); - _transactionComparerProvider = - new TransactionComparerProvider(specProvider, _blockTree); - } - - public IComparer DefaultComparer => _transactionComparerProvider.GetDefaultComparer(); - - public IComparer GetProducerComparer(BlockPreparationContext blockPreparationContext) - { - return _transactionComparerProvider.GetDefaultProducerComparer(blockPreparationContext); - } - - public TestingContext WithHeadBlockNumber(long headBlockNumber) - { - _blockNumber = headBlockNumber; - UpdateBlockTreeHead(); - return this; - } - - public TestingContext WithHeadBaseFeeNumber(UInt256 headBaseFee) - { - _baseFee = headBaseFee; - UpdateBlockTreeHead(); - return this; - } - - private void UpdateBlockTreeHead() - { - Block block = Build.A.Block - .WithNumber(_blockNumber) - .WithBaseFeePerGas(_baseFee).TestObject; - _blockTree.Head.Returns(block); - } + Block block = Build.A.Block + .WithNumber(_blockNumber) + .WithBaseFeePerGas(_baseFee).TestObject; + _blockTree.Head.Returns(block); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs index ebb834463d8..0ee1de5ced9 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Consensus.Messages; using Nethermind.Consensus.Validators; using Nethermind.Core.ConsensusRequests; using Nethermind.Core; @@ -9,7 +8,6 @@ using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; -using Nethermind.Evm; using Nethermind.Logging; using Nethermind.Specs; using Nethermind.Specs.Forks; @@ -17,238 +15,235 @@ using NSubstitute; using NUnit.Framework; using System; -using System.Collections; using System.Collections.Generic; -namespace Nethermind.Blockchain.Test.Validators +namespace Nethermind.Blockchain.Test.Validators; + +public class BlockValidatorTests { - [TestFixture] - public class BlockValidatorTests + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_more_uncles_than_allowed_returns_false() + { + TxValidator txValidator = new(TestBlockchainIds.ChainId); + ReleaseSpec releaseSpec = new(); + releaseSpec.MaximumUncleCount = 0; + ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, releaseSpec)); + + BlockValidator blockValidator = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); + bool noiseRemoved = blockValidator.ValidateSuggestedBlock(Build.A.Block.TestObject); + Assert.That(noiseRemoved, Is.True); + + bool result = blockValidator.ValidateSuggestedBlock(Build.A.Block.WithUncles(Build.A.BlockHeader.TestObject).TestObject); + Assert.That(result, Is.False); + } + + [Test] + public void ValidateBodyAgainstHeader_BlockIsValid_ReturnsTrue() { - [Test, Timeout(Timeout.MaxTestTime)] - public void When_more_uncles_than_allowed_returns_false() - { - TxValidator txValidator = new(TestBlockchainIds.ChainId); - ReleaseSpec releaseSpec = new(); - releaseSpec.MaximumUncleCount = 0; - ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, releaseSpec)); - - BlockValidator blockValidator = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); - bool noiseRemoved = blockValidator.ValidateSuggestedBlock(Build.A.Block.TestObject); - Assert.True(noiseRemoved); - - bool result = blockValidator.ValidateSuggestedBlock(Build.A.Block.WithUncles(Build.A.BlockHeader.TestObject).TestObject); - Assert.False(result); - } - - [Test] - public void ValidateBodyAgainstHeader_BlockIsValid_ReturnsTrue() - { - Block block = Build.A.Block - .WithTransactions(1, Substitute.For()) - .WithWithdrawals(1) - .TestObject; - - Assert.That( - BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), - Is.True); - } - - [Test] - public void ValidateBodyAgainstHeader_BlockHasInvalidTxRoot_ReturnsFalse() - { - Block block = Build.A.Block - .WithTransactions(1, Substitute.For()) - .WithWithdrawals(1) - .TestObject; - block.Header.TxRoot = Keccak.OfAnEmptyString; - - Assert.That( - BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), - Is.False); - } - - - [Test] - public void ValidateBodyAgainstHeader_BlockHasInvalidUnclesRoot_ReturnsFalse() - { - Block block = Build.A.Block - .WithTransactions(1, Substitute.For()) - .WithWithdrawals(1) - .TestObject; - block.Header.UnclesHash = Keccak.OfAnEmptyString; - - Assert.That( - BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), - Is.False); - } - - [Test] - public void ValidateBodyAgainstHeader_BlockHasInvalidWithdrawalsRoot_ReturnsFalse() - { - Block block = Build.A.Block - .WithTransactions(1, Substitute.For()) - .WithWithdrawals(1) - .TestObject; - block.Header.WithdrawalsRoot = Keccak.OfAnEmptyString; - - Assert.That( - BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), - Is.False); - } - - [Test] - public void ValidateProcessedBlock_HashesAreTheSame_ReturnsTrue() - { - TxValidator txValidator = new(TestBlockchainIds.ChainId); - ISpecProvider specProvider = Substitute.For(); - BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); - Block suggestedBlock = Build.A.Block.TestObject; - Block processedBlock = Build.A.Block.TestObject; - - Assert.That(sut.ValidateProcessedBlock( - suggestedBlock, - Array.Empty(), - processedBlock), Is.True); - } - - [Test] - public void ValidateProcessedBlock_HashesAreTheSame_ErrorIsNull() - { - TxValidator txValidator = new(TestBlockchainIds.ChainId); - ISpecProvider specProvider = Substitute.For(); - BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); - Block suggestedBlock = Build.A.Block.TestObject; - Block processedBlock = Build.A.Block.TestObject; - string? error; - - sut.ValidateProcessedBlock( - suggestedBlock, - Array.Empty(), - processedBlock, out error); - - Assert.That(error, Is.Null); - } - - [Test] - public void ValidateProcessedBlock_StateRootIsWrong_ReturnsFalse() - { - TxValidator txValidator = new(TestBlockchainIds.ChainId); - ISpecProvider specProvider = Substitute.For(); - BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); - Block suggestedBlock = Build.A.Block.TestObject; - Block processedBlock = Build.A.Block.WithStateRoot(Keccak.Zero).TestObject; - - Assert.That(sut.ValidateProcessedBlock( - suggestedBlock, - Array.Empty(), - processedBlock), Is.False); - } - - [Test] - public void ValidateProcessedBlock_StateRootIsWrong_ErrorIsSet() - { - TxValidator txValidator = new(TestBlockchainIds.ChainId); - ISpecProvider specProvider = Substitute.For(); - BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); - Block suggestedBlock = Build.A.Block.TestObject; - Block processedBlock = Build.A.Block.WithStateRoot(Keccak.Zero).TestObject; - string? error; - - sut.ValidateProcessedBlock( - suggestedBlock, - Array.Empty(), - processedBlock, out error); - - Assert.That(error, Does.StartWith("InvalidStateRoot")); - } - - private static IEnumerable BadSuggestedBlocks() - { - KzgPolynomialCommitments.InitializeAsync().Wait(); - - yield return new TestCaseData( - Build.A.Block.WithHeader(Build.A.BlockHeader.WithUnclesHash(Keccak.Zero).TestObject).TestObject, - Substitute.For(), - "InvalidUnclesHash"); - - yield return new TestCaseData( - Build.A.Block.WithHeader(Build.A.BlockHeader.WithTransactionsRoot(Keccak.Zero).TestObject).TestObject, - Substitute.For(), - "InvalidTxRoot"); - - yield return new TestCaseData( - Build.A.Block.WithBlobGasUsed(131072) - .WithExcessBlobGas(1) - .WithTransactions( - Build.A.Transaction.WithShardBlobTxTypeAndFields(1) - .WithMaxFeePerBlobGas(0) - .WithMaxFeePerGas(1000000) - .Signed() - .TestObject) - .TestObject, - new CustomSpecProvider(((ForkActivation)0, Cancun.Instance)), - "InsufficientMaxFeePerBlobGas"); - } - - [TestCaseSource(nameof(BadSuggestedBlocks))] - public void ValidateSuggestedBlock_SuggestedBlockIsInvalid_CorrectErrorIsSet(Block suggestedBlock, ISpecProvider specProvider, string expectedError) - { - TxValidator txValidator = new(TestBlockchainIds.ChainId); - BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); - string? error; - - sut.ValidateSuggestedBlock( - suggestedBlock, out error); - - Assert.That(error, Does.StartWith(expectedError)); - } - - [Test] - public void ValidateBodyAgainstHeader_BlockHasInvalidRequestRoot_ReturnsFalse() - { - Block block = Build.A.Block - .WithConsensusRequests(new ConsensusRequest[] { - Build.A.Deposit.WithIndex(0).TestObject, - Build.A.WithdrawalRequest.TestObject - }) - .TestObject; - block.Header.RequestsRoot = Keccak.OfAnEmptyString; - - Assert.That( - BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), - Is.False); - } - - [Test] - public void ValidateBodyRequests_BlockHasReuests_InOrder_ReturnsTrue() - { - Block block = Build.A.Block - .WithConsensusRequests(new ConsensusRequest[] { - Build.A.Deposit.WithIndex(0).TestObject, - Build.A.WithdrawalRequest.TestObject - }) - .TestObject; - - Assert.That( - BlockValidator.ValidateRequestsOrder(block, out string? _), - Is.True); - } - - [Test] - public void ValidateBodyRequests_BlockHasReuests_OutOfOrder_ReturnsFalse() - { - Block block = Build.A.Block - .WithConsensusRequests(new ConsensusRequest[] { - Build.A.WithdrawalRequest.TestObject, - Build.A.Deposit.WithIndex(0).TestObject - }) - .TestObject; - - Assert.That( - BlockValidator.ValidateRequestsOrder(block, out string? _), - Is.False); - } + Block block = Build.A.Block + .WithTransactions(1, Substitute.For()) + .WithWithdrawals(1) + .TestObject; + + Assert.That( + BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), + Is.True); + } + + [Test] + public void ValidateBodyAgainstHeader_BlockHasInvalidTxRoot_ReturnsFalse() + { + Block block = Build.A.Block + .WithTransactions(1, Substitute.For()) + .WithWithdrawals(1) + .TestObject; + block.Header.TxRoot = Keccak.OfAnEmptyString; + + Assert.That( + BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), + Is.False); + } + + [Test] + public void ValidateBodyAgainstHeader_BlockHasInvalidUnclesRoot_ReturnsFalse() + { + Block block = Build.A.Block + .WithTransactions(1, Substitute.For()) + .WithWithdrawals(1) + .TestObject; + block.Header.UnclesHash = Keccak.OfAnEmptyString; + + Assert.That( + BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), + Is.False); } + + [Test] + public void ValidateBodyAgainstHeader_BlockHasInvalidWithdrawalsRoot_ReturnsFalse() + { + Block block = Build.A.Block + .WithTransactions(1, Substitute.For()) + .WithWithdrawals(1) + .TestObject; + block.Header.WithdrawalsRoot = Keccak.OfAnEmptyString; + + Assert.That( + BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), + Is.False); + } + + [Test] + public void ValidateProcessedBlock_HashesAreTheSame_ReturnsTrue() + { + TxValidator txValidator = new(TestBlockchainIds.ChainId); + ISpecProvider specProvider = Substitute.For(); + BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); + Block suggestedBlock = Build.A.Block.TestObject; + Block processedBlock = Build.A.Block.TestObject; + + Assert.That(sut.ValidateProcessedBlock( + suggestedBlock, + Array.Empty(), + processedBlock), Is.True); + } + + [Test] + public void ValidateProcessedBlock_HashesAreTheSame_ErrorIsNull() + { + TxValidator txValidator = new(TestBlockchainIds.ChainId); + ISpecProvider specProvider = Substitute.For(); + BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); + Block suggestedBlock = Build.A.Block.TestObject; + Block processedBlock = Build.A.Block.TestObject; + string? error; + + sut.ValidateProcessedBlock( + suggestedBlock, + Array.Empty(), + processedBlock, out error); + + Assert.That(error, Is.Null); + } + + [Test] + public void ValidateProcessedBlock_StateRootIsWrong_ReturnsFalse() + { + TxValidator txValidator = new(TestBlockchainIds.ChainId); + ISpecProvider specProvider = Substitute.For(); + BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); + Block suggestedBlock = Build.A.Block.TestObject; + Block processedBlock = Build.A.Block.WithStateRoot(Keccak.Zero).TestObject; + + Assert.That(sut.ValidateProcessedBlock( + suggestedBlock, + Array.Empty(), + processedBlock), Is.False); + } + + [Test] + public void ValidateProcessedBlock_StateRootIsWrong_ErrorIsSet() + { + TxValidator txValidator = new(TestBlockchainIds.ChainId); + ISpecProvider specProvider = Substitute.For(); + BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); + Block suggestedBlock = Build.A.Block.TestObject; + Block processedBlock = Build.A.Block.WithStateRoot(Keccak.Zero).TestObject; + string? error; + + sut.ValidateProcessedBlock( + suggestedBlock, + Array.Empty(), + processedBlock, out error); + + Assert.That(error, Does.StartWith("InvalidStateRoot")); + } + + private static IEnumerable BadSuggestedBlocks() + { + KzgPolynomialCommitments.InitializeAsync().Wait(); + + yield return new TestCaseData( + Build.A.Block.WithHeader(Build.A.BlockHeader.WithUnclesHash(Keccak.Zero).TestObject).TestObject, + Substitute.For(), + "InvalidUnclesHash"); + + yield return new TestCaseData( + Build.A.Block.WithHeader(Build.A.BlockHeader.WithTransactionsRoot(Keccak.Zero).TestObject).TestObject, + Substitute.For(), + "InvalidTxRoot"); + + yield return new TestCaseData( + Build.A.Block.WithBlobGasUsed(131072) + .WithExcessBlobGas(1) + .WithTransactions( + Build.A.Transaction.WithShardBlobTxTypeAndFields(1) + .WithMaxFeePerBlobGas(0) + .WithMaxFeePerGas(1000000) + .Signed() + .TestObject) + .TestObject, + new CustomSpecProvider(((ForkActivation)0, Cancun.Instance)), + "InsufficientMaxFeePerBlobGas"); + } + + [TestCaseSource(nameof(BadSuggestedBlocks))] + public void ValidateSuggestedBlock_SuggestedBlockIsInvalid_CorrectErrorIsSet(Block suggestedBlock, ISpecProvider specProvider, string expectedError) + { + TxValidator txValidator = new(TestBlockchainIds.ChainId); + BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); + string? error; + + sut.ValidateSuggestedBlock( + suggestedBlock, out error); + + Assert.That(error, Does.StartWith(expectedError)); + } + + [Test] + public void ValidateBodyAgainstHeader_BlockHasInvalidRequestRoot_ReturnsFalse() + { + Block block = Build.A.Block + .WithConsensusRequests(new ConsensusRequest[] { + Build.A.Deposit.WithIndex(0).TestObject, + Build.A.WithdrawalRequest.TestObject + }) + .TestObject; + block.Header.RequestsRoot = Keccak.OfAnEmptyString; + + Assert.That( + BlockValidator.ValidateBodyAgainstHeader(block.Header, block.Body), + Is.False); + } + + [Test] + public void ValidateBodyRequests_BlockHasReuests_InOrder_ReturnsTrue() + { + Block block = Build.A.Block + .WithConsensusRequests(new ConsensusRequest[] { + Build.A.Deposit.WithIndex(0).TestObject, + Build.A.WithdrawalRequest.TestObject + }) + .TestObject; + + Assert.That( + BlockValidator.ValidateRequestsOrder(block, out string? _), + Is.True); + } + + [Test] + public void ValidateBodyRequests_BlockHasReuests_OutOfOrder_ReturnsFalse() + { + Block block = Build.A.Block + .WithConsensusRequests(new ConsensusRequest[] { + Build.A.WithdrawalRequest.TestObject, + Build.A.Deposit.WithIndex(0).TestObject + }) + .TestObject; + + Assert.That( + BlockValidator.ValidateRequestsOrder(block, out string? _), + Is.False); + } + } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/HeaderValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/HeaderValidatorTests.cs index bbbec170112..eb28f0160bc 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/HeaderValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/HeaderValidatorTests.cs @@ -20,316 +20,314 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Validators +namespace Nethermind.Blockchain.Test.Validators; + +public class HeaderValidatorTests { - [TestFixture] - public class HeaderValidatorTests + private IHeaderValidator _validator = null!; + private ISealValidator _ethash = null!; + private TestLogger _testLogger = null!; + private Block _parentBlock = null!; + private Block _block = null!; + private IBlockTree _blockTree = null!; + private ISpecProvider _specProvider = null!; + + [SetUp] + public void Setup() { - private IHeaderValidator _validator = null!; - private ISealValidator _ethash = null!; - private TestLogger _testLogger = null!; - private Block _parentBlock = null!; - private Block _block = null!; - private IBlockTree _blockTree = null!; - private ISpecProvider _specProvider = null!; - - [SetUp] - public void Setup() - { - EthashDifficultyCalculator calculator = new(new TestSingleReleaseSpecProvider(Frontier.Instance)); - _ethash = new EthashSealValidator(LimboLogs.Instance, calculator, new CryptoRandom(), new Ethash(LimboLogs.Instance), Timestamper.Default); - _testLogger = new TestLogger(); - _blockTree = Build.A.BlockTree() - .WithSpecProvider(FrontierSpecProvider.Instance) - .WithoutSettingHead - .TestObject; - _specProvider = new TestSingleReleaseSpecProvider(Byzantium.Instance); - - _validator = new HeaderValidator(_blockTree, _ethash, _specProvider, new OneLoggerLogManager(new(_testLogger))); - _parentBlock = Build.A.Block.WithDifficulty(1).TestObject; - _block = Build.A.Block.WithParent(_parentBlock) - .WithDifficulty(131072) - .WithMixHash(new Hash256("0xd7db5fdd332d3a65d6ac9c4c530929369905734d3ef7a91e373e81d0f010b8e8")) - .WithNonce(0).TestObject; - - _blockTree.SuggestBlock(_parentBlock); - _blockTree.SuggestBlock(_block); - } + EthashDifficultyCalculator calculator = new(new TestSingleReleaseSpecProvider(Frontier.Instance)); + _ethash = new EthashSealValidator(LimboLogs.Instance, calculator, new CryptoRandom(), new Ethash(LimboLogs.Instance), Timestamper.Default); + _testLogger = new TestLogger(); + _blockTree = Build.A.BlockTree() + .WithSpecProvider(FrontierSpecProvider.Instance) + .WithoutSettingHead + .TestObject; + _specProvider = new TestSingleReleaseSpecProvider(Byzantium.Instance); + + _validator = new HeaderValidator(_blockTree, _ethash, _specProvider, new OneLoggerLogManager(new(_testLogger))); + _parentBlock = Build.A.Block.WithDifficulty(1).TestObject; + _block = Build.A.Block.WithParent(_parentBlock) + .WithDifficulty(131072) + .WithMixHash(new Hash256("0xd7db5fdd332d3a65d6ac9c4c530929369905734d3ef7a91e373e81d0f010b8e8")) + .WithNonce(0).TestObject; + + _blockTree.SuggestBlock(_parentBlock); + _blockTree.SuggestBlock(_block); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Valid_when_valid() + [Test, MaxTime(Timeout.MaxTestTime)] + public void Valid_when_valid() + { + _block.Header.SealEngineType = SealEngineType.None; + bool result = _validator.Validate(_block.Header); + if (!result) { - _block.Header.SealEngineType = SealEngineType.None; - bool result = _validator.Validate(_block.Header); - if (!result) + foreach (string error in _testLogger.LogList) { - foreach (string error in _testLogger.LogList) - { - Console.WriteLine(error); - } + Console.WriteLine(error); } - - Assert.True(result); } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_limit_too_high() - { - _block.Header.GasLimit = _parentBlock.Header.GasLimit + (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024); - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); - - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + Assert.That(result, Is.True); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_limit_just_correct_high() - { - _block.Header.GasLimit = _parentBlock.Header.GasLimit + (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024) - 1; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_limit_too_high() + { + _block.Header.GasLimit = _parentBlock.Header.GasLimit + (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024); + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.True(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_limit_just_correct_low() - { - _block.Header.GasLimit = _parentBlock.Header.GasLimit - (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024) + 1; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_limit_just_correct_high() + { + _block.Header.GasLimit = _parentBlock.Header.GasLimit + (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024) - 1; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.True(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.True); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_limit_is_just_too_low() - { - _block.Header.GasLimit = _parentBlock.Header.GasLimit - (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024); - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_limit_just_correct_low() + { + _block.Header.GasLimit = _parentBlock.Header.GasLimit - (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024) + 1; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.True); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_used_above_gas_limit() - { - _block.Header.GasUsed = _parentBlock.Header.GasLimit + 1; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_limit_is_just_too_low() + { + _block.Header.GasLimit = _parentBlock.Header.GasLimit - (long)BigInteger.Divide(_parentBlock.Header.GasLimit, 1024); + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_no_parent_invalid() - { - _block.Header.ParentHash = Keccak.Zero; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); - _block.Header.MaybeParent = null; + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_used_above_gas_limit() + { + _block.Header.GasUsed = _parentBlock.Header.GasLimit + 1; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_timestamp_same_as_parent() - { - _block.Header.Timestamp = _parentBlock.Header.Timestamp; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_no_parent_invalid() + { + _block.Header.ParentHash = Keccak.Zero; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); + _block.Header.MaybeParent = null; - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_extra_data_too_long() - { - _block.Header.ExtraData = new byte[33]; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_timestamp_same_as_parent() + { + _block.Header.Timestamp = _parentBlock.Header.Timestamp; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_incorrect_difficulty_then_invalid() - { - _block.Header.Difficulty = 1; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_extra_data_too_long() + { + _block.Header.ExtraData = new byte[33]; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_incorrect_number_then_invalid() - { - _block.Header.Number += 1; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_incorrect_difficulty_then_invalid() + { + _block.Header.Difficulty = 1; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Timeout(Timeout.MaxTestTime)] - [TestCase(10000000, 4, 20000000, true)] - [TestCase(10000000, 4, 20019530, true)] - [TestCase(10000000, 4, 20019531, false)] - [TestCase(10000000, 4, 19980470, true)] - [TestCase(10000000, 4, 19980469, false)] - [TestCase(20000000, 5, 20000000, true)] - [TestCase(20000000, 5, 20019530, true)] - [TestCase(20000000, 5, 20019531, false)] - [TestCase(20000000, 5, 19980470, true)] - [TestCase(20000000, 5, 19980469, false)] - [TestCase(40000000, 5, 40039061, true)] - [TestCase(40000000, 5, 40039062, false)] - [TestCase(40000000, 5, 39960939, true)] - [TestCase(40000000, 5, 39960938, false)] - public void When_gaslimit_is_on_london_fork(long parentGasLimit, long blockNumber, long gasLimit, bool expectedResult) - { - OverridableReleaseSpec spec = new(London.Instance) - { - Eip1559TransitionBlock = 5 - }; - TestSpecProvider specProvider = new(spec); - _validator = new HeaderValidator(_blockTree, _ethash, specProvider, new OneLoggerLogManager(new(_testLogger))); - _parentBlock = Build.A.Block.WithDifficulty(1) - .WithGasLimit(parentGasLimit) - .WithNumber(blockNumber) - .TestObject; - _block = Build.A.Block.WithParent(_parentBlock) - .WithDifficulty(131072) - .WithMixHash(new Hash256("0xd7db5fdd332d3a65d6ac9c4c530929369905734d3ef7a91e373e81d0f010b8e8")) - .WithGasLimit(gasLimit) - .WithNumber(_parentBlock.Number + 1) - .WithBaseFeePerGas(BaseFeeCalculator.Calculate(_parentBlock.Header, specProvider.GetSpec((ForkActivation)(_parentBlock.Number + 1)))) - .WithNonce(0).TestObject; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); - - bool result = _validator.Validate(_block.Header, _parentBlock.Header); - Assert.That(result, Is.EqualTo(expectedResult)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_incorrect_number_then_invalid() + { + _block.Header.Number += 1; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_limit_is_long_max_value() - { - _validator = new HeaderValidator(_blockTree, _ethash, _specProvider, new OneLoggerLogManager(new(_testLogger))); - _parentBlock = Build.A.Block.WithDifficulty(1) - .WithGasLimit(long.MaxValue) - .WithNumber(5) - .TestObject; - _block = Build.A.Block.WithParent(_parentBlock) - .WithDifficulty(131072) - .WithMixHash(new Hash256("0xd7db5fdd332d3a65d6ac9c4c530929369905734d3ef7a91e373e81d0f010b8e8")) - .WithGasLimit(long.MaxValue) - .WithNumber(_parentBlock.Number + 1) - .WithNonce(0).TestObject; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); - - bool result = _validator.Validate(_block.Header, _parentBlock.Header); - - Assert.True(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_block_number_is_negative() + [MaxTime(Timeout.MaxTestTime)] + [TestCase(10000000, 4, 20000000, true)] + [TestCase(10000000, 4, 20019530, true)] + [TestCase(10000000, 4, 20019531, false)] + [TestCase(10000000, 4, 19980470, true)] + [TestCase(10000000, 4, 19980469, false)] + [TestCase(20000000, 5, 20000000, true)] + [TestCase(20000000, 5, 20019530, true)] + [TestCase(20000000, 5, 20019531, false)] + [TestCase(20000000, 5, 19980470, true)] + [TestCase(20000000, 5, 19980469, false)] + [TestCase(40000000, 5, 40039061, true)] + [TestCase(40000000, 5, 40039062, false)] + [TestCase(40000000, 5, 39960939, true)] + [TestCase(40000000, 5, 39960938, false)] + public void When_gaslimit_is_on_london_fork(long parentGasLimit, long blockNumber, long gasLimit, bool expectedResult) + { + OverridableReleaseSpec spec = new(London.Instance) { - _block.Header.Number = -1; - _block.Header.Hash = _block.CalculateHash(); + Eip1559TransitionBlock = 5 + }; + TestSpecProvider specProvider = new(spec); + _validator = new HeaderValidator(_blockTree, _ethash, specProvider, new OneLoggerLogManager(new(_testLogger))); + _parentBlock = Build.A.Block.WithDifficulty(1) + .WithGasLimit(parentGasLimit) + .WithNumber(blockNumber) + .TestObject; + _block = Build.A.Block.WithParent(_parentBlock) + .WithDifficulty(131072) + .WithMixHash(new Hash256("0xd7db5fdd332d3a65d6ac9c4c530929369905734d3ef7a91e373e81d0f010b8e8")) + .WithGasLimit(gasLimit) + .WithNumber(_parentBlock.Number + 1) + .WithBaseFeePerGas(BaseFeeCalculator.Calculate(_parentBlock.Header, specProvider.GetSpec((ForkActivation)(_parentBlock.Number + 1)))) + .WithNonce(0).TestObject; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); + + bool result = _validator.Validate(_block.Header, _parentBlock.Header); + Assert.That(result, Is.EqualTo(expectedResult)); + } - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_limit_is_long_max_value() + { + _validator = new HeaderValidator(_blockTree, _ethash, _specProvider, new OneLoggerLogManager(new(_testLogger))); + _parentBlock = Build.A.Block.WithDifficulty(1) + .WithGasLimit(long.MaxValue) + .WithNumber(5) + .TestObject; + _block = Build.A.Block.WithParent(_parentBlock) + .WithDifficulty(131072) + .WithMixHash(new Hash256("0xd7db5fdd332d3a65d6ac9c4c530929369905734d3ef7a91e373e81d0f010b8e8")) + .WithGasLimit(long.MaxValue) + .WithNumber(_parentBlock.Number + 1) + .WithNonce(0).TestObject; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); + + bool result = _validator.Validate(_block.Header, _parentBlock.Header); + + Assert.That(result, Is.True); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_used_is_negative() - { - _block.Header.GasUsed = -1; - _block.Header.Hash = _block.CalculateHash(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_block_number_is_negative() + { + _block.Header.Number = -1; + _block.Header.Hash = _block.CalculateHash(); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_total_difficulty_null_we_should_skip_total_difficulty_validation() - { - _block.Header.Difficulty = 1; - _block.Header.TotalDifficulty = null; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); - - HeaderValidator validator = new HeaderValidator(_blockTree, Always.Valid, _specProvider, new OneLoggerLogManager(new(_testLogger))); - bool result = validator.Validate(_block.Header); - Assert.True(result); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_used_is_negative() + { + _block.Header.GasUsed = -1; + _block.Header.Hash = _block.CalculateHash(); - [Timeout(Timeout.MaxTestTime)] - [TestCase(0, 0, true)] - [TestCase(0, null, false)] - [TestCase(0, 1, false)] - [TestCase(1, 0, false)] - [TestCase(1, null, false)] - [TestCase(1, 1, false)] - public void When_total_difficulty_zero_we_should_skip_total_difficulty_validation_depending_on_ttd_and_genesis_td( - long genesisTd, long? ttd, bool expectedResult) - { - _block.Header.Difficulty = 1; - _block.Header.TotalDifficulty = 0; - _block.Header.SealEngineType = SealEngineType.None; - _block.Header.Hash = _block.CalculateHash(); + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } - { - _blockTree = Build.A.BlockTree() - .WithSpecProvider(FrontierSpecProvider.Instance) - .WithoutSettingHead - .TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_total_difficulty_null_we_should_skip_total_difficulty_validation() + { + _block.Header.Difficulty = 1; + _block.Header.TotalDifficulty = null; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); + + HeaderValidator validator = new HeaderValidator(_blockTree, Always.Valid, _specProvider, new OneLoggerLogManager(new(_testLogger))); + bool result = validator.Validate(_block.Header); + Assert.That(result, Is.True); + } - Block genesis = Build.A.Block.WithDifficulty((UInt256)genesisTd).TestObject; - _blockTree.SuggestBlock(genesis); - } + [MaxTime(Timeout.MaxTestTime)] + [TestCase(0, 0, true)] + [TestCase(0, null, false)] + [TestCase(0, 1, false)] + [TestCase(1, 0, false)] + [TestCase(1, null, false)] + [TestCase(1, 1, false)] + public void When_total_difficulty_zero_we_should_skip_total_difficulty_validation_depending_on_ttd_and_genesis_td( + long genesisTd, long? ttd, bool expectedResult) + { + _block.Header.Difficulty = 1; + _block.Header.TotalDifficulty = 0; + _block.Header.SealEngineType = SealEngineType.None; + _block.Header.Hash = _block.CalculateHash(); - _specProvider.UpdateMergeTransitionInfo(null, (UInt256?)ttd); + { + _blockTree = Build.A.BlockTree() + .WithSpecProvider(FrontierSpecProvider.Instance) + .WithoutSettingHead + .TestObject; - HeaderValidator validator = new(_blockTree, Always.Valid, _specProvider, new OneLoggerLogManager(new(_testLogger))); - bool result = validator.Validate(_block.Header); - Assert.That(result, Is.EqualTo(expectedResult)); + Block genesis = Build.A.Block.WithDifficulty((UInt256)genesisTd).TestObject; + _blockTree.SuggestBlock(genesis); } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_gas_limit_is_negative() - { - _block.Header.GasLimit = -1; - _block.Header.Hash = _block.CalculateHash(); + _specProvider.UpdateMergeTransitionInfo(null, (UInt256?)ttd); - bool result = _validator.Validate(_block.Header); - Assert.False(result); - } + HeaderValidator validator = new(_blockTree, Always.Valid, _specProvider, new OneLoggerLogManager(new(_testLogger))); + bool result = validator.Validate(_block.Header); + Assert.That(result, Is.EqualTo(expectedResult)); + } - [Test] - public void Validate_HashIsWrong_ErrorMessageIsSet() - { - HeaderValidator sut = new HeaderValidator(_blockTree, Always.Valid, Substitute.For(), new OneLoggerLogManager(new(_testLogger))); - _block.Header.Hash = Keccak.Zero; - string? error; - sut.Validate(_block.Header, false, out error); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_gas_limit_is_negative() + { + _block.Header.GasLimit = -1; + _block.Header.Hash = _block.CalculateHash(); - Assert.That(error, Does.StartWith("InvalidHeaderHash")); - } + bool result = _validator.Validate(_block.Header); + Assert.That(result, Is.False); + } + + [Test] + public void Validate_HashIsWrong_ErrorMessageIsSet() + { + HeaderValidator sut = new HeaderValidator(_blockTree, Always.Valid, Substitute.For(), new OneLoggerLogManager(new(_testLogger))); + _block.Header.Hash = Keccak.Zero; + string? error; + sut.Validate(_block.Header, false, out error); + + Assert.That(error, Does.StartWith("InvalidHeaderHash")); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs index 7d3bb9bc00b..c7cd07b95e1 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs @@ -23,7 +23,6 @@ namespace Nethermind.Blockchain.Test.Validators; -[TestFixture] public class TxValidatorTests { [SetUp] @@ -31,7 +30,7 @@ public void Setup() { } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Curve_is_correct() { BigInteger N = @@ -45,7 +44,7 @@ public void Curve_is_correct() (HalfN == halfN).Should().BeTrue(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Zero_r_is_not_valid() { byte[] sigData = new byte[65]; @@ -61,7 +60,7 @@ public void Zero_r_is_not_valid() private static byte CalculateV() => (byte)EthereumEcdsa.CalculateV(TestBlockchainIds.ChainId); - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Zero_s_is_not_valid() { byte[] sigData = new byte[65]; @@ -75,7 +74,7 @@ public void Zero_s_is_not_valid() txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeFalse(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Bad_chain_id_is_not_valid() { byte[] sigData = new byte[65]; @@ -89,7 +88,7 @@ public void Bad_chain_id_is_not_valid() txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeFalse(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void No_chain_id_legacy_tx_is_valid() { byte[] sigData = new byte[65]; @@ -103,7 +102,7 @@ public void No_chain_id_legacy_tx_is_valid() txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeTrue(); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Is_valid_with_valid_chain_id() { byte[] sigData = new byte[65]; @@ -117,7 +116,7 @@ public void Is_valid_with_valid_chain_id() txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeTrue(); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(true)] [TestCase(false)] public void Before_eip_155_has_to_have_valid_chain_id_unless_overridden(bool validateChainId) @@ -137,7 +136,7 @@ public void Before_eip_155_has_to_have_valid_chain_id_unless_overridden(bool val txValidator.IsWellFormed(tx, releaseSpec).AsBool().Should().Be(!validateChainId); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(TxType.Legacy, true, ExpectedResult = true)] [TestCase(TxType.Legacy, false, ExpectedResult = true)] [TestCase(TxType.AccessList, false, ExpectedResult = false)] @@ -164,7 +163,7 @@ public bool Before_eip_2930_has_to_be_legacy_tx(TxType txType, bool eip2930) return txValidator.IsWellFormed(tx, eip2930 ? Berlin.Instance : MuirGlacier.Instance); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(TxType.Legacy, true, false, ExpectedResult = true)] [TestCase(TxType.Legacy, false, false, ExpectedResult = true)] [TestCase(TxType.AccessList, false, false, ExpectedResult = false)] @@ -195,7 +194,7 @@ public bool Before_eip_1559_has_to_be_legacy_or_access_list_tx(TxType txType, bo return txValidator.IsWellFormed(tx, releaseSpec); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(TxType.Legacy, ExpectedResult = true)] [TestCase(TxType.AccessList, ExpectedResult = false)] [TestCase(TxType.EIP1559, ExpectedResult = false)] @@ -219,7 +218,7 @@ public bool Chain_Id_required_for_non_legacy_transactions_after_Berlin(TxType tx return txValidator.IsWellFormed(tx, Berlin.Instance); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(TxType.Legacy, 10, 5, ExpectedResult = true)] [TestCase(TxType.AccessList, 10, 5, ExpectedResult = true)] [TestCase(TxType.EIP1559, 10, 5, ExpectedResult = true)] @@ -250,7 +249,7 @@ public bool MaxFeePerGas_is_required_to_be_greater_than_MaxPriorityFeePerGas(TxT return txValidator.IsWellFormed(tx, London.Instance); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(true, 1, false)] [TestCase(false, 1, true)] [TestCase(true, -1, true)] @@ -349,7 +348,7 @@ public void ShardBlobTransactions_should_have_destination_set() Assert.That(txValidator.IsWellFormed(txWithTo, Cancun.Instance).AsBool()); } - [Timeout(Timeout.MaxTestTime)] + [MaxTime(Timeout.MaxTestTime)] [TestCase(TxType.EIP1559, false, ExpectedResult = true)] [TestCase(TxType.EIP1559, true, ExpectedResult = false)] [TestCase(TxType.Blob, true, ExpectedResult = true)] diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/UnclesValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/UnclesValidatorTests.cs index f0d01c68da3..b11bac8ab05 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/UnclesValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/UnclesValidatorTests.cs @@ -9,136 +9,131 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Validators +namespace Nethermind.Blockchain.Test.Validators; + +public class UnclesValidatorTests { - [TestFixture] - public class UnclesValidatorTests - { - private readonly Block _grandgrandparent; - private readonly Block _grandparent; - private readonly Block _parent; - private readonly Block _block; - private readonly IBlockTree _blockTree; - private IHeaderValidator _headerValidator = null!; + private readonly Block _grandgrandparent; + private readonly Block _grandparent; + private readonly Block _parent; + private readonly Block _block; + private readonly IBlockTree _blockTree; + private IHeaderValidator _headerValidator = null!; - private readonly Block _duplicateUncle; + private readonly Block _duplicateUncle; - [SetUp] - public void Setup() - { - _headerValidator = Substitute.For(); - _headerValidator.Validate(Arg.Any(), true).Returns(true); - } + [SetUp] + public void Setup() + { + _headerValidator = Substitute.For(); + _headerValidator.Validate(Arg.Any(), true).Returns(true); + } - public UnclesValidatorTests() - { - _blockTree = Build.A.BlockTree().OfChainLength(1).TestObject; - _grandgrandparent = _blockTree.FindBlock(0, BlockTreeLookupOptions.None)!; - _grandparent = Build.A.Block.WithParent(_grandgrandparent).TestObject; - _duplicateUncle = Build.A.Block.WithParent(_grandgrandparent).TestObject; - _parent = Build.A.Block.WithParent(_grandparent).WithUncles(_duplicateUncle).TestObject; - _block = Build.A.Block.WithParent(_parent).TestObject; - - _blockTree.SuggestHeader(_grandparent.Header); - _blockTree.SuggestHeader(_parent.Header); - _blockTree.SuggestHeader(_block.Header); - } + public UnclesValidatorTests() + { + _blockTree = Build.A.BlockTree().OfChainLength(1).TestObject; + _grandgrandparent = _blockTree.FindBlock(0, BlockTreeLookupOptions.None)!; + _grandparent = Build.A.Block.WithParent(_grandgrandparent).TestObject; + _duplicateUncle = Build.A.Block.WithParent(_grandgrandparent).TestObject; + _parent = Build.A.Block.WithParent(_grandparent).WithUncles(_duplicateUncle).TestObject; + _block = Build.A.Block.WithParent(_parent).TestObject; + + _blockTree.SuggestHeader(_grandparent.Header); + _blockTree.SuggestHeader(_parent.Header); + _blockTree.SuggestHeader(_block.Header); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_more_than_two_uncles_returns_false() - { - BlockHeader[] uncles = GetValidUncles(3); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_more_than_two_uncles_returns_false() + { + BlockHeader[] uncles = GetValidUncles(3); - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.False(unclesValidator.Validate(Build.A.BlockHeader.TestObject, uncles)); - } + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(Build.A.BlockHeader.TestObject, uncles), Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_uncle_is_self_returns_false() - { - BlockHeader[] uncles = new BlockHeader[1]; - uncles[0] = _block.Header; + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_uncle_is_self_returns_false() + { + BlockHeader[] uncles = new BlockHeader[1]; + uncles[0] = _block.Header; - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.False(unclesValidator.Validate(_block.Header, uncles)); - } + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(_block.Header, uncles), Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_uncle_is_brother_returns_false() - { - BlockHeader[] uncles = new BlockHeader[1]; - uncles[0] = Build.A.BlockHeader.TestObject; - uncles[0].ParentHash = _parent.Hash; - uncles[0].Number = _block.Number; + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_uncle_is_brother_returns_false() + { + BlockHeader[] uncles = [Build.A.BlockHeader.TestObject]; + uncles[0].ParentHash = _parent.Hash; + uncles[0].Number = _block.Number; - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.False(unclesValidator.Validate(_block.Header, uncles)); - } + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(_block.Header, uncles), Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_uncle_is_parent_returns_false() - { - BlockHeader[] uncles = new BlockHeader[1]; - uncles[0] = _parent.Header; + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_uncle_is_parent_returns_false() + { + BlockHeader[] uncles = [_parent.Header]; + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(_block.Header, uncles), Is.False); + } - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.False(unclesValidator.Validate(_block.Header, uncles)); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_uncle_was_already_included_return_false() + { + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(_block.Header, [_duplicateUncle.Header]), Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_uncle_was_already_included_return_false() + private BlockHeader[] GetValidUncles(int count) + { + BlockHeader[] uncles = new BlockHeader[count]; + for (int i = 0; i < count; i++) { - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.False(unclesValidator.Validate(_block.Header, new[] { _duplicateUncle.Header })); + uncles[i] = Build.A.BlockHeader.WithParent(_grandparent.Header).TestObject; } - private BlockHeader[] GetValidUncles(int count) - { - BlockHeader[] uncles = new BlockHeader[count]; - for (int i = 0; i < count; i++) - { - uncles[i] = Build.A.BlockHeader.WithParent(_grandparent.Header).TestObject; - } - - return uncles; - } + return uncles; + } - [Test, Timeout(Timeout.MaxTestTime)] - public void When_all_is_fine_returns_true() - { - BlockHeader[] uncles = GetValidUncles(1); + [Test, MaxTime(Timeout.MaxTestTime)] + public void When_all_is_fine_returns_true() + { + BlockHeader[] uncles = GetValidUncles(1); - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.True(unclesValidator.Validate(_block.Header, uncles)); - } + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(_block.Header, uncles)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Grandpas_brother_is_fine() - { - BlockHeader[] uncles = GetValidUncles(1); - uncles[0].Number = _grandparent.Number; - uncles[0].ParentHash = _grandgrandparent.Hash; + [Test, MaxTime(Timeout.MaxTestTime)] + public void Grandpas_brother_is_fine() + { + BlockHeader[] uncles = GetValidUncles(1); + uncles[0].Number = _grandparent.Number; + uncles[0].ParentHash = _grandgrandparent.Hash; - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.True(unclesValidator.Validate(_block.Header, uncles)); - } + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(_block.Header, uncles), Is.True); + } - [Test, Timeout(Timeout.MaxTestTime)] - public void Same_uncle_twice_returns_false() - { - BlockHeader[] uncles = GetValidUncles(1).Union(GetValidUncles(1)).ToArray(); + [Test, MaxTime(Timeout.MaxTestTime)] + public void Same_uncle_twice_returns_false() + { + BlockHeader[] uncles = GetValidUncles(1).Union(GetValidUncles(1)).ToArray(); - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.False(unclesValidator.Validate(_block.Header, uncles)); - } + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(_block.Header, uncles), Is.False); + } - [Test, Timeout(Timeout.MaxTestTime)] // because we decided to store the head block at 0x00..., eh - public void Uncles_near_genesis_with_00_address_used() - { - Block falseUncle = Build.A.Block.WithParent(Build.A.Block.WithDifficulty(123).TestObject).TestObject; - Block toValidate = Build.A.Block.WithParent(_parent).WithUncles(falseUncle).TestObject; - UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); - Assert.False(unclesValidator.Validate(toValidate.Header, toValidate.Uncles)); - } + [Test, MaxTime(Timeout.MaxTestTime)] // because we decided to store the head block at 0x00..., eh + public void Uncles_near_genesis_with_00_address_used() + { + Block falseUncle = Build.A.Block.WithParent(Build.A.Block.WithDifficulty(123).TestObject).TestObject; + Block toValidate = Build.A.Block.WithParent(_parent).WithUncles(falseUncle).TestObject; + UnclesValidator unclesValidator = new(_blockTree, _headerValidator, LimboLogs.Instance); + Assert.That(unclesValidator.Validate(toValidate.Header, toValidate.Uncles), Is.False); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/WithdrawalValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/WithdrawalValidatorTests.cs index 8d065f2666e..f1a92192a91 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/WithdrawalValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/WithdrawalValidatorTests.cs @@ -16,35 +16,35 @@ namespace Nethermind.Blockchain.Test.Validators; public class WithdrawalValidatorTests { - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Not_null_withdrawals_are_invalid_pre_shanghai() { ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, London.Instance)); BlockValidator blockValidator = new(Always.Valid, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); bool isValid = blockValidator.ValidateSuggestedBlock(Build.A.Block.WithWithdrawals(new Withdrawal[] { TestItem.WithdrawalA_1Eth, TestItem.WithdrawalB_2Eth }).TestObject); - Assert.False(isValid); + Assert.That(isValid, Is.False); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Null_withdrawals_are_invalid_post_shanghai() { ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Shanghai.Instance)); BlockValidator blockValidator = new(Always.Valid, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); bool isValid = blockValidator.ValidateSuggestedBlock(Build.A.Block.TestObject); - Assert.False(isValid); + Assert.That(isValid, Is.False); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Withdrawals_with_incorrect_withdrawals_root_are_invalid() { ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Shanghai.Instance)); BlockValidator blockValidator = new(Always.Valid, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); Withdrawal[] withdrawals = [TestItem.WithdrawalA_1Eth, TestItem.WithdrawalB_2Eth]; bool isValid = blockValidator.ValidateSuggestedBlock(Build.A.Block.WithWithdrawals(withdrawals).WithWithdrawalsRoot(TestItem.KeccakD).TestObject); - Assert.False(isValid); + Assert.That(isValid, Is.False); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Empty_withdrawals_are_valid_post_shanghai() { ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Shanghai.Instance)); @@ -52,10 +52,10 @@ public void Empty_withdrawals_are_valid_post_shanghai() Withdrawal[] withdrawals = []; Hash256 withdrawalRoot = new WithdrawalTrie(withdrawals).RootHash; bool isValid = blockValidator.ValidateSuggestedBlock(Build.A.Block.WithWithdrawals(withdrawals).WithWithdrawalsRoot(withdrawalRoot).TestObject); - Assert.True(isValid); + Assert.That(isValid, Is.True); } - [Test, Timeout(Timeout.MaxTestTime)] + [Test, MaxTime(Timeout.MaxTestTime)] public void Correct_withdrawals_block_post_shanghai() { ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Shanghai.Instance)); @@ -63,6 +63,6 @@ public void Correct_withdrawals_block_post_shanghai() Withdrawal[] withdrawals = [TestItem.WithdrawalA_1Eth, TestItem.WithdrawalB_2Eth]; Hash256 withdrawalRoot = new WithdrawalTrie(withdrawals).RootHash; bool isValid = blockValidator.ValidateSuggestedBlock(Build.A.Block.WithWithdrawals(withdrawals).WithWithdrawalsRoot(withdrawalRoot).TestObject); - Assert.True(isValid); + Assert.That(isValid, Is.True); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/DbBlocksLoaderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/DbBlocksLoaderTests.cs index bbe3446b9e4..d44aa2ad5ab 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/DbBlocksLoaderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/DbBlocksLoaderTests.cs @@ -13,238 +13,234 @@ using Nethermind.Logging; using Nethermind.Serialization.Rlp; using Nethermind.Specs; -using Nethermind.State.Repositories; -using Nethermind.Db.Blooms; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Visitors +namespace Nethermind.Blockchain.Test.Visitors; + +public class DbBlocksLoaderTests { - [TestFixture] - public class DbBlocksLoaderTests - { - private readonly int _dbLoadTimeout = 5000; + private readonly int _dbLoadTimeout = 5000; - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Can_load_blocks_from_db() + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Can_load_blocks_from_db() + { + for (int chainLength = 2; chainLength <= 32; chainLength++) { - for (int chainLength = 2; chainLength <= 32; chainLength++) - { - Block genesisBlock = Build.A.Block.Genesis.TestObject; - - BlockStore blockStore = new(new MemDb()); - MemDb blockInfosDb = new(); - MemDb headersDb = new(); + Block genesisBlock = Build.A.Block.Genesis.TestObject; - BlockTree testTree = Build.A.BlockTree(genesisBlock).OfChainLength(chainLength).TestObject; - for (int i = 0; i < testTree.Head!.Number + 1; i++) - { - Block ithBlock = testTree.FindBlock(i, BlockTreeLookupOptions.None)!; - blockStore.Insert(ithBlock); - - headersDb.Set(ithBlock.Hash!, Rlp.Encode(ithBlock.Header).Bytes); - - ChainLevelInfo ithLevel = new( - true, - blockInfos: new[] - { - new BlockInfo(ithBlock.Hash!, ithBlock.TotalDifficulty!.Value) {WasProcessed = true} - }); - blockInfosDb.Set(i, Rlp.Encode(ithLevel).Bytes); - } - - blockInfosDb.Set(Keccak.Zero, genesisBlock.Header.Hash!.Bytes); - headersDb.Set(genesisBlock.Header.Hash, Rlp.Encode(genesisBlock.Header).Bytes); - - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockStore(blockStore) - .WithHeadersDb(headersDb) - .WithBlockInfoDb(blockInfosDb) - .WithSpecProvider(OlympicSpecProvider.Instance) - .TestObject; - - DbBlocksLoader loader = new(blockTree, LimboNoErrorLogger.Instance); - await blockTree.Accept(loader, CancellationToken.None); - - Assert.That(blockTree.BestSuggestedHeader!.Hash, Is.EqualTo(testTree.Head.Hash), $"head {chainLength}"); - } - } + BlockStore blockStore = new(new MemDb()); + MemDb blockInfosDb = new(); + MemDb headersDb = new(); - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Can_load_blocks_from_db_odd() - { - for (int chainLength = 2; chainLength <= 32; chainLength++) + BlockTree testTree = Build.A.BlockTree(genesisBlock).OfChainLength(chainLength).TestObject; + for (int i = 0; i < testTree.Head!.Number + 1; i++) { - Block genesisBlock = Build.A.Block.Genesis.TestObject; - - BlockStore blockStore = new(new MemDb()); - MemDb blockInfosDb = new(); - MemDb headersDb = new(); - - BlockTree testTree = Build.A.BlockTree(genesisBlock).OfChainLength(chainLength).TestObject; - for (int i = 0; i < testTree.Head!.Number + 1; i++) - { - Block ithBlock = testTree.FindBlock(i, BlockTreeLookupOptions.None)!; - blockStore.Insert(ithBlock); + Block ithBlock = testTree.FindBlock(i, BlockTreeLookupOptions.None)!; + blockStore.Insert(ithBlock); - headersDb.Set(ithBlock.Hash!, Rlp.Encode(ithBlock.Header).Bytes); + headersDb.Set(ithBlock.Hash!, Rlp.Encode(ithBlock.Header).Bytes); - ChainLevelInfo ithLevel = new(true, blockInfos: new[] + ChainLevelInfo ithLevel = new( + true, + blockInfos: new[] { - new BlockInfo(ithBlock.Hash!, ithBlock.TotalDifficulty!.Value) + new BlockInfo(ithBlock.Hash!, ithBlock.TotalDifficulty!.Value) {WasProcessed = true} }); + blockInfosDb.Set(i, Rlp.Encode(ithLevel).Bytes); + } - blockInfosDb.Set(i, Rlp.Encode(ithLevel).Bytes); - } - - blockInfosDb.Set(Keccak.Zero, genesisBlock.Header.Hash!.Bytes); - headersDb.Set(genesisBlock.Header.Hash, Rlp.Encode(genesisBlock.Header).Bytes); + blockInfosDb.Set(Keccak.Zero, genesisBlock.Header.Hash!.Bytes); + headersDb.Set(genesisBlock.Header.Hash, Rlp.Encode(genesisBlock.Header).Bytes); - BlockTree blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockStore(blockStore) - .WithHeadersDb(headersDb) - .WithBlockInfoDb(blockInfosDb) - .WithSpecProvider(OlympicSpecProvider.Instance) - .TestObject; + BlockTree blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockStore(blockStore) + .WithHeadersDb(headersDb) + .WithBlockInfoDb(blockInfosDb) + .WithSpecProvider(OlympicSpecProvider.Instance) + .TestObject; - DbBlocksLoader loader = new(blockTree, LimboNoErrorLogger.Instance); - await blockTree.Accept(loader, CancellationToken.None); + DbBlocksLoader loader = new(blockTree, LimboNoErrorLogger.Instance); + await blockTree.Accept(loader, CancellationToken.None); - Assert.That(blockTree.BestSuggestedHeader!.Hash, Is.EqualTo(testTree.Head.Hash), $"head {chainLength}"); - } + Assert.That(blockTree.BestSuggestedHeader!.Hash, Is.EqualTo(testTree.Head.Hash), $"head {chainLength}"); } + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Can_load_from_DB_when_there_is_an_invalid_block_in_DB_and_a_valid_branch() + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Can_load_blocks_from_db_odd() + { + for (int chainLength = 2; chainLength <= 32; chainLength++) { + Block genesisBlock = Build.A.Block.Genesis.TestObject; + BlockStore blockStore = new(new MemDb()); MemDb blockInfosDb = new(); + MemDb headersDb = new(); + + BlockTree testTree = Build.A.BlockTree(genesisBlock).OfChainLength(chainLength).TestObject; + for (int i = 0; i < testTree.Head!.Number + 1; i++) + { + Block ithBlock = testTree.FindBlock(i, BlockTreeLookupOptions.None)!; + blockStore.Insert(ithBlock); - BlockTreeBuilder builder = Build.A.BlockTree() + headersDb.Set(ithBlock.Hash!, Rlp.Encode(ithBlock.Header).Bytes); + + ChainLevelInfo ithLevel = new(true, blockInfos: new[] + { + new BlockInfo(ithBlock.Hash!, ithBlock.TotalDifficulty!.Value) + }); + + blockInfosDb.Set(i, Rlp.Encode(ithLevel).Bytes); + } + + blockInfosDb.Set(Keccak.Zero, genesisBlock.Header.Hash!.Bytes); + headersDb.Set(genesisBlock.Header.Hash, Rlp.Encode(genesisBlock.Header).Bytes); + + BlockTree blockTree = Build.A.BlockTree() .WithoutSettingHead + .WithBlockStore(blockStore) + .WithHeadersDb(headersDb) .WithBlockInfoDb(blockInfosDb) - .WithBlockStore(blockStore); - - BlockTree tree1 = builder + .WithSpecProvider(OlympicSpecProvider.Instance) .TestObject; - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + DbBlocksLoader loader = new(blockTree, LimboNoErrorLogger.Instance); + await blockTree.Accept(loader, CancellationToken.None); - Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; - Block block2B = Build.A.Block.WithNumber(2).WithDifficulty(1).WithParent(block1B).TestObject; - Block block3B = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2B).TestObject; + Assert.That(blockTree.BestSuggestedHeader!.Hash, Is.EqualTo(testTree.Head.Hash), $"head {chainLength}"); + } + } - tree1.SuggestBlock(block0); - tree1.SuggestBlock(block1); // invalid block - tree1.SuggestBlock(block2); // invalid branch - tree1.SuggestBlock(block3); // invalid branch + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Can_load_from_DB_when_there_is_an_invalid_block_in_DB_and_a_valid_branch() + { + BlockStore blockStore = new(new MemDb()); + MemDb blockInfosDb = new(); - tree1.SuggestBlock(block1B); - tree1.SuggestBlock(block2B); - tree1.SuggestBlock(block3B); // expected to be head + BlockTreeBuilder builder = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .WithBlockStore(blockStore); - tree1.UpdateMainChain(block0); + BlockTree tree1 = builder + .TestObject; - BlockTree tree2 = Build.A.BlockTree() - .WithDatabaseFrom(builder) - .WithoutSettingHead - .TestObject; + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - CancellationTokenSource tokenSource = new(); - tokenSource.CancelAfter(_dbLoadTimeout); + Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; + Block block2B = Build.A.Block.WithNumber(2).WithDifficulty(1).WithParent(block1B).TestObject; + Block block3B = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2B).TestObject; - tree2.NewBestSuggestedBlock += (_, args) => - { - if (args.Block.Hash == block1.Hash) - { - tree2.DeleteInvalidBlock(args.Block); - } - else - { - tree2.UpdateMainChain(args.Block); - } - }; + tree1.SuggestBlock(block0); + tree1.SuggestBlock(block1); // invalid block + tree1.SuggestBlock(block2); // invalid branch + tree1.SuggestBlock(block3); // invalid branch - DbBlocksLoader loader = new(tree2, LimboNoErrorLogger.Instance, null, 1); - await tree2.Accept(loader, tokenSource.Token); + tree1.SuggestBlock(block1B); + tree1.SuggestBlock(block2B); + tree1.SuggestBlock(block3B); // expected to be head - Assert.That(tree2.BestKnownNumber, Is.EqualTo(3L), "best known"); - tree2.Head!.Header.Should().BeEquivalentTo(block3B.Header, options => { return options.Excluding(t => t.MaybeParent); }); - tree2.BestSuggestedHeader.Should().BeEquivalentTo(block3B.Header, options => { return options.Excluding(t => t.MaybeParent); }); + tree1.UpdateMainChain(block0); - Assert.IsNull(blockStore.Get(block1.Number, block1.Hash!), "block 1"); - Assert.IsNull(blockStore.Get(block2.Number, block2.Hash!), "block 2"); - Assert.IsNull(blockStore.Get(block3.Number, block3.Hash!), "block 3"); + BlockTree tree2 = Build.A.BlockTree() + .WithDatabaseFrom(builder) + .WithoutSettingHead + .TestObject; - Assert.NotNull(blockInfosDb.Get(1), "level 1"); - Assert.NotNull(blockInfosDb.Get(2), "level 2"); - Assert.NotNull(blockInfosDb.Get(3), "level 3"); - } + CancellationTokenSource tokenSource = new(); + tokenSource.CancelAfter(_dbLoadTimeout); - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Can_load_from_DB_when_there_is_only_an_invalid_chain_in_DB() + tree2.NewBestSuggestedBlock += (_, args) => { - BlockStore blockStore = new(new MemDb()); - MemDb blockInfosDb = new(); + if (args.Block.Hash == block1.Hash) + { + tree2.DeleteInvalidBlock(args.Block); + } + else + { + tree2.UpdateMainChain(args.Block); + } + }; - BlockTreeBuilder builder = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockInfoDb(blockInfosDb) - .WithBlockStore(blockStore); - BlockTree tree1 = builder.TestObject; + DbBlocksLoader loader = new(tree2, LimboNoErrorLogger.Instance, null, 1); + await tree2.Accept(loader, tokenSource.Token); - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + Assert.That(tree2.BestKnownNumber, Is.EqualTo(3L), "best known"); + tree2.Head!.Header.Should().BeEquivalentTo(block3B.Header, options => { return options.Excluding(t => t.MaybeParent); }); + tree2.BestSuggestedHeader.Should().BeEquivalentTo(block3B.Header, options => { return options.Excluding(t => t.MaybeParent); }); - tree1.SuggestBlock(block0); - tree1.SuggestBlock(block1); - tree1.SuggestBlock(block2); - tree1.SuggestBlock(block3); + Assert.That(blockStore.Get(block1.Number, block1.Hash!), Is.Null, "block 1"); + Assert.That(blockStore.Get(block2.Number, block2.Hash!), Is.Null, "block 2"); + Assert.That(blockStore.Get(block3.Number, block3.Hash!), Is.Null, "block 3"); - tree1.UpdateMainChain(block0); + Assert.That(blockInfosDb.Get(1), Is.Not.Null, "level 1"); + Assert.That(blockInfosDb.Get(2), Is.Not.Null, "level 2"); + Assert.That(blockInfosDb.Get(3), Is.Not.Null, "level 3"); + } - BlockTree tree2 = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .TestObject; + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Can_load_from_DB_when_there_is_only_an_invalid_chain_in_DB() + { + BlockStore blockStore = new(new MemDb()); + MemDb blockInfosDb = new(); + + BlockTreeBuilder builder = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .WithBlockStore(blockStore); + BlockTree tree1 = builder.TestObject; + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + + tree1.SuggestBlock(block0); + tree1.SuggestBlock(block1); + tree1.SuggestBlock(block2); + tree1.SuggestBlock(block3); + + tree1.UpdateMainChain(block0); - CancellationTokenSource tokenSource = new(); - tokenSource.CancelAfter(_dbLoadTimeout); + BlockTree tree2 = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .TestObject; - tree2.NewBestSuggestedBlock += (_, args) => + CancellationTokenSource tokenSource = new(); + tokenSource.CancelAfter(_dbLoadTimeout); + + tree2.NewBestSuggestedBlock += (_, args) => + { + if (args.Block.Hash == block1.Hash) { - if (args.Block.Hash == block1.Hash) - { - tree2.DeleteInvalidBlock(args.Block); - } - else - { - tree2.UpdateMainChain(args.Block); - } - }; + tree2.DeleteInvalidBlock(args.Block); + } + else + { + tree2.UpdateMainChain(args.Block); + } + }; - DbBlocksLoader loader = new(tree2, LimboNoErrorLogger.Instance, null, 1); - await tree2.Accept(loader, tokenSource.Token); + DbBlocksLoader loader = new(tree2, LimboNoErrorLogger.Instance, null, 1); + await tree2.Accept(loader, tokenSource.Token); - /* note the block tree historically loads one less block than it could */ + /* note the block tree historically loads one less block than it could */ - Assert.That(tree2.BestKnownNumber, Is.EqualTo(0L), "best known"); - Assert.That(tree2.Head!.Hash, Is.EqualTo(block0.Hash), "head"); - Assert.That(tree2.BestSuggestedHeader!.Hash, Is.EqualTo(block0.Hash), "suggested"); + Assert.That(tree2.BestKnownNumber, Is.EqualTo(0L), "best known"); + Assert.That(tree2.Head!.Hash, Is.EqualTo(block0.Hash), "head"); + Assert.That(tree2.BestSuggestedHeader!.Hash, Is.EqualTo(block0.Hash), "suggested"); - Assert.IsNull(blockStore.Get(block1.Number, block1.Hash!), "block 1"); - Assert.IsNull(blockStore.Get(block2.Number, block2.Hash!), "block 2"); - Assert.IsNull(blockStore.Get(block3.Number, block3.Hash!), "block 3"); + Assert.That(blockStore.Get(block1.Number, block1.Hash!), Is.Null, "block 1"); + Assert.That(blockStore.Get(block2.Number, block2.Hash!), Is.Null, "block 2"); + Assert.That(blockStore.Get(block3.Number, block3.Hash!), Is.Null, "block 3"); - Assert.IsNull(blockInfosDb.Get(1), "level 1"); - Assert.IsNull(blockInfosDb.Get(2), "level 2"); - Assert.IsNull(blockInfosDb.Get(3), "level 3"); - } + Assert.That(blockInfosDb.Get(1), Is.Null, "level 1"); + Assert.That(blockInfosDb.Get(2), Is.Null, "level 2"); + Assert.That(blockInfosDb.Get(3), Is.Null, "level 3"); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs index a6cc779152e..366cbec9617 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs @@ -11,219 +11,215 @@ using Nethermind.Core.Test.Builders; using Nethermind.Db; using Nethermind.Logging; -using Nethermind.Specs; -using Nethermind.State.Repositories; -using Nethermind.Db.Blooms; using Nethermind.JsonRpc.Test.Modules; using Nethermind.State; using NSubstitute; using NUnit.Framework; -namespace Nethermind.Blockchain.Test.Visitors +namespace Nethermind.Blockchain.Test.Visitors; + +public class StartupTreeFixerTests { - public class StartupTreeFixerTests + [Test, MaxTime(Timeout.MaxTestTime), Ignore("Not implemented")] + public void Cleans_missing_references_from_chain_level_info() { - [Test, Timeout(Timeout.MaxTestTime), Ignore("Not implemented")] - public void Cleans_missing_references_from_chain_level_info() - { - // for now let us just look at the warnings (before we start adding cleanup) - } + // for now let us just look at the warnings (before we start adding cleanup) + } - [Test, Timeout(Timeout.MaxTestTime), Ignore("Not implemented")] - public void Warns_when_blocks_are_marked_as_processed_but_there_are_no_bodies() - { - // for now let us just look at the warnings (before we start adding cleanup) - } + [Test, MaxTime(Timeout.MaxTestTime), Ignore("Not implemented")] + public void Warns_when_blocks_are_marked_as_processed_but_there_are_no_bodies() + { + // for now let us just look at the warnings (before we start adding cleanup) + } - [Test, Timeout(Timeout.MaxTestTime), Ignore("Not implemented")] - public void Warns_when_there_is_a_hole_in_processed_blocks() - { - } + [Test, MaxTime(Timeout.MaxTestTime), Ignore("Not implemented")] + public void Warns_when_there_is_a_hole_in_processed_blocks() + { + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Deletes_everything_after_the_missing_level() - { - MemDb blockInfosDb = new(); - BlockTreeBuilder builder = Build.A.BlockTree(); - BlockTree tree = builder - .WithoutSettingHead - .WithBlockInfoDb(blockInfosDb) - .TestObject; - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; - Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestBlock(block3); - tree.SuggestBlock(block4); - tree.SuggestHeader(block5.Header); - - tree.UpdateMainChain(block0); - tree.UpdateMainChain(block1); - tree.UpdateMainChain(block2); - - blockInfosDb.Delete(3); - - tree = Build.A.BlockTree() - .WithoutSettingHead - .WithDatabaseFrom(builder) - .TestObject; - - StartupBlockTreeFixer fixer = new(new SyncConfig(), tree, Substitute.For(), LimboNoErrorLogger.Instance); - await tree.Accept(fixer, CancellationToken.None); - - Assert.Null(blockInfosDb.Get(3), "level 3"); - Assert.Null(blockInfosDb.Get(4), "level 4"); - Assert.Null(blockInfosDb.Get(5), "level 5"); - - tree.Head!.Header.Should().BeEquivalentTo(block2.Header, options => options.Excluding(t => t.MaybeParent)); - tree.BestSuggestedHeader.Should().BeEquivalentTo(block2.Header, options => options.Excluding(t => t.MaybeParent)); - tree.BestSuggestedBody?.Body.Should().BeEquivalentTo(block2.Body); - tree.BestKnownNumber.Should().Be(2); - } + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Deletes_everything_after_the_missing_level() + { + MemDb blockInfosDb = new(); + BlockTreeBuilder builder = Build.A.BlockTree(); + BlockTree tree = builder + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .TestObject; + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; + Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestBlock(block3); + tree.SuggestBlock(block4); + tree.SuggestHeader(block5.Header); + + tree.UpdateMainChain(block0); + tree.UpdateMainChain(block1); + tree.UpdateMainChain(block2); + + blockInfosDb.Delete(3); + + tree = Build.A.BlockTree() + .WithoutSettingHead + .WithDatabaseFrom(builder) + .TestObject; + + StartupBlockTreeFixer fixer = new(new SyncConfig(), tree, Substitute.For(), LimboNoErrorLogger.Instance); + await tree.Accept(fixer, CancellationToken.None); + + Assert.That(blockInfosDb.Get(3), Is.Null, "level 3"); + Assert.That(blockInfosDb.Get(4), Is.Null, "level 4"); + Assert.That(blockInfosDb.Get(5), Is.Null, "level 5"); + + tree.Head!.Header.Should().BeEquivalentTo(block2.Header, options => options.Excluding(t => t.MaybeParent)); + tree.BestSuggestedHeader.Should().BeEquivalentTo(block2.Header, options => options.Excluding(t => t.MaybeParent)); + tree.BestSuggestedBody?.Body.Should().BeEquivalentTo(block2.Body); + tree.BestKnownNumber.Should().Be(2); + } + + [Retry(30)] + [MaxTime(Timeout.MaxTestTime * 4)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(4)] + [TestCase(5)] + [TestCase(6)] + [TestCase(65)] + public async Task Suggesting_blocks_works_correctly_after_processor_restart(int suggestedBlocksAmount) + { + TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); + await testRpc.BlockchainProcessor.StopAsync(); + IBlockTree tree = testRpc.BlockTree; + long startingBlockNumber = tree.Head!.Number; - [Retry(30)] - [Timeout(Timeout.MaxTestTime * 4)] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - [TestCase(4)] - [TestCase(5)] - [TestCase(6)] - [TestCase(65)] - public async Task Suggesting_blocks_works_correctly_after_processor_restart(int suggestedBlocksAmount) + SuggestNumberOfBlocks(tree, suggestedBlocksAmount); + + // simulating restarts - we stopped the old blockchain processor and create the new one + BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, + testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); + newBlockchainProcessor.Start(); + testRpc.BlockchainProcessor = newBlockchainProcessor; + + // fixing after restart + StartupBlockTreeFixer fixer = new(new SyncConfig(), tree, testRpc.StateReader, LimboNoErrorLogger.Instance, 5); + await tree.Accept(fixer, CancellationToken.None); + + // waiting for N new heads + for (int i = 0; i < suggestedBlocksAmount; ++i) { - TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); - await testRpc.BlockchainProcessor.StopAsync(); - IBlockTree tree = testRpc.BlockTree; - long startingBlockNumber = tree.Head!.Number; - - SuggestNumberOfBlocks(tree, suggestedBlocksAmount); - - // simulating restarts - we stopped the old blockchain processor and create the new one - BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, - testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); - newBlockchainProcessor.Start(); - testRpc.BlockchainProcessor = newBlockchainProcessor; - - // fixing after restart - StartupBlockTreeFixer fixer = new(new SyncConfig(), tree, testRpc.StateReader, LimboNoErrorLogger.Instance, 5); - await tree.Accept(fixer, CancellationToken.None); - - // waiting for N new heads - for (int i = 0; i < suggestedBlocksAmount; ++i) - { - await testRpc.WaitForNewHead(); - } - - // add a new block at the end - await testRpc.AddBlock(); - Assert.That(tree.Head!.Number, Is.EqualTo(startingBlockNumber + suggestedBlocksAmount + 1)); + await testRpc.WaitForNewHead(); } - [Timeout(Timeout.MaxTestTime)] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - [TestCase(6)] - public async Task Fixer_should_not_suggest_block_without_state(int suggestedBlocksAmount) - { - TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); - await testRpc.BlockchainProcessor.StopAsync(); - IBlockTree tree = testRpc.BlockTree; + // add a new block at the end + await testRpc.AddBlock(); + Assert.That(tree.Head!.Number, Is.EqualTo(startingBlockNumber + suggestedBlocksAmount + 1)); + } - SuggestNumberOfBlocks(tree, suggestedBlocksAmount); + [MaxTime(Timeout.MaxTestTime)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(6)] + public async Task Fixer_should_not_suggest_block_without_state(int suggestedBlocksAmount) + { + TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); + await testRpc.BlockchainProcessor.StopAsync(); + IBlockTree tree = testRpc.BlockTree; - // simulating restarts - we stopped the old blockchain processor and create the new one - BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, - testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); - newBlockchainProcessor.Start(); - testRpc.BlockchainProcessor = newBlockchainProcessor; + SuggestNumberOfBlocks(tree, suggestedBlocksAmount); - // we create a new empty db for stateDb so we shouldn't suggest new blocks - IBlockTreeVisitor fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, Substitute.For(), LimboNoErrorLogger.Instance, 5); - BlockVisitOutcome result = await fixer.VisitBlock(tree.Head!, CancellationToken.None); + // simulating restarts - we stopped the old blockchain processor and create the new one + BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, + testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); + newBlockchainProcessor.Start(); + testRpc.BlockchainProcessor = newBlockchainProcessor; - Assert.That(result, Is.EqualTo(BlockVisitOutcome.None)); - } + // we create a new empty db for stateDb so we shouldn't suggest new blocks + IBlockTreeVisitor fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, Substitute.For(), LimboNoErrorLogger.Instance, 5); + BlockVisitOutcome result = await fixer.VisitBlock(tree.Head!, CancellationToken.None); - [Test, Timeout(Timeout.MaxTestTime)] - public async Task Fixer_should_not_suggest_block_with_null_block() - { - TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); - await testRpc.BlockchainProcessor.StopAsync(); - IBlockTree tree = testRpc.BlockTree; + Assert.That(result, Is.EqualTo(BlockVisitOutcome.None)); + } - SuggestNumberOfBlocks(tree, 1); + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task Fixer_should_not_suggest_block_with_null_block() + { + TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); + await testRpc.BlockchainProcessor.StopAsync(); + IBlockTree tree = testRpc.BlockTree; - // simulating restarts - we stopped the old blockchain processor and create the new one - BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, - testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); - newBlockchainProcessor.Start(); - testRpc.BlockchainProcessor = newBlockchainProcessor; + SuggestNumberOfBlocks(tree, 1); - IBlockTreeVisitor fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, testRpc.StateReader, LimboNoErrorLogger.Instance, 5); - BlockVisitOutcome result = await fixer.VisitBlock(null!, CancellationToken.None); + // simulating restarts - we stopped the old blockchain processor and create the new one + BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, + testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); + newBlockchainProcessor.Start(); + testRpc.BlockchainProcessor = newBlockchainProcessor; - Assert.That(result, Is.EqualTo(BlockVisitOutcome.None)); - } + IBlockTreeVisitor fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, testRpc.StateReader, LimboNoErrorLogger.Instance, 5); + BlockVisitOutcome result = await fixer.VisitBlock(null!, CancellationToken.None); - private static void SuggestNumberOfBlocks(IBlockTree blockTree, int blockAmount) - { - Block newParent = blockTree.Head!; - for (int i = 0; i < blockAmount; ++i) - { - Block newBlock = Build.A.Block - .WithNumber(newParent.Number + 1) - .WithDifficulty(newParent.Difficulty + 1) - .WithParent(newParent) - .WithStateRoot(newParent.StateRoot!).TestObject; - blockTree.SuggestBlock(newBlock); - newParent = newBlock; - } - } + Assert.That(result, Is.EqualTo(BlockVisitOutcome.None)); + } - [Test, Timeout(Timeout.MaxTestTime)] - public async Task When_head_block_is_followed_by_a_block_bodies_gap_it_should_delete_all_levels_after_the_gap_start() + private static void SuggestNumberOfBlocks(IBlockTree blockTree, int blockAmount) + { + Block newParent = blockTree.Head!; + for (int i = 0; i < blockAmount; ++i) { - MemDb blockInfosDb = new(); - - BlockTree tree = Build.A.BlockTree() - .WithoutSettingHead - .WithBlockInfoDb(blockInfosDb) - .TestObject; - - Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; - Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; - Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; - Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; - Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; - Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; - - tree.SuggestBlock(block0); - tree.SuggestBlock(block1); - tree.SuggestBlock(block2); - tree.SuggestHeader(block3.Header); - tree.SuggestHeader(block4.Header); - tree.SuggestBlock(block5); - - tree.UpdateMainChain(block2); - - StartupBlockTreeFixer fixer = new(new SyncConfig(), tree, Substitute.For(), LimboNoErrorLogger.Instance); - await tree.Accept(fixer, CancellationToken.None); - - Assert.Null(blockInfosDb.Get(3), "level 3"); - Assert.Null(blockInfosDb.Get(4), "level 4"); - Assert.Null(blockInfosDb.Get(5), "level 5"); - - Assert.That(tree.BestKnownNumber, Is.EqualTo(2L), "best known"); - Assert.That(tree.Head?.Header, Is.EqualTo(block2.Header), "head"); - Assert.That(tree.BestSuggestedHeader!.Hash, Is.EqualTo(block2.Hash), "suggested"); + Block newBlock = Build.A.Block + .WithNumber(newParent.Number + 1) + .WithDifficulty(newParent.Difficulty + 1) + .WithParent(newParent) + .WithStateRoot(newParent.StateRoot!).TestObject; + blockTree.SuggestBlock(newBlock); + newParent = newBlock; } } + + [Test, MaxTime(Timeout.MaxTestTime)] + public async Task When_head_block_is_followed_by_a_block_bodies_gap_it_should_delete_all_levels_after_the_gap_start() + { + MemDb blockInfosDb = new(); + + BlockTree tree = Build.A.BlockTree() + .WithoutSettingHead + .WithBlockInfoDb(blockInfosDb) + .TestObject; + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; + Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; + Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; + + tree.SuggestBlock(block0); + tree.SuggestBlock(block1); + tree.SuggestBlock(block2); + tree.SuggestHeader(block3.Header); + tree.SuggestHeader(block4.Header); + tree.SuggestBlock(block5); + + tree.UpdateMainChain(block2); + + StartupBlockTreeFixer fixer = new(new SyncConfig(), tree, Substitute.For(), LimboNoErrorLogger.Instance); + await tree.Accept(fixer, CancellationToken.None); + + Assert.That(blockInfosDb.Get(3), Is.Null, "level 3"); + Assert.That(blockInfosDb.Get(4), Is.Null, "level 4"); + Assert.That(blockInfosDb.Get(5), Is.Null, "level 5"); + + Assert.That(tree.BestKnownNumber, Is.EqualTo(2L), "best known"); + Assert.That(tree.Head?.Header, Is.EqualTo(block2.Header), "head"); + Assert.That(tree.BestSuggestedHeader!.Hash, Is.EqualTo(block2.Hash), "suggested"); + } } diff --git a/src/Nethermind/Nethermind.Cli.Test/StatementHistoryManagerTests.cs b/src/Nethermind/Nethermind.Cli.Test/StatementHistoryManagerTests.cs index 0d92355cf77..0758bcf4d02 100644 --- a/src/Nethermind/Nethermind.Cli.Test/StatementHistoryManagerTests.cs +++ b/src/Nethermind/Nethermind.Cli.Test/StatementHistoryManagerTests.cs @@ -39,23 +39,23 @@ public void should_write_removed_to_history_if_secured_command_received() _historyManager.UpdateHistory("notSecured"); - CollectionAssert.AreEqual(new[] { "notSecured" }, fileContents); - CollectionAssert.AreEqual(new[] { "notSecured" }, ReadLine.GetHistory()); + Assert.That(new[] { "notSecured" }, Is.EqualTo(fileContents).AsCollection); + Assert.That(new[] { "notSecured" }, Is.EqualTo(ReadLine.GetHistory()).AsCollection); _historyManager.UpdateHistory("unlockAccount"); - CollectionAssert.AreEqual(new[] { "notSecured" }, fileContents); - CollectionAssert.AreEqual(new[] { "notSecured", "*removed*" }, ReadLine.GetHistory()); + Assert.That(new[] { "notSecured" }, Is.EqualTo(fileContents).AsCollection); + Assert.That(new[] { "notSecured", "*removed*" }, Is.EqualTo(ReadLine.GetHistory()).AsCollection); _historyManager.UpdateHistory("notSecured2"); - CollectionAssert.AreEqual(new[] { "notSecured", "notSecured2" }, fileContents); - CollectionAssert.AreEqual(new[] { "notSecured", "*removed*", "notSecured2" }, ReadLine.GetHistory()); + Assert.That(new[] { "notSecured", "notSecured2" }, Is.EqualTo(fileContents).AsCollection); + Assert.That(new[] { "notSecured", "*removed*", "notSecured2" }, Is.EqualTo(ReadLine.GetHistory()).AsCollection); _historyManager.UpdateHistory("newAccount"); - CollectionAssert.AreEqual(new[] { "notSecured", "notSecured2" }, fileContents); - CollectionAssert.AreEqual(new[] { "notSecured", "*removed*", "notSecured2", "*removed*" }, ReadLine.GetHistory()); + Assert.That(new[] { "notSecured", "notSecured2" }, Is.EqualTo(fileContents).AsCollection); + Assert.That(new[] { "notSecured", "*removed*", "notSecured2", "*removed*" }, Is.EqualTo(ReadLine.GetHistory()).AsCollection); } [Test] @@ -68,6 +68,6 @@ public void Init_should_read_history_from_file() _historyManager.Init(); - CollectionAssert.AreEqual(fileContents, ReadLine.GetHistory()); + Assert.That(fileContents, Is.EqualTo(ReadLine.GetHistory()).AsCollection); } } diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs index f27ce90d447..2769e365735 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using FluentAssertions; using Nethermind.Blockchain; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; @@ -39,899 +38,899 @@ using NUnit.Framework; using Nethermind.Config; -namespace Nethermind.Clique.Test +namespace Nethermind.Clique.Test; + +[Parallelizable(ParallelScope.All)] +public class CliqueBlockProducerTests { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class CliqueBlockProducerTests + private class On { - private class On - { - private readonly ILogManager _logManager = LimboLogs.Instance; - // private ILogManager _logManager = new OneLoggerLogManager(new ConsoleAsyncLogger(LogLevel.Debug)); - private readonly ILogger _logger; - private static readonly ITimestamper _timestamper = Timestamper.Default; - private readonly CliqueConfig _cliqueConfig; - private readonly EthereumEcdsa _ethereumEcdsa = new(BlockchainIds.Goerli); - private readonly Dictionary _logManagers = new(); - private readonly Dictionary _snapshotManager = new(); - private readonly Dictionary _blockTrees = new(); - private readonly Dictionary _blockEvents = new(); - private readonly Dictionary _producers = new(); - private readonly Dictionary _pools = new(); - - private On() - : this(15) - { - } - - private On(ulong blockPeriod) - { - _logger = _logManager.GetClassLogger(); - _cliqueConfig = new CliqueConfig(); - _cliqueConfig.BlockPeriod = blockPeriod; - _cliqueConfig.Epoch = 30000; - _genesis = GetGenesis(); - _genesis3Validators = GetGenesis(3); - } + private readonly ILogManager _logManager = LimboLogs.Instance; + // private ILogManager _logManager = new OneLoggerLogManager(new ConsoleAsyncLogger(LogLevel.Debug)); + private readonly ILogger _logger; + private static readonly ITimestamper _timestamper = Timestamper.Default; + private readonly CliqueConfig _cliqueConfig; + private readonly EthereumEcdsa _ethereumEcdsa = new(BlockchainIds.Goerli); + private readonly Dictionary _logManagers = new(); + private readonly Dictionary _snapshotManager = new(); + private readonly Dictionary _blockTrees = new(); + private readonly Dictionary _blockEvents = new(); + private readonly Dictionary _producers = new(); + private readonly Dictionary _pools = new(); + + private On() + : this(15) + { + } - public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = false) - { - if (_logger.IsInfo) _logger.Info($"CREATING NODE {privateKey.Address}"); - _logManagers[privateKey] = LimboLogs.Instance; - // _logManagers[privateKey] = new OneLoggerLogManager(new ConsoleAsyncLogger(LogLevel.Debug, $"{privateKey.Address} ")); - ILogManager nodeLogManager = _logManagers[privateKey]; - - AutoResetEvent newHeadBlockEvent = new(false); - _blockEvents.Add(privateKey, newHeadBlockEvent); - - MemDb blocksDb = new(); - MemDb stateDb = new(); - MemDb codeDb = new(); - - ISpecProvider specProvider = GoerliSpecProvider.Instance; - - var trieStore = new TrieStore(stateDb, nodeLogManager); - StateReader stateReader = new(trieStore, codeDb, nodeLogManager); - WorldState stateProvider = new(trieStore, codeDb, nodeLogManager); - stateProvider.CreateAccount(TestItem.PrivateKeyD.Address, 100.Ether()); - GoerliSpecProvider goerliSpecProvider = GoerliSpecProvider.Instance; - stateProvider.Commit(goerliSpecProvider.GenesisSpec); - stateProvider.CommitTree(0); - - BlockTree blockTree = Build.A.BlockTree() - .WithSpecProvider(goerliSpecProvider) - .WithBlocksDb(blocksDb) - .WithoutSettingHead - .TestObject; - - blockTree.NewHeadBlock += (sender, args) => { _blockEvents[privateKey].Set(); }; - ITransactionComparerProvider transactionComparerProvider = - new TransactionComparerProvider(specProvider, blockTree); - - TxPool.TxPool txPool = new(_ethereumEcdsa, - new BlobTxStorage(), - new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(GoerliSpecProvider.Instance), blockTree, stateProvider), - new TxPoolConfig(), - new TxValidator(goerliSpecProvider.ChainId), - _logManager, - transactionComparerProvider.GetDefaultComparer()); - _pools[privateKey] = txPool; - - BlockhashProvider blockhashProvider = new(blockTree, specProvider, stateProvider, LimboLogs.Instance); - _blockTrees.Add(privateKey, blockTree); - - SnapshotManager snapshotManager = new(_cliqueConfig, blocksDb, blockTree, _ethereumEcdsa, nodeLogManager); - _snapshotManager[privateKey] = snapshotManager; - CliqueSealer cliqueSealer = new(new Signer(BlockchainIds.Goerli, privateKey, LimboLogs.Instance), _cliqueConfig, snapshotManager, nodeLogManager); - - _genesis.Header.StateRoot = _genesis3Validators.Header.StateRoot = stateProvider.StateRoot; - _genesis.Header.Hash = _genesis.Header.CalculateHash(); - _genesis3Validators.Header.Hash = _genesis3Validators.Header.CalculateHash(); - - CodeInfoRepository codeInfoRepository = new(); - TransactionProcessor transactionProcessor = new(goerliSpecProvider, stateProvider, - new VirtualMachine(blockhashProvider, specProvider, codeInfoRepository, nodeLogManager), - codeInfoRepository, - nodeLogManager); - BlockProcessor blockProcessor = new( - goerliSpecProvider, - Always.Valid, - NoBlockRewards.Instance, - new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), - stateProvider, - NullReceiptStorage.Instance, - transactionProcessor, - new BeaconBlockRootHandler(transactionProcessor), - new BlockhashStore(goerliSpecProvider, stateProvider), - nodeLogManager); - - BlockchainProcessor processor = new(blockTree, blockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); - processor.Start(); - - IReadOnlyTrieStore minerTrieStore = trieStore.AsReadOnly(); - - WorldState minerStateProvider = new(minerTrieStore, codeDb, nodeLogManager); - VirtualMachine minerVirtualMachine = new(blockhashProvider, specProvider, codeInfoRepository, nodeLogManager); - TransactionProcessor minerTransactionProcessor = new(goerliSpecProvider, minerStateProvider, minerVirtualMachine, codeInfoRepository, nodeLogManager); - - BlockProcessor minerBlockProcessor = new( - goerliSpecProvider, - Always.Valid, - NoBlockRewards.Instance, - new BlockProcessor.BlockProductionTransactionsExecutor(minerTransactionProcessor, minerStateProvider, goerliSpecProvider, _logManager), - minerStateProvider, - NullReceiptStorage.Instance, - minerTransactionProcessor, - new BeaconBlockRootHandler(minerTransactionProcessor), - new BlockhashStore(goerliSpecProvider, minerStateProvider), - nodeLogManager); - - BlockchainProcessor minerProcessor = new(blockTree, minerBlockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); - - if (withGenesisAlreadyProcessed) - { - ProcessGenesis(privateKey); - } - BlocksConfig blocksConfig = new() - { - MinGasPrice = 0 - }; - ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(nodeLogManager, specProvider, blocksConfig); - TxPoolTxSource txPoolTxSource = new(txPool, specProvider, transactionComparerProvider, nodeLogManager, txFilterPipeline); - CliqueBlockProducer blockProducer = new( - txPoolTxSource, - minerProcessor, - minerStateProvider, - _timestamper, - new CryptoRandom(), - snapshotManager, - cliqueSealer, - new TargetAdjustedGasLimitCalculator(goerliSpecProvider, new BlocksConfig()), - MainnetSpecProvider.Instance, - _cliqueConfig, - nodeLogManager); - - CliqueBlockProducerRunner producerRunner = new CliqueBlockProducerRunner( - blockTree, - _timestamper, - new CryptoRandom(), - snapshotManager, - blockProducer, - _cliqueConfig, - LimboLogs.Instance); - - producerRunner.Start(); - - ProducedBlockSuggester suggester = new ProducedBlockSuggester(blockTree, producerRunner); - - _producers.Add(privateKey, producerRunner); + private On(ulong blockPeriod) + { + _logger = _logManager.GetClassLogger(); + _cliqueConfig = new CliqueConfig(); + _cliqueConfig.BlockPeriod = blockPeriod; + _cliqueConfig.Epoch = 30000; + _genesis = GetGenesis(); + _genesis3Validators = GetGenesis(3); + } - return this; - } + public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = false) + { + if (_logger.IsInfo) _logger.Info($"CREATING NODE {privateKey.Address}"); + _logManagers[privateKey] = LimboLogs.Instance; + // _logManagers[privateKey] = new OneLoggerLogManager(new ConsoleAsyncLogger(LogLevel.Debug, $"{privateKey.Address} ")); + ILogManager nodeLogManager = _logManagers[privateKey]; + + AutoResetEvent newHeadBlockEvent = new(false); + _blockEvents.Add(privateKey, newHeadBlockEvent); + + MemDb blocksDb = new(); + MemDb stateDb = new(); + MemDb codeDb = new(); + + ISpecProvider specProvider = GoerliSpecProvider.Instance; + + var trieStore = new TrieStore(stateDb, nodeLogManager); + StateReader stateReader = new(trieStore, codeDb, nodeLogManager); + WorldState stateProvider = new(trieStore, codeDb, nodeLogManager); + stateProvider.CreateAccount(TestItem.PrivateKeyD.Address, 100.Ether()); + GoerliSpecProvider goerliSpecProvider = GoerliSpecProvider.Instance; + stateProvider.Commit(goerliSpecProvider.GenesisSpec); + stateProvider.CommitTree(0); + + BlockTree blockTree = Build.A.BlockTree() + .WithSpecProvider(goerliSpecProvider) + .WithBlocksDb(blocksDb) + .WithoutSettingHead + .TestObject; + + blockTree.NewHeadBlock += (sender, args) => { _blockEvents[privateKey].Set(); }; + ITransactionComparerProvider transactionComparerProvider = + new TransactionComparerProvider(specProvider, blockTree); + + TxPool.TxPool txPool = new(_ethereumEcdsa, + new BlobTxStorage(), + new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(GoerliSpecProvider.Instance), blockTree, stateProvider), + new TxPoolConfig(), + new TxValidator(goerliSpecProvider.ChainId), + _logManager, + transactionComparerProvider.GetDefaultComparer()); + _pools[privateKey] = txPool; + + BlockhashProvider blockhashProvider = new(blockTree, specProvider, stateProvider, LimboLogs.Instance); + _blockTrees.Add(privateKey, blockTree); + + SnapshotManager snapshotManager = new(_cliqueConfig, blocksDb, blockTree, _ethereumEcdsa, nodeLogManager); + _snapshotManager[privateKey] = snapshotManager; + CliqueSealer cliqueSealer = new(new Signer(BlockchainIds.Goerli, privateKey, LimboLogs.Instance), _cliqueConfig, snapshotManager, nodeLogManager); + + _genesis.Header.StateRoot = _genesis3Validators.Header.StateRoot = stateProvider.StateRoot; + _genesis.Header.Hash = _genesis.Header.CalculateHash(); + _genesis3Validators.Header.Hash = _genesis3Validators.Header.CalculateHash(); + + CodeInfoRepository codeInfoRepository = new(); + TransactionProcessor transactionProcessor = new(goerliSpecProvider, stateProvider, + new VirtualMachine(blockhashProvider, specProvider, codeInfoRepository, nodeLogManager), + codeInfoRepository, + nodeLogManager); + BlockProcessor blockProcessor = new( + goerliSpecProvider, + Always.Valid, + NoBlockRewards.Instance, + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), + stateProvider, + NullReceiptStorage.Instance, + transactionProcessor, + new BeaconBlockRootHandler(transactionProcessor), + new BlockhashStore(goerliSpecProvider, stateProvider), + nodeLogManager); + + BlockchainProcessor processor = new(blockTree, blockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); + processor.Start(); + + IReadOnlyTrieStore minerTrieStore = trieStore.AsReadOnly(); + + WorldState minerStateProvider = new(minerTrieStore, codeDb, nodeLogManager); + VirtualMachine minerVirtualMachine = new(blockhashProvider, specProvider, codeInfoRepository, nodeLogManager); + TransactionProcessor minerTransactionProcessor = new(goerliSpecProvider, minerStateProvider, minerVirtualMachine, codeInfoRepository, nodeLogManager); + + BlockProcessor minerBlockProcessor = new( + goerliSpecProvider, + Always.Valid, + NoBlockRewards.Instance, + new BlockProcessor.BlockProductionTransactionsExecutor(minerTransactionProcessor, minerStateProvider, goerliSpecProvider, _logManager), + minerStateProvider, + NullReceiptStorage.Instance, + minerTransactionProcessor, + new BeaconBlockRootHandler(minerTransactionProcessor), + new BlockhashStore(goerliSpecProvider, minerStateProvider), + nodeLogManager); + + BlockchainProcessor minerProcessor = new(blockTree, minerBlockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); + + if (withGenesisAlreadyProcessed) + { + ProcessGenesis(privateKey); + } + BlocksConfig blocksConfig = new() + { + MinGasPrice = 0 + }; + ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(nodeLogManager, specProvider, blocksConfig); + TxPoolTxSource txPoolTxSource = new(txPool, specProvider, transactionComparerProvider, nodeLogManager, txFilterPipeline); + CliqueBlockProducer blockProducer = new( + txPoolTxSource, + minerProcessor, + minerStateProvider, + _timestamper, + new CryptoRandom(), + snapshotManager, + cliqueSealer, + new TargetAdjustedGasLimitCalculator(goerliSpecProvider, new BlocksConfig()), + MainnetSpecProvider.Instance, + _cliqueConfig, + nodeLogManager); + + CliqueBlockProducerRunner producerRunner = new CliqueBlockProducerRunner( + blockTree, + _timestamper, + new CryptoRandom(), + snapshotManager, + blockProducer, + _cliqueConfig, + LimboLogs.Instance); + + producerRunner.Start(); + + ProducedBlockSuggester suggester = new ProducedBlockSuggester(blockTree, producerRunner); + + _producers.Add(privateKey, producerRunner); + + return this; + } - public static On Goerli => new(); + public static On Goerli => new(); - public static On FastGoerli => new(1); + public static On FastGoerli => new(1); - private readonly Block _genesis3Validators; + private readonly Block _genesis3Validators; - private readonly Block _genesis; + private readonly Block _genesis; - private Block GetGenesis(int validatorsCount = 2) - { - Hash256 parentHash = Keccak.Zero; - Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; - Address beneficiary = Address.Zero; - UInt256 difficulty = new(1); - long number = 0L; - int gasLimit = 4700000; - ulong timestamp = _timestamper.UnixTime.Seconds - _cliqueConfig.BlockPeriod; - string extraDataHex = "0x2249276d20646f6e652077616974696e672e2e2e20666f7220626c6f636b2066"; - extraDataHex += TestItem.PrivateKeyA.Address.ToString(false).Replace("0x", string.Empty); - extraDataHex += TestItem.PrivateKeyB.Address.ToString(false).Replace("0x", string.Empty); - if (validatorsCount > 2) - { - extraDataHex += TestItem.PrivateKeyC.Address.ToString(false).Replace("0x", string.Empty); - } + private Block GetGenesis(int validatorsCount = 2) + { + Hash256 parentHash = Keccak.Zero; + Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; + Address beneficiary = Address.Zero; + UInt256 difficulty = new(1); + long number = 0L; + int gasLimit = 4700000; + ulong timestamp = _timestamper.UnixTime.Seconds - _cliqueConfig.BlockPeriod; + string extraDataHex = "0x2249276d20646f6e652077616974696e672e2e2e20666f7220626c6f636b2066"; + extraDataHex += TestItem.PrivateKeyA.Address.ToString(false).Replace("0x", string.Empty); + extraDataHex += TestItem.PrivateKeyB.Address.ToString(false).Replace("0x", string.Empty); + if (validatorsCount > 2) + { + extraDataHex += TestItem.PrivateKeyC.Address.ToString(false).Replace("0x", string.Empty); + } + + extraDataHex += "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + + byte[] extraData = Bytes.FromHexString(extraDataHex); + BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); + Block genesis = new(header); + genesis.Header.Hash = genesis.Header.CalculateHash(); + genesis.Header.StateRoot = Keccak.EmptyTreeHash; + genesis.Header.TxRoot = Keccak.EmptyTreeHash; + genesis.Header.ReceiptsRoot = Keccak.EmptyTreeHash; + genesis.Header.Bloom = Bloom.Empty; + + return genesis; + } - extraDataHex += "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + public On VoteToInclude(PrivateKey nodeId, Address address) + { + if (_logger.IsInfo) _logger.Info($"VOTE {address} IN"); + _producers[nodeId].CastVote(address, true); + return this; + } - byte[] extraData = Bytes.FromHexString(extraDataHex); - BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); - Block genesis = new(header); - genesis.Header.Hash = genesis.Header.CalculateHash(); - genesis.Header.StateRoot = Keccak.EmptyTreeHash; - genesis.Header.TxRoot = Keccak.EmptyTreeHash; - genesis.Header.ReceiptsRoot = Keccak.EmptyTreeHash; - genesis.Header.Bloom = Bloom.Empty; + public On UncastVote(PrivateKey nodeId, Address address) + { + if (_logger.IsInfo) _logger.Info($"UNCAST VOTE ON {address}"); + _producers[nodeId].UncastVote(address); + return this; + } - return genesis; - } + public On IsProducingBlocks(PrivateKey nodeId, bool expected, ulong? maxInterval) + { + if (_logger.IsInfo) _logger.Info($"IsProducingBlocks"); + Assert.That(((IBlockProducerRunner)_producers[nodeId]).IsProducingBlocks(maxInterval), Is.EqualTo(expected)); + return this; + } - public On VoteToInclude(PrivateKey nodeId, Address address) - { - if (_logger.IsInfo) _logger.Info($"VOTE {address} IN"); - _producers[nodeId].CastVote(address, true); - return this; - } + public On VoteToExclude(PrivateKey nodeId, Address address) + { + if (_logger.IsInfo) _logger.Info($"VOTE {address} OUT"); + _producers[nodeId].CastVote(address, false); + return this; + } - public On UncastVote(PrivateKey nodeId, Address address) + public On ProcessGenesis() + { + foreach (KeyValuePair node in _blockTrees) { - if (_logger.IsInfo) _logger.Info($"UNCAST VOTE ON {address}"); - _producers[nodeId].UncastVote(address); - return this; + ProcessGenesis(node.Key); } - public On IsProducingBlocks(PrivateKey nodeId, bool expected, ulong? maxInterval) - { - if (_logger.IsInfo) _logger.Info($"IsProducingBlocks"); - Assert.That(((IBlockProducerRunner)_producers[nodeId]).IsProducingBlocks(maxInterval), Is.EqualTo(expected)); - return this; - } + return this; + } - public On VoteToExclude(PrivateKey nodeId, Address address) + public On ProcessGenesis3Validators() + { + foreach (KeyValuePair node in _blockTrees) { - if (_logger.IsInfo) _logger.Info($"VOTE {address} OUT"); - _producers[nodeId].CastVote(address, false); - return this; + ProcessGenesis3Validators(node.Key); } - public On ProcessGenesis() - { - foreach (KeyValuePair node in _blockTrees) - { - ProcessGenesis(node.Key); - } - - return this; - } + return this; + } - public On ProcessGenesis3Validators() + public On ProcessBadGenesis() + { + foreach (KeyValuePair node in _blockTrees) { - foreach (KeyValuePair node in _blockTrees) - { - ProcessGenesis3Validators(node.Key); - } - - return this; + ProcessBadGenesis(node.Key); } - public On ProcessBadGenesis() - { - foreach (KeyValuePair node in _blockTrees) - { - ProcessBadGenesis(node.Key); - } + return this; + } - return this; - } + public On ProcessGenesis(PrivateKey nodeKey) + { + if (_logger.IsInfo) _logger.Info($"SUGGESTING GENESIS ON {nodeKey.Address}"); + _blockTrees[nodeKey].SuggestBlock(_genesis); + _blockEvents[nodeKey].WaitOne(_timeout); + return this; + } - public On ProcessGenesis(PrivateKey nodeKey) - { - if (_logger.IsInfo) _logger.Info($"SUGGESTING GENESIS ON {nodeKey.Address}"); - _blockTrees[nodeKey].SuggestBlock(_genesis); - _blockEvents[nodeKey].WaitOne(_timeout); - return this; - } + public On ProcessGenesis3Validators(PrivateKey nodeKey) + { + _blockTrees[nodeKey].SuggestBlock(_genesis3Validators); + _blockEvents[nodeKey].WaitOne(_timeout); + return this; + } - public On ProcessGenesis3Validators(PrivateKey nodeKey) - { - _blockTrees[nodeKey].SuggestBlock(_genesis3Validators); - _blockEvents[nodeKey].WaitOne(_timeout); - return this; - } + public On ProcessBadGenesis(PrivateKey nodeKey) + { + Wait(10); // wait a moment so the timestamp changes + if (_logger.IsInfo) _logger.Info($"SUGGESTING BAD GENESIS ON {nodeKey.Address}"); + _blockTrees[nodeKey].SuggestBlock(GetGenesis()); + _blockEvents[nodeKey].WaitOne(_timeout); + return this; + } - public On ProcessBadGenesis(PrivateKey nodeKey) + public On Process(PrivateKey nodeKey, Block block) + { + if (_logger.IsInfo) _logger.Info($"SUGGESTING BLOCK {block.ToString(Block.Format.Short)} ON {nodeKey.Address}"); + try { - Wait(10); // wait a moment so the timestamp changes - if (_logger.IsInfo) _logger.Info($"SUGGESTING BAD GENESIS ON {nodeKey.Address}"); - _blockTrees[nodeKey].SuggestBlock(GetGenesis()); + _blockTrees[nodeKey].SuggestBlock(block); _blockEvents[nodeKey].WaitOne(_timeout); return this; } - - public On Process(PrivateKey nodeKey, Block block) + catch (Exception e) { - if (_logger.IsInfo) _logger.Info($"SUGGESTING BLOCK {block.ToString(Block.Format.Short)} ON {nodeKey.Address}"); - try - { - _blockTrees[nodeKey].SuggestBlock(block); - _blockEvents[nodeKey].WaitOne(_timeout); - return this; - } - catch (Exception e) - { - _logger.Error("PROCESS ERROR", e); - throw; - } - } - public On AssertHeadBlockParentIs(PrivateKey nodeKey, Hash256 hash) - { - if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD PARENT HASH ON {nodeKey.Address}"); - Assert.That(_blockTrees[nodeKey].Head.ParentHash, Is.EqualTo(hash), nodeKey.Address + " head parent hash"); - return this; - } - - public On AssertHeadBlockIs(PrivateKey nodeKey, long number) - { - WaitForNumber(nodeKey, number); - if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD BLOCK IS BLOCK {number} ON {nodeKey.Address}"); - Assert.That(_blockTrees[nodeKey].Head.Number, Is.EqualTo(number), nodeKey.Address + " head number"); - return this; + _logger.Error("PROCESS ERROR", e); + throw; } + } + public On AssertHeadBlockParentIs(PrivateKey nodeKey, Hash256 hash) + { + if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD PARENT HASH ON {nodeKey.Address}"); + Assert.That(_blockTrees[nodeKey].Head.ParentHash, Is.EqualTo(hash), nodeKey.Address + " head parent hash"); + return this; + } - public On AssertTransactionCount(PrivateKey nodeKey, long number, int transactionCount) - { - WaitForNumber(nodeKey, number); - if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD BLOCK IS BLOCK {number} ON {nodeKey.Address}"); - Assert.That(_blockTrees[nodeKey].Head.Transactions.Length, Is.EqualTo(transactionCount), nodeKey.Address + $" transaction count should be equal {transactionCount} for block number {number}"); - return this; - } + public On AssertHeadBlockIs(PrivateKey nodeKey, long number) + { + WaitForNumber(nodeKey, number); + if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD BLOCK IS BLOCK {number} ON {nodeKey.Address}"); + Assert.That(_blockTrees[nodeKey].Head.Number, Is.EqualTo(number), nodeKey.Address + " head number"); + return this; + } - public On AssertHeadBlockTimestamp(PrivateKey nodeKey) - { - if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD BLOCK TIMESTAMP ON {nodeKey.Address}"); - Assert.LessOrEqual(_blockTrees[nodeKey].FindBlock(_blockTrees[nodeKey].Head.Number - 1, BlockTreeLookupOptions.None).Timestamp + _cliqueConfig.BlockPeriod, _blockTrees[nodeKey].Head.Timestamp + 1); - return this; - } + public On AssertTransactionCount(PrivateKey nodeKey, long number, int transactionCount) + { + WaitForNumber(nodeKey, number); + if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD BLOCK IS BLOCK {number} ON {nodeKey.Address}"); + Assert.That(_blockTrees[nodeKey].Head.Transactions.Length, Is.EqualTo(transactionCount), nodeKey.Address + $" transaction count should be equal {transactionCount} for block number {number}"); + return this; + } - public On AssertVote(PrivateKey nodeKey, long number, Address address, bool vote) - { - WaitForNumber(nodeKey, number); - if (_logger.IsInfo) _logger.Info($"ASSERTING {vote} VOTE ON {address} AT BLOCK {number}"); - Assert.That(_blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Header.Nonce, Is.EqualTo(vote ? Consensus.Clique.Clique.NonceAuthVote : Consensus.Clique.Clique.NonceDropVote), nodeKey + " vote nonce"); - Assert.That(_blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Beneficiary, Is.EqualTo(address), nodeKey.Address + " vote nonce"); - return this; - } + public On AssertHeadBlockTimestamp(PrivateKey nodeKey) + { + if (_logger.IsInfo) _logger.Info($"ASSERTING HEAD BLOCK TIMESTAMP ON {nodeKey.Address}"); + Assert.That( + _blockTrees[nodeKey].FindBlock(_blockTrees[nodeKey].Head.Number - 1, BlockTreeLookupOptions.None).Timestamp + _cliqueConfig.BlockPeriod, + Is.LessThan(_blockTrees[nodeKey].Head.Timestamp + 1)); + return this; + } - public On AssertSignersCount(PrivateKey nodeKey, long number, int count) - { - WaitForNumber(nodeKey, number); - if (_logger.IsInfo) _logger.Info($"ASSERTING {count} SIGNERS AT BLOCK {number}"); - BlockHeader header = _blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Header; - Assert.That(_snapshotManager[nodeKey].GetOrCreateSnapshot(header.Number, header.Hash).Signers.Count, Is.EqualTo(count), nodeKey + " signers count"); - return this; - } + public On AssertVote(PrivateKey nodeKey, long number, Address address, bool vote) + { + WaitForNumber(nodeKey, number); + if (_logger.IsInfo) _logger.Info($"ASSERTING {vote} VOTE ON {address} AT BLOCK {number}"); + Assert.That(_blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Header.Nonce, Is.EqualTo(vote ? Consensus.Clique.Clique.NonceAuthVote : Consensus.Clique.Clique.NonceDropVote), nodeKey + " vote nonce"); + Assert.That(_blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Beneficiary, Is.EqualTo(address), nodeKey.Address + " vote nonce"); + return this; + } + public On AssertSignersCount(PrivateKey nodeKey, long number, int count) + { + WaitForNumber(nodeKey, number); + if (_logger.IsInfo) _logger.Info($"ASSERTING {count} SIGNERS AT BLOCK {number}"); + BlockHeader header = _blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Header; + Assert.That(_snapshotManager[nodeKey].GetOrCreateSnapshot(header.Number, header.Hash).Signers.Count, Is.EqualTo(count), nodeKey + " signers count"); + return this; + } - public On AssertTallyEmpty(PrivateKey nodeKey, long number, PrivateKey privateKeyB) - { - WaitForNumber(nodeKey, number); - if (_logger.IsInfo) _logger.Info($"ASSERTING EMPTY TALLY FOR {privateKeyB.Address} EMPTY AT {number}"); - BlockHeader header = _blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Header; - Assert.That(_snapshotManager[nodeKey].GetOrCreateSnapshot(header.Number, header.Hash).Tally.ContainsKey(privateKeyB.Address), Is.EqualTo(false), nodeKey + " tally empty"); - return this; - } - public On AssertOutOfTurn(PrivateKey nodeKey, long number) - { - WaitForNumber(nodeKey, number); - if (_logger.IsInfo) _logger.Info($"ASSERTING OUT TURN ON AT {nodeKey.Address} EMPTY AT BLOCK {number}"); - Assert.That(_blockTrees[nodeKey].Head.Difficulty, Is.EqualTo(Consensus.Clique.Clique.DifficultyNoTurn), nodeKey.Address + $" {number} out of turn"); - return this; - } + public On AssertTallyEmpty(PrivateKey nodeKey, long number, PrivateKey privateKeyB) + { + WaitForNumber(nodeKey, number); + if (_logger.IsInfo) _logger.Info($"ASSERTING EMPTY TALLY FOR {privateKeyB.Address} EMPTY AT {number}"); + BlockHeader header = _blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Header; + Assert.That(_snapshotManager[nodeKey].GetOrCreateSnapshot(header.Number, header.Hash).Tally.ContainsKey(privateKeyB.Address), Is.EqualTo(false), nodeKey + " tally empty"); + return this; + } - public On AssertInTurn(PrivateKey nodeKey, long number) - { - WaitForNumber(nodeKey, number); - if (_logger.IsInfo) _logger.Info($"ASSERTING IN TURN ON AT {nodeKey.Address} EMPTY AT BLOCK {number}"); - Assert.That(_blockTrees[nodeKey].Head.Difficulty, Is.EqualTo(Consensus.Clique.Clique.DifficultyInTurn), nodeKey.Address + $" {number} in turn"); - return this; - } + public On AssertOutOfTurn(PrivateKey nodeKey, long number) + { + WaitForNumber(nodeKey, number); + if (_logger.IsInfo) _logger.Info($"ASSERTING OUT TURN ON AT {nodeKey.Address} EMPTY AT BLOCK {number}"); + Assert.That(_blockTrees[nodeKey].Head.Difficulty, Is.EqualTo(Consensus.Clique.Clique.DifficultyNoTurn), nodeKey.Address + $" {number} out of turn"); + return this; + } - private void WaitForNumber(PrivateKey nodeKey, long number) - { - if (_logger.IsInfo) _logger.Info($"WAITING ON {nodeKey.Address} FOR BLOCK {number}"); - SpinWait spinWait = new(); - Stopwatch stopwatch = new(); - stopwatch.Start(); - while (stopwatch.ElapsedMilliseconds < _timeout) - { - spinWait.SpinOnce(); - if (_blockTrees[nodeKey].Head.Number >= number) - { - break; - } - } - } + public On AssertInTurn(PrivateKey nodeKey, long number) + { + WaitForNumber(nodeKey, number); + if (_logger.IsInfo) _logger.Info($"ASSERTING IN TURN ON AT {nodeKey.Address} EMPTY AT BLOCK {number}"); + Assert.That(_blockTrees[nodeKey].Head.Difficulty, Is.EqualTo(Consensus.Clique.Clique.DifficultyInTurn), nodeKey.Address + $" {number} in turn"); + return this; + } - public Block GetBlock(PrivateKey privateKey, long number) - { - Block block = _blockTrees[privateKey].FindBlock(number, BlockTreeLookupOptions.None); - if (block is null) + private void WaitForNumber(PrivateKey nodeKey, long number) + { + if (_logger.IsInfo) _logger.Info($"WAITING ON {nodeKey.Address} FOR BLOCK {number}"); + SpinWait spinWait = new(); + Stopwatch stopwatch = new(); + stopwatch.Start(); + while (stopwatch.ElapsedMilliseconds < _timeout) + { + spinWait.SpinOnce(); + if (_blockTrees[nodeKey].Head.Number >= number) { - throw new InvalidOperationException($"Cannot find block {number}"); + break; } - - return block; - } - - public async Task StopNode(PrivateKey privateKeyA) - { - if (_logger.IsInfo) _logger.Info($"STOPPING {privateKeyA.Address}"); - await _producers[privateKeyA].StopAsync(); - return this; - } - - private readonly UInt256 _currentNonce = 0; - - public On AddPendingTransaction(PrivateKey nodeKey) - { - Transaction transaction = new(); - transaction.Value = 1; - transaction.To = TestItem.AddressC; - transaction.GasLimit = 30000; - transaction.GasPrice = 20.GWei(); - transaction.Nonce = _currentNonce + 1; - transaction.SenderAddress = TestItem.PrivateKeyD.Address; - transaction.Hash = transaction.CalculateHash(); - _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); - _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); - - return this; - } - - public On AddAllBadTransactions(PrivateKey nodeKey) - { - // 0 gas price - Transaction transaction = new(); - transaction.Value = 1; - transaction.To = TestItem.AddressC; - transaction.GasLimit = 30000; - transaction.GasPrice = 0.GWei(); - transaction.Nonce = _currentNonce; - transaction.SenderAddress = TestItem.PrivateKeyD.Address; - transaction.Hash = transaction.CalculateHash(); - _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); - _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); - - // bad nonce - transaction = new Transaction(); - transaction.Value = 1; - transaction.To = TestItem.AddressC; - transaction.GasLimit = 30000; - transaction.GasPrice = 20.GWei(); - transaction.Nonce = 0; - transaction.SenderAddress = TestItem.PrivateKeyD.Address; - transaction.Hash = transaction.CalculateHash(); - _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); - _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); - - // gas limit too high - transaction = new Transaction(); - transaction.Value = 1; - transaction.To = TestItem.AddressC; - transaction.GasLimit = 100000000; - transaction.GasPrice = 20.GWei(); - transaction.Nonce = _currentNonce; - transaction.SenderAddress = TestItem.PrivateKeyD.Address; - transaction.Hash = transaction.CalculateHash(); - _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); - _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); - - // insufficient balance - transaction = new Transaction(); - transaction.Value = 1000000000.Ether(); - transaction.To = TestItem.AddressC; - transaction.GasLimit = 30000; - transaction.GasPrice = 20.GWei(); - transaction.Nonce = _currentNonce; - transaction.SenderAddress = TestItem.PrivateKeyD.Address; - transaction.Hash = transaction.CalculateHash(); - _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); - _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); - - return this; } + } - public On AddTransactionWithGasLimitToHigh(PrivateKey nodeKey) + public Block GetBlock(PrivateKey privateKey, long number) + { + Block block = _blockTrees[privateKey].FindBlock(number, BlockTreeLookupOptions.None); + if (block is null) { - Transaction transaction = new(); - - // gas limit too high - transaction = new Transaction(); - transaction.Value = 1; - transaction.To = TestItem.AddressC; - transaction.GasLimit = 100000000; - transaction.GasPrice = 20.GWei(); - transaction.Nonce = _currentNonce; - transaction.Data = Bytes.FromHexString("0xEF"); - transaction.SenderAddress = TestItem.PrivateKeyD.Address; - transaction.Hash = transaction.CalculateHash(); - _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); - _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); - - return this; + throw new InvalidOperationException($"Cannot find block {number}"); } - public On AddQueuedTransaction(PrivateKey nodeKey) - { - Transaction transaction = new(); - transaction.Value = 1; - transaction.To = TestItem.AddressC; - transaction.GasLimit = 30000; - transaction.GasPrice = 20.GWei(); - transaction.Nonce = _currentNonce + 1000; - transaction.SenderAddress = TestItem.PrivateKeyD.Address; - transaction.Hash = transaction.CalculateHash(); - _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); - _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); - - return this; - } - - public On Wait(int i) - { - if (_logger.IsInfo) _logger.Info($"WAIT {i}"); - Thread.Sleep(i); - return this; - } + return block; } - private static readonly int _timeout = 2000; // this has to cover block period of second + wiggle of up to 500ms * (signers - 1) + 100ms delay of the block readiness check - - [Test] - public async Task Can_produce_block_with_transactions() + public async Task StopNode(PrivateKey privateKeyA) { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .AddPendingTransaction(TestItem.PrivateKeyA) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1L) - .StopNode(TestItem.PrivateKeyA); + if (_logger.IsInfo) _logger.Info($"STOPPING {privateKeyA.Address}"); + await _producers[privateKeyA].StopAsync(); + return this; } - [Test] - public async Task IsProducingBlocks_returns_expected_results() - { - On result = await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .ProcessGenesis() - .IsProducingBlocks(TestItem.PrivateKeyA, true, null) - .StopNode(TestItem.PrivateKeyA); - - result - .IsProducingBlocks(TestItem.PrivateKeyA, false, null); - } + private readonly UInt256 _currentNonce = 0; - [Test] - public async Task When_producing_blocks_skips_queued_and_bad_transactions() + public On AddPendingTransaction(PrivateKey nodeKey) { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .AddPendingTransaction(TestItem.PrivateKeyA) - .AddPendingTransaction(TestItem.PrivateKeyA) - .AddPendingTransaction(TestItem.PrivateKeyA) - .AddAllBadTransactions(TestItem.PrivateKeyA) - .AddQueuedTransaction(TestItem.PrivateKeyA) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) - .StopNode(TestItem.PrivateKeyA); + Transaction transaction = new(); + transaction.Value = 1; + transaction.To = TestItem.AddressC; + transaction.GasLimit = 30000; + transaction.GasPrice = 20.GWei(); + transaction.Nonce = _currentNonce + 1; + transaction.SenderAddress = TestItem.PrivateKeyD.Address; + transaction.Hash = transaction.CalculateHash(); + _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); + _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); + + return this; } - [Test] - public async Task Transaction_with_gas_limit_higher_than_block_gas_limit_should_not_be_send() + public On AddAllBadTransactions(PrivateKey nodeKey) { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .AddTransactionWithGasLimitToHigh(TestItem.PrivateKeyA) - .ProcessGenesis() - .AssertTransactionCount(TestItem.PrivateKeyA, 1, 0) - .StopNode(TestItem.PrivateKeyA); + // 0 gas price + Transaction transaction = new(); + transaction.Value = 1; + transaction.To = TestItem.AddressC; + transaction.GasLimit = 30000; + transaction.GasPrice = 0.GWei(); + transaction.Nonce = _currentNonce; + transaction.SenderAddress = TestItem.PrivateKeyD.Address; + transaction.Hash = transaction.CalculateHash(); + _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); + _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); + + // bad nonce + transaction = new Transaction(); + transaction.Value = 1; + transaction.To = TestItem.AddressC; + transaction.GasLimit = 30000; + transaction.GasPrice = 20.GWei(); + transaction.Nonce = 0; + transaction.SenderAddress = TestItem.PrivateKeyD.Address; + transaction.Hash = transaction.CalculateHash(); + _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); + _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); + + // gas limit too high + transaction = new Transaction(); + transaction.Value = 1; + transaction.To = TestItem.AddressC; + transaction.GasLimit = 100000000; + transaction.GasPrice = 20.GWei(); + transaction.Nonce = _currentNonce; + transaction.SenderAddress = TestItem.PrivateKeyD.Address; + transaction.Hash = transaction.CalculateHash(); + _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); + _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); + + // insufficient balance + transaction = new Transaction(); + transaction.Value = 1000000000.Ether(); + transaction.To = TestItem.AddressC; + transaction.GasLimit = 30000; + transaction.GasPrice = 20.GWei(); + transaction.Nonce = _currentNonce; + transaction.SenderAddress = TestItem.PrivateKeyD.Address; + transaction.Hash = transaction.CalculateHash(); + _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); + _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); + + return this; } - [Test] - public async Task Produces_block_on_top_of_genesis() + public On AddTransactionWithGasLimitToHigh(PrivateKey nodeKey) { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .CreateNode(TestItem.PrivateKeyB) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .AssertInTurn(TestItem.PrivateKeyA, 1) - .AssertOutOfTurn(TestItem.PrivateKeyB, 1) - .StopNode(TestItem.PrivateKeyA) - .ContinueWith(t => t.Result.StopNode(TestItem.PrivateKeyB)); + Transaction transaction = new(); + + // gas limit too high + transaction = new Transaction(); + transaction.Value = 1; + transaction.To = TestItem.AddressC; + transaction.GasLimit = 100000000; + transaction.GasPrice = 20.GWei(); + transaction.Nonce = _currentNonce; + transaction.Data = Bytes.FromHexString("0xEF"); + transaction.SenderAddress = TestItem.PrivateKeyD.Address; + transaction.Hash = transaction.CalculateHash(); + _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); + _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); + + return this; } - [Test] - public void Single_validator_can_produce_first_block_in_turn() + public On AddQueuedTransaction(PrivateKey nodeKey) { - On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) - .AssertInTurn(TestItem.PrivateKeyA, 1); + Transaction transaction = new(); + transaction.Value = 1; + transaction.To = TestItem.AddressC; + transaction.GasLimit = 30000; + transaction.GasPrice = 20.GWei(); + transaction.Nonce = _currentNonce + 1000; + transaction.SenderAddress = TestItem.PrivateKeyD.Address; + transaction.Hash = transaction.CalculateHash(); + _ethereumEcdsa.Sign(TestItem.PrivateKeyD, transaction, true); + _pools[nodeKey].SubmitTx(transaction, TxHandlingOptions.None); + + return this; } - [Test] - public async Task Single_validator_can_produce_first_block_out_of_turn() + public On Wait(int i) { - await On.Goerli - .CreateNode(TestItem.PrivateKeyB) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .AssertOutOfTurn(TestItem.PrivateKeyB, 1) - .StopNode(TestItem.PrivateKeyB); + if (_logger.IsInfo) _logger.Info($"WAIT {i}"); + Thread.Sleep(i); + return this; } + } - [Test] - public async Task Cannot_produce_blocks_when_not_on_signers_list() - { - await On.Goerli - .CreateNode(TestItem.PrivateKeyC) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyC, 0) - .StopNode(TestItem.PrivateKeyC); - } + private static readonly int _timeout = 2000; // this has to cover block period of second + wiggle of up to 500ms * (signers - 1) + 100ms delay of the block readiness check - [Test] - public async Task Can_cast_vote_to_include() - { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressC) - .ProcessGenesis() - .AssertVote(TestItem.PrivateKeyA, 1, TestItem.AddressC, true) - .StopNode(TestItem.PrivateKeyA); - } + [Test] + public async Task Can_produce_block_with_transactions() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .AddPendingTransaction(TestItem.PrivateKeyA) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1L) + .StopNode(TestItem.PrivateKeyA); + } - [Test] - public async Task Can_uncast_vote_to() - { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressC) - .UncastVote(TestItem.PrivateKeyA, TestItem.AddressC) - .ProcessGenesis() - .AssertVote(TestItem.PrivateKeyA, 1, Address.Zero, false) - .StopNode(TestItem.PrivateKeyA); - } + [Test] + public async Task IsProducingBlocks_returns_expected_results() + { + On result = await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .ProcessGenesis() + .IsProducingBlocks(TestItem.PrivateKeyA, true, null) + .StopNode(TestItem.PrivateKeyA); + + result + .IsProducingBlocks(TestItem.PrivateKeyA, false, null); + } - [Test] - public async Task Can_vote_a_validator_in() - { - On goerli = On.FastGoerli; - goerli - .CreateNode(TestItem.PrivateKeyA) - .CreateNode(TestItem.PrivateKeyB) - .CreateNode(TestItem.PrivateKeyC) - .VoteToInclude(TestItem.PrivateKeyB, TestItem.AddressD) - .ProcessGenesis3Validators() - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .AssertHeadBlockIs(TestItem.PrivateKeyC, 1) - .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressD) - .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 1)) - .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 1)) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 2) - .AssertHeadBlockIs(TestItem.PrivateKeyC, 2) - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 2)) - .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyA, 2)) - .Wait(1000) - .AssertSignersCount(TestItem.PrivateKeyC, 2, 4); - - await goerli.StopNode(TestItem.PrivateKeyA); - await goerli.StopNode(TestItem.PrivateKeyB); - await goerli.StopNode(TestItem.PrivateKeyC); - } - - [Test, Retry(3)] - public async Task Can_vote_a_validator_out() - { - On goerli = On.FastGoerli; - goerli - .CreateNode(TestItem.PrivateKeyA) - .CreateNode(TestItem.PrivateKeyB) - .CreateNode(TestItem.PrivateKeyC) - .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressC) - .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressB) - .ProcessGenesis3Validators() - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .AssertHeadBlockIs(TestItem.PrivateKeyC, 1) - .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 1)) - .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 1)) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 2) - .AssertHeadBlockIs(TestItem.PrivateKeyC, 2) - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 2)) - .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyA, 2)) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 3) - .AssertHeadBlockIs(TestItem.PrivateKeyC, 3) - .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyC, 3)) - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyC, 3)) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 4) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 4) - .VoteToExclude(TestItem.PrivateKeyB, TestItem.AddressA) - .VoteToExclude(TestItem.PrivateKeyC, TestItem.AddressA) - .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 4)) - .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 4)) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 5) - .AssertHeadBlockIs(TestItem.PrivateKeyC, 5) - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 5)) - .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyA, 5)) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 6) - .AssertHeadBlockIs(TestItem.PrivateKeyC, 6) - .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyC, 6)) - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyC, 6)) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 6) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 7) - .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 7)) - .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 7)) - .Wait(1000) - .AssertSignersCount(TestItem.PrivateKeyA, 7, 2) - .AssertTallyEmpty(TestItem.PrivateKeyA, 7, TestItem.PrivateKeyB) - .AssertTallyEmpty(TestItem.PrivateKeyA, 7, TestItem.PrivateKeyA) - .AssertTallyEmpty(TestItem.PrivateKeyA, 7, TestItem.PrivateKeyC); - - await goerli.StopNode(TestItem.PrivateKeyA); - await goerli.StopNode(TestItem.PrivateKeyB); - await goerli.StopNode(TestItem.PrivateKeyC); - } - - [Test] - public async Task Can_cast_vote_to_exclude() - { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressB) - .ProcessGenesis() - .AssertVote(TestItem.PrivateKeyA, 1, TestItem.AddressB, false) - .StopNode(TestItem.PrivateKeyA); - } - - [Test] - public async Task Cannot_vote_to_exclude_node_that_is_not_on_the_list() - { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressC) - .ProcessGenesis() - .AssertVote(TestItem.PrivateKeyA, 1, Address.Zero, false) - .StopNode(TestItem.PrivateKeyA); - } - - [Test] - public async Task Cannot_vote_to_include_node_that_is_already_on_the_list() - { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA) - .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressB) - .ProcessGenesis() - .AssertVote(TestItem.PrivateKeyA, 1, Address.Zero, false) - .StopNode(TestItem.PrivateKeyA); - } - - [Test] - public async Task Can_reorganize_when_receiving_in_turn_blocks() - { - On goerli = On.FastGoerli; - goerli - .CreateNode(TestItem.PrivateKeyB) - .CreateNode(TestItem.PrivateKeyA) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 1)) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 2); + [Test] + public async Task When_producing_blocks_skips_queued_and_bad_transactions() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .AddPendingTransaction(TestItem.PrivateKeyA) + .AddPendingTransaction(TestItem.PrivateKeyA) + .AddPendingTransaction(TestItem.PrivateKeyA) + .AddAllBadTransactions(TestItem.PrivateKeyA) + .AddQueuedTransaction(TestItem.PrivateKeyA) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) + .StopNode(TestItem.PrivateKeyA); + } - await goerli.StopNode(TestItem.PrivateKeyA); - await goerli.StopNode(TestItem.PrivateKeyB); - } + [Test] + public async Task Transaction_with_gas_limit_higher_than_block_gas_limit_should_not_be_send() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .AddTransactionWithGasLimitToHigh(TestItem.PrivateKeyA) + .ProcessGenesis() + .AssertTransactionCount(TestItem.PrivateKeyA, 1, 0) + .StopNode(TestItem.PrivateKeyA); + } - [Test] - public async Task Ignores_blocks_from_bad_network() - { - On goerli = On.FastGoerli; - goerli - .CreateNode(TestItem.PrivateKeyB) - .ProcessGenesis(TestItem.PrivateKeyB) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .CreateNode(TestItem.PrivateKeyA) - .ProcessBadGenesis(TestItem.PrivateKeyA) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1); + [Test] + public async Task Produces_block_on_top_of_genesis() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .CreateNode(TestItem.PrivateKeyB) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .AssertInTurn(TestItem.PrivateKeyA, 1) + .AssertOutOfTurn(TestItem.PrivateKeyB, 1) + .StopNode(TestItem.PrivateKeyA) + .ContinueWith(t => t.Result.StopNode(TestItem.PrivateKeyB)); + } - Assert.That(goerli.GetBlock(TestItem.PrivateKeyB, 0).Hash, Is.Not.EqualTo(goerli.GetBlock(TestItem.PrivateKeyA, 0).Hash), "same genesis"); + [Test] + public void Single_validator_can_produce_first_block_in_turn() + { + On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) + .AssertInTurn(TestItem.PrivateKeyA, 1); + } - goerli - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 1)) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1); + [Test] + public async Task Single_validator_can_produce_first_block_out_of_turn() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyB) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .AssertOutOfTurn(TestItem.PrivateKeyB, 1) + .StopNode(TestItem.PrivateKeyB); + } - await goerli.StopNode(TestItem.PrivateKeyA); - await goerli.StopNode(TestItem.PrivateKeyB); - } + [Test] + public async Task Cannot_produce_blocks_when_not_on_signers_list() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyC) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyC, 0) + .StopNode(TestItem.PrivateKeyC); + } - [Test] - public async Task Waits_for_block_timestamp_before_broadcasting() - { - On goerli = On.Goerli; - goerli - .CreateNode(TestItem.PrivateKeyB) - .CreateNode(TestItem.PrivateKeyA) - .ProcessGenesis() - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1); + [Test] + public async Task Can_cast_vote_to_include() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressC) + .ProcessGenesis() + .AssertVote(TestItem.PrivateKeyA, 1, TestItem.AddressC, true) + .StopNode(TestItem.PrivateKeyA); + } - Assert.That(goerli.GetBlock(TestItem.PrivateKeyB, 0).Hash, Is.EqualTo(goerli.GetBlock(TestItem.PrivateKeyA, 0).Hash), "same genesis"); - goerli - .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 1)) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1); + [Test] + public async Task Can_uncast_vote_to() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressC) + .UncastVote(TestItem.PrivateKeyA, TestItem.AddressC) + .ProcessGenesis() + .AssertVote(TestItem.PrivateKeyA, 1, Address.Zero, false) + .StopNode(TestItem.PrivateKeyA); + } - await goerli.StopNode(TestItem.PrivateKeyA); - await goerli.StopNode(TestItem.PrivateKeyB); - } + [Test] + public async Task Can_vote_a_validator_in() + { + On goerli = On.FastGoerli; + goerli + .CreateNode(TestItem.PrivateKeyA) + .CreateNode(TestItem.PrivateKeyB) + .CreateNode(TestItem.PrivateKeyC) + .VoteToInclude(TestItem.PrivateKeyB, TestItem.AddressD) + .ProcessGenesis3Validators() + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .AssertHeadBlockIs(TestItem.PrivateKeyC, 1) + .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressD) + .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 1)) + .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 1)) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 2) + .AssertHeadBlockIs(TestItem.PrivateKeyC, 2) + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 2)) + .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyA, 2)) + .Wait(1000) + .AssertSignersCount(TestItem.PrivateKeyC, 2, 4); + + await goerli.StopNode(TestItem.PrivateKeyA); + await goerli.StopNode(TestItem.PrivateKeyB); + await goerli.StopNode(TestItem.PrivateKeyC); + } - [Test] - [Retry(3)] - public async Task Creates_blocks_without_signals_from_block_tree() - { - await On.Goerli - .CreateNode(TestItem.PrivateKeyA, true) - .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) - .StopNode(TestItem.PrivateKeyA); + [Test, Retry(3)] + public async Task Can_vote_a_validator_out() + { + On goerli = On.FastGoerli; + goerli + .CreateNode(TestItem.PrivateKeyA) + .CreateNode(TestItem.PrivateKeyB) + .CreateNode(TestItem.PrivateKeyC) + .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressC) + .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressB) + .ProcessGenesis3Validators() + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .AssertHeadBlockIs(TestItem.PrivateKeyC, 1) + .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 1)) + .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 1)) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 2) + .AssertHeadBlockIs(TestItem.PrivateKeyC, 2) + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 2)) + .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyA, 2)) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 3) + .AssertHeadBlockIs(TestItem.PrivateKeyC, 3) + .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyC, 3)) + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyC, 3)) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 4) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 4) + .VoteToExclude(TestItem.PrivateKeyB, TestItem.AddressA) + .VoteToExclude(TestItem.PrivateKeyC, TestItem.AddressA) + .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 4)) + .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 4)) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 5) + .AssertHeadBlockIs(TestItem.PrivateKeyC, 5) + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 5)) + .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyA, 5)) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 6) + .AssertHeadBlockIs(TestItem.PrivateKeyC, 6) + .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyC, 6)) + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyC, 6)) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 6) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 7) + .Process(TestItem.PrivateKeyA, goerli.GetBlock(TestItem.PrivateKeyB, 7)) + .Process(TestItem.PrivateKeyC, goerli.GetBlock(TestItem.PrivateKeyB, 7)) + .Wait(1000) + .AssertSignersCount(TestItem.PrivateKeyA, 7, 2) + .AssertTallyEmpty(TestItem.PrivateKeyA, 7, TestItem.PrivateKeyB) + .AssertTallyEmpty(TestItem.PrivateKeyA, 7, TestItem.PrivateKeyA) + .AssertTallyEmpty(TestItem.PrivateKeyA, 7, TestItem.PrivateKeyC); + + await goerli.StopNode(TestItem.PrivateKeyA); + await goerli.StopNode(TestItem.PrivateKeyB); + await goerli.StopNode(TestItem.PrivateKeyC); + } - await On.Goerli - .CreateNode(TestItem.PrivateKeyB, true) - .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) - .StopNode(TestItem.PrivateKeyB); - } + [Test] + public async Task Can_cast_vote_to_exclude() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressB) + .ProcessGenesis() + .AssertVote(TestItem.PrivateKeyA, 1, TestItem.AddressB, false) + .StopNode(TestItem.PrivateKeyA); + } - [Test] - public async Task Can_stop() - { - On goerli = On.Goerli - .CreateNode(TestItem.PrivateKeyA); + [Test] + public async Task Cannot_vote_to_exclude_node_that_is_not_on_the_list() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .VoteToExclude(TestItem.PrivateKeyA, TestItem.AddressC) + .ProcessGenesis() + .AssertVote(TestItem.PrivateKeyA, 1, Address.Zero, false) + .StopNode(TestItem.PrivateKeyA); + } + + [Test] + public async Task Cannot_vote_to_include_node_that_is_already_on_the_list() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA) + .VoteToInclude(TestItem.PrivateKeyA, TestItem.AddressB) + .ProcessGenesis() + .AssertVote(TestItem.PrivateKeyA, 1, Address.Zero, false) + .StopNode(TestItem.PrivateKeyA); + } - await goerli.StopNode(TestItem.PrivateKeyA); + [Test] + public async Task Can_reorganize_when_receiving_in_turn_blocks() + { + On goerli = On.FastGoerli; + goerli + .CreateNode(TestItem.PrivateKeyB) + .CreateNode(TestItem.PrivateKeyA) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 1)) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 2); + + await goerli.StopNode(TestItem.PrivateKeyA); + await goerli.StopNode(TestItem.PrivateKeyB); + } - goerli.ProcessGenesis(); - await Task.Delay(1000); - goerli.AssertHeadBlockIs(TestItem.PrivateKeyA, 0); + [Test] + public async Task Ignores_blocks_from_bad_network() + { + On goerli = On.FastGoerli; + goerli + .CreateNode(TestItem.PrivateKeyB) + .ProcessGenesis(TestItem.PrivateKeyB) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .CreateNode(TestItem.PrivateKeyA) + .ProcessBadGenesis(TestItem.PrivateKeyA) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1); + + Assert.That(goerli.GetBlock(TestItem.PrivateKeyB, 0).Hash, Is.Not.EqualTo(goerli.GetBlock(TestItem.PrivateKeyA, 0).Hash), "same genesis"); + + goerli + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 1)) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1); + + await goerli.StopNode(TestItem.PrivateKeyA); + await goerli.StopNode(TestItem.PrivateKeyB); + } - await goerli.StopNode(TestItem.PrivateKeyA); - } + [Test] + public async Task Waits_for_block_timestamp_before_broadcasting() + { + On goerli = On.Goerli; + goerli + .CreateNode(TestItem.PrivateKeyB) + .CreateNode(TestItem.PrivateKeyA) + .ProcessGenesis() + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1); + + Assert.That(goerli.GetBlock(TestItem.PrivateKeyB, 0).Hash, Is.EqualTo(goerli.GetBlock(TestItem.PrivateKeyA, 0).Hash), "same genesis"); + goerli + .Process(TestItem.PrivateKeyB, goerli.GetBlock(TestItem.PrivateKeyA, 1)) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1); + + await goerli.StopNode(TestItem.PrivateKeyA); + await goerli.StopNode(TestItem.PrivateKeyB); + } - [Test, Retry(3)] - public async Task Many_validators_can_process_blocks() - { - PrivateKey[] keys = new[] { TestItem.PrivateKeyA, TestItem.PrivateKeyB, TestItem.PrivateKeyC }.OrderBy(pk => pk.Address, AddressComparer.Instance).ToArray(); + [Test] + [Retry(3)] + public async Task Creates_blocks_without_signals_from_block_tree() + { + await On.Goerli + .CreateNode(TestItem.PrivateKeyA, true) + .AssertHeadBlockIs(TestItem.PrivateKeyA, 1) + .StopNode(TestItem.PrivateKeyA); + + await On.Goerli + .CreateNode(TestItem.PrivateKeyB, true) + .AssertHeadBlockIs(TestItem.PrivateKeyB, 1) + .StopNode(TestItem.PrivateKeyB); + } - On goerli = On.FastGoerli; - for (int i = 0; i < keys.Length; i++) - { - goerli - .CreateNode(keys[i]) - .ProcessGenesis3Validators(keys[i]) - .AssertHeadBlockIs(keys[i], 1); - } + [Test] + public async Task Can_stop() + { + On goerli = On.Goerli + .CreateNode(TestItem.PrivateKeyA); + + await goerli.StopNode(TestItem.PrivateKeyA); + + goerli.ProcessGenesis(); + await Task.Delay(1000); + goerli.AssertHeadBlockIs(TestItem.PrivateKeyA, 0); - for (int i = 1; i <= 10; i++) + await goerli.StopNode(TestItem.PrivateKeyA); + } + + [Test, Retry(3)] + public async Task Many_validators_can_process_blocks() + { + PrivateKey[] keys = new[] { TestItem.PrivateKeyA, TestItem.PrivateKeyB, TestItem.PrivateKeyC }.OrderBy(pk => pk.Address, AddressComparer.Instance).ToArray(); + + On goerli = On.FastGoerli; + for (int i = 0; i < keys.Length; i++) + { + goerli + .CreateNode(keys[i]) + .ProcessGenesis3Validators(keys[i]) + .AssertHeadBlockIs(keys[i], 1); + } + + for (int i = 1; i <= 10; i++) + { + PrivateKey inTurnKey = keys[i % 3]; + goerli.AddPendingTransaction(keys[(i + 1) % 3]); + for (int j = 0; j < keys.Length; j++) { - PrivateKey inTurnKey = keys[i % 3]; - goerli.AddPendingTransaction(keys[(i + 1) % 3]); - for (int j = 0; j < keys.Length; j++) + PrivateKey nodeKey = keys[j]; + if (!nodeKey.Equals(inTurnKey)) + { + goerli.Process(nodeKey, goerli.GetBlock(inTurnKey, i)); + goerli.AssertHeadBlockIs(keys[j], i + 1); + goerli.AssertHeadBlockTimestamp(keys[j]); + } + else { - PrivateKey nodeKey = keys[j]; - if (!nodeKey.Equals(inTurnKey)) - { - goerli.Process(nodeKey, goerli.GetBlock(inTurnKey, i)); - goerli.AssertHeadBlockIs(keys[j], i + 1); - goerli.AssertHeadBlockTimestamp(keys[j]); - } - else - { - goerli.AssertHeadBlockIs(keys[j], i); - goerli.AssertHeadBlockTimestamp(keys[j]); - } + goerli.AssertHeadBlockIs(keys[j], i); + goerli.AssertHeadBlockTimestamp(keys[j]); } } + } - for (int i = 0; i < keys.Length; i++) - { - await goerli.StopNode(keys[i]); - } + for (int i = 0; i < keys.Length; i++) + { + await goerli.StopNode(keys[i]); } } } diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs index 38eefe80efe..f277963e1a3 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs @@ -22,189 +22,187 @@ using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; -namespace Nethermind.Clique.Test +namespace Nethermind.Clique.Test; + +[Parallelizable(ParallelScope.Self)] +public class CliqueSealEngineTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class CliqueSealEngineTests + private const string Block1Rlp = "f9025bf90256a0bc3546bbc73f86a96f5d966965ded9873dddc2278ce48c7251ef3062620a3543a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002018347c94c808458ee45dab861d783010600846765746887676f312e372e33856c696e75780000000000000000a06daa01cc93a2875795a705f8eae4d00de10d513bf975515a12e545254ae3195be42d6c49a83ae580f8c7ff7c69eef4f16626e8fd873114b46edec7744edca400a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block2Rlp = "f9025bf90256a03a060a78114b179fffc5581fbf36668f39a9928e58eaaf693c971b32446bd376a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002028347db3d808458ee45eab861d783010600846765746887676f312e372e33856c696e75780000000000000000e237c51d592ede43af886756f5ef941ae195bcfc2c324a206e753e070e3174a7649bc0ce5e17c94ecae5087fc6796c02a231fdfb94e4c9b3d1e19dd9bdb2040800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block3Rlp = "f9025bf90256a012d6551b449ce661299860948eccc6d65b26a67deef09d408ac6dfce1fac995aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002038347e7c4808458ee45f9b861d783010600846765746887676f312e372e33856c696e7578000000000000000021dfd43d2956e78e06eaf747f43858d442a79c970a109a6c39385bee232996b64a1de72743fa56efc967fd19cb9308174340f94a2f07b96eb82f82a3c72ce86300a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block4Rlp = "f9025bf90256a01ef022156ff2d5730931028d3fddaccf9ccda8818ba7f79dbeea78302550824ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002048347e7c4808458ee4608b861d783010600846765746887676f312e372e33856c696e7578000000000000000095ed0b3d04835d9ccbf11f79fdf75cf01a4a79fcb4b417b00acf461306e565616ed1903b307407143f2393af49d892399e8b09e01728d419f900ae99e13437f000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block5Rlp = "f9025bf90256a017d9b71cd90b4381da41265491792f5f78d36f80b14c3c7073af470d7e9b882aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002058347e7c4808458ee4617b861d783010600846765746887676f312e372e33856c696e75780000000000000000840db225f54032162d91245cc2f6c1b80b2e1d2b0657c3707e9c1f46add7b7525e0ba267addc476724e1eb70f7f76a5fd8c95df3d82dfb7a3d8c334c2fcb5ad201a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + + private readonly List _signers = new() + { + new PrivateKey("06E84833EAC809859F46F84311CB152E2D2A505FE6B5FBC4CD2CABD37B678F1C"), + new PrivateKey("C7B39D4F871ACA337E3CC3AB956F1A916B5EF23AF9F5571566DDB8D3C99F66AC"), + new PrivateKey("9BD8E918E3176E86D406BFCE261D4CD2589167E3DBD0236B08B0B285783D7553"), + new PrivateKey("7DC56B10FD1EC64A8BF7547D3BAA254ACB96E8F2AD5A006DD2EBF9C40409A2CE") + }; + private CliqueSealer _clique; + private CliqueSealValidator _sealValidator; + private SnapshotManager _snapshotManager; + private Block _lastBlock; + private PrivateKey _currentSigner; + private BlockTree _blockTree; + + [OneTimeSetUp] + public void Setup_chain() { - private const string Block1Rlp = "f9025bf90256a0bc3546bbc73f86a96f5d966965ded9873dddc2278ce48c7251ef3062620a3543a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002018347c94c808458ee45dab861d783010600846765746887676f312e372e33856c696e75780000000000000000a06daa01cc93a2875795a705f8eae4d00de10d513bf975515a12e545254ae3195be42d6c49a83ae580f8c7ff7c69eef4f16626e8fd873114b46edec7744edca400a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block2Rlp = "f9025bf90256a03a060a78114b179fffc5581fbf36668f39a9928e58eaaf693c971b32446bd376a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002028347db3d808458ee45eab861d783010600846765746887676f312e372e33856c696e75780000000000000000e237c51d592ede43af886756f5ef941ae195bcfc2c324a206e753e070e3174a7649bc0ce5e17c94ecae5087fc6796c02a231fdfb94e4c9b3d1e19dd9bdb2040800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block3Rlp = "f9025bf90256a012d6551b449ce661299860948eccc6d65b26a67deef09d408ac6dfce1fac995aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002038347e7c4808458ee45f9b861d783010600846765746887676f312e372e33856c696e7578000000000000000021dfd43d2956e78e06eaf747f43858d442a79c970a109a6c39385bee232996b64a1de72743fa56efc967fd19cb9308174340f94a2f07b96eb82f82a3c72ce86300a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block4Rlp = "f9025bf90256a01ef022156ff2d5730931028d3fddaccf9ccda8818ba7f79dbeea78302550824ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002048347e7c4808458ee4608b861d783010600846765746887676f312e372e33856c696e7578000000000000000095ed0b3d04835d9ccbf11f79fdf75cf01a4a79fcb4b417b00acf461306e565616ed1903b307407143f2393af49d892399e8b09e01728d419f900ae99e13437f000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block5Rlp = "f9025bf90256a017d9b71cd90b4381da41265491792f5f78d36f80b14c3c7073af470d7e9b882aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002058347e7c4808458ee4617b861d783010600846765746887676f312e372e33856c696e75780000000000000000840db225f54032162d91245cc2f6c1b80b2e1d2b0657c3707e9c1f46add7b7525e0ba267addc476724e1eb70f7f76a5fd8c95df3d82dfb7a3d8c334c2fcb5ad201a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + IDb db = new MemDb(); + // Import blocks + _blockTree = Build.A.BlockTree().TestObject; + Block genesisBlock = GetGenesis(); + MineBlock(_blockTree, genesisBlock); + + Block block1 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block1Rlp))); + block1.Header.ParentHash = genesisBlock.Hash; + BuildSealer(1, db).SealBlock(block1, CancellationToken.None).Wait(); + block1.Header.Hash = block1.CalculateHash(); + MineBlock(_blockTree, block1); + + Block block2 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block2Rlp))); + block2.Header.ParentHash = block1.Hash; + BuildSealer(2, db).SealBlock(block2, CancellationToken.None).Wait(); + block2.Header.Hash = block2.CalculateHash(); + MineBlock(_blockTree, block2); + + Block block3 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block3Rlp))); + block3.Header.ParentHash = block2.Hash; + BuildSealer(3, db).SealBlock(block3, CancellationToken.None).Wait(); + block3.Header.Hash = block3.CalculateHash(); + MineBlock(_blockTree, block3); + + Block block4 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block4Rlp))); + block4.Header.ParentHash = block3.Hash; + BuildSealer(4, db).SealBlock(block4, CancellationToken.None).Wait(); + block4.Header.Hash = block4.CalculateHash(); + MineBlock(_blockTree, block4); + + Block block5 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block5Rlp))); + block5.Header.ParentHash = block4.Hash; + BuildSealer(5, db).SealBlock(block5, CancellationToken.None).Wait(); + block5.Header.Hash = block5.CalculateHash(); + MineBlock(_blockTree, block5); + _lastBlock = block5; + // Init snapshot db + + + // Select in-turn signer + int currentBlock = 6; + + BuildSealer(currentBlock, db); + } - private readonly List _signers = new() - { - new PrivateKey("06E84833EAC809859F46F84311CB152E2D2A505FE6B5FBC4CD2CABD37B678F1C"), - new PrivateKey("C7B39D4F871ACA337E3CC3AB956F1A916B5EF23AF9F5571566DDB8D3C99F66AC"), - new PrivateKey("9BD8E918E3176E86D406BFCE261D4CD2589167E3DBD0236B08B0B285783D7553"), - new PrivateKey("7DC56B10FD1EC64A8BF7547D3BAA254ACB96E8F2AD5A006DD2EBF9C40409A2CE") - }; - private CliqueSealer _clique; - private CliqueSealValidator _sealValidator; - private SnapshotManager _snapshotManager; - private Block _lastBlock; - private PrivateKey _currentSigner; - private BlockTree _blockTree; - - [OneTimeSetUp] - public void Setup_chain() - { - IDb db = new MemDb(); - // Import blocks - _blockTree = Build.A.BlockTree().TestObject; - Block genesisBlock = GetGenesis(); - MineBlock(_blockTree, genesisBlock); - - Block block1 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block1Rlp))); - block1.Header.ParentHash = genesisBlock.Hash; - BuildSealer(1, db).SealBlock(block1, CancellationToken.None).Wait(); - block1.Header.Hash = block1.CalculateHash(); - MineBlock(_blockTree, block1); - - Block block2 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block2Rlp))); - block2.Header.ParentHash = block1.Hash; - BuildSealer(2, db).SealBlock(block2, CancellationToken.None).Wait(); - block2.Header.Hash = block2.CalculateHash(); - MineBlock(_blockTree, block2); - - Block block3 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block3Rlp))); - block3.Header.ParentHash = block2.Hash; - BuildSealer(3, db).SealBlock(block3, CancellationToken.None).Wait(); - block3.Header.Hash = block3.CalculateHash(); - MineBlock(_blockTree, block3); - - Block block4 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block4Rlp))); - block4.Header.ParentHash = block3.Hash; - BuildSealer(4, db).SealBlock(block4, CancellationToken.None).Wait(); - block4.Header.Hash = block4.CalculateHash(); - MineBlock(_blockTree, block4); - - Block block5 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block5Rlp))); - block5.Header.ParentHash = block4.Hash; - BuildSealer(5, db).SealBlock(block5, CancellationToken.None).Wait(); - block5.Header.Hash = block5.CalculateHash(); - MineBlock(_blockTree, block5); - _lastBlock = block5; - // Init snapshot db - - - // Select in-turn signer - int currentBlock = 6; - - BuildSealer(currentBlock, db); - } + private CliqueSealer BuildSealer(int currentBlock, IDb db) + { + IEthereumEcdsa ecdsa = new EthereumEcdsa(BlockchainIds.Goerli); + CliqueConfig config = new(); + int currentSignerIndex = (currentBlock % _signers.Count); + _currentSigner = _signers[currentSignerIndex]; + _snapshotManager = new SnapshotManager(config, db, _blockTree, ecdsa, LimboLogs.Instance); + _sealValidator = new CliqueSealValidator(config, _snapshotManager, LimboLogs.Instance); + _clique = new CliqueSealer(new Signer(BlockchainIds.Goerli, _currentSigner, LimboLogs.Instance), config, + _snapshotManager, LimboLogs.Instance); + return _clique; + } - private CliqueSealer BuildSealer(int currentBlock, IDb db) - { - IEthereumEcdsa ecdsa = new EthereumEcdsa(BlockchainIds.Goerli); - CliqueConfig config = new(); - int currentSignerIndex = (currentBlock % _signers.Count); - _currentSigner = _signers[currentSignerIndex]; - _snapshotManager = new SnapshotManager(config, db, _blockTree, ecdsa, LimboLogs.Instance); - _sealValidator = new CliqueSealValidator(config, _snapshotManager, LimboLogs.Instance); - _clique = new CliqueSealer(new Signer(BlockchainIds.Goerli, _currentSigner, LimboLogs.Instance), config, - _snapshotManager, LimboLogs.Instance); - return _clique; - } + [Test] + public async Task Can_sign_block() + { + Block block6 = CreateBlock(2, 6, _lastBlock); + Block signed = await _clique.SealBlock(block6, CancellationToken.None); + bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(signed.ParentHash, BlockTreeLookupOptions.None), signed.Header); + bool validSeal = _sealValidator.ValidateSeal(signed.Header, true); + Assert.That(validHeader, Is.True); + Assert.That(validSeal, Is.True); + } - [Test] - public async Task Can_sign_block() - { - Block block6 = CreateBlock(2, 6, _lastBlock); - Block signed = await _clique.SealBlock(block6, CancellationToken.None); - bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(signed.ParentHash, BlockTreeLookupOptions.None), signed.Header); - bool validSeal = _sealValidator.ValidateSeal(signed.Header, true); - Assert.True(validHeader); - Assert.True(validSeal); - } + private Block GetGenesis() + { + Hash256 parentHash = Keccak.Zero; + Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; + Address beneficiary = Address.Zero; + UInt256 difficulty = new(1); + long number = 0L; + int gasLimit = 4700000; + ulong timestamp = 1492009146UL; + byte[] extraData = Bytes.FromHexString(GetGenesisExtraData()); + BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); + header.Bloom = Bloom.Empty; + Block genesis = new(header); + genesis.Header.Bloom = Bloom.Empty; + genesis.Header.Hash = genesis.CalculateHash(); + + return genesis; + } - private Block GetGenesis() + private string GetGenesisExtraData() + { + StringBuilder extraDataString = new(); + extraDataString.Append("52657370656374206d7920617574686f7269746168207e452e436172746d616e"); + for (int i = 0; i < _signers.Count; i++) { - Hash256 parentHash = Keccak.Zero; - Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; - Address beneficiary = Address.Zero; - UInt256 difficulty = new(1); - long number = 0L; - int gasLimit = 4700000; - ulong timestamp = 1492009146UL; - byte[] extraData = Bytes.FromHexString(GetGenesisExtraData()); - BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); - header.Bloom = Bloom.Empty; - Block genesis = new(header); - genesis.Header.Bloom = Bloom.Empty; - genesis.Header.Hash = genesis.CalculateHash(); - - return genesis; + extraDataString.Append(_signers[i].Address.ToString(false, false)); } - private string GetGenesisExtraData() - { - StringBuilder extraDataString = new(); - extraDataString.Append("52657370656374206d7920617574686f7269746168207e452e436172746d616e"); - for (int i = 0; i < _signers.Count; i++) - { - extraDataString.Append(_signers[i].Address.ToString(false, false)); - } - - extraDataString.Append("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - return extraDataString.ToString(); - } + extraDataString.Append("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + return extraDataString.ToString(); + } - private static void MineBlock(BlockTree tree, Block block) - { - tree.SuggestBlock(block); - } + private static void MineBlock(BlockTree tree, Block block) + { + tree.SuggestBlock(block); + } - private Block CreateBlock(int blockDifficulty, int blockNumber, Block lastBlock) - { - Hash256 parentHash = lastBlock.Hash; - Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; - Address beneficiary = Address.Zero; - UInt256 difficulty = (UInt256)blockDifficulty; - long number = blockNumber; - int gasLimit = 4700000; - ulong timestamp = (ulong)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - byte[] extraData = Bytes.FromHexString("d883010812846765746888676f312e31312e31856c696e75780000000000000028eb026ab5355b45499053382886754f1db544618d45edc979de1864d83a626b77513bd34d7f21059e79e303c3ab210e1424e71bcb8347835cbd378a785a06f800"); - BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); - header.MixHash = Keccak.Zero; - Block block = new(header); - block.Header.Bloom = Bloom.Empty; - block.Header.Hash = block.CalculateHash(); - return block; - } + private Block CreateBlock(int blockDifficulty, int blockNumber, Block lastBlock) + { + Hash256 parentHash = lastBlock.Hash; + Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; + Address beneficiary = Address.Zero; + UInt256 difficulty = (UInt256)blockDifficulty; + long number = blockNumber; + int gasLimit = 4700000; + ulong timestamp = (ulong)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + byte[] extraData = Bytes.FromHexString("d883010812846765746888676f312e31312e31856c696e75780000000000000028eb026ab5355b45499053382886754f1db544618d45edc979de1864d83a626b77513bd34d7f21059e79e303c3ab210e1424e71bcb8347835cbd378a785a06f800"); + BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); + header.MixHash = Keccak.Zero; + Block block = new(header); + block.Header.Bloom = Bloom.Empty; + block.Header.Hash = block.CalculateHash(); + return block; + } - [Test] - public void BlockSealer() - { - BlockHeader header = BuildCliqueBlock(); + [Test] + public void BlockSealer() + { + BlockHeader header = BuildCliqueBlock(); - Address expectedBlockSealer = new("0xb279182d99e65703f0076e4812653aab85fca0f0"); - Address blockSealer = _snapshotManager.GetBlockSealer(header); - Assert.That(blockSealer, Is.EqualTo(expectedBlockSealer)); - } + Address expectedBlockSealer = new("0xb279182d99e65703f0076e4812653aab85fca0f0"); + Address blockSealer = _snapshotManager.GetBlockSealer(header); + Assert.That(blockSealer, Is.EqualTo(expectedBlockSealer)); + } - private static BlockHeader BuildCliqueBlock() - { - BlockHeader header = Build.A.BlockHeader - .WithParentHash(new Hash256("0x6d31ab6b6ee360d075bb032a094fb4ea52617268b760d15b47aa439604583453")) - .WithUnclesHash(Keccak.OfAnEmptySequenceRlp) - .WithBeneficiary(Address.Zero) - .WithBloom(Bloom.Empty) - .WithStateRoot(new Hash256("0x9853b6c62bd454466f4843b73e2f0bdd655a4e754c259d6cc0ad4e580d788f43")) - .WithTransactionsRoot(PatriciaTree.EmptyTreeHash) - .WithReceiptsRoot(PatriciaTree.EmptyTreeHash) - .WithDifficulty(2) - .WithNumber(269) - .WithGasLimit(4712388) - .WithGasUsed(0) - .WithTimestamp(1492014479) - .WithExtraData(Bytes.FromHexString("0xd783010600846765746887676f312e372e33856c696e757800000000000000004e2b663c52c4c1ef0db29649f1f4addd93257f33d6fe0ae6bd365e63ac9aac4169e2b761aa245fabbf0302055f01b8b5391fa0a134bab19710fd225ffac3afdf01")) - .WithMixHash(Keccak.Zero) - .WithNonce(0UL) - .TestObject; - return header; - } + private static BlockHeader BuildCliqueBlock() + { + BlockHeader header = Build.A.BlockHeader + .WithParentHash(new Hash256("0x6d31ab6b6ee360d075bb032a094fb4ea52617268b760d15b47aa439604583453")) + .WithUnclesHash(Keccak.OfAnEmptySequenceRlp) + .WithBeneficiary(Address.Zero) + .WithBloom(Bloom.Empty) + .WithStateRoot(new Hash256("0x9853b6c62bd454466f4843b73e2f0bdd655a4e754c259d6cc0ad4e580d788f43")) + .WithTransactionsRoot(PatriciaTree.EmptyTreeHash) + .WithReceiptsRoot(PatriciaTree.EmptyTreeHash) + .WithDifficulty(2) + .WithNumber(269) + .WithGasLimit(4712388) + .WithGasUsed(0) + .WithTimestamp(1492014479) + .WithExtraData(Bytes.FromHexString("0xd783010600846765746887676f312e372e33856c696e757800000000000000004e2b663c52c4c1ef0db29649f1f4addd93257f33d6fe0ae6bd365e63ac9aac4169e2b761aa245fabbf0302055f01b8b5391fa0a134bab19710fd225ffac3afdf01")) + .WithMixHash(Keccak.Zero) + .WithNonce(0UL) + .TestObject; + return header; } } diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs index 5bdaa0eac99..cbda530dd4e 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs @@ -18,134 +18,132 @@ using System.Threading.Tasks; using BlockTree = Nethermind.Blockchain.BlockTree; -namespace Nethermind.Clique.Test +namespace Nethermind.Clique.Test; + +[Parallelizable(ParallelScope.Self)] +public class CliqueTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class CliqueTests + private const string Block1Rlp = "f9025bf90256a06341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002018347c94c808458ee45dab861d783010600846765746887676f312e372e33856c696e757800000000000000009f1efa1efa72af138c915966c639544a0255e6288e188c22ce9168c10dbe46da3d88b4aa065930119fb886210bf01a084fde5d3bc48d8aa38bca92e4fcc5215100a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block2Rlp = "f9025bf90256a0a7684ac44d48494670b2e0d9085b7750e7341620f0a271db146ed5e70c1db854a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002028347db3d808458ee45eab861d783010600846765746887676f312e372e33856c696e75780000000000000000b5a4a624d2e19fdab62ff7f4d2f2b80dfab4c518761beb56c2319c4224dd156f698bb1a2750c7edf12d61c4022079622062039637f40fb817e2cce0f0a4dae9c01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block3Rlp = "f9025bf90256a09b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002038347e7c4808458ee45f9b861d783010600846765746887676f312e372e33856c696e757800000000000000004e10f96536e45ceca7e34cc1bdda71db3f3bb029eb69afd28b57eb0202c0ec0859d383a99f63503c4df9ab6c1dc63bf6b9db77be952f47d86d2d7b208e77397301a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block4Rlp = "f9025bf90256a09eb9db9c3ec72918c7db73ae44e520139e95319c421ed6f9fc11fa8dd0cddc56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002048347e7c4808458ee4608b861d783010600846765746887676f312e372e33856c696e75780000000000000000713c53f21fd59a94de9c3f8342777f6660a3e99187114ebf52f0127caf6bcefa77195308fb80b4e6223673757732485c234d8f431a99c46799c57a4ecc4e4e5401a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block5Rlp = "f9025bf90256a08dabb64040467fa4e99a061878d90396978d173ecf47b2f72aa31e8d7ad917a9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002058347e7c4808458ee4617b861d783010600846765746887676f312e372e33856c696e7578000000000000000052ad0baf5fefa05b3a51cdcc6484901465c66be48c3c9b7a4fcb5fcb867ea220390bcb6e4d740bc17d0c9e948cf0803cab107b538fb3a3efde89e26ede9ee26801a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + + private SnapshotManager _snapshotManager; + private CliqueSealer _clique; + private CliqueSealValidator _sealValidator; + private EthereumEcdsa _ecdsa; + private BlockTree _blockTree; + + [SetUp] + public void Setup_chain() + { + // Import blocks + _blockTree = Build.A.BlockTree().TestObject; + Block block1 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block1Rlp))); + Block block2 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block2Rlp))); + Block block3 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block3Rlp))); + Block block4 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block4Rlp))); + Block block5 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block5Rlp))); + Block genesisBlock = GetGenesis(); + // Add blocks + MineBlock(_blockTree, genesisBlock); + MineBlock(_blockTree, block1); + MineBlock(_blockTree, block2); + MineBlock(_blockTree, block3); + MineBlock(_blockTree, block4); + MineBlock(_blockTree, block5); + // Get a test private key + PrivateKey key = Build.A.PrivateKey.TestObject; + // Init snapshot db + MemDb db = new(); + CliqueConfig config = new(); + + _ecdsa = new EthereumEcdsa(BlockchainIds.Goerli); + _snapshotManager = new SnapshotManager(config, db, _blockTree, _ecdsa, LimboLogs.Instance); + _clique = new CliqueSealer(new Signer(BlockchainIds.Goerli, key, LimboLogs.Instance), config, _snapshotManager, LimboLogs.Instance); + _sealValidator = new CliqueSealValidator(config, _snapshotManager, LimboLogs.Instance); + } + + [TestCase(Block1Rlp)] + [TestCase(Block2Rlp)] + [TestCase(Block3Rlp)] + [TestCase(Block4Rlp)] + [TestCase(Block5Rlp)] + public void Test_real_block(string blockRlp) + { + Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(block.ParentHash, BlockTreeLookupOptions.None), block.Header); + bool validSeal = _sealValidator.ValidateSeal(block.Header, true); + Assert.That(validHeader, Is.True); + Assert.That(validSeal, Is.True); + } + + [TestCase(Block4Rlp)] + public void Test_no_signer_data_at_epoch_fails(string blockRlp) + { + CliqueConfig config = new() { Epoch = 4 }; + _clique = new CliqueSealer(NullSigner.Instance, config, _snapshotManager, LimboLogs.Instance); + _sealValidator = new CliqueSealValidator(config, _snapshotManager, LimboLogs.Instance); + Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(block.ParentHash, BlockTreeLookupOptions.None), block.Header); + bool validSeal = _sealValidator.ValidateSeal(block.Header, true); + Assert.That(validHeader, Is.False); + Assert.That(validSeal, Is.True); + } + + [TestCase(Block4Rlp)] + public async Task SealBlock_SignerCanSignHeader_FullHeaderIsUsedToSign(string blockRlp) + { + IHeaderSigner signer = Substitute.For(); + signer.CanSignHeader.Returns(true); + signer.CanSign.Returns(true); + signer.Address.Returns(new Address("0x7ffc57839b00206d1ad20c69a1981b489f772031")); + signer.Sign(Arg.Any()).Returns(new Signature(new byte[65])); + CliqueSealer sut = new CliqueSealer(signer, new CliqueConfig(), _snapshotManager, LimboLogs.Instance); + Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + + await sut.SealBlock(block, System.Threading.CancellationToken.None); + + signer.Received().Sign(Arg.Any()); + } + + [TestCase(Block4Rlp)] + public async Task SealBlock_SignerCannotSignHeader_HashIsUsedToSign(string blockRlp) + { + ISigner signer = Substitute.For(); + signer.CanSign.Returns(true); + signer.Address.Returns(new Address("0x7ffc57839b00206d1ad20c69a1981b489f772031")); + signer.Sign(Arg.Any()).Returns(new Signature(new byte[65])); + CliqueSealer sut = new CliqueSealer(signer, new CliqueConfig(), _snapshotManager, LimboLogs.Instance); + Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + + await sut.SealBlock(block, System.Threading.CancellationToken.None); + + signer.Received().Sign(Arg.Any()); + } + + public static Block GetGenesis() + { + Hash256 parentHash = Keccak.Zero; + Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; + Address beneficiary = Address.Zero; + UInt256 difficulty = new(1); + long number = 0L; + int gasLimit = 4700000; + ulong timestamp = 1492009146UL; + byte[] extraData = Bytes.FromHexString("52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); + header.Bloom = Bloom.Empty; + Block genesis = new(header); + genesis.Header.Hash = new Hash256("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177"); + + return genesis; + } + + private void MineBlock(BlockTree tree, Block block) { - private const string Block1Rlp = "f9025bf90256a06341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002018347c94c808458ee45dab861d783010600846765746887676f312e372e33856c696e757800000000000000009f1efa1efa72af138c915966c639544a0255e6288e188c22ce9168c10dbe46da3d88b4aa065930119fb886210bf01a084fde5d3bc48d8aa38bca92e4fcc5215100a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block2Rlp = "f9025bf90256a0a7684ac44d48494670b2e0d9085b7750e7341620f0a271db146ed5e70c1db854a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002028347db3d808458ee45eab861d783010600846765746887676f312e372e33856c696e75780000000000000000b5a4a624d2e19fdab62ff7f4d2f2b80dfab4c518761beb56c2319c4224dd156f698bb1a2750c7edf12d61c4022079622062039637f40fb817e2cce0f0a4dae9c01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block3Rlp = "f9025bf90256a09b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002038347e7c4808458ee45f9b861d783010600846765746887676f312e372e33856c696e757800000000000000004e10f96536e45ceca7e34cc1bdda71db3f3bb029eb69afd28b57eb0202c0ec0859d383a99f63503c4df9ab6c1dc63bf6b9db77be952f47d86d2d7b208e77397301a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block4Rlp = "f9025bf90256a09eb9db9c3ec72918c7db73ae44e520139e95319c421ed6f9fc11fa8dd0cddc56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002048347e7c4808458ee4608b861d783010600846765746887676f312e372e33856c696e75780000000000000000713c53f21fd59a94de9c3f8342777f6660a3e99187114ebf52f0127caf6bcefa77195308fb80b4e6223673757732485c234d8f431a99c46799c57a4ecc4e4e5401a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block5Rlp = "f9025bf90256a08dabb64040467fa4e99a061878d90396978d173ecf47b2f72aa31e8d7ad917a9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002058347e7c4808458ee4617b861d783010600846765746887676f312e372e33856c696e7578000000000000000052ad0baf5fefa05b3a51cdcc6484901465c66be48c3c9b7a4fcb5fcb867ea220390bcb6e4d740bc17d0c9e948cf0803cab107b538fb3a3efde89e26ede9ee26801a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - - private SnapshotManager _snapshotManager; - private CliqueSealer _clique; - private CliqueSealValidator _sealValidator; - private EthereumEcdsa _ecdsa; - private BlockTree _blockTree; - - [SetUp] - public void Setup_chain() - { - // Import blocks - _blockTree = Build.A.BlockTree().TestObject; - Block block1 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block1Rlp))); - Block block2 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block2Rlp))); - Block block3 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block3Rlp))); - Block block4 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block4Rlp))); - Block block5 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block5Rlp))); - Block genesisBlock = GetGenesis(); - // Add blocks - MineBlock(_blockTree, genesisBlock); - MineBlock(_blockTree, block1); - MineBlock(_blockTree, block2); - MineBlock(_blockTree, block3); - MineBlock(_blockTree, block4); - MineBlock(_blockTree, block5); - // Get a test private key - PrivateKey key = Build.A.PrivateKey.TestObject; - // Init snapshot db - MemDb db = new(); - CliqueConfig config = new(); - - _ecdsa = new EthereumEcdsa(BlockchainIds.Goerli); - _snapshotManager = new SnapshotManager(config, db, _blockTree, _ecdsa, LimboLogs.Instance); - _clique = new CliqueSealer(new Signer(BlockchainIds.Goerli, key, LimboLogs.Instance), config, _snapshotManager, LimboLogs.Instance); - _sealValidator = new CliqueSealValidator(config, _snapshotManager, LimboLogs.Instance); - } - - [TestCase(Block1Rlp)] - [TestCase(Block2Rlp)] - [TestCase(Block3Rlp)] - [TestCase(Block4Rlp)] - [TestCase(Block5Rlp)] - public void Test_real_block(string blockRlp) - { - Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(block.ParentHash, BlockTreeLookupOptions.None), block.Header); - bool validSeal = _sealValidator.ValidateSeal(block.Header, true); - Assert.True(validHeader); - Assert.True(validSeal); - } - - [TestCase(Block4Rlp)] - public void Test_no_signer_data_at_epoch_fails(string blockRlp) - { - CliqueConfig config = new() { Epoch = 4 }; - _clique = new CliqueSealer(NullSigner.Instance, config, _snapshotManager, LimboLogs.Instance); - _sealValidator = new CliqueSealValidator(config, _snapshotManager, LimboLogs.Instance); - Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(block.ParentHash, BlockTreeLookupOptions.None), block.Header); - bool validSeal = _sealValidator.ValidateSeal(block.Header, true); - Assert.False(validHeader); - Assert.True(validSeal); - } - - [TestCase(Block4Rlp)] - public async Task SealBlock_SignerCanSignHeader_FullHeaderIsUsedToSign(string blockRlp) - { - IHeaderSigner signer = Substitute.For(); - signer.CanSignHeader.Returns(true); - signer.CanSign.Returns(true); - signer.Address.Returns(new Address("0x7ffc57839b00206d1ad20c69a1981b489f772031")); - signer.Sign(Arg.Any()).Returns(new Signature(new byte[65])); - CliqueSealer sut = new CliqueSealer(signer, new CliqueConfig(), _snapshotManager, LimboLogs.Instance); - Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - - await sut.SealBlock(block, System.Threading.CancellationToken.None); - - signer.Received().Sign(Arg.Any()); - } - - [TestCase(Block4Rlp)] - public async Task SealBlock_SignerCannotSignHeader_HashIsUsedToSign(string blockRlp) - { - ISigner signer = Substitute.For(); - signer.CanSign.Returns(true); - signer.Address.Returns(new Address("0x7ffc57839b00206d1ad20c69a1981b489f772031")); - signer.Sign(Arg.Any()).Returns(new Signature(new byte[65])); - CliqueSealer sut = new CliqueSealer(signer, new CliqueConfig(), _snapshotManager, LimboLogs.Instance); - Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - - await sut.SealBlock(block, System.Threading.CancellationToken.None); - - signer.Received().Sign(Arg.Any()); - } - - public static Block GetGenesis() - { - Hash256 parentHash = Keccak.Zero; - Hash256 unclesHash = Keccak.OfAnEmptySequenceRlp; - Address beneficiary = Address.Zero; - UInt256 difficulty = new(1); - long number = 0L; - int gasLimit = 4700000; - ulong timestamp = 1492009146UL; - byte[] extraData = Bytes.FromHexString("52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - BlockHeader header = new(parentHash, unclesHash, beneficiary, difficulty, number, gasLimit, timestamp, extraData); - header.Bloom = Bloom.Empty; - Block genesis = new(header); - genesis.Header.Hash = new Hash256("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177"); - - return genesis; - } - - private void MineBlock(BlockTree tree, Block block) - { - tree.SuggestBlock(block); - tree.UpdateMainChain(block); - } + tree.SuggestBlock(block); + tree.UpdateMainChain(block); } } diff --git a/src/Nethermind/Nethermind.Clique.Test/SnapshotManagerTests.cs b/src/Nethermind/Nethermind.Clique.Test/SnapshotManagerTests.cs index 549f5175241..b86130b86c0 100644 --- a/src/Nethermind/Nethermind.Clique.Test/SnapshotManagerTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/SnapshotManagerTests.cs @@ -14,131 +14,129 @@ using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; -namespace Nethermind.Clique.Test +namespace Nethermind.Clique.Test; + +[Parallelizable(ParallelScope.Self)] +public class SnapshotManagerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class SnapshotManagerTests - { - private readonly IDb _snapshotDb = new MemDb(); + private readonly IDb _snapshotDb = new MemDb(); - private const string Block1Rlp = "f9025bf90256a06341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002018347c94c808458ee45dab861d783010600846765746887676f312e372e33856c696e757800000000000000009f1efa1efa72af138c915966c639544a0255e6288e188c22ce9168c10dbe46da3d88b4aa065930119fb886210bf01a084fde5d3bc48d8aa38bca92e4fcc5215100a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block2Rlp = "f9025bf90256a0a7684ac44d48494670b2e0d9085b7750e7341620f0a271db146ed5e70c1db854a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002028347db3d808458ee45eab861d783010600846765746887676f312e372e33856c696e75780000000000000000b5a4a624d2e19fdab62ff7f4d2f2b80dfab4c518761beb56c2319c4224dd156f698bb1a2750c7edf12d61c4022079622062039637f40fb817e2cce0f0a4dae9c01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block3Rlp = "f9025bf90256a09b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002038347e7c4808458ee45f9b861d783010600846765746887676f312e372e33856c696e757800000000000000004e10f96536e45ceca7e34cc1bdda71db3f3bb029eb69afd28b57eb0202c0ec0859d383a99f63503c4df9ab6c1dc63bf6b9db77be952f47d86d2d7b208e77397301a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block4Rlp = "f9025bf90256a09eb9db9c3ec72918c7db73ae44e520139e95319c421ed6f9fc11fa8dd0cddc56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002048347e7c4808458ee4608b861d783010600846765746887676f312e372e33856c696e75780000000000000000713c53f21fd59a94de9c3f8342777f6660a3e99187114ebf52f0127caf6bcefa77195308fb80b4e6223673757732485c234d8f431a99c46799c57a4ecc4e4e5401a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private const string Block5Rlp = "f9025bf90256a08dabb64040467fa4e99a061878d90396978d173ecf47b2f72aa31e8d7ad917a9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002058347e7c4808458ee4617b861d783010600846765746887676f312e372e33856c696e7578000000000000000052ad0baf5fefa05b3a51cdcc6484901465c66be48c3c9b7a4fcb5fcb867ea220390bcb6e4d740bc17d0c9e948cf0803cab107b538fb3a3efde89e26ede9ee26801a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block1Rlp = "f9025bf90256a06341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002018347c94c808458ee45dab861d783010600846765746887676f312e372e33856c696e757800000000000000009f1efa1efa72af138c915966c639544a0255e6288e188c22ce9168c10dbe46da3d88b4aa065930119fb886210bf01a084fde5d3bc48d8aa38bca92e4fcc5215100a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block2Rlp = "f9025bf90256a0a7684ac44d48494670b2e0d9085b7750e7341620f0a271db146ed5e70c1db854a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002028347db3d808458ee45eab861d783010600846765746887676f312e372e33856c696e75780000000000000000b5a4a624d2e19fdab62ff7f4d2f2b80dfab4c518761beb56c2319c4224dd156f698bb1a2750c7edf12d61c4022079622062039637f40fb817e2cce0f0a4dae9c01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block3Rlp = "f9025bf90256a09b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002038347e7c4808458ee45f9b861d783010600846765746887676f312e372e33856c696e757800000000000000004e10f96536e45ceca7e34cc1bdda71db3f3bb029eb69afd28b57eb0202c0ec0859d383a99f63503c4df9ab6c1dc63bf6b9db77be952f47d86d2d7b208e77397301a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block4Rlp = "f9025bf90256a09eb9db9c3ec72918c7db73ae44e520139e95319c421ed6f9fc11fa8dd0cddc56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002048347e7c4808458ee4608b861d783010600846765746887676f312e372e33856c696e75780000000000000000713c53f21fd59a94de9c3f8342777f6660a3e99187114ebf52f0127caf6bcefa77195308fb80b4e6223673757732485c234d8f431a99c46799c57a4ecc4e4e5401a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; + private const string Block5Rlp = "f9025bf90256a08dabb64040467fa4e99a061878d90396978d173ecf47b2f72aa31e8d7ad917a9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a053580584816f617295ea26c0e17641e0120cab2f0a8ffb53a866fd53aa8e8c2da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002058347e7c4808458ee4617b861d783010600846765746887676f312e372e33856c696e7578000000000000000052ad0baf5fefa05b3a51cdcc6484901465c66be48c3c9b7a4fcb5fcb867ea220390bcb6e4d740bc17d0c9e948cf0803cab107b538fb3a3efde89e26ede9ee26801a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0"; - private readonly Address _signer1 = new("0x7ffc57839b00206d1ad20c69a1981b489f772031"); - private readonly Address _signer2 = new("0xb279182d99e65703f0076e4812653aab85fca0f0"); - private readonly Address _signer3 = new("0x42eb768f2244c8811c63729a21a3569731535f06"); + private readonly Address _signer1 = new("0x7ffc57839b00206d1ad20c69a1981b489f772031"); + private readonly Address _signer2 = new("0xb279182d99e65703f0076e4812653aab85fca0f0"); + private readonly Address _signer3 = new("0x42eb768f2244c8811c63729a21a3569731535f06"); - private BlockTree _blockTree; + private BlockTree _blockTree; - [OneTimeSetUp] - public void Setup_chain() - { - // Import blocks - _blockTree = Build.A.BlockTree().TestObject; - Block block1 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block1Rlp))); - Block block2 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block2Rlp))); - Block block3 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block3Rlp))); - Block block4 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block4Rlp))); - Block block5 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block5Rlp))); - Block genesisBlock = CliqueTests.GetGenesis(); - // Add blocks - MineBlock(_blockTree, genesisBlock); - MineBlock(_blockTree, block1); - MineBlock(_blockTree, block2); - MineBlock(_blockTree, block3); - MineBlock(_blockTree, block4); - MineBlock(_blockTree, block5); - } + [OneTimeSetUp] + public void Setup_chain() + { + // Import blocks + _blockTree = Build.A.BlockTree().TestObject; + Block block1 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block1Rlp))); + Block block2 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block2Rlp))); + Block block3 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block3Rlp))); + Block block4 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block4Rlp))); + Block block5 = Rlp.Decode(new Rlp(Bytes.FromHexString(Block5Rlp))); + Block genesisBlock = CliqueTests.GetGenesis(); + // Add blocks + MineBlock(_blockTree, genesisBlock); + MineBlock(_blockTree, block1); + MineBlock(_blockTree, block2); + MineBlock(_blockTree, block3); + MineBlock(_blockTree, block4); + MineBlock(_blockTree, block5); + } - [OneTimeTearDown] - public void TearDown() => _snapshotDb?.Dispose(); + [OneTimeTearDown] + public void TearDown() => _snapshotDb?.Dispose(); - [Test] - public void Creates_new_snapshot() - { - SnapshotManager snapshotManager = new(CliqueConfig.Default, _snapshotDb, _blockTree, NullEthereumEcdsa.Instance, LimboLogs.Instance); - Block genesis = CliqueTests.GetGenesis(); - Snapshot snapshot = snapshotManager.GetOrCreateSnapshot(0, genesis.Hash); - Assert.That(snapshot.Hash, Is.EqualTo(genesis.Hash)); - } + [Test] + public void Creates_new_snapshot() + { + SnapshotManager snapshotManager = new(CliqueConfig.Default, _snapshotDb, _blockTree, NullEthereumEcdsa.Instance, LimboLogs.Instance); + Block genesis = CliqueTests.GetGenesis(); + Snapshot snapshot = snapshotManager.GetOrCreateSnapshot(0, genesis.Hash); + Assert.That(snapshot.Hash, Is.EqualTo(genesis.Hash)); + } - [Test] - public void Loads_snapshot() - { - SnapshotManager snapshotManager = new(CliqueConfig.Default, _snapshotDb, _blockTree, NullEthereumEcdsa.Instance, LimboLogs.Instance); - Block genesis = CliqueTests.GetGenesis(); - Snapshot snapshot = snapshotManager.GetOrCreateSnapshot(0, genesis.Hash); - Assert.NotNull(snapshot); - Assert.That(snapshot.Hash, Is.EqualTo(genesis.Hash)); - Assert.That(snapshot.Number, Is.EqualTo(genesis.Number)); - // Check signers - Assert.IsTrue(snapshot.Signers.ContainsKey(_signer1)); - Assert.IsTrue(snapshot.Signers.ContainsKey(_signer2)); - Assert.IsTrue(snapshot.Signers.ContainsKey(_signer3)); - } + [Test] + public void Loads_snapshot() + { + SnapshotManager snapshotManager = new(CliqueConfig.Default, _snapshotDb, _blockTree, NullEthereumEcdsa.Instance, LimboLogs.Instance); + Block genesis = CliqueTests.GetGenesis(); + Snapshot snapshot = snapshotManager.GetOrCreateSnapshot(0, genesis.Hash); + Assert.That(snapshot, Is.Not.Null); + Assert.That(snapshot.Hash, Is.EqualTo(genesis.Hash)); + Assert.That(snapshot.Number, Is.EqualTo(genesis.Number)); + // Check signers + Assert.That(snapshot.Signers.ContainsKey(_signer1), Is.True); + Assert.That(snapshot.Signers.ContainsKey(_signer2), Is.True); + Assert.That(snapshot.Signers.ContainsKey(_signer3), Is.True); + } - [Test] - public void Can_calculate_clique_header_hash() - { - BlockHeader header = BuildCliqueBlock(); + [Test] + public void Can_calculate_clique_header_hash() + { + BlockHeader header = BuildCliqueBlock(); - Hash256 expectedHeaderHash = new("0x7b27b6add9e8d0184c722dde86a2a3f626630264bae3d62ffeea1585ce6e3cdd"); - Hash256 headerHash = SnapshotManager.CalculateCliqueHeaderHash(header); - Assert.That(headerHash, Is.EqualTo(expectedHeaderHash)); - } + Hash256 expectedHeaderHash = new("0x7b27b6add9e8d0184c722dde86a2a3f626630264bae3d62ffeea1585ce6e3cdd"); + Hash256 headerHash = SnapshotManager.CalculateCliqueHeaderHash(header); + Assert.That(headerHash, Is.EqualTo(expectedHeaderHash)); + } - [Test] - public void Recognises_signer_turn() - { - SnapshotManager snapshotManager = new(CliqueConfig.Default, _snapshotDb, _blockTree, NullEthereumEcdsa.Instance, LimboLogs.Instance); - Block genesis = CliqueTests.GetGenesis(); - Snapshot snapshot = snapshotManager.GetOrCreateSnapshot(0, genesis.Hash); - // Here we use a random chain id, should be test independent. - SnapshotManager manager = new(CliqueConfig.Default, _snapshotDb, _blockTree, new EthereumEcdsa(BlockchainIds.GenericNonRealNetwork), LimboLogs.Instance); - // Block 1 - Assert.IsTrue(manager.IsInTurn(snapshot, 1, _signer1)); - Assert.IsFalse(manager.IsInTurn(snapshot, 1, _signer2)); - Assert.IsFalse(manager.IsInTurn(snapshot, 1, _signer3)); - // Block 2 - Assert.IsFalse(manager.IsInTurn(snapshot, 2, _signer1)); - Assert.IsTrue(manager.IsInTurn(snapshot, 2, _signer2)); - Assert.IsFalse(manager.IsInTurn(snapshot, 2, _signer3)); - // Block 3 - Assert.IsFalse(manager.IsInTurn(snapshot, 3, _signer1)); - Assert.IsFalse(manager.IsInTurn(snapshot, 3, _signer2)); - Assert.IsTrue(manager.IsInTurn(snapshot, 3, _signer3)); - } + [Test] + public void Recognises_signer_turn() + { + SnapshotManager snapshotManager = new(CliqueConfig.Default, _snapshotDb, _blockTree, NullEthereumEcdsa.Instance, LimboLogs.Instance); + Block genesis = CliqueTests.GetGenesis(); + Snapshot snapshot = snapshotManager.GetOrCreateSnapshot(0, genesis.Hash); + // Here we use a random chain id, should be test independent. + SnapshotManager manager = new(CliqueConfig.Default, _snapshotDb, _blockTree, new EthereumEcdsa(BlockchainIds.GenericNonRealNetwork), LimboLogs.Instance); + // Block 1 + Assert.That(manager.IsInTurn(snapshot, 1, _signer1), Is.True); + Assert.That(manager.IsInTurn(snapshot, 1, _signer2), Is.False); + Assert.That(manager.IsInTurn(snapshot, 1, _signer3), Is.False); + // Block 2 + Assert.That(manager.IsInTurn(snapshot, 2, _signer1), Is.False); + Assert.That(manager.IsInTurn(snapshot, 2, _signer2), Is.True); + Assert.That(manager.IsInTurn(snapshot, 2, _signer3), Is.False); + // Block 3 + Assert.That(manager.IsInTurn(snapshot, 3, _signer1), Is.False); + Assert.That(manager.IsInTurn(snapshot, 3, _signer2), Is.False); + Assert.That(manager.IsInTurn(snapshot, 3, _signer3), Is.True); + } - private static BlockHeader BuildCliqueBlock() - { - BlockHeader header = Build.A.BlockHeader - .WithParentHash(new Hash256("0x6d31ab6b6ee360d075bb032a094fb4ea52617268b760d15b47aa439604583453")) - .WithUnclesHash(Keccak.OfAnEmptySequenceRlp) - .WithBeneficiary(Address.Zero) - .WithBloom(Bloom.Empty) - .WithStateRoot(new Hash256("0x9853b6c62bd454466f4843b73e2f0bdd655a4e754c259d6cc0ad4e580d788f43")) - .WithTransactionsRoot(PatriciaTree.EmptyTreeHash) - .WithReceiptsRoot(PatriciaTree.EmptyTreeHash) - .WithDifficulty(2) - .WithNumber(269) - .WithGasLimit(4712388) - .WithGasUsed(0) - .WithTimestamp(1492014479) - .WithExtraData(Bytes.FromHexString("0xd783010600846765746887676f312e372e33856c696e757800000000000000004e2b663c52c4c1ef0db29649f1f4addd93257f33d6fe0ae6bd365e63ac9aac4169e2b761aa245fabbf0302055f01b8b5391fa0a134bab19710fd225ffac3afdf01")) - .WithMixHash(Keccak.Zero) - .WithNonce(0UL) - .TestObject; - return header; - } + private static BlockHeader BuildCliqueBlock() + { + BlockHeader header = Build.A.BlockHeader + .WithParentHash(new Hash256("0x6d31ab6b6ee360d075bb032a094fb4ea52617268b760d15b47aa439604583453")) + .WithUnclesHash(Keccak.OfAnEmptySequenceRlp) + .WithBeneficiary(Address.Zero) + .WithBloom(Bloom.Empty) + .WithStateRoot(new Hash256("0x9853b6c62bd454466f4843b73e2f0bdd655a4e754c259d6cc0ad4e580d788f43")) + .WithTransactionsRoot(PatriciaTree.EmptyTreeHash) + .WithReceiptsRoot(PatriciaTree.EmptyTreeHash) + .WithDifficulty(2) + .WithNumber(269) + .WithGasLimit(4712388) + .WithGasUsed(0) + .WithTimestamp(1492014479) + .WithExtraData(Bytes.FromHexString("0xd783010600846765746887676f312e372e33856c696e757800000000000000004e2b663c52c4c1ef0db29649f1f4addd93257f33d6fe0ae6bd365e63ac9aac4169e2b761aa245fabbf0302055f01b8b5391fa0a134bab19710fd225ffac3afdf01")) + .WithMixHash(Keccak.Zero) + .WithNonce(0UL) + .TestObject; + return header; + } - private void MineBlock(BlockTree tree, Block block) - { - tree.SuggestBlock(block); - tree.UpdateMainChain(block); - } + private void MineBlock(BlockTree tree, Block block) + { + tree.SuggestBlock(block); + tree.UpdateMainChain(block); } } diff --git a/src/Nethermind/Nethermind.Config.Test/ArgsConfigSourceTests.cs b/src/Nethermind/Nethermind.Config.Test/ArgsConfigSourceTests.cs index 0151976e2b8..2b65a4f2c9a 100644 --- a/src/Nethermind/Nethermind.Config.Test/ArgsConfigSourceTests.cs +++ b/src/Nethermind/Nethermind.Config.Test/ArgsConfigSourceTests.cs @@ -5,42 +5,40 @@ using System.Collections.Generic; using NUnit.Framework; -namespace Nethermind.Config.Test +namespace Nethermind.Config.Test; + +[Parallelizable(ParallelScope.All)] +public class ArgsConfigSourceTests { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class ArgsConfigSourceTests + [Test] + public void Works_fine_with_unset_values() { - [Test] - public void Works_fine_with_unset_values() - { - Dictionary args = new(); - ArgsConfigSource configSource = new(args); - Assert.IsFalse(configSource.GetValue(typeof(int), "a", "a").IsSet); - } + Dictionary args = new(); + ArgsConfigSource configSource = new(args); + Assert.That(configSource.GetValue(typeof(int), "a", "a").IsSet, Is.False); + } - [Test] - public void Is_case_insensitive() - { - Dictionary args = new(); - args.Add("A.a", "12"); - ArgsConfigSource configSource = new(args); - Assert.IsTrue(configSource.GetValue(typeof(int), "a", "A").IsSet); - } + [Test] + public void Is_case_insensitive() + { + Dictionary args = new(); + args.Add("A.a", "12"); + ArgsConfigSource configSource = new(args); + Assert.That(configSource.GetValue(typeof(int), "a", "A").IsSet, Is.True); + } - [TestCase(typeof(byte), "12", (byte)12)] - [TestCase(typeof(int), "12", 12)] - [TestCase(typeof(uint), "12", 12U)] - [TestCase(typeof(long), "12", 12L)] - [TestCase(typeof(ulong), "12", 12UL)] - [TestCase(typeof(string), "12", "12")] - [TestCase(typeof(bool), "false", false)] - public void Can_parse_various_values(Type valueType, string valueString, object parsedValue) - { - Dictionary args = new(); - args.Add("A.a", valueString); - ArgsConfigSource configSource = new(args); - Assert.That(configSource.GetValue(valueType, "a", "A").Value, Is.EqualTo(parsedValue)); - } + [TestCase(typeof(byte), "12", (byte)12)] + [TestCase(typeof(int), "12", 12)] + [TestCase(typeof(uint), "12", 12U)] + [TestCase(typeof(long), "12", 12L)] + [TestCase(typeof(ulong), "12", 12UL)] + [TestCase(typeof(string), "12", "12")] + [TestCase(typeof(bool), "false", false)] + public void Can_parse_various_values(Type valueType, string valueString, object parsedValue) + { + Dictionary args = new(); + args.Add("A.a", valueString); + ArgsConfigSource configSource = new(args); + Assert.That(configSource.GetValue(valueType, "a", "A").Value, Is.EqualTo(parsedValue)); } } diff --git a/src/Nethermind/Nethermind.Config.Test/EnvConfigSourceTests.cs b/src/Nethermind/Nethermind.Config.Test/EnvConfigSourceTests.cs index d2169b3e5e3..83673e30f05 100644 --- a/src/Nethermind/Nethermind.Config.Test/EnvConfigSourceTests.cs +++ b/src/Nethermind/Nethermind.Config.Test/EnvConfigSourceTests.cs @@ -4,38 +4,36 @@ using System; using NUnit.Framework; -namespace Nethermind.Config.Test +namespace Nethermind.Config.Test; + +public class EnvConfigSourceTests { - [TestFixture] - public class EnvConfigSourceTests + [Test] + public void Works_fine_with_unset_values() { - [Test] - public void Works_fine_with_unset_values() - { - EnvConfigSource configSource = new(); - Assert.IsFalse(configSource.GetValue(typeof(int), "b", "a").IsSet); - } + EnvConfigSource configSource = new(); + Assert.That(configSource.GetValue(typeof(int), "b", "a").IsSet, Is.False); + } - [Test] - public void Is_case_insensitive() - { - EnvConfigSource configSource = new(); - Environment.SetEnvironmentVariable("NETHERMIND_A_A", "12", EnvironmentVariableTarget.Process); - Assert.IsTrue(configSource.GetValue(typeof(int), "a", "A").IsSet); - } + [Test] + public void Is_case_insensitive() + { + EnvConfigSource configSource = new(); + Environment.SetEnvironmentVariable("NETHERMIND_A_A", "12", EnvironmentVariableTarget.Process); + Assert.That(configSource.GetValue(typeof(int), "a", "A").IsSet, Is.True); + } - [TestCase(typeof(byte), "12", (byte)12)] - [TestCase(typeof(int), "12", 12)] - [TestCase(typeof(uint), "12", 12U)] - [TestCase(typeof(long), "12", 12L)] - [TestCase(typeof(ulong), "12", 12UL)] - [TestCase(typeof(string), "12", "12")] - [TestCase(typeof(bool), "false", false)] - public void Can_parse_various_values(Type valueType, string valueString, object parsedValue) - { - Environment.SetEnvironmentVariable("NETHERMIND_A_A", valueString, EnvironmentVariableTarget.Process); - EnvConfigSource configSource = new(); - Assert.That(configSource.GetValue(valueType, "a", "A").Value, Is.EqualTo(parsedValue)); - } + [TestCase(typeof(byte), "12", (byte)12)] + [TestCase(typeof(int), "12", 12)] + [TestCase(typeof(uint), "12", 12U)] + [TestCase(typeof(long), "12", 12L)] + [TestCase(typeof(ulong), "12", 12UL)] + [TestCase(typeof(string), "12", "12")] + [TestCase(typeof(bool), "false", false)] + public void Can_parse_various_values(Type valueType, string valueString, object parsedValue) + { + Environment.SetEnvironmentVariable("NETHERMIND_A_A", valueString, EnvironmentVariableTarget.Process); + EnvConfigSource configSource = new(); + Assert.That(configSource.GetValue(valueType, "a", "A").Value, Is.EqualTo(parsedValue)); } } diff --git a/src/Nethermind/Nethermind.Config.Test/JsonConfigProviderTests.cs b/src/Nethermind/Nethermind.Config.Test/JsonConfigProviderTests.cs index 784277655e1..5017671f906 100644 --- a/src/Nethermind/Nethermind.Config.Test/JsonConfigProviderTests.cs +++ b/src/Nethermind/Nethermind.Config.Test/JsonConfigProviderTests.cs @@ -16,68 +16,66 @@ using Nethermind.Stats; using NUnit.Framework; -namespace Nethermind.Config.Test +namespace Nethermind.Config.Test; + +public class JsonConfigProviderTests { - [TestFixture] - public class JsonConfigProviderTests - { - private JsonConfigProvider _configProvider = null!; + private JsonConfigProvider _configProvider = null!; - [SetUp] - [SuppressMessage("ReSharper", "UnusedVariable")] - public void Initialize() - { - KeyStoreConfig keystoreConfig = new(); - NetworkConfig networkConfig = new(); - JsonRpcConfig jsonRpcConfig = new(); - StatsParameters statsConfig = StatsParameters.Instance; + [SetUp] + [SuppressMessage("ReSharper", "UnusedVariable")] + public void Initialize() + { + KeyStoreConfig keystoreConfig = new(); + NetworkConfig networkConfig = new(); + JsonRpcConfig jsonRpcConfig = new(); + StatsParameters statsConfig = StatsParameters.Instance; - _configProvider = new JsonConfigProvider("SampleJson/SampleJsonConfig.cfg"); - } + _configProvider = new JsonConfigProvider("SampleJson/SampleJsonConfig.cfg"); + } - [TestCase(12ul, typeof(BlocksConfig), nameof(BlocksConfig.SecondsPerSlot))] - [TestCase(false, typeof(BlocksConfig), nameof(BlocksConfig.RandomizedBlocks))] - [TestCase("chainspec/foundation.json", typeof(InitConfig), nameof(InitConfig.ChainSpecPath))] - [TestCase(DumpOptions.Default, typeof(InitConfig), nameof(InitConfig.AutoDump))] - public void Test_getDefaultValue(T expected, Type type, string propName) - { - IConfig config = Activator.CreateInstance(type) as IConfig ?? throw new Exception("type is not IConfig"); - T actual = config.GetDefaultValue(propName); - Assert.That(actual, Is.EqualTo(expected)); - } + [TestCase(12ul, typeof(BlocksConfig), nameof(BlocksConfig.SecondsPerSlot))] + [TestCase(false, typeof(BlocksConfig), nameof(BlocksConfig.RandomizedBlocks))] + [TestCase("chainspec/foundation.json", typeof(InitConfig), nameof(InitConfig.ChainSpecPath))] + [TestCase(DumpOptions.Default, typeof(InitConfig), nameof(InitConfig.AutoDump))] + public void Test_getDefaultValue(T expected, Type type, string propName) + { + IConfig config = Activator.CreateInstance(type) as IConfig ?? throw new Exception("type is not IConfig"); + T actual = config.GetDefaultValue(propName); + Assert.That(actual, Is.EqualTo(expected)); + } - [Test] - public void Provides_helpful_error_message_when_file_does_not_exist() - { - Assert.Throws(() => _configProvider = new JsonConfigProvider("SampleJson.cfg")); - } + [Test] + public void Provides_helpful_error_message_when_file_does_not_exist() + { + Assert.Throws(() => _configProvider = new JsonConfigProvider("SampleJson.cfg")); + } - [Test] - public void Can_load_config_from_file() - { - IKeyStoreConfig? keystoreConfig = _configProvider.GetConfig(); - IDiscoveryConfig? networkConfig = _configProvider.GetConfig(); - IJsonRpcConfig? jsonRpcConfig = _configProvider.GetConfig(); + [Test] + public void Can_load_config_from_file() + { + IKeyStoreConfig? keystoreConfig = _configProvider.GetConfig(); + IDiscoveryConfig? networkConfig = _configProvider.GetConfig(); + IJsonRpcConfig? jsonRpcConfig = _configProvider.GetConfig(); - Assert.That(keystoreConfig.KdfparamsDklen, Is.EqualTo(100)); - Assert.That(keystoreConfig.Cipher, Is.EqualTo("test")); + Assert.That(keystoreConfig.KdfparamsDklen, Is.EqualTo(100)); + Assert.That(keystoreConfig.Cipher, Is.EqualTo("test")); - Assert.That(jsonRpcConfig.EnabledModules.Count(), Is.EqualTo(2)); + Assert.That(jsonRpcConfig.EnabledModules.Count(), Is.EqualTo(2)); - void CheckIfEnabled(string x) - { - Assert.IsTrue(jsonRpcConfig.EnabledModules.Contains(x)); - } + void CheckIfEnabled(string x) + { + Assert.That(jsonRpcConfig.EnabledModules.Contains(x), Is.True); + } - new[] { ModuleType.Eth, ModuleType.Debug }.ForEach(CheckIfEnabled); + new[] { ModuleType.Eth, ModuleType.Debug }.ForEach(CheckIfEnabled); - Assert.That(networkConfig.Concurrency, Is.EqualTo(4)); - } + Assert.That(networkConfig.Concurrency, Is.EqualTo(4)); + } - [Test] - public void Can_load_raw_value() - { - Assert.That(_configProvider.GetRawValue("KeyStoreConfig", "KdfparamsDklen"), Is.EqualTo("100")); - } + [Test] + public void Can_load_raw_value() + { + Assert.That(_configProvider.GetRawValue("KeyStoreConfig", "KdfparamsDklen"), Is.EqualTo("100")); } } diff --git a/src/Nethermind/Nethermind.Config.Test/StandardConfigTests.cs b/src/Nethermind/Nethermind.Config.Test/StandardConfigTests.cs index 15443b22a45..9c1c3c38c4d 100644 --- a/src/Nethermind/Nethermind.Config.Test/StandardConfigTests.cs +++ b/src/Nethermind/Nethermind.Config.Test/StandardConfigTests.cs @@ -31,7 +31,7 @@ private static void ForEachProperty(Action verifier) string[] dlls = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "Nethermind.JsonRpc.dll").OrderBy(n => n).ToArray(); foreach (string dll in dlls) { - TestContext.WriteLine($"Verifying {nameof(StandardConfigTests)} on {Path.GetFileName(dll)}"); + TestContext.Out.WriteLine($"Verifying {nameof(StandardConfigTests)} on {Path.GetFileName(dll)}"); Assembly assembly = Assembly.LoadFile(dll); Type[] configs = assembly.GetExportedTypes().Where(t => typeof(IConfig).IsAssignableFrom(t) && t.IsInterface) @@ -39,7 +39,7 @@ private static void ForEachProperty(Action verifier) foreach (Type configType in configs) { - TestContext.WriteLine($" Verifying type {configType.Name}"); + TestContext.Out.WriteLine($" Verifying type {configType.Name}"); PropertyInfo[] properties = configType.GetProperties(); Type? implementationType = configType.Assembly.GetExportedTypes() @@ -56,7 +56,7 @@ private static void ForEachProperty(Action verifier) { try { - TestContext.WriteLine($" Verifying property {property.Name}"); + TestContext.Out.WriteLine($" Verifying property {property.Name}"); verifier(property, instance); } catch (Exception e) diff --git a/src/Nethermind/Nethermind.Core.Test/AccountTests.cs b/src/Nethermind/Nethermind.Core.Test/AccountTests.cs index 63708822ce4..d9471d8ec04 100644 --- a/src/Nethermind/Nethermind.Core.Test/AccountTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/AccountTests.cs @@ -4,44 +4,42 @@ using Nethermind.Core.Test.Builders; using NUnit.Framework; -namespace Nethermind.Core.Test +namespace Nethermind.Core.Test; + +public class AccountTests { - [TestFixture] - public class AccountTests + [Test] + public void Test_totally_empty() { - [Test] - public void Test_totally_empty() - { - Account account = Account.TotallyEmpty; - Assert.True(account.IsTotallyEmpty, "totally empty"); - Assert.True(account.IsEmpty, "empty"); - } + Account account = Account.TotallyEmpty; + Assert.That(account.IsTotallyEmpty, Is.True, "totally empty"); + Assert.That(account.IsEmpty, Is.True, "empty"); + } - [Test] - public void Test_just_empty() - { - Account account = Account.TotallyEmpty; - account = account.WithChangedStorageRoot(TestItem.KeccakA); - Assert.False(account.IsTotallyEmpty, "totally empty"); - Assert.True(account.IsEmpty, "empty"); - } + [Test] + public void Test_just_empty() + { + Account account = Account.TotallyEmpty; + account = account.WithChangedStorageRoot(TestItem.KeccakA); + Assert.That(account.IsTotallyEmpty, Is.False, "totally empty"); + Assert.That(account.IsEmpty, Is.True, "empty"); + } - [Test] - public void Test_has_code() - { - Account account = Account.TotallyEmpty; - Assert.False(account.HasCode); - account = account.WithChangedCodeHash(TestItem.KeccakA); - Assert.True(account.HasCode); - } + [Test] + public void Test_has_code() + { + Account account = Account.TotallyEmpty; + Assert.That(account.HasCode, Is.False); + account = account.WithChangedCodeHash(TestItem.KeccakA); + Assert.That(account.HasCode, Is.True); + } - [Test] - public void Test_has_storage() - { - Account account = Account.TotallyEmpty; - Assert.False(account.HasStorage); - account = account.WithChangedStorageRoot(TestItem.KeccakA); - Assert.True(account.HasStorage); - } + [Test] + public void Test_has_storage() + { + Account account = Account.TotallyEmpty; + Assert.That(account.HasStorage, Is.False); + account = account.WithChangedStorageRoot(TestItem.KeccakA); + Assert.That(account.HasStorage, Is.True); } } diff --git a/src/Nethermind/Nethermind.Core.Test/AddressTests.cs b/src/Nethermind/Nethermind.Core.Test/AddressTests.cs index ae97cef42ae..7f6593fad3a 100644 --- a/src/Nethermind/Nethermind.Core.Test/AddressTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/AddressTests.cs @@ -3,7 +3,6 @@ using System.Collections; using FluentAssertions; -using Nethermind.Blockchain; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -14,203 +13,197 @@ using Nethermind.Evm.Precompiles; using NUnit.Framework; -namespace Nethermind.Core.Test +namespace Nethermind.Core.Test; + +public class AddressTests { - [TestFixture] - public class AddressTests + [TestCase("0x5A4EAB120fB44eb6684E5e32785702FF45ea344D", "0x5a4eab120fb44eb6684e5e32785702ff45ea344d")] + [TestCase("0x5a4eab120fb44eb6684e5e32785702ff45ea344d", "0x5a4eab120fb44eb6684e5e32785702ff45ea344d")] + public void String_representation_is_correct(string init, string expected) { - [TestCase("0x5A4EAB120fB44eb6684E5e32785702FF45ea344D", "0x5a4eab120fb44eb6684e5e32785702ff45ea344d")] - [TestCase("0x5a4eab120fb44eb6684e5e32785702ff45ea344d", "0x5a4eab120fb44eb6684e5e32785702ff45ea344d")] - public void String_representation_is_correct(string init, string expected) - { - Address address = new(init); - string addressString = address.ToString(); - Assert.That(addressString, Is.EqualTo(expected)); - } + Address address = new(init); + string addressString = address.ToString(); + Assert.That(addressString, Is.EqualTo(expected)); + } - [TestCase("0x52908400098527886E0F7030069857D2E4169EE7", "0x52908400098527886E0F7030069857D2E4169EE7")] - [TestCase("0x8617E340B3D01FA5F11F306F4090FD50E238070D", "0x8617E340B3D01FA5F11F306F4090FD50E238070D")] - [TestCase("0xde709f2102306220921060314715629080e2fb77", "0xde709f2102306220921060314715629080e2fb77")] - [TestCase("0x27b1fdb04752bbc536007a920d24acb045561c26", "0x27b1fdb04752bbc536007a920d24acb045561c26")] - [TestCase("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")] - [TestCase("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359")] - [TestCase("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB")] - [TestCase("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb")] - [TestCase("0x5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", "0x5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741")] - [TestCase("0x5A4EAB120fB44eb6684E5e32785702FF45ea344D", "0x5A4EAB120fB44eb6684E5e32785702FF45ea344D")] - [TestCase("0xa7dD84573f5ffF821baf2205745f768F8edCDD58", "0xa7dD84573f5ffF821baf2205745f768F8edCDD58")] - [TestCase("0x027a49d11d118c0060746F1990273FcB8c2fC196", "0x027a49d11d118c0060746F1990273FcB8c2fC196")] - public void String_representation_with_checksum_is_correct(string init, string expected) - { - Address address = new(init); - string addressString = address.ToString(true); - Assert.That(addressString, Is.EqualTo(expected)); - } + [TestCase("0x52908400098527886E0F7030069857D2E4169EE7", "0x52908400098527886E0F7030069857D2E4169EE7")] + [TestCase("0x8617E340B3D01FA5F11F306F4090FD50E238070D", "0x8617E340B3D01FA5F11F306F4090FD50E238070D")] + [TestCase("0xde709f2102306220921060314715629080e2fb77", "0xde709f2102306220921060314715629080e2fb77")] + [TestCase("0x27b1fdb04752bbc536007a920d24acb045561c26", "0x27b1fdb04752bbc536007a920d24acb045561c26")] + [TestCase("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")] + [TestCase("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359")] + [TestCase("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB")] + [TestCase("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb")] + [TestCase("0x5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", "0x5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741")] + [TestCase("0x5A4EAB120fB44eb6684E5e32785702FF45ea344D", "0x5A4EAB120fB44eb6684E5e32785702FF45ea344D")] + [TestCase("0xa7dD84573f5ffF821baf2205745f768F8edCDD58", "0xa7dD84573f5ffF821baf2205745f768F8edCDD58")] + [TestCase("0x027a49d11d118c0060746F1990273FcB8c2fC196", "0x027a49d11d118c0060746F1990273FcB8c2fC196")] + public void String_representation_with_checksum_is_correct(string init, string expected) + { + Address address = new(init); + string addressString = address.ToString(true); + Assert.That(addressString, Is.EqualTo(expected)); + } - [TestCase("0x52908400098527886E0F7030069857D2E4169EE7", true, true)] - [TestCase("52908400098527886E0F7030069857D2E4169EE7", true, true)] - [TestCase("0x52908400098527886E0F7030069857D2E4169EE7", false, false)] - [TestCase("52908400098527886E0F7030069857D2E4169EE7", false, true)] - public void Can_check_if_address_is_valid(string addressHex, bool allowPrefix, bool expectedResult) - { - Assert.That(Address.IsValidAddress(addressHex, allowPrefix), Is.EqualTo(expectedResult)); - } + [TestCase("0x52908400098527886E0F7030069857D2E4169EE7", true, true)] + [TestCase("52908400098527886E0F7030069857D2E4169EE7", true, true)] + [TestCase("0x52908400098527886E0F7030069857D2E4169EE7", false, false)] + [TestCase("52908400098527886E0F7030069857D2E4169EE7", false, true)] + public void Can_check_if_address_is_valid(string addressHex, bool allowPrefix, bool expectedResult) + { + Assert.That(Address.IsValidAddress(addressHex, allowPrefix), Is.EqualTo(expectedResult)); + } - [Test] - public void Bytes_are_correctly_assigned() - { - byte[] bytes = new byte[20]; - new System.Random(1).NextBytes(bytes); - Address address = new(bytes); - Assert.True(Bytes.AreEqual(address.Bytes, bytes)); - } + [Test] + public void Bytes_are_correctly_assigned() + { + byte[] bytes = new byte[20]; + new System.Random(1).NextBytes(bytes); + Address address = new(bytes); + Assert.That(Bytes.AreEqual(address.Bytes, bytes), Is.True); + } - [Test] - public void Equals_works() - { - Address addressA = new(Keccak.Compute("a")); - Address addressA2 = new(Keccak.Compute("a")); - Address addressB = new(Keccak.Compute("b")); - Assert.True(addressA.Equals(addressA2)); - // ReSharper disable once EqualExpressionComparison - Assert.True(addressA.Equals(addressA)); - Assert.False(addressA.Equals(addressB)); - Assert.False(addressA.Equals(null)); - } + [Test] + public void Equals_works() + { + Address addressA = new(Keccak.Compute("a")); + Address addressA2 = new(Keccak.Compute("a")); + Address addressB = new(Keccak.Compute("b")); + Assert.That(addressA.Equals(addressA2), Is.True); + // ReSharper disable once EqualExpressionComparison + Assert.That(addressA.Equals(addressA), Is.True); + Assert.That(addressA.Equals(addressB), Is.False); + Assert.That(addressA.Equals(null), Is.False); + } - [Test] - public void Equals_operator_works() - { - Address addressA = new(Keccak.Compute("a")); - Address addressA2 = new(Keccak.Compute("a")); - Address addressB = new(Keccak.Compute("b")); - Assert.True(addressA == addressA2); - // ReSharper disable once EqualExpressionComparison + [Test] + public void Equals_operator_works() + { + Address addressA = new(Keccak.Compute("a")); + Address addressA2 = new(Keccak.Compute("a")); + Address addressB = new(Keccak.Compute("b")); + Assert.That(addressA == addressA2, Is.True); + // ReSharper disable once EqualExpressionComparison #pragma warning disable CS1718 - Assert.True(addressA == addressA); + Assert.That(addressA == addressA, Is.True); #pragma warning restore CS1718 - Assert.False(addressA == addressB); - Assert.False(addressA is null); - Assert.False(null == addressA); - { - Address? address = null; - Assert.True(address is null); - } - } + Assert.That(addressA == addressB, Is.False); + Assert.That(addressA is null, Is.False); + Assert.That(null == addressA, Is.False); + Address? address = null; + Assert.That(address is null, Is.True); + } - [Test] - public void Not_equals_operator_works() - { - Address addressA = new(Keccak.Compute("a")); - Address addressA2 = new(Keccak.Compute("a")); - Address addressB = new(Keccak.Compute("b")); - Assert.False(addressA != addressA2); - // ReSharper disable once EqualExpressionComparison + [Test] + public void Not_equals_operator_works() + { + Address addressA = new(Keccak.Compute("a")); + Address addressA2 = new(Keccak.Compute("a")); + Address addressB = new(Keccak.Compute("b")); + Assert.That(addressA != addressA2, Is.False); + // ReSharper disable once EqualExpressionComparison #pragma warning disable CS1718 - Assert.False(addressA != addressA); + Assert.That(addressA != addressA, Is.False); #pragma warning restore CS1718 - Assert.True(addressA != addressB); - Assert.True(addressA is not null); - Assert.True(null != addressA); - { - Address? address = null; - Assert.False(address is not null); - } - } + Assert.That(addressA != addressB, Is.True); + Assert.That(addressA is not null, Is.True); + Assert.That(null != addressA, Is.True); + Address? address = null; + Assert.That(address is not null, Is.False); + } - [Test] - public void Is_precompiled_1() - { - byte[] addressBytes = new byte[20]; - addressBytes[19] = 1; - Address address = new(addressBytes); - Assert.True(address.IsPrecompile(Frontier.Instance)); - } + [Test] + public void Is_precompiled_1() + { + byte[] addressBytes = new byte[20]; + addressBytes[19] = 1; + Address address = new(addressBytes); + Assert.That(address.IsPrecompile(Frontier.Instance), Is.True); + } - [Test] - public void Is_precompiled_4_regression() - { - byte[] addressBytes = new byte[20]; - addressBytes[19] = 4; - Address address = new(addressBytes); - Assert.True(address.IsPrecompile(Frontier.Instance)); - } + [Test] + public void Is_precompiled_4_regression() + { + byte[] addressBytes = new byte[20]; + addressBytes[19] = 4; + Address address = new(addressBytes); + Assert.That(address.IsPrecompile(Frontier.Instance), Is.True); + } - [Test] - public void Is_precompiled_5_frontier() - { - byte[] addressBytes = new byte[20]; - addressBytes[19] = 5; - Address address = new(addressBytes); - Assert.False(address.IsPrecompile(Frontier.Instance)); - } + [Test] + public void Is_precompiled_5_frontier() + { + byte[] addressBytes = new byte[20]; + addressBytes[19] = 5; + Address address = new(addressBytes); + Assert.That(address.IsPrecompile(Frontier.Instance), Is.False); + } - [Test] - public void Is_precompiled_5_byzantium() - { - byte[] addressBytes = new byte[20]; - addressBytes[19] = 5; - Address address = new(addressBytes); - Assert.True(address.IsPrecompile(Byzantium.Instance)); - } + [Test] + public void Is_precompiled_5_byzantium() + { + byte[] addressBytes = new byte[20]; + addressBytes[19] = 5; + Address address = new(addressBytes); + Assert.That(address.IsPrecompile(Byzantium.Instance), Is.True); + } - [Test] - public void Is_precompiled_9_byzantium() - { - byte[] addressBytes = new byte[20]; - addressBytes[19] = 9; - Address address = new(addressBytes); - Assert.False(address.IsPrecompile(Byzantium.Instance)); - } + [Test] + public void Is_precompiled_9_byzantium() + { + byte[] addressBytes = new byte[20]; + addressBytes[19] = 9; + Address address = new(addressBytes); + Assert.That(address.IsPrecompile(Byzantium.Instance), Is.False); + } - [TestCase(0, false)] - [TestCase(1, true)] - [TestCase(1000, false)] - public void From_number_for_precompile(int number, bool isPrecompile) - { - Address address = Address.FromNumber((UInt256)number); - Assert.That(address.IsPrecompile(Byzantium.Instance), Is.EqualTo(isPrecompile)); - } + [TestCase(0, false)] + [TestCase(1, true)] + [TestCase(1000, false)] + public void From_number_for_precompile(int number, bool isPrecompile) + { + Address address = Address.FromNumber((UInt256)number); + Assert.That(address.IsPrecompile(Byzantium.Instance), Is.EqualTo(isPrecompile)); + } - [TestCase(0, "0x24cd2edba056b7c654a50e8201b619d4f624fdda")] - [TestCase(1, "0xdc98b4d0af603b4fb5ccdd840406a0210e5deff8")] - public void Of_contract(long nonce, string expectedAddress) - { - Address address = ContractAddress.From(TestItem.AddressA, (UInt256)nonce); - Assert.That(new Address(expectedAddress), Is.EqualTo(address)); - } + [TestCase(0, "0x24cd2edba056b7c654a50e8201b619d4f624fdda")] + [TestCase(1, "0xdc98b4d0af603b4fb5ccdd840406a0210e5deff8")] + public void Of_contract(long nonce, string expectedAddress) + { + Address address = ContractAddress.From(TestItem.AddressA, (UInt256)nonce); + Assert.That(new Address(expectedAddress), Is.EqualTo(address)); + } - [TestCaseSource(nameof(PointEvaluationPrecompileTestCases))] - public bool Is_PointEvaluationPrecompile_properly_activated(IReleaseSpec spec) => - Address.FromNumber(0x0a).IsPrecompile(spec); + [TestCaseSource(nameof(PointEvaluationPrecompileTestCases))] + public bool Is_PointEvaluationPrecompile_properly_activated(IReleaseSpec spec) => + Address.FromNumber(0x0a).IsPrecompile(spec); - [TestCase(Address.SystemUserHex, false)] - [TestCase("2" + Address.SystemUserHex, false)] - [TestCase("2" + Address.SystemUserHex, true)] - public void Parse_variable_length(string addressHex, bool allowOverflow) + [TestCase(Address.SystemUserHex, false)] + [TestCase("2" + Address.SystemUserHex, false)] + [TestCase("2" + Address.SystemUserHex, true)] + public void Parse_variable_length(string addressHex, bool allowOverflow) + { + var result = Address.TryParseVariableLength(addressHex, out Address? address, allowOverflow); + result.Should().Be(addressHex.Length <= Address.SystemUserHex.Length || allowOverflow); + if (result) { - var result = Address.TryParseVariableLength(addressHex, out Address? address, allowOverflow); - result.Should().Be(addressHex.Length <= Address.SystemUserHex.Length || allowOverflow); - if (result) - { - address.Should().Be(Address.SystemUser); - } + address.Should().Be(Address.SystemUser); } + } - [Test] - public void Parse_variable_length_too_short() - { - Address.TryParseVariableLength("1", out Address? address).Should().Be(true); - address.Should().Be(new Address("0000000000000000000000000000000000000001")); - } + [Test] + public void Parse_variable_length_too_short() + { + Address.TryParseVariableLength("1", out Address? address).Should().Be(true); + address.Should().Be(new Address("0000000000000000000000000000000000000001")); + } - public static IEnumerable PointEvaluationPrecompileTestCases + public static IEnumerable PointEvaluationPrecompileTestCases + { + get { - get - { - yield return new TestCaseData(Shanghai.Instance) { ExpectedResult = false, TestName = nameof(Shanghai) }; - yield return new TestCaseData(Cancun.Instance) { ExpectedResult = true, TestName = nameof(Cancun) }; - } + yield return new TestCaseData(Shanghai.Instance) { ExpectedResult = false, TestName = nameof(Shanghai) }; + yield return new TestCaseData(Cancun.Instance) { ExpectedResult = true, TestName = nameof(Cancun) }; } } } diff --git a/src/Nethermind/Nethermind.Core.Test/BytesTests.cs b/src/Nethermind/Nethermind.Core.Test/BytesTests.cs index ed69bfeeea6..56b8882e2a7 100644 --- a/src/Nethermind/Nethermind.Core.Test/BytesTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/BytesTests.cs @@ -161,8 +161,8 @@ public void Reversal() Assert.That(bytes[32 - 1 - i], Is.EqualTo(before[i])); } - TestContext.WriteLine(before.ToHexString()); - TestContext.WriteLine(bytes.ToHexString()); + TestContext.Out.WriteLine(before.ToHexString()); + TestContext.Out.WriteLine(bytes.ToHexString()); } } diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs index c18bb3ee666..e4ced1ba301 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs @@ -8,15 +8,12 @@ using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; -using Nethermind.Evm.Tracing.GethStyle.Custom.JavaScript; using Nethermind.Int256; -using Nethermind.Logging; using Nethermind.Serialization.Rlp; using NUnit.Framework; namespace Nethermind.Core.Test.Encoding; -[TestFixture] public class BlockDecoderTests { private readonly Block[] _scenarios; @@ -134,7 +131,7 @@ public void Can_do_roundtrip_null([Values(true, false)] bool valueDecoder) BlockDecoder decoder = new(); Rlp result = decoder.Encode(null); Block decoded = valueDecoder ? Rlp.Decode(result.Bytes.AsSpan()) : Rlp.Decode(result); - Assert.IsNull(decoded); + Assert.That(decoded, Is.Null); } private readonly string regression5644 = "f902cff9025aa05297f2a4a699ba7d038a229a8eb7ab29d0073b37376ff0311f2bd9c608411830a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fe77dd4ad7c2a3fa4c11868a00e4d728adcdfef8d2e3c13b256b06cbdbb02ec9a00d0abe08c162e4e0891e7a45a8107a98ae44ed47195c2d041fe574de40272df0a0056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000182160c837a1200825208845c54648eb8613078366336393733363936653733366236390000000000000000000000000000f3ec96e458292ccea72a1e53e95f94c28051ab51880b7e03d933f7fa78c9692f635ae55ac3899c9c6999d33c758b5248a05894a3471282333bcd76067c5d391300a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f86ff86d80843b9aca008252089422ea9f6b28db76a7162054c05ed812deb2f519cd8a152d02c7e14af6800000802da0f67424c67d9f91a87b5437db1bdaa05e29bd020ab474b2f67f7be163c9f650dda02f90ab34b44165d776ae04449b15210076d6a72abe2bda2903d4b87f0d1ce541c0"; diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockInfoDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockInfoDecoderTests.cs index c1afa9f984f..1cd9a3a6628 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockInfoDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockInfoDecoderTests.cs @@ -8,101 +8,99 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Core.Test.Encoding +namespace Nethermind.Core.Test.Encoding; + +public class BlockInfoDecoderTests { - [TestFixture] - public class BlockInfoDecoderTests + [TestCase(true)] + [TestCase(false)] + public void Can_do_roundtrip(bool valueDecode) { - [TestCase(true)] - [TestCase(false)] - public void Can_do_roundtrip(bool valueDecode) - { - Roundtrip(valueDecode); - } + Roundtrip(valueDecode); + } - [TestCase(true, true, true)] - [TestCase(true, true, false)] - [TestCase(true, false, true)] - [TestCase(true, false, false)] - [TestCase(false, true, true)] - [TestCase(false, true, false)] - [TestCase(false, false, true)] - [TestCase(false, false, false)] - public void Is_Backwards_compatible(bool valueDecode, bool chainWithFinalization, bool isFinalized) - { - RoundtripBackwardsCompatible(valueDecode, chainWithFinalization, isFinalized); - } + [TestCase(true, true, true)] + [TestCase(true, true, false)] + [TestCase(true, false, true)] + [TestCase(true, false, false)] + [TestCase(false, true, true)] + [TestCase(false, true, false)] + [TestCase(false, false, true)] + [TestCase(false, false, false)] + public void Is_Backwards_compatible(bool valueDecode, bool chainWithFinalization, bool isFinalized) + { + RoundtripBackwardsCompatible(valueDecode, chainWithFinalization, isFinalized); + } - [Test] - public void Can_handle_nulls() - { - Rlp rlp = Rlp.Encode((BlockInfo)null!); - rlp.Length.Should().Be(1); + [Test] + public void Can_handle_nulls() + { + Rlp rlp = Rlp.Encode((BlockInfo)null!); + rlp.Length.Should().Be(1); - BlockInfo decoded = Rlp.Decode(rlp); - decoded.Should().BeNull(); - } + BlockInfo decoded = Rlp.Decode(rlp); + decoded.Should().BeNull(); + } - private static void Roundtrip(bool valueDecode) + private static void Roundtrip(bool valueDecode) + { + BlockInfo blockInfo = new(TestItem.KeccakA, 1); + blockInfo.WasProcessed = true; + blockInfo.IsFinalized = true; + blockInfo.Metadata |= BlockMetadata.Invalid; + + Rlp rlp = Rlp.Encode(blockInfo); + BlockInfo decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); + + Assert.That(decoded.WasProcessed, Is.True, "0 processed"); + Assert.That((decoded.Metadata & BlockMetadata.Finalized) == BlockMetadata.Finalized, Is.True, "metadata finalized"); + Assert.That((decoded.Metadata & BlockMetadata.Invalid) == BlockMetadata.Invalid, Is.True, "metadata invalid"); + Assert.That(decoded.BlockHash, Is.EqualTo(TestItem.KeccakA), "block hash"); + Assert.That(decoded.TotalDifficulty, Is.EqualTo(UInt256.One), "difficulty"); + } + + private static void RoundtripBackwardsCompatible(bool valueDecode, bool chainWithFinalization, bool isFinalized) + { + BlockInfo blockInfo = new(TestItem.KeccakA, 1); + blockInfo.WasProcessed = true; + blockInfo.IsFinalized = isFinalized; + + Rlp rlp = BlockInfoEncodeDeprecated(blockInfo, chainWithFinalization); + BlockInfo decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); + + Assert.That(decoded.WasProcessed, Is.True, "0 processed"); + Assert.That(decoded.IsFinalized, Is.EqualTo(chainWithFinalization && isFinalized), "finalized"); + Assert.That(decoded.BlockHash, Is.EqualTo(TestItem.KeccakA), "block hash"); + Assert.That(decoded.TotalDifficulty, Is.EqualTo(UInt256.One), "difficulty"); + } + + public static Rlp BlockInfoEncodeDeprecated(BlockInfo? item, bool chainWithFinalization) + { + if (item is null) { - BlockInfo blockInfo = new(TestItem.KeccakA, 1); - blockInfo.WasProcessed = true; - blockInfo.IsFinalized = true; - blockInfo.Metadata |= BlockMetadata.Invalid; - - Rlp rlp = Rlp.Encode(blockInfo); - BlockInfo decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); - - Assert.True(decoded.WasProcessed, "0 processed"); - Assert.True((decoded.Metadata & BlockMetadata.Finalized) == BlockMetadata.Finalized, "metadata finalized"); - Assert.True((decoded.Metadata & BlockMetadata.Invalid) == BlockMetadata.Invalid, "metadata invalid"); - Assert.That(decoded.BlockHash, Is.EqualTo(TestItem.KeccakA), "block hash"); - Assert.That(decoded.TotalDifficulty, Is.EqualTo(UInt256.One), "difficulty"); + return Rlp.OfEmptySequence; } - private static void RoundtripBackwardsCompatible(bool valueDecode, bool chainWithFinalization, bool isFinalized) + int contentLength = 0; + contentLength += Rlp.LengthOf(item.BlockHash); + contentLength += Rlp.LengthOf(item.WasProcessed); + contentLength += Rlp.LengthOf(item.TotalDifficulty); + if (chainWithFinalization) { - BlockInfo blockInfo = new(TestItem.KeccakA, 1); - blockInfo.WasProcessed = true; - blockInfo.IsFinalized = isFinalized; - - Rlp rlp = BlockInfoEncodeDeprecated(blockInfo, chainWithFinalization); - BlockInfo decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); - - Assert.True(decoded.WasProcessed, "0 processed"); - Assert.That(decoded.IsFinalized, Is.EqualTo(chainWithFinalization && isFinalized), "finalized"); - Assert.That(decoded.BlockHash, Is.EqualTo(TestItem.KeccakA), "block hash"); - Assert.That(decoded.TotalDifficulty, Is.EqualTo(UInt256.One), "difficulty"); + contentLength += Rlp.LengthOf(item.IsFinalized); } - public static Rlp BlockInfoEncodeDeprecated(BlockInfo? item, bool chainWithFinalization) + RlpStream stream = new(Rlp.LengthOfSequence(contentLength)); + stream.StartSequence(contentLength); + stream.Encode(item.BlockHash); + stream.Encode(item.WasProcessed); + stream.Encode(item.TotalDifficulty); + + if (chainWithFinalization) { - if (item is null) - { - return Rlp.OfEmptySequence; - } - - int contentLength = 0; - contentLength += Rlp.LengthOf(item.BlockHash); - contentLength += Rlp.LengthOf(item.WasProcessed); - contentLength += Rlp.LengthOf(item.TotalDifficulty); - if (chainWithFinalization) - { - contentLength += Rlp.LengthOf(item.IsFinalized); - } - - RlpStream stream = new(Rlp.LengthOfSequence(contentLength)); - stream.StartSequence(contentLength); - stream.Encode(item.BlockHash); - stream.Encode(item.WasProcessed); - stream.Encode(item.TotalDifficulty); - - if (chainWithFinalization) - { - stream.Encode(item.IsFinalized); - } - - return new Rlp(stream.Data.ToArray()!); + stream.Encode(item.IsFinalized); } + + return new Rlp(stream.Data.ToArray()!); } } diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/ChainLevelDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/ChainLevelDecoderTests.cs index 097629a4366..530d6124906 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/ChainLevelDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/ChainLevelDecoderTests.cs @@ -7,41 +7,39 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Core.Test.Encoding +namespace Nethermind.Core.Test.Encoding; + +public class ChainLevelDecoderTests { - [TestFixture] - public class ChainLevelDecoderTests + [TestCase(true)] + [TestCase(false)] + public void Can_do_roundtrip(bool valueDecode) + { + BlockInfo blockInfo = new(TestItem.KeccakA, 1); + blockInfo.WasProcessed = true; + + BlockInfo blockInfo2 = new(TestItem.KeccakB, 2); + blockInfo2.WasProcessed = false; + + ChainLevelInfo chainLevelInfo = new(true, new[] { blockInfo, blockInfo2 }); + chainLevelInfo.HasBlockOnMainChain = true; + + Rlp rlp = Rlp.Encode(chainLevelInfo); + + ChainLevelInfo decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); + + Assert.That(decoded.HasBlockOnMainChain, Is.True, "has block on the main chain"); + Assert.That(decoded.BlockInfos[0].WasProcessed, Is.True, "0 processed"); + Assert.That(decoded.BlockInfos[1].WasProcessed, Is.False, "1 not processed"); + Assert.That(decoded.BlockInfos[0].BlockHash, Is.EqualTo(TestItem.KeccakA), "block hash"); + Assert.That(decoded.BlockInfos[0].TotalDifficulty, Is.EqualTo(UInt256.One), "difficulty"); + } + + [Test] + public void Can_handle_nulls() { - [TestCase(true)] - [TestCase(false)] - public void Can_do_roundtrip(bool valueDecode) - { - BlockInfo blockInfo = new(TestItem.KeccakA, 1); - blockInfo.WasProcessed = true; - - BlockInfo blockInfo2 = new(TestItem.KeccakB, 2); - blockInfo2.WasProcessed = false; - - ChainLevelInfo chainLevelInfo = new(true, new[] { blockInfo, blockInfo2 }); - chainLevelInfo.HasBlockOnMainChain = true; - - Rlp rlp = Rlp.Encode(chainLevelInfo); - - ChainLevelInfo decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); - - Assert.True(decoded.HasBlockOnMainChain, "has block on the main chain"); - Assert.True(decoded.BlockInfos[0].WasProcessed, "0 processed"); - Assert.False(decoded.BlockInfos[1].WasProcessed, "1 not processed"); - Assert.That(decoded.BlockInfos[0].BlockHash, Is.EqualTo(TestItem.KeccakA), "block hash"); - Assert.That(decoded.BlockInfos[0].TotalDifficulty, Is.EqualTo(UInt256.One), "difficulty"); - } - - [Test] - public void Can_handle_nulls() - { - Rlp rlp = Rlp.Encode((ChainLevelInfo)null!); - ChainLevelInfo decoded = Rlp.Decode(rlp); - Assert.Null(decoded); - } + Rlp rlp = Rlp.Encode((ChainLevelInfo)null!); + ChainLevelInfo decoded = Rlp.Decode(rlp); + Assert.That(decoded, Is.Null); } } diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs index 587f3476ccb..71d51a66333 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using FluentAssertions; using Nethermind.Core.Crypto; -using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; using Nethermind.Int256; @@ -14,7 +13,6 @@ namespace Nethermind.Core.Test.Encoding; -[TestFixture] public class HeaderDecoderTests { [TestCase(true)] @@ -66,7 +64,7 @@ public void Can_handle_nulls() { Rlp rlp = Rlp.Encode((BlockHeader?)null); BlockHeader decoded = Rlp.Decode(rlp); - Assert.Null(decoded); + Assert.That(decoded, Is.Null); } [Test] diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs index 1c538ddb554..bc6188fedfe 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs @@ -9,76 +9,74 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Core.Test.Encoding +namespace Nethermind.Core.Test.Encoding; + +public class LogEntryDecoderTests { - [TestFixture] - public class LogEntryDecoderTests + [TestCase(true)] + [TestCase(false)] + public void Can_do_roundtrip(bool valueDecode) { - [TestCase(true)] - [TestCase(false)] - public void Can_do_roundtrip(bool valueDecode) - { - LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); - Rlp rlp = Rlp.Encode(logEntry); - LogEntry decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); + LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); + Rlp rlp = Rlp.Encode(logEntry); + LogEntry decoded = valueDecode ? Rlp.Decode(rlp.Bytes.AsSpan()) : Rlp.Decode(rlp); - Assert.That(decoded.Data, Is.EqualTo(logEntry.Data), "data"); - Assert.That(decoded.LoggersAddress, Is.EqualTo(logEntry.LoggersAddress), "address"); - Assert.That(decoded.Topics, Is.EqualTo(logEntry.Topics), "topics"); - } - - [Test] - public void Can_do_roundtrip_ref_struct() - { - LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); - Rlp rlp = Rlp.Encode(logEntry); - Rlp.ValueDecoderContext valueDecoderContext = new(rlp.Bytes); - LogEntryDecoder.DecodeStructRef(ref valueDecoderContext, RlpBehaviors.None, out LogEntryStructRef decoded); + Assert.That(decoded.Data, Is.EqualTo(logEntry.Data), "data"); + Assert.That(decoded.LoggersAddress, Is.EqualTo(logEntry.LoggersAddress), "address"); + Assert.That(decoded.Topics, Is.EqualTo(logEntry.Topics), "topics"); + } - Assert.That(Bytes.AreEqual(logEntry.Data, decoded.Data), "data"); - Assert.That(logEntry.LoggersAddress == decoded.LoggersAddress, "address"); + [Test] + public void Can_do_roundtrip_ref_struct() + { + LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); + Rlp rlp = Rlp.Encode(logEntry); + Rlp.ValueDecoderContext valueDecoderContext = new(rlp.Bytes); + LogEntryDecoder.DecodeStructRef(ref valueDecoderContext, RlpBehaviors.None, out LogEntryStructRef decoded); - Span buffer = stackalloc byte[32]; - KeccaksIterator iterator = new(decoded.TopicsRlp, buffer); - for (int i = 0; i < logEntry.Topics.Length; i++) - { - iterator.TryGetNext(out Hash256StructRef keccak); - Assert.That(logEntry.Topics[i] == keccak, $"topics[{i}]"); - } - } + Assert.That(Bytes.AreEqual(logEntry.Data, decoded.Data), "data"); + Assert.That(logEntry.LoggersAddress == decoded.LoggersAddress, "address"); - [Test] - public void Can_handle_nulls() + Span buffer = stackalloc byte[32]; + KeccaksIterator iterator = new(decoded.TopicsRlp, buffer); + for (int i = 0; i < logEntry.Topics.Length; i++) { - Rlp rlp = Rlp.Encode((LogEntry)null!); - LogEntry decoded = Rlp.Decode(rlp); - Assert.Null(decoded); + iterator.TryGetNext(out Hash256StructRef keccak); + Assert.That(logEntry.Topics[i] == keccak, $"topics[{i}]"); } + } - [Test] - public void Can_do_roundtrip_rlp_stream() - { - LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); - LogEntryDecoder decoder = LogEntryDecoder.Instance; + [Test] + public void Can_handle_nulls() + { + Rlp rlp = Rlp.Encode((LogEntry)null!); + LogEntry decoded = Rlp.Decode(rlp); + Assert.That(decoded, Is.Null); + } - Rlp encoded = decoder.Encode(logEntry); - LogEntry deserialized = decoder.Decode(new RlpStream(encoded.Bytes))!; + [Test] + public void Can_do_roundtrip_rlp_stream() + { + LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); + LogEntryDecoder decoder = LogEntryDecoder.Instance; - Assert.That(deserialized.Data, Is.EqualTo(logEntry.Data), "data"); - Assert.That(deserialized.LoggersAddress, Is.EqualTo(logEntry.LoggersAddress), "address"); - Assert.That(deserialized.Topics, Is.EqualTo(logEntry.Topics), "topics"); - } + Rlp encoded = decoder.Encode(logEntry); + LogEntry deserialized = decoder.Decode(new RlpStream(encoded.Bytes))!; - [Test] - public void Rlp_stream_and_standard_have_same_results() - { - LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); - LogEntryDecoder decoder = LogEntryDecoder.Instance; + Assert.That(deserialized.Data, Is.EqualTo(logEntry.Data), "data"); + Assert.That(deserialized.LoggersAddress, Is.EqualTo(logEntry.LoggersAddress), "address"); + Assert.That(deserialized.Topics, Is.EqualTo(logEntry.Topics), "topics"); + } + + [Test] + public void Rlp_stream_and_standard_have_same_results() + { + LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); + LogEntryDecoder decoder = LogEntryDecoder.Instance; - Rlp rlpStreamResult = decoder.Encode(logEntry); + Rlp rlpStreamResult = decoder.Encode(logEntry); - Rlp rlp = decoder.Encode(logEntry); - Assert.That(rlpStreamResult.Bytes.ToHexString(), Is.EqualTo(rlp.Bytes.ToHexString())); - } + Rlp rlp = decoder.Encode(logEntry); + Assert.That(rlpStreamResult.Bytes.ToHexString(), Is.EqualTo(rlp.Bytes.ToHexString())); } } diff --git a/src/Nethermind/Nethermind.Core.Test/Json/ConverterTestBase.cs b/src/Nethermind/Nethermind.Core.Test/Json/ConverterTestBase.cs index 03329a6e88e..7f38126cda1 100644 --- a/src/Nethermind/Nethermind.Core.Test/Json/ConverterTestBase.cs +++ b/src/Nethermind/Nethermind.Core.Test/Json/ConverterTestBase.cs @@ -2,33 +2,30 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.IO; -using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using NUnit.Framework; -namespace Nethermind.Core.Test.Json +namespace Nethermind.Core.Test.Json; + +public class ConverterTestBase { - public class ConverterTestBase + protected void TestConverter(T? item, Func equalityComparer, JsonConverter converter) { - protected void TestConverter(T? item, Func equalityComparer, JsonConverter converter) + var options = new JsonSerializerOptions { - var options = new JsonSerializerOptions + Converters = { - Converters = - { - converter - } - }; + converter + } + }; - string result = JsonSerializer.Serialize(item, options); + string result = JsonSerializer.Serialize(item, options); - T? deserialized = JsonSerializer.Deserialize(result, options); + T? deserialized = JsonSerializer.Deserialize(result, options); #pragma warning disable CS8604 - Assert.True(equalityComparer(item, deserialized)); + Assert.That(equalityComparer(item, deserialized), Is.True); #pragma warning restore CS8604 - } } } diff --git a/src/Nethermind/Nethermind.Core.Test/MCSLockTests.cs b/src/Nethermind/Nethermind.Core.Test/MCSLockTests.cs index a74f887d6b7..0dbf3e1ea56 100644 --- a/src/Nethermind/Nethermind.Core.Test/MCSLockTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/MCSLockTests.cs @@ -10,7 +10,6 @@ namespace Nethermind.Core.Test; -[TestFixture] public class MCSLockTests { private McsLock mcsLock; @@ -86,6 +85,6 @@ public void LockFairnessTest() } var expectedOrder = Enumerable.Range(0, numberOfThreads).ToList(); - CollectionAssert.AreEqual(expectedOrder, executionOrder, "Threads did not acquire lock in the order they were started."); + Assert.That(expectedOrder, Is.EqualTo(executionOrder), "Threads did not acquire lock in the order they were started."); } } diff --git a/src/Nethermind/Nethermind.Core.Test/McsPriorityLock.cs b/src/Nethermind/Nethermind.Core.Test/McsPriorityLock.cs index febca4f7bf1..1044a2df09c 100644 --- a/src/Nethermind/Nethermind.Core.Test/McsPriorityLock.cs +++ b/src/Nethermind/Nethermind.Core.Test/McsPriorityLock.cs @@ -1,18 +1,14 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Core.Threading; -using NUnit.Framework; -using NUnit.Framework.Internal; - -using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using Nethermind.Core.Threading; +using NUnit.Framework; namespace Nethermind.Core.Test; -[TestFixture] public class McsPriorityLockTests { private McsPriorityLock mcsLock; @@ -88,7 +84,7 @@ public void LockFairnessTest() } var expectedOrder = Enumerable.Range(0, numberOfThreads).ToList(); - CollectionAssert.AreEqual(expectedOrder, executionOrder, "Threads did not acquire lock in the order they were started."); + Assert.That(expectedOrder, Is.EqualTo(executionOrder), "Threads did not acquire lock in the order they were started."); } diff --git a/src/Nethermind/Nethermind.Core.Test/MeasuredProgressTests.cs b/src/Nethermind/Nethermind.Core.Test/MeasuredProgressTests.cs index 770dc4f7b1e..682290e45fb 100644 --- a/src/Nethermind/Nethermind.Core.Test/MeasuredProgressTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/MeasuredProgressTests.cs @@ -4,151 +4,149 @@ using System; using NUnit.Framework; -namespace Nethermind.Core.Test +namespace Nethermind.Core.Test; + +public class MeasuredProgressTests { - [TestFixture] - public class MeasuredProgressTests + [Test] + public void Current_per_second_uninitialized() { - [Test] - public void Current_per_second_uninitialized() - { - MeasuredProgress measuredProgress = new(); - Assert.That(measuredProgress.CurrentPerSecond, Is.EqualTo(decimal.Zero)); - } + MeasuredProgress measuredProgress = new(); + Assert.That(measuredProgress.CurrentPerSecond, Is.EqualTo(decimal.Zero)); + } - [Test] - public void Total_per_second_uninitialized() - { - MeasuredProgress measuredProgress = new(); - Assert.That(measuredProgress.TotalPerSecond, Is.EqualTo(decimal.Zero)); - } + [Test] + public void Total_per_second_uninitialized() + { + MeasuredProgress measuredProgress = new(); + Assert.That(measuredProgress.TotalPerSecond, Is.EqualTo(decimal.Zero)); + } - [Test] - public void Current_value_uninitialized() - { - MeasuredProgress measuredProgress = new(); - Assert.That(measuredProgress.CurrentValue, Is.EqualTo(0L)); - } + [Test] + public void Current_value_uninitialized() + { + MeasuredProgress measuredProgress = new(); + Assert.That(measuredProgress.CurrentValue, Is.EqualTo(0L)); + } - [Test] - public void Update_0L() - { - MeasuredProgress measuredProgress = new(); - measuredProgress.Update(0L); - Assert.That(measuredProgress.CurrentValue, Is.EqualTo(0L)); - } + [Test] + public void Update_0L() + { + MeasuredProgress measuredProgress = new(); + measuredProgress.Update(0L); + Assert.That(measuredProgress.CurrentValue, Is.EqualTo(0L)); + } - [Test] - public void Update_0L_total_per_second() - { - MeasuredProgress measuredProgress = new(); - measuredProgress.Update(0L); - Assert.That(measuredProgress.TotalPerSecond, Is.EqualTo(0L)); - } + [Test] + public void Update_0L_total_per_second() + { + MeasuredProgress measuredProgress = new(); + measuredProgress.Update(0L); + Assert.That(measuredProgress.TotalPerSecond, Is.EqualTo(0L)); + } - [Test] - public void Update_0L_current_per_second() - { - MeasuredProgress measuredProgress = new(); - measuredProgress.Update(0L); - Assert.That(measuredProgress.CurrentPerSecond, Is.EqualTo(0L)); - } + [Test] + public void Update_0L_current_per_second() + { + MeasuredProgress measuredProgress = new(); + measuredProgress.Update(0L); + Assert.That(measuredProgress.CurrentPerSecond, Is.EqualTo(0L)); + } - [Test] - [Retry(3)] - public void Update_twice_total_per_second() - { - ManualTimestamper manualTimestamper = new(); - MeasuredProgress measuredProgress = new(manualTimestamper); - measuredProgress.Update(0L); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.Update(1L); - Assert.GreaterOrEqual(measuredProgress.TotalPerSecond, 4M); - Assert.LessOrEqual(measuredProgress.TotalPerSecond, 10M); - } + [Test] + [Retry(3)] + public void Update_twice_total_per_second() + { + ManualTimestamper manualTimestamper = new(); + MeasuredProgress measuredProgress = new(manualTimestamper); + measuredProgress.Update(0L); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.Update(1L); + Assert.That(measuredProgress.TotalPerSecond, Is.GreaterThanOrEqualTo(4M)); + Assert.That(measuredProgress.TotalPerSecond, Is.LessThanOrEqualTo(10M)); + } - [Test] - [Retry(3)] - public void Update_twice_current_per_second() - { - ManualTimestamper manualTimestamper = new(); - MeasuredProgress measuredProgress = new(manualTimestamper); - measuredProgress.Update(0L); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.Update(1L); - Assert.LessOrEqual(measuredProgress.CurrentPerSecond, 10M); - Assert.GreaterOrEqual(measuredProgress.CurrentPerSecond, 4M); - } + [Test] + [Retry(3)] + public void Update_twice_current_per_second() + { + ManualTimestamper manualTimestamper = new(); + MeasuredProgress measuredProgress = new(manualTimestamper); + measuredProgress.Update(0L); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.Update(1L); + Assert.That(measuredProgress.CurrentPerSecond, Is.LessThanOrEqualTo(10M)); + Assert.That(measuredProgress.CurrentPerSecond, Is.GreaterThanOrEqualTo(4M)); + } - [Test] - public void Current_starting_from_non_zero() - { - ManualTimestamper manualTimestamper = new(); - MeasuredProgress measuredProgress = new(manualTimestamper); - measuredProgress.Update(10L); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.Update(20L); - Assert.LessOrEqual(measuredProgress.CurrentPerSecond, 105M); - } + [Test] + public void Current_starting_from_non_zero() + { + ManualTimestamper manualTimestamper = new(); + MeasuredProgress measuredProgress = new(manualTimestamper); + measuredProgress.Update(10L); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.Update(20L); + Assert.That(measuredProgress.CurrentPerSecond, Is.LessThanOrEqualTo(105M)); + } - [Test] - public void Update_thrice_result_per_second() - { - ManualTimestamper manualTimestamper = new(); - MeasuredProgress measuredProgress = new(manualTimestamper); - measuredProgress.Update(0L); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.Update(1L); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.Update(3L); - Assert.GreaterOrEqual(measuredProgress.TotalPerSecond, 6M); - Assert.LessOrEqual(measuredProgress.TotalPerSecond, 15M); - Assert.GreaterOrEqual(measuredProgress.CurrentPerSecond, 6M); - Assert.LessOrEqual(measuredProgress.CurrentPerSecond, 30M); - } + [Test] + public void Update_thrice_result_per_second() + { + ManualTimestamper manualTimestamper = new(); + MeasuredProgress measuredProgress = new(manualTimestamper); + measuredProgress.Update(0L); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.Update(1L); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.Update(3L); + Assert.That(measuredProgress.TotalPerSecond, Is.GreaterThanOrEqualTo(6M)); + Assert.That(measuredProgress.TotalPerSecond, Is.LessThanOrEqualTo(15M)); + Assert.That(measuredProgress.CurrentPerSecond, Is.GreaterThanOrEqualTo(6M)); + Assert.That(measuredProgress.CurrentPerSecond, Is.LessThanOrEqualTo(30M)); + } - [Test] - public void After_ending_does_not_update_total_or_current() - { - ManualTimestamper manualTimestamper = new(); - MeasuredProgress measuredProgress = new(manualTimestamper); - measuredProgress.Update(0L); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.Update(1L); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.Update(3L); - measuredProgress.MarkEnd(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.SetMeasuringPoint(); - manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); - measuredProgress.SetMeasuringPoint(); - Assert.GreaterOrEqual(measuredProgress.TotalPerSecond, 6M); - Assert.LessOrEqual(measuredProgress.TotalPerSecond, 15M); - Assert.That(measuredProgress.CurrentPerSecond, Is.EqualTo(0M)); - } + [Test] + public void After_ending_does_not_update_total_or_current() + { + ManualTimestamper manualTimestamper = new(); + MeasuredProgress measuredProgress = new(manualTimestamper); + measuredProgress.Update(0L); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.Update(1L); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.Update(3L); + measuredProgress.MarkEnd(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.SetMeasuringPoint(); + manualTimestamper.Add(TimeSpan.FromMilliseconds(100)); + measuredProgress.SetMeasuringPoint(); + Assert.That(measuredProgress.TotalPerSecond, Is.GreaterThanOrEqualTo(6M)); + Assert.That(measuredProgress.TotalPerSecond, Is.LessThanOrEqualTo(15M)); + Assert.That(measuredProgress.CurrentPerSecond, Is.EqualTo(0M)); + } - [Test] - public void Has_ended_returns_true_when_ended() - { - MeasuredProgress measuredProgress = new(); - measuredProgress.MarkEnd(); - Assert.True(measuredProgress.HasEnded); - } + [Test] + public void Has_ended_returns_true_when_ended() + { + MeasuredProgress measuredProgress = new(); + measuredProgress.MarkEnd(); + Assert.That(measuredProgress.HasEnded, Is.True); + } - [Test] - public void Has_ended_returns_false_when_ended() - { - MeasuredProgress measuredProgress = new(); - Assert.False(measuredProgress.HasEnded); - } + [Test] + public void Has_ended_returns_false_when_ended() + { + MeasuredProgress measuredProgress = new(); + Assert.That(measuredProgress.HasEnded, Is.False); } } diff --git a/src/Nethermind/Nethermind.Core.Test/PrivateKeyTests.cs b/src/Nethermind/Nethermind.Core.Test/PrivateKeyTests.cs index c95f482198c..76f90c979c6 100644 --- a/src/Nethermind/Nethermind.Core.Test/PrivateKeyTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/PrivateKeyTests.cs @@ -8,107 +8,105 @@ using Nethermind.Crypto; using NUnit.Framework; -namespace Nethermind.Core.Test +namespace Nethermind.Core.Test; + +public class PrivateKeyTests { - [TestFixture] - public class PrivateKeyTests + private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; + + [OneTimeSetUp] + public void SetUp() { - private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; + Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); + } - [OneTimeSetUp] - public void SetUp() - { - Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); - } + [TestCase(0)] + [TestCase(1)] + [TestCase(16)] + [TestCase(31)] + [TestCase(33)] + public void Cannot_be_initialized_with_array_of_length_different_than_32(int length) + { + byte[] bytes = new byte[length]; + // ReSharper disable once ObjectCreationAsStatement + Assert.Throws(() => new PrivateKey(bytes)); + } - [TestCase(0)] - [TestCase(1)] - [TestCase(16)] - [TestCase(31)] - [TestCase(33)] - public void Cannot_be_initialized_with_array_of_length_different_than_32(int length) - { - byte[] bytes = new byte[length]; - // ReSharper disable once ObjectCreationAsStatement - Assert.Throws(() => new PrivateKey(bytes)); - } + [Test] + public void Cannot_be_initialized_with_null_bytes() + { + // ReSharper disable once ObjectCreationAsStatement + Assert.Throws(() => new PrivateKey((byte[])null!)); + } - [Test] - public void Cannot_be_initialized_with_null_bytes() - { - // ReSharper disable once ObjectCreationAsStatement - Assert.Throws(() => new PrivateKey((byte[])null!)); - } + [Test] + public void Cannot_be_initialized_with_null_string() + { + // ReSharper disable once ObjectCreationAsStatement + Assert.Throws(() => new PrivateKey((string)null!)); + } - [Test] - public void Cannot_be_initialized_with_null_string() - { - // ReSharper disable once ObjectCreationAsStatement - Assert.Throws(() => new PrivateKey((string)null!)); - } + [Test] + public void Bytes_are_stored_correctly() + { + byte[] bytes = new byte[32]; + new Random(12).NextBytes(bytes); + PrivateKey privateKey = new(bytes); + Assert.That(Bytes.AreEqual(bytes, privateKey.KeyBytes), Is.True); + } - [Test] - public void Bytes_are_stored_correctly() - { - byte[] bytes = new byte[32]; - new Random(12).NextBytes(bytes); - PrivateKey privateKey = new(bytes); - Assert.True(Bytes.AreEqual(bytes, privateKey.KeyBytes)); - } + [TestCase(TestPrivateKeyHex)] + public void String_representation_is_correct(string hexString) + { + PrivateKey privateKey = new(hexString); + string privateKeyString = privateKey.ToString(); + Assert.That(privateKeyString, Is.EqualTo(hexString)); + } - [TestCase(TestPrivateKeyHex)] - public void String_representation_is_correct(string hexString) - { - PrivateKey privateKey = new(hexString); - string privateKeyString = privateKey.ToString(); - Assert.That(privateKeyString, Is.EqualTo(hexString)); - } + [TestCase("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266", "0xc2d7cf95645d33006175b78989035c7c9061d3f9")] + [TestCase("56e044e40c2d225593bc0a4ae3fd4a31ab11f9351f98e60109c1fb429b52e876", "0xd1dc4a77be62d06f0760187be2e505d270c170fd")] + public void Address_as_expected(string privateKeyHex, string addressHex) + { + PrivateKey privateKey = new(privateKeyHex); + Address address = privateKey.Address; + Assert.That(address.ToString(), Is.EqualTo(addressHex)); + } - [TestCase("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266", "0xc2d7cf95645d33006175b78989035c7c9061d3f9")] - [TestCase("56e044e40c2d225593bc0a4ae3fd4a31ab11f9351f98e60109c1fb429b52e876", "0xd1dc4a77be62d06f0760187be2e505d270c170fd")] - public void Address_as_expected(string privateKeyHex, string addressHex) - { - PrivateKey privateKey = new(privateKeyHex); - Address address = privateKey.Address; - Assert.That(address.ToString(), Is.EqualTo(addressHex)); - } + [Test] + public void Address_returns_the_same_value_when_called_twice() + { + PrivateKey privateKey = new(TestPrivateKeyHex); + Address address1 = privateKey.Address; + Address address2 = privateKey.Address; + Assert.That(address2, Is.SameAs(address1)); + } - [Test] - public void Address_returns_the_same_value_when_called_twice() - { - PrivateKey privateKey = new(TestPrivateKeyHex); - Address address1 = privateKey.Address; - Address address2 = privateKey.Address; - Assert.That(address2, Is.SameAs(address1)); - } + [Test] + public void Can_decompress_public_key() + { + PrivateKey privateKey = new(TestPrivateKeyHex); + PublicKey a = privateKey.PublicKey; + PublicKey b = privateKey.CompressedPublicKey.Decompress(); + Assert.That(b, Is.EqualTo(a)); + } - [Test] - public void Can_decompress_public_key() + + /// + /// https://en.bitcoin.it/wiki/Private_key + /// + [TestCase("0000000000000000000000000000000000000000000000000000000000000000", false)] + [TestCase("0000000000000000000000000000000000000000000000000000000000000001", true)] + [TestCase("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140", true)] + [TestCase("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", false)] + public void Fails_on_invalid(string hex, bool expectedValid) + { + if (!expectedValid) { - PrivateKey privateKey = new(TestPrivateKeyHex); - PublicKey a = privateKey.PublicKey; - PublicKey b = privateKey.CompressedPublicKey.Decompress(); - Assert.That(b, Is.EqualTo(a)); + Assert.Throws(() => _ = new PrivateKey(Bytes.FromHexString(hex))); } - - - /// - /// https://en.bitcoin.it/wiki/Private_key - /// - [TestCase("0000000000000000000000000000000000000000000000000000000000000000", false)] - [TestCase("0000000000000000000000000000000000000000000000000000000000000001", true)] - [TestCase("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140", true)] - [TestCase("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", false)] - public void Fails_on_invalid(string hex, bool expectedValid) + else { - if (!expectedValid) - { - Assert.Throws(() => _ = new PrivateKey(Bytes.FromHexString(hex))); - } - else - { - _ = new PrivateKey(Bytes.FromHexString(hex)); - } + _ = new PrivateKey(Bytes.FromHexString(hex)); } } } diff --git a/src/Nethermind/Nethermind.Core.Test/SizeExtensionsTests.cs b/src/Nethermind/Nethermind.Core.Test/SizeExtensionsTests.cs index ea7939ef720..4df1fb4c64a 100644 --- a/src/Nethermind/Nethermind.Core.Test/SizeExtensionsTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/SizeExtensionsTests.cs @@ -4,25 +4,24 @@ using Nethermind.Core.Extensions; using NUnit.Framework; -namespace Nethermind.Core.Test +namespace Nethermind.Core.Test; + +[TestFixture] +public class SizeExtensionsTests { - [TestFixture] - public class SizeExtensionsTests + [TestCase(0)] + [TestCase(1000)] + [TestCase(9223372036)] // Int64.MaxValue / 1_000_000_000 + public void CheckOverflow_long(long testCase) { - [TestCase(0)] - [TestCase(1000)] - [TestCase(9223372036)] // Int64.MaxValue / 1_000_000_000 - public void CheckOverflow_long(long testCase) - { - Assert.IsTrue(testCase.GB() >= 0); - } + Assert.That(testCase.GB() >= 0, Is.True); + } - [TestCase(0)] - [TestCase(1000)] - [TestCase(2147483647)] // Int32.MaxValue - public void CheckOverflow_int(int testCase) - { - Assert.IsTrue(testCase.GB() >= 0); - } + [TestCase(0)] + [TestCase(1000)] + [TestCase(2147483647)] // Int32.MaxValue + public void CheckOverflow_int(int testCase) + { + Assert.That(testCase.GB() >= 0, Is.True); } } diff --git a/src/Nethermind/Nethermind.Core.Test/TransactionExtensionsTests.cs b/src/Nethermind/Nethermind.Core.Test/TransactionExtensionsTests.cs index 189e1df0412..7c28ffcf52b 100644 --- a/src/Nethermind/Nethermind.Core.Test/TransactionExtensionsTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/TransactionExtensionsTests.cs @@ -5,231 +5,229 @@ using Nethermind.Int256; using NUnit.Framework; -namespace Nethermind.Core.Test +namespace Nethermind.Core.Test; + +public class TransactionExtensionsTests { - [TestFixture] - public class TransactionExtensionsTests + [Test] + public void GetTransactionPotentialCost_returns_expected_results([ValueSource(nameof(TransactionPotentialCostsTestCases))] + TransactionPotentialCostsAndEffectiveGasPrice test) { - [Test] - public void GetTransactionPotentialCost_returns_expected_results([ValueSource(nameof(TransactionPotentialCostsTestCases))] - TransactionPotentialCostsAndEffectiveGasPrice test) - { - Transaction transaction = new(); - transaction.GasPrice = test.GasPrice; - transaction.GasLimit = test.GasLimit; - transaction.Value = test.Value; - transaction.DecodedMaxFeePerGas = test.FeeCap; - transaction.Type = test.Type; - UInt256 actualResult = transaction.CalculateTransactionPotentialCost(test.IsEip1559Enabled, test.BaseFee); - UInt256 effectiveGasPrice = transaction.CalculateEffectiveGasPrice(test.IsEip1559Enabled, test.BaseFee); - Assert.That(actualResult, Is.EqualTo(test.ExpectedPotentialCostResult)); - Assert.That(effectiveGasPrice, Is.EqualTo(test.ExpectedEffectiveGasPriceResult)); - Assert.That(test.ExpectedPotentialCostResult, Is.EqualTo(test.ExpectedEffectiveGasPriceResult * (UInt256)test.GasLimit + test.Value)); - } + Transaction transaction = new(); + transaction.GasPrice = test.GasPrice; + transaction.GasLimit = test.GasLimit; + transaction.Value = test.Value; + transaction.DecodedMaxFeePerGas = test.FeeCap; + transaction.Type = test.Type; + UInt256 actualResult = transaction.CalculateTransactionPotentialCost(test.IsEip1559Enabled, test.BaseFee); + UInt256 effectiveGasPrice = transaction.CalculateEffectiveGasPrice(test.IsEip1559Enabled, test.BaseFee); + Assert.That(actualResult, Is.EqualTo(test.ExpectedPotentialCostResult)); + Assert.That(effectiveGasPrice, Is.EqualTo(test.ExpectedEffectiveGasPriceResult)); + Assert.That(test.ExpectedPotentialCostResult, Is.EqualTo(test.ExpectedEffectiveGasPriceResult * (UInt256)test.GasLimit + test.Value)); + } - [Test] - public void TryCalculatePremiumPerGas_should_succeeds_for_free_transactions() - { - Transaction transaction = new SystemTransaction(); - transaction.DecodedMaxFeePerGas = 10; - transaction.GasPrice = 30; - transaction.Type = TxType.EIP1559; - bool tryResult = transaction.TryCalculatePremiumPerGas(100, out UInt256 premiumPerGas); - Assert.That(premiumPerGas, Is.EqualTo(UInt256.Zero)); - Assert.True(tryResult); - } + [Test] + public void TryCalculatePremiumPerGas_should_succeeds_for_free_transactions() + { + Transaction transaction = new SystemTransaction(); + transaction.DecodedMaxFeePerGas = 10; + transaction.GasPrice = 30; + transaction.Type = TxType.EIP1559; + bool tryResult = transaction.TryCalculatePremiumPerGas(100, out UInt256 premiumPerGas); + Assert.That(premiumPerGas, Is.EqualTo(UInt256.Zero)); + Assert.That(tryResult, Is.True); + } - [Test] - public void CalculateEffectiveGasPrice_can_handle_overflow_scenario_with_max_priority() - { - Transaction transaction = new(); - transaction.DecodedMaxFeePerGas = UInt256.MaxValue; - transaction.GasPrice = UInt256.MaxValue; - transaction.Type = TxType.EIP1559; - UInt256 effectiveGasPrice = transaction.CalculateEffectiveGasPrice(true, 100); - Assert.That(effectiveGasPrice, Is.EqualTo(UInt256.MaxValue)); - } + [Test] + public void CalculateEffectiveGasPrice_can_handle_overflow_scenario_with_max_priority() + { + Transaction transaction = new(); + transaction.DecodedMaxFeePerGas = UInt256.MaxValue; + transaction.GasPrice = UInt256.MaxValue; + transaction.Type = TxType.EIP1559; + UInt256 effectiveGasPrice = transaction.CalculateEffectiveGasPrice(true, 100); + Assert.That(effectiveGasPrice, Is.EqualTo(UInt256.MaxValue)); + } - [Test] - public void CalculateEffectiveGasPrice_can_handle_overflow_scenario_with_max_baseFee() - { - UInt256 expectedValue = UInt256.MaxValue - 10; - Transaction transaction = new(); - transaction.DecodedMaxFeePerGas = expectedValue; - transaction.GasPrice = 100; - transaction.Type = TxType.EIP1559; - UInt256 effectiveGasPrice = transaction.CalculateEffectiveGasPrice(true, UInt256.MaxValue); - Assert.That(effectiveGasPrice, Is.EqualTo(expectedValue)); - } + [Test] + public void CalculateEffectiveGasPrice_can_handle_overflow_scenario_with_max_baseFee() + { + UInt256 expectedValue = UInt256.MaxValue - 10; + Transaction transaction = new(); + transaction.DecodedMaxFeePerGas = expectedValue; + transaction.GasPrice = 100; + transaction.Type = TxType.EIP1559; + UInt256 effectiveGasPrice = transaction.CalculateEffectiveGasPrice(true, UInt256.MaxValue); + Assert.That(effectiveGasPrice, Is.EqualTo(expectedValue)); + } - [Test] - public void TryCalculatePremiumPerGas_should_fails_when_base_fee_is_greater_than_fee() - { - Transaction transaction = new(); - transaction.DecodedMaxFeePerGas = 10; - transaction.GasPrice = 30; - transaction.Type = TxType.EIP1559; - bool tryResult = transaction.TryCalculatePremiumPerGas(100, out UInt256 premiumPerGas); - Assert.That(premiumPerGas, Is.EqualTo(UInt256.Zero)); - Assert.False(tryResult); - } + [Test] + public void TryCalculatePremiumPerGas_should_fails_when_base_fee_is_greater_than_fee() + { + Transaction transaction = new(); + transaction.DecodedMaxFeePerGas = 10; + transaction.GasPrice = 30; + transaction.Type = TxType.EIP1559; + bool tryResult = transaction.TryCalculatePremiumPerGas(100, out UInt256 premiumPerGas); + Assert.That(premiumPerGas, Is.EqualTo(UInt256.Zero)); + Assert.That(tryResult, Is.False); + } - public class TransactionPotentialCostsAndEffectiveGasPrice - { - public int Lp { get; set; } - public UInt256 BaseFee { get; set; } - public UInt256 FeeCap { get; set; } - public UInt256 GasPrice { get; set; } - public TxType Type { get; set; } - public long GasLimit { get; set; } - public UInt256 Value { get; set; } - public bool IsEip1559Enabled { get; set; } - public UInt256 ExpectedPotentialCostResult { get; set; } + public class TransactionPotentialCostsAndEffectiveGasPrice + { + public int Lp { get; set; } + public UInt256 BaseFee { get; set; } + public UInt256 FeeCap { get; set; } + public UInt256 GasPrice { get; set; } + public TxType Type { get; set; } + public long GasLimit { get; set; } + public UInt256 Value { get; set; } + public bool IsEip1559Enabled { get; set; } + public UInt256 ExpectedPotentialCostResult { get; set; } - public UInt256 ExpectedEffectiveGasPriceResult { get; set; } + public UInt256 ExpectedEffectiveGasPriceResult { get; set; } - public override string ToString() => - $"Lp: {Lp}, ExpectedPotentialCostResult: {ExpectedPotentialCostResult}, ExpectedEffectiveGasPriceResult: {ExpectedEffectiveGasPriceResult}"; - } + public override string ToString() => + $"Lp: {Lp}, ExpectedPotentialCostResult: {ExpectedPotentialCostResult}, ExpectedEffectiveGasPriceResult: {ExpectedEffectiveGasPriceResult}"; + } - public static IEnumerable TransactionPotentialCostsTestCases + public static IEnumerable TransactionPotentialCostsTestCases + { + get { - get + /* Legacy transactions before 1559 fork:*/ + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 1, + GasPrice = 10, + ExpectedPotentialCostResult = 0, + ExpectedEffectiveGasPriceResult = 10 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 2, + GasPrice = 21, + GasLimit = 100, + ExpectedPotentialCostResult = 2100, + ExpectedEffectiveGasPriceResult = 21 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() { - /* Legacy transactions before 1559 fork:*/ - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 1, - GasPrice = 10, - ExpectedPotentialCostResult = 0, - ExpectedEffectiveGasPriceResult = 10 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 2, - GasPrice = 21, - GasLimit = 100, - ExpectedPotentialCostResult = 2100, - ExpectedEffectiveGasPriceResult = 21 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 3, - GasPrice = 21, - GasLimit = 100, - Value = 3, - ExpectedPotentialCostResult = 2103, - ExpectedEffectiveGasPriceResult = 21 - }; + Lp = 3, + GasPrice = 21, + GasLimit = 100, + Value = 3, + ExpectedPotentialCostResult = 2103, + ExpectedEffectiveGasPriceResult = 21 + }; - /*Legacy after 1559 fork:*/ - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 4, - IsEip1559Enabled = true, - GasPrice = 10, - GasLimit = 300, - Value = 5, - ExpectedPotentialCostResult = 3005, - ExpectedEffectiveGasPriceResult = 10 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 5, - IsEip1559Enabled = true, - GasPrice = 10, - GasLimit = 300, - Value = 5, - BaseFee = 200, - ExpectedPotentialCostResult = 3005, - ExpectedEffectiveGasPriceResult = 10 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 6, - IsEip1559Enabled = true, - GasPrice = 10, - GasLimit = 300, - Value = 5, - BaseFee = 5, - ExpectedPotentialCostResult = 3005, - ExpectedEffectiveGasPriceResult = 10 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 7, - IsEip1559Enabled = true, - GasPrice = 0, - GasLimit = 300, - Value = 0, - BaseFee = 5, - ExpectedPotentialCostResult = 0, - ExpectedEffectiveGasPriceResult = 0 - }; + /*Legacy after 1559 fork:*/ + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 4, + IsEip1559Enabled = true, + GasPrice = 10, + GasLimit = 300, + Value = 5, + ExpectedPotentialCostResult = 3005, + ExpectedEffectiveGasPriceResult = 10 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 5, + IsEip1559Enabled = true, + GasPrice = 10, + GasLimit = 300, + Value = 5, + BaseFee = 200, + ExpectedPotentialCostResult = 3005, + ExpectedEffectiveGasPriceResult = 10 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 6, + IsEip1559Enabled = true, + GasPrice = 10, + GasLimit = 300, + Value = 5, + BaseFee = 5, + ExpectedPotentialCostResult = 3005, + ExpectedEffectiveGasPriceResult = 10 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 7, + IsEip1559Enabled = true, + GasPrice = 0, + GasLimit = 300, + Value = 0, + BaseFee = 5, + ExpectedPotentialCostResult = 0, + ExpectedEffectiveGasPriceResult = 0 + }; - /* Eip1559 transactions before 1559 fork:*/ - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 8, - Type = TxType.EIP1559, - GasPrice = 10, - GasLimit = 300, - FeeCap = 500, - Value = 5, - ExpectedPotentialCostResult = 3005, - ExpectedEffectiveGasPriceResult = 10 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 9, - Type = TxType.EIP1559, - GasPrice = 10, - FeeCap = 300, - ExpectedPotentialCostResult = 0, - ExpectedEffectiveGasPriceResult = 10 - }; + /* Eip1559 transactions before 1559 fork:*/ + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 8, + Type = TxType.EIP1559, + GasPrice = 10, + GasLimit = 300, + FeeCap = 500, + Value = 5, + ExpectedPotentialCostResult = 3005, + ExpectedEffectiveGasPriceResult = 10 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 9, + Type = TxType.EIP1559, + GasPrice = 10, + FeeCap = 300, + ExpectedPotentialCostResult = 0, + ExpectedEffectiveGasPriceResult = 10 + }; - /* Eip1559 transactions after 1559 fork:*/ - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 10, - IsEip1559Enabled = true, - Type = TxType.EIP1559, - GasPrice = 10, - GasLimit = 300, - FeeCap = 5, - Value = 5, - BaseFee = 200, - ExpectedPotentialCostResult = 1505, - ExpectedEffectiveGasPriceResult = 5 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 11, - IsEip1559Enabled = true, - Type = TxType.EIP1559, - GasPrice = 10, - GasLimit = 300, - FeeCap = 300, - Value = 5, - BaseFee = 200, - ExpectedPotentialCostResult = 63005, - ExpectedEffectiveGasPriceResult = 210 - }; - yield return new TransactionPotentialCostsAndEffectiveGasPrice() - { - Lp = 12, - IsEip1559Enabled = true, - Type = TxType.EIP1559, - GasPrice = 0, - GasLimit = 300, - FeeCap = 0, - Value = 5, - BaseFee = 200, - ExpectedPotentialCostResult = 5, - ExpectedEffectiveGasPriceResult = 0 - }; - } + /* Eip1559 transactions after 1559 fork:*/ + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 10, + IsEip1559Enabled = true, + Type = TxType.EIP1559, + GasPrice = 10, + GasLimit = 300, + FeeCap = 5, + Value = 5, + BaseFee = 200, + ExpectedPotentialCostResult = 1505, + ExpectedEffectiveGasPriceResult = 5 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 11, + IsEip1559Enabled = true, + Type = TxType.EIP1559, + GasPrice = 10, + GasLimit = 300, + FeeCap = 300, + Value = 5, + BaseFee = 200, + ExpectedPotentialCostResult = 63005, + ExpectedEffectiveGasPriceResult = 210 + }; + yield return new TransactionPotentialCostsAndEffectiveGasPrice() + { + Lp = 12, + IsEip1559Enabled = true, + Type = TxType.EIP1559, + GasPrice = 0, + GasLimit = 300, + FeeCap = 0, + Value = 5, + BaseFee = 200, + ExpectedPotentialCostResult = 5, + ExpectedEffectiveGasPriceResult = 0 + }; } } } diff --git a/src/Nethermind/Nethermind.Core.Test/TransactionTests.cs b/src/Nethermind/Nethermind.Core.Test/TransactionTests.cs index 9d371f038cd..3b3d8c602c4 100644 --- a/src/Nethermind/Nethermind.Core.Test/TransactionTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/TransactionTests.cs @@ -6,52 +6,50 @@ using Nethermind.Core.Extensions; using NUnit.Framework; -namespace Nethermind.Core.Test +namespace Nethermind.Core.Test; + +public class TransactionTests { - [TestFixture] - public class TransactionTests + [Test] + public void When_to_not_empty_then_is_message_call() { - [Test] - public void When_to_not_empty_then_is_message_call() - { - Transaction transaction = new(); - transaction.To = Address.Zero; - Assert.True(transaction.IsMessageCall, nameof(Transaction.IsMessageCall)); - Assert.False(transaction.IsContractCreation, nameof(Transaction.IsContractCreation)); - } + Transaction transaction = new(); + transaction.To = Address.Zero; + Assert.That(transaction.IsMessageCall, Is.True, nameof(Transaction.IsMessageCall)); + Assert.That(transaction.IsContractCreation, Is.False, nameof(Transaction.IsContractCreation)); + } - [Test] - public void When_to_empty_then_is_message_call() - { - Transaction transaction = new(); - transaction.To = null; - Assert.False(transaction.IsMessageCall, nameof(Transaction.IsMessageCall)); - Assert.True(transaction.IsContractCreation, nameof(Transaction.IsContractCreation)); - } + [Test] + public void When_to_empty_then_is_message_call() + { + Transaction transaction = new(); + transaction.To = null; + Assert.That(transaction.IsMessageCall, Is.False, nameof(Transaction.IsMessageCall)); + Assert.That(transaction.IsContractCreation, Is.True, nameof(Transaction.IsContractCreation)); + } - [TestCase(1, true)] - [TestCase(300, true)] - public void Supports1559_returns_expected_results(int decodedFeeCap, bool expectedSupports1559) - { - Transaction transaction = new(); - transaction.DecodedMaxFeePerGas = (uint)decodedFeeCap; - transaction.Type = TxType.EIP1559; - Assert.That(transaction.DecodedMaxFeePerGas, Is.EqualTo(transaction.MaxFeePerGas)); - Assert.That(transaction.Supports1559, Is.EqualTo(expectedSupports1559)); - } + [TestCase(1, true)] + [TestCase(300, true)] + public void Supports1559_returns_expected_results(int decodedFeeCap, bool expectedSupports1559) + { + Transaction transaction = new(); + transaction.DecodedMaxFeePerGas = (uint)decodedFeeCap; + transaction.Type = TxType.EIP1559; + Assert.That(transaction.DecodedMaxFeePerGas, Is.EqualTo(transaction.MaxFeePerGas)); + Assert.That(transaction.Supports1559, Is.EqualTo(expectedSupports1559)); } +} - public static class TransactionTestExtensions +public static class TransactionTestExtensions +{ + public static void EqualToTransaction(this Transaction subject, Transaction expectation) { - public static void EqualToTransaction(this Transaction subject, Transaction expectation) - { - subject.Should().BeEquivalentTo( - expectation, - o => o - .ComparingByMembers() - .Using>(ctx => ctx.Subject.AsArray().Should().BeEquivalentTo(ctx.Expectation.AsArray())) - .WhenTypeIs>() - ); - } + subject.Should().BeEquivalentTo( + expectation, + o => o + .ComparingByMembers() + .Using>(ctx => ctx.Subject.AsArray().Should().BeEquivalentTo(ctx.Expectation.AsArray())) + .WhenTypeIs>() + ); } } diff --git a/src/Nethermind/Nethermind.Db.Test/CompressingStoreTests.cs b/src/Nethermind/Nethermind.Db.Test/CompressingStoreTests.cs index 4a35934e70f..b1e7886a88a 100644 --- a/src/Nethermind/Nethermind.Db.Test/CompressingStoreTests.cs +++ b/src/Nethermind/Nethermind.Db.Test/CompressingStoreTests.cs @@ -9,130 +9,129 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Store.Test +namespace Nethermind.Store.Test; + +[Parallelizable(ParallelScope.All)] +public class CompressingStoreTests { - [Parallelizable(ParallelScope.All)] - public class CompressingStoreTests + [Test] + public void Null() { - [Test] - public void Null() - { - Context ctx = new(); + Context ctx = new(); - ctx.Compressed[Key] = null; + ctx.Compressed[Key] = null; - Assert.IsNull(ctx.Compressed[Key]); - Assert.IsNull(ctx.Wrapped[Key]); - } + Assert.That(ctx.Compressed[Key], Is.Null); + Assert.That(ctx.Wrapped[Key], Is.Null); + } - [Test] - public void Empty() - { - Context ctx = new(); + [Test] + public void Empty() + { + Context ctx = new(); - byte[] empty = Array.Empty(); + byte[] empty = Array.Empty(); - ctx.Compressed[Key] = empty; + ctx.Compressed[Key] = empty; - CollectionAssert.AreEqual(empty, ctx.Compressed[Key]); - CollectionAssert.AreEqual(empty, ctx.Wrapped[Key]); - } + Assert.That(empty, Is.EqualTo(ctx.Compressed[Key]).AsCollection); + Assert.That(empty, Is.EqualTo(ctx.Wrapped[Key]).AsCollection); + } - [Test] - public void Single() - { - Context ctx = new(); + [Test] + public void Single() + { + Context ctx = new(); - byte[] value = { 13 }; + byte[] value = { 13 }; - ctx.Compressed[Key] = value; + ctx.Compressed[Key] = value; - CollectionAssert.AreEqual(value, ctx.Compressed[Key]); - CollectionAssert.AreEqual(value, ctx.Wrapped[Key]); - } + Assert.That(value, Is.EqualTo(ctx.Compressed[Key]).AsCollection); + Assert.That(value, Is.EqualTo(ctx.Wrapped[Key]).AsCollection); + } - [Test] - public void EOA() - { - Context ctx = new(); + [Test] + public void EOA() + { + Context ctx = new(); - Rlp encoded = new AccountDecoder().Encode((Account)new(1)); - ctx.Compressed[Key] = encoded.Bytes; + Rlp encoded = new AccountDecoder().Encode(new(1)); + ctx.Compressed[Key] = encoded.Bytes; - CollectionAssert.AreEqual(encoded.Bytes, ctx.Compressed[Key]); - ctx.Wrapped[Key]!.Length.Should().Be(5); - } + Assert.That(encoded.Bytes, Is.EqualTo(ctx.Compressed[Key]).AsCollection); + ctx.Wrapped[Key]!.Length.Should().Be(5); + } - [Test] - public void EOAWithSPan() - { - Context ctx = new(); + [Test] + public void EOAWithSPan() + { + Context ctx = new(); - Rlp encoded = new AccountDecoder().Encode((Account)new(1)); - ctx.Compressed.PutSpan(Key, encoded.Bytes); + Rlp encoded = new AccountDecoder().Encode(new(1)); + ctx.Compressed.PutSpan(Key, encoded.Bytes); - CollectionAssert.AreEqual(encoded.Bytes, ctx.Compressed[Key]); - CollectionAssert.AreEqual(encoded.Bytes, ctx.Compressed.GetSpan(Key).ToArray()); - ctx.Wrapped[Key]!.Length.Should().Be(5); - } + Assert.That(encoded.Bytes, Is.EqualTo(ctx.Compressed[Key]).AsCollection); + Assert.That(encoded.Bytes, Is.EqualTo(ctx.Compressed.GetSpan(Key).ToArray()).AsCollection); + ctx.Wrapped[Key]!.Length.Should().Be(5); + } - [Test] - public void Backward_compatible_read() - { - Context ctx = new(); - byte[] value = { 1, 2, 34 }; + [Test] + public void Backward_compatible_read() + { + Context ctx = new(); + byte[] value = { 1, 2, 34 }; - ctx.Wrapped[Key] = value; + ctx.Wrapped[Key] = value; - CollectionAssert.AreEqual(value, ctx.Compressed[Key]); - } + Assert.That(value, Is.EqualTo(ctx.Compressed[Key]).AsCollection); + } + + [Test] + public void Batch() + { + Context ctx = new(); - [Test] - public void Batch() + using (IWriteBatch writeBatch = ctx.Compressed.StartWriteBatch()) { - Context ctx = new(); + writeBatch[Key] = EOABytes; + } - using (IWriteBatch writeBatch = ctx.Compressed.StartWriteBatch()) - { - writeBatch[Key] = EOABytes; - } + Assert.That(EOABytes, Is.EqualTo(ctx.Compressed[Key]).AsCollection); - CollectionAssert.AreEqual(EOABytes, ctx.Compressed[Key]); + ctx.Wrapped[Key]!.Length.Should().Be(5); + } - ctx.Wrapped[Key]!.Length.Should().Be(5); - } + [Test] + public void TestTuneForwarded() + { + Context ctx = new(); - [Test] - public void TestTuneForwarded() + if (ctx.Compressed is not ITunableDb tunable) { - Context ctx = new(); - - if (ctx.Compressed is not ITunableDb tunable) - { - Assert.Fail("Db must me tunable"); - return; - } + Assert.Fail("Db must me tunable"); + return; + } - tunable.Tune(ITunableDb.TuneType.HeavyWrite); + tunable.Tune(ITunableDb.TuneType.HeavyWrite); - ctx.Wrapped.WasTunedWith(ITunableDb.TuneType.HeavyWrite).Should().BeTrue(); - } + ctx.Wrapped.WasTunedWith(ITunableDb.TuneType.HeavyWrite).Should().BeTrue(); + } - private class Context - { - public TestMemDb Wrapped { get; } + private class Context + { + public TestMemDb Wrapped { get; } - public IDb Compressed { get; } + public IDb Compressed { get; } - public Context() - { - Wrapped = new TestMemDb(); - Compressed = Wrapped.WithEOACompressed(); - } + public Context() + { + Wrapped = new TestMemDb(); + Compressed = Wrapped.WithEOACompressed(); } + } - private static readonly byte[] EOABytes = new AccountDecoder().Encode((Account)new(1)).Bytes; + private static readonly byte[] EOABytes = new AccountDecoder().Encode((Account)new(1)).Bytes; - private static readonly byte[] Key = { 1 }; - } + private static readonly byte[] Key = { 1 }; } diff --git a/src/Nethermind/Nethermind.Db.Test/DbProviderTests.cs b/src/Nethermind/Nethermind.Db.Test/DbProviderTests.cs index 1a45a8ccd80..edc441243f8 100644 --- a/src/Nethermind/Nethermind.Db.Test/DbProviderTests.cs +++ b/src/Nethermind/Nethermind.Db.Test/DbProviderTests.cs @@ -4,60 +4,59 @@ using System; using NUnit.Framework; -namespace Nethermind.Db.Test +namespace Nethermind.Db.Test; + +[Parallelizable(ParallelScope.All)] +public class DbProviderTests { - [Parallelizable(ParallelScope.All)] - public class DbProviderTests + [Test] + public void DbProvider_CanRegisterMemDb() { - [Test] - public void DbProvider_CanRegisterMemDb() + MemDbFactory memDbFactory = new MemDbFactory(); + using (DbProvider dbProvider = new DbProvider()) { - MemDbFactory memDbFactory = new MemDbFactory(); - using (DbProvider dbProvider = new DbProvider()) - { - IDb memDb = memDbFactory.CreateDb(new DbSettings("MemDb", "MemDb")); - dbProvider.RegisterDb("MemDb", memDb); - IDb db = dbProvider.GetDb("MemDb"); - Assert.That(db, Is.EqualTo(memDb)); - } + IDb memDb = memDbFactory.CreateDb(new DbSettings("MemDb", "MemDb")); + dbProvider.RegisterDb("MemDb", memDb); + IDb db = dbProvider.GetDb("MemDb"); + Assert.That(db, Is.EqualTo(memDb)); } + } - [Test] - public void DbProvider_CanRegisterColumnsDb() + [Test] + public void DbProvider_CanRegisterColumnsDb() + { + using (DbProvider dbProvider = new DbProvider()) { - using (DbProvider dbProvider = new DbProvider()) - { - MemDbFactory memDbFactory = new MemDbFactory(); - IColumnsDb memSnapshotableDb = memDbFactory.CreateColumnsDb("ColumnsDb"); - dbProvider.RegisterColumnDb("ColumnsDb", memSnapshotableDb); - IColumnsDb columnsDb = dbProvider.GetColumnDb("ColumnsDb"); - Assert.That(columnsDb, Is.EqualTo(memSnapshotableDb)); - Assert.IsTrue(memSnapshotableDb is IColumnsDb); - } + MemDbFactory memDbFactory = new MemDbFactory(); + IColumnsDb memSnapshotableDb = memDbFactory.CreateColumnsDb("ColumnsDb"); + dbProvider.RegisterColumnDb("ColumnsDb", memSnapshotableDb); + IColumnsDb columnsDb = dbProvider.GetColumnDb("ColumnsDb"); + Assert.That(columnsDb, Is.EqualTo(memSnapshotableDb)); + Assert.That(memSnapshotableDb is IColumnsDb, Is.True); } + } - [Test] - public void DbProvider_ThrowExceptionOnRegisteringTheSameDb() + [Test] + public void DbProvider_ThrowExceptionOnRegisteringTheSameDb() + { + using (DbProvider dbProvider = new DbProvider()) { - using (DbProvider dbProvider = new DbProvider()) - { - MemDbFactory memDbFactory = new MemDbFactory(); - IColumnsDb memSnapshotableDb = memDbFactory.CreateColumnsDb("ColumnsDb"); - dbProvider.RegisterColumnDb("ColumnsDb", memSnapshotableDb); - Assert.Throws(() => dbProvider.RegisterColumnDb("columnsdb", new MemColumnsDb())); - } + MemDbFactory memDbFactory = new MemDbFactory(); + IColumnsDb memSnapshotableDb = memDbFactory.CreateColumnsDb("ColumnsDb"); + dbProvider.RegisterColumnDb("ColumnsDb", memSnapshotableDb); + Assert.Throws(() => dbProvider.RegisterColumnDb("columnsdb", new MemColumnsDb())); } + } - [Test] - public void DbProvider_ThrowExceptionOnGettingNotRegisteredDb() + [Test] + public void DbProvider_ThrowExceptionOnGettingNotRegisteredDb() + { + using (DbProvider dbProvider = new DbProvider()) { - using (DbProvider dbProvider = new DbProvider()) - { - MemDbFactory memDbFactory = new MemDbFactory(); - IColumnsDb memSnapshotableDb = memDbFactory.CreateColumnsDb("ColumnsDb"); - dbProvider.RegisterColumnDb("ColumnsDb", memSnapshotableDb); - Assert.Throws(() => dbProvider.GetColumnDb("differentdb")); - } + MemDbFactory memDbFactory = new MemDbFactory(); + IColumnsDb memSnapshotableDb = memDbFactory.CreateColumnsDb("ColumnsDb"); + dbProvider.RegisterColumnDb("ColumnsDb", memSnapshotableDb); + Assert.Throws(() => dbProvider.GetColumnDb("differentdb")); } } } diff --git a/src/Nethermind/Nethermind.Db.Test/SimpleFilePublicKeyDbTests.cs b/src/Nethermind/Nethermind.Db.Test/SimpleFilePublicKeyDbTests.cs index 96066249e37..a99ef9c7c44 100644 --- a/src/Nethermind/Nethermind.Db.Test/SimpleFilePublicKeyDbTests.cs +++ b/src/Nethermind/Nethermind.Db.Test/SimpleFilePublicKeyDbTests.cs @@ -4,70 +4,67 @@ using System; using System.Collections.Generic; using System.IO; -using FluentAssertions; using Nethermind.Core.Extensions; using Nethermind.Core.Test.IO; using Nethermind.Logging; using NUnit.Framework; -namespace Nethermind.Db.Test +namespace Nethermind.Db.Test; + +[Parallelizable(ParallelScope.Self)] +public class SimpleFilePublicKeyDbTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class SimpleFilePublicKeyDbTests + [Test] + public void Save_and_load() { - [Test] - public void Save_and_load() - { - using TempPath tempPath = TempPath.GetTempFile(SimpleFilePublicKeyDb.DbFileName); - tempPath.Dispose(); + using TempPath tempPath = TempPath.GetTempFile(SimpleFilePublicKeyDb.DbFileName); + tempPath.Dispose(); - SimpleFilePublicKeyDb filePublicKeyDb = new("Test", Path.GetTempPath(), LimboLogs.Instance); + SimpleFilePublicKeyDb filePublicKeyDb = new("Test", Path.GetTempPath(), LimboLogs.Instance); - Random random = new Random(); - Dictionary dict = new Dictionary(Bytes.EqualityComparer); - for (int i = 0; i < 1024; i++) - { - byte[] key = new byte[random.Next(64, 128)]; - byte[] value = new byte[random.Next(200, 250)]; + Random random = new Random(); + Dictionary dict = new Dictionary(Bytes.EqualityComparer); + for (int i = 0; i < 1024; i++) + { + byte[] key = new byte[random.Next(64, 128)]; + byte[] value = new byte[random.Next(200, 250)]; - random.NextBytes(key); - random.NextBytes(value); + random.NextBytes(key); + random.NextBytes(value); - dict[key] = value; - } - - using (filePublicKeyDb.StartWriteBatch()) - { - foreach (var kv in dict) - { - filePublicKeyDb[kv.Key] = kv.Value; - } - } + dict[key] = value; + } - SimpleFilePublicKeyDb copy = new("Test", Path.GetTempPath(), LimboLogs.Instance); - Assert.That(copy.Keys.Count, Is.EqualTo(dict.Count)); + using (filePublicKeyDb.StartWriteBatch()) + { foreach (var kv in dict) { - Assert.True(filePublicKeyDb[kv.Key].AsSpan().SequenceEqual(kv.Value)); + filePublicKeyDb[kv.Key] = kv.Value; } } - [Test] - public void Clear() + SimpleFilePublicKeyDb copy = new("Test", Path.GetTempPath(), LimboLogs.Instance); + Assert.That(copy.Keys.Count, Is.EqualTo(dict.Count)); + foreach (var kv in dict) { - using TempPath tempPath = TempPath.GetTempFile(SimpleFilePublicKeyDb.DbFileName); - tempPath.Dispose(); + Assert.That(filePublicKeyDb[kv.Key].AsSpan().SequenceEqual(kv.Value), Is.True); + } + } - SimpleFilePublicKeyDb filePublicKeyDb = new("Test", Path.GetTempPath(), LimboLogs.Instance); - using (filePublicKeyDb.StartWriteBatch()) - { - filePublicKeyDb[[1, 2, 3]] = [1, 2, 3]; - } + [Test] + public void Clear() + { + using TempPath tempPath = TempPath.GetTempFile(SimpleFilePublicKeyDb.DbFileName); + tempPath.Dispose(); - filePublicKeyDb.KeyExists([1, 2, 3]).Should().BeTrue(); - filePublicKeyDb.Clear(); - filePublicKeyDb.KeyExists([1, 2, 3]).Should().BeFalse(); + SimpleFilePublicKeyDb filePublicKeyDb = new("Test", Path.GetTempPath(), LimboLogs.Instance); + using (filePublicKeyDb.StartWriteBatch()) + { + filePublicKeyDb[[1, 2, 3]] = [1, 2, 3]; } + + Assert.That(filePublicKeyDb.KeyExists([1, 2, 3]), Is.True); + filePublicKeyDb.Clear(); + Assert.That(filePublicKeyDb.KeyExists([1, 2, 3]), Is.False); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs index ae825118bac..04816819562 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs @@ -14,272 +14,270 @@ using Nethermind.State; using NUnit.Framework; -namespace Nethermind.Evm.Test +namespace Nethermind.Evm.Test; + +public class Eip1052Tests : VirtualMachineTestsBase { - [TestFixture] - public class Eip1052Tests : VirtualMachineTestsBase + protected override long BlockNumber => 10000001; + + protected override ISpecProvider SpecProvider => new CustomSpecProvider( + ((ForkActivation)0, Byzantium.Instance), ((ForkActivation)10000001, Constantinople.Instance)); + + [Test] + public void Account_without_code_returns_empty_data_hash() + { + TestState.CreateAccount(TestItem.AddressC, 100.Ether()); + + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + TestAllTracerWithOutput result = Execute(code); + AssertGas(result, 21000 + GasCostOf.VeryLow * 2 + GasCostOf.SSet + GasCostOf.ExtCodeHash); + AssertStorage(UInt256.Zero, Keccak.OfAnEmptyString.Bytes); + } + + [Test] + public void Non_existing_account_returns_0() + { + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + TestAllTracerWithOutput result = Execute(code); + AssertGas(result, + 21000 + GasCostOf.VeryLow * 2 + GasCostOf.SStoreNetMeteredEip1283 + GasCostOf.ExtCodeHash); + AssertStorage(UInt256.Zero, Keccak.Zero); + } + + [Test] + public void Non_existing_precompile_returns_0() + { + Address precompileAddress = Sha256Precompile.Address; + Assert.That(precompileAddress.IsPrecompile(Spec), Is.True); + + byte[] code = Prepare.EvmCode + .PushData(precompileAddress) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + AssertStorage(UInt256.Zero, Keccak.Zero); + } + + [Test] + public void Existing_precompile_returns_empty_data_hash() + { + Address precompileAddress = Sha256Precompile.Address; + Assert.That(precompileAddress.IsPrecompile(Spec), Is.True); + + TestState.CreateAccount(precompileAddress, 1.Wei()); + + byte[] code = Prepare.EvmCode + .PushData(precompileAddress) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + AssertStorage(UInt256.Zero, Keccak.OfAnEmptyString.Bytes); + } + + [Test] + public void Before_constantinople_throws_an_exception() + { + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + TestAllTracerWithOutput receipt = Execute(1000000, 100000, code); + Assert.That(receipt.StatusCode, Is.EqualTo(StatusCode.Failure)); + } + + [Test] + public void Addresses_are_trimmed_properly() + { + byte[] addressWithGarbage = TestItem.AddressC.Bytes.PadLeft(32); + addressWithGarbage[11] = 88; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, "some code"u8.ToArray(), Spec); + + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .PushData(addressWithGarbage) + .Op(Instruction.EXTCODEHASH) + .PushData(1) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + Hash256 codehash = Keccak.Compute("some code"); + AssertStorage(0, codehash.Bytes); + AssertStorage(1, codehash.Bytes); + } + + [Test] + public void Self_destructed_returns_zero() { - protected override long BlockNumber => 10000001; - - protected override ISpecProvider SpecProvider => new CustomSpecProvider( - ((ForkActivation)0, Byzantium.Instance), ((ForkActivation)10000001, Constantinople.Instance)); - - [Test] - public void Account_without_code_returns_empty_data_hash() - { - TestState.CreateAccount(TestItem.AddressC, 100.Ether()); - - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - TestAllTracerWithOutput result = Execute(code); - AssertGas(result, 21000 + GasCostOf.VeryLow * 2 + GasCostOf.SSet + GasCostOf.ExtCodeHash); - AssertStorage(UInt256.Zero, Keccak.OfAnEmptyString.Bytes); - } - - [Test] - public void Non_existing_account_returns_0() - { - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - TestAllTracerWithOutput result = Execute(code); - AssertGas(result, - 21000 + GasCostOf.VeryLow * 2 + GasCostOf.SStoreNetMeteredEip1283 + GasCostOf.ExtCodeHash); - AssertStorage(UInt256.Zero, Keccak.Zero); - } - - [Test] - public void Non_existing_precompile_returns_0() - { - Address precompileAddress = Sha256Precompile.Address; - Assert.True(precompileAddress.IsPrecompile(Spec)); - - byte[] code = Prepare.EvmCode - .PushData(precompileAddress) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - AssertStorage(UInt256.Zero, Keccak.Zero); - } - - [Test] - public void Existing_precompile_returns_empty_data_hash() - { - Address precompileAddress = Sha256Precompile.Address; - Assert.True(precompileAddress.IsPrecompile(Spec)); - - TestState.CreateAccount(precompileAddress, 1.Wei()); - - byte[] code = Prepare.EvmCode - .PushData(precompileAddress) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - AssertStorage(UInt256.Zero, Keccak.OfAnEmptyString.Bytes); - } - - [Test] - public void Before_constantinople_throws_an_exception() - { - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - TestAllTracerWithOutput receipt = Execute(1000000, 100000, code); - Assert.That(receipt.StatusCode, Is.EqualTo(StatusCode.Failure)); - } - - [Test] - public void Addresses_are_trimmed_properly() - { - byte[] addressWithGarbage = TestItem.AddressC.Bytes.PadLeft(32); - addressWithGarbage[11] = 88; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, "some code"u8.ToArray(), Spec); - - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .PushData(addressWithGarbage) - .Op(Instruction.EXTCODEHASH) - .PushData(1) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - Hash256 codehash = Keccak.Compute("some code"); - AssertStorage(0, codehash.Bytes); - AssertStorage(1, codehash.Bytes); - } - - [Test] - public void Self_destructed_returns_zero() - { - byte[] selfDestructCode = Prepare.EvmCode - .PushData(Recipient) - .Op(Instruction.SELFDESTRUCT).Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, selfDestructCode, Spec); - - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressC, 50000) - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - AssertStorage(0, Keccak.Compute(selfDestructCode)); - } - - [Test] - public void Self_destructed_and_reverted_returns_code_hash() - { - byte[] callAndRevertCode = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .Op(Instruction.REVERT).Done; - - byte[] selfDestructCode = Prepare.EvmCode - .PushData(Recipient) - .Op(Instruction.SELFDESTRUCT).Done; - - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, selfDestructCode, Spec); - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, callAndRevertCode, Spec); - - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressC, 50000) - .PushData(TestItem.AddressD) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - AssertStorage(0, Keccak.Compute(selfDestructCode)); - } - - [Test] - public void Empty_account_that_would_be_cleared_returns_zero() - { - TestState.CreateAccount(TestItem.AddressC, 0.Ether()); - - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressC, 0) - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - - AssertStorage(UInt256.Zero, UInt256.Zero); - Assert.False(TestState.AccountExists(TestItem.AddressC), "did not test the right thing - it was not an empty account + touch scenario"); - } - - [Test] - public void Newly_created_empty_account_returns_empty_data_hash() - { - byte[] code = Prepare.EvmCode - .Create(Array.Empty(), 0) - .PushData(ContractAddress.From(Recipient, 0)) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - - // todo: so far EIP does not define whether it should be zero or empty data - AssertStorage(0, Keccak.OfAnEmptyString); - Assert.True(TestState.AccountExists(ContractAddress.From(Recipient, 0)), - "did not test the right thing - it was not a newly created empty account scenario"); - } - - [Test] - public void Create_and_revert_returns_zero() - { - byte[] deployedCode = { 1, 2, 3 }; - - byte[] initCode = Prepare.EvmCode - .PushData(deployedCode.PadRight(32)) - .PushData(0) - .Op(Instruction.MSTORE) - .PushData(3) - .PushData(0) - .Op(Instruction.RETURN) - .Done; - - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.REVERT).Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressC, 50000) - .PushData(ContractAddress.From(TestItem.AddressC, 0)) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - AssertStorage(0, Keccak.Zero); - } - - [Test] - public void Create_returns_code_hash() - { - byte[] deployedCode = { 1, 2, 3 }; - Hash256 deployedCodeHash = Keccak.Compute(deployedCode); - - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode).Done; - - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0).Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressC, 50000) - .PushData(ContractAddress.From(TestItem.AddressC, 0)) - .Op(Instruction.EXTCODEHASH) - .PushData(0) - .Op(Instruction.SSTORE) - .Done; - - Execute(code); - AssertStorage(0, deployedCodeHash); - } + byte[] selfDestructCode = Prepare.EvmCode + .PushData(Recipient) + .Op(Instruction.SELFDESTRUCT).Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, selfDestructCode, Spec); + + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressC, 50000) + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + AssertStorage(0, Keccak.Compute(selfDestructCode)); + } + + [Test] + public void Self_destructed_and_reverted_returns_code_hash() + { + byte[] callAndRevertCode = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .Op(Instruction.REVERT).Done; + + byte[] selfDestructCode = Prepare.EvmCode + .PushData(Recipient) + .Op(Instruction.SELFDESTRUCT).Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, selfDestructCode, Spec); + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, callAndRevertCode, Spec); + + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressC, 50000) + .PushData(TestItem.AddressD) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + AssertStorage(0, Keccak.Compute(selfDestructCode)); + } + + [Test] + public void Empty_account_that_would_be_cleared_returns_zero() + { + TestState.CreateAccount(TestItem.AddressC, 0.Ether()); + + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressC, 0) + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + + AssertStorage(UInt256.Zero, UInt256.Zero); + Assert.That(TestState.AccountExists(TestItem.AddressC), Is.False, "did not test the right thing - it was not an empty account + touch scenario"); + } + + [Test] + public void Newly_created_empty_account_returns_empty_data_hash() + { + byte[] code = Prepare.EvmCode + .Create(Array.Empty(), 0) + .PushData(ContractAddress.From(Recipient, 0)) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + + // todo: so far EIP does not define whether it should be zero or empty data + AssertStorage(0, Keccak.OfAnEmptyString); + Assert.That(TestState.AccountExists(ContractAddress.From(Recipient, 0)), Is.True, + "did not test the right thing - it was not a newly created empty account scenario"); + } + + [Test] + public void Create_and_revert_returns_zero() + { + byte[] deployedCode = { 1, 2, 3 }; + + byte[] initCode = Prepare.EvmCode + .PushData(deployedCode.PadRight(32)) + .PushData(0) + .Op(Instruction.MSTORE) + .PushData(3) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.REVERT).Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressC, 50000) + .PushData(ContractAddress.From(TestItem.AddressC, 0)) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + AssertStorage(0, Keccak.Zero); + } + + [Test] + public void Create_returns_code_hash() + { + byte[] deployedCode = { 1, 2, 3 }; + Hash256 deployedCodeHash = Keccak.Compute(deployedCode); + + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode).Done; + + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0).Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressC, 50000) + .PushData(ContractAddress.From(TestItem.AddressC, 0)) + .Op(Instruction.EXTCODEHASH) + .PushData(0) + .Op(Instruction.SSTORE) + .Done; + + Execute(code); + AssertStorage(0, deployedCodeHash); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs index 2a242e3eb4a..97d509a3b57 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs @@ -8,816 +8,815 @@ using NUnit.Framework; using System.Diagnostics; -namespace Nethermind.Evm.Test +namespace Nethermind.Evm.Test; + +/// +/// Tests functionality of Transient Storage +/// +internal class Eip1153Tests : VirtualMachineTestsBase { + protected override long BlockNumber => MainnetSpecProvider.ParisBlockNumber; + protected override ulong Timestamp => MainnetSpecProvider.CancunBlockTimestamp; + /// - /// Tests functionality of Transient Storage + /// Transient storage should be activated after activation hardfork /// - internal class Eip1153Tests : VirtualMachineTestsBase + [Test] + public void after_activation_can_call_tstore_tload() { - protected override long BlockNumber => MainnetSpecProvider.ParisBlockNumber; - protected override ulong Timestamp => MainnetSpecProvider.CancunBlockTimestamp; - - /// - /// Transient storage should be activated after activation hardfork - /// - [Test] - public void after_activation_can_call_tstore_tload() - { - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 8) - .LoadDataFromTransientStorage(1) - .Done; - - TestAllTracerWithOutput result = Execute(code); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - } - - /// - /// Transient storage should not be activated until after activation hardfork - /// - [Test] - public void before_activation_can_not_call_tstore_tload() - { - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 8) - .Done; - - TestAllTracerWithOutput result = Execute((MainnetSpecProvider.GrayGlacierBlockNumber, MainnetSpecProvider.CancunBlockTimestamp - 1), 100000, code); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Failure)); - - code = Prepare.EvmCode - .LoadDataFromTransientStorage(1) - .Done; - - result = Execute((MainnetSpecProvider.GrayGlacierBlockNumber, MainnetSpecProvider.CancunBlockTimestamp - 1), 100000, code); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Failure)); - } - - /// - /// Uninitialized transient storage is zero - /// - [Test] - public void tload_uninitialized_returns_zero() - { - byte[] code = Prepare.EvmCode - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .Return(32, 0) - .Done; + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 8) + .LoadDataFromTransientStorage(1) + .Done; - TestAllTracerWithOutput result = Execute(code); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - - // Should be 0 since it's not yet set - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(0)); - } - - /// - /// Simple performance test - /// - [Explicit("Depends on hardware")] - [Test] - public void transient_storage_performance_test() - { - Stopwatch stopwatch = new Stopwatch(); - long blockGasLimit = 30000000; - long numOfOps = (long)(blockGasLimit * .95) / (GasCostOf.TLoad + GasCostOf.TStore + GasCostOf.VeryLow * 4); - Prepare prepare = Prepare.EvmCode; - for (long i = 0; i < numOfOps; i++) - { - prepare.StoreDataInTransientStorage(1, 8); - prepare.LoadDataFromTransientStorage(1); - prepare.Op(Instruction.POP); - } - - byte[] code = prepare.Done; - - stopwatch.Start(); - TestAllTracerWithOutput result = Execute((MainnetSpecProvider.GrayGlacierBlockNumber, Timestamp), blockGasLimit, code, blockGasLimit); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - stopwatch.Stop(); - Assert.IsTrue(stopwatch.ElapsedMilliseconds < 5000); - } - - /// - /// Simple functionality test - /// - [Test] - public void tload_after_tstore() - { - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 8) - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .Return(32, 0) - .Done; - - TestAllTracerWithOutput result = Execute(code); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); - } - - /// - /// Testing transient data store/load from different locations - /// - /// Location - [TestCase(2)] - [TestCase(3)] - [TestCase(4)] - [TestCase(5)] - [TestCase(6)] - public void tload_after_tstore_from_different_locations(int loadLocation) - { - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 8) - .LoadDataFromTransientStorage(loadLocation) - .DataOnStackToMemory(0) - .Return(32, 0) - .Done; + TestAllTracerWithOutput result = Execute(code); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); + } - TestAllTracerWithOutput result = Execute(code); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); + /// + /// Transient storage should not be activated until after activation hardfork + /// + [Test] + public void before_activation_can_not_call_tstore_tload() + { + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 8) + .Done; - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(0)); - } + TestAllTracerWithOutput result = Execute((MainnetSpecProvider.GrayGlacierBlockNumber, MainnetSpecProvider.CancunBlockTimestamp - 1), 100000, code); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Failure)); - /// - /// Contracts have separate transient storage - /// - [Test] - public void tload_from_different_contract() - { - // TLOAD and RETURN the resulting value - byte[] contractCode = Prepare.EvmCode - .PushData(1) - .Op(Instruction.TLOAD) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - .Done; + code = Prepare.EvmCode + .LoadDataFromTransientStorage(1) + .Done; - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + result = Execute((MainnetSpecProvider.GrayGlacierBlockNumber, MainnetSpecProvider.CancunBlockTimestamp - 1), 100000, code); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Failure)); + } - // Store 8 at index 1 and call contract from above - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 8) - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; + /// + /// Uninitialized transient storage is zero + /// + [Test] + public void tload_uninitialized_returns_zero() + { + byte[] code = Prepare.EvmCode + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .Return(32, 0) + .Done; - TestAllTracerWithOutput result = Execute(code); + TestAllTracerWithOutput result = Execute(code); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - // If transient state was not isolated, the return value would be 8 - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(0)); - } + // Should be 0 since it's not yet set + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(0)); + } - /// - /// Reentrant calls access the same transient storage - /// - [Test] - public void tload_from_reentrant_call() + /// + /// Simple performance test + /// + [Explicit("Depends on hardware")] + [Test] + public void transient_storage_performance_test() + { + Stopwatch stopwatch = new Stopwatch(); + long blockGasLimit = 30000000; + long numOfOps = (long)(blockGasLimit * .95) / (GasCostOf.TLoad + GasCostOf.TStore + GasCostOf.VeryLow * 4); + Prepare prepare = Prepare.EvmCode; + for (long i = 0; i < numOfOps; i++) { - // If caller is self, TLOAD and return value (break recursion) - // Else, TSTORE and call self, return the response - byte[] contractCode = Prepare.EvmCode - // Check if caller is self - .Op(Instruction.CALLER) - .PushData(TestItem.AddressD) - .Op(Instruction.EQ) - .PushData(78) - .Op(Instruction.JUMPI) - - // Non-reentrant, call self after TSTORE - .StoreDataInTransientStorage(1, 8) - .Call(TestItem.AddressD, 50000) - // Return the response - .ReturnInnerCallResult() - - // Reentrant, TLOAD and return value - .Op(Instruction.JUMPDEST) - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - .Done; - - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); - - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; - - TestAllTracerWithOutput result = Execute(code); - - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); + prepare.StoreDataInTransientStorage(1, 8); + prepare.LoadDataFromTransientStorage(1); + prepare.Op(Instruction.POP); } - /// - /// Reentrant calls can manipulate the same transient storage - /// - [Test] - public void tstore_from_reentrant_call() - { - // If caller is self, TLOAD and return value (break recursion) - // Else, TSTORE and call self, return the response - byte[] contractCode = Prepare.EvmCode - // Check if caller is self - .Op(Instruction.CALLER) - .PushData(TestItem.AddressD) - .Op(Instruction.EQ) - .PushData(78) - .Op(Instruction.JUMPI) - - // Non-reentrant, call self after TSTORE - .StoreDataInTransientStorage(1, 8) - .Call(TestItem.AddressD, 50000) - // Return the response - .ReturnInnerCallResult() - - // Reentrant, TLOAD and return value - .Op(Instruction.JUMPDEST) // PC = 78 - .StoreDataInTransientStorage(1, 9) - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - .Done; + byte[] code = prepare.Done; - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); - - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; - - TestAllTracerWithOutput result = Execute(code); - - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(9)); - } - - /// - /// Successfully returned calls do not revert transient storage writes - /// - [Test] - public void tstore_from_reentrant_call_read_by_caller() - { - // If caller is self, TLOAD and return value (break recursion) - // Else, TSTORE and call self, return the response - byte[] contractCode = Prepare.EvmCode - // Check if caller is self - .Op(Instruction.CALLER) - .PushData(TestItem.AddressD) - .Op(Instruction.EQ) - .PushData(77) - .Op(Instruction.JUMPI) - - // Non-reentrant, call self after TSTORE - .StoreDataInTransientStorage(1, 8) - .Call(TestItem.AddressD, 50000) - // TLOAD and return value (should be 9) - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - - // Reentrant, TSTORE 9 - .Op(Instruction.JUMPDEST) // PC = 77 - .StoreDataInTransientStorage(1, 9) - .Done; - - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); - - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; - - TestAllTracerWithOutput result = Execute(code); - - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(9)); - } + stopwatch.Start(); + TestAllTracerWithOutput result = Execute((MainnetSpecProvider.GrayGlacierBlockNumber, Timestamp), blockGasLimit, code, blockGasLimit); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); + stopwatch.Stop(); + Assert.That(stopwatch.ElapsedMilliseconds < 5000, Is.True); + } - /// - /// Revert undoes the transient storage write from the failed call - /// - [Test] - public void revert_resets_transient_state() - { - // If caller is self, TLOAD and return value (break recursion) - // Else, TSTORE and call self, return the response - byte[] contractCode = Prepare.EvmCode - // Check if caller is self - .Op(Instruction.CALLER) - .PushData(TestItem.AddressD) - .Op(Instruction.EQ) - .PushData(77) - .Op(Instruction.JUMPI) - - // Non-reentrant, call self after TSTORE - .StoreDataInTransientStorage(1, 8) - .Call(TestItem.AddressD, 50000) - // TLOAD and return value - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) + /// + /// Simple functionality test + /// + [Test] + public void tload_after_tstore() + { + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 8) + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .Return(32, 0) + .Done; - // Reentrant, TSTORE 9 but REVERT - .Op(Instruction.JUMPDEST) // PC = 77 - .StoreDataInTransientStorage(1, 9) - .Op(Instruction.REVERT) - .Done; + TestAllTracerWithOutput result = Execute(code); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); + } - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; + /// + /// Testing transient data store/load from different locations + /// + /// Location + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [TestCase(5)] + [TestCase(6)] + public void tload_after_tstore_from_different_locations(int loadLocation) + { + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 8) + .LoadDataFromTransientStorage(loadLocation) + .DataOnStackToMemory(0) + .Return(32, 0) + .Done; - TestAllTracerWithOutput result = Execute(code); + TestAllTracerWithOutput result = Execute(code); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - // Should be original TSTORE value - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); - } + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(0)); + } - /// - /// Revert undoes all the transient storage writes to the same key from the failed call - /// - [Test] - public void revert_resets_all_transient_state() - { - // If caller is self, TLOAD and return value (break recursion) - // Else, TSTORE and call self, return the response - byte[] contractCode = Prepare.EvmCode - // Check if caller is self - .Op(Instruction.CALLER) - .PushData(TestItem.AddressD) - .Op(Instruction.EQ) - .PushData(77) - .Op(Instruction.JUMPI) - - // Non-reentrant, call self after TSTORE - .StoreDataInTransientStorage(1, 8) - .Call(TestItem.AddressD, 50000) - // TLOAD and return value - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) + /// + /// Contracts have separate transient storage + /// + [Test] + public void tload_from_different_contract() + { + // TLOAD and RETURN the resulting value + byte[] contractCode = Prepare.EvmCode + .PushData(1) + .Op(Instruction.TLOAD) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Store 8 at index 1 and call contract from above + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 8) + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + // If transient state was not isolated, the return value would be 8 + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(0)); + } - // Reentrant, TSTORE 9 but REVERT - .Op(Instruction.JUMPDEST) // PC = 77 - .StoreDataInTransientStorage(1, 9) - .StoreDataInTransientStorage(1, 10) - .Op(Instruction.REVERT) - .Done; + /// + /// Reentrant calls access the same transient storage + /// + [Test] + public void tload_from_reentrant_call() + { + // If caller is self, TLOAD and return value (break recursion) + // Else, TSTORE and call self, return the response + byte[] contractCode = Prepare.EvmCode + // Check if caller is self + .Op(Instruction.CALLER) + .PushData(TestItem.AddressD) + .Op(Instruction.EQ) + .PushData(78) + .Op(Instruction.JUMPI) + + // Non-reentrant, call self after TSTORE + .StoreDataInTransientStorage(1, 8) + .Call(TestItem.AddressD, 50000) + // Return the response + .ReturnInnerCallResult() + + // Reentrant, TLOAD and return value + .Op(Instruction.JUMPDEST) + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); + } - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + /// + /// Reentrant calls can manipulate the same transient storage + /// + [Test] + public void tstore_from_reentrant_call() + { + // If caller is self, TLOAD and return value (break recursion) + // Else, TSTORE and call self, return the response + byte[] contractCode = Prepare.EvmCode + // Check if caller is self + .Op(Instruction.CALLER) + .PushData(TestItem.AddressD) + .Op(Instruction.EQ) + .PushData(78) + .Op(Instruction.JUMPI) + + // Non-reentrant, call self after TSTORE + .StoreDataInTransientStorage(1, 8) + .Call(TestItem.AddressD, 50000) + // Return the response + .ReturnInnerCallResult() + + // Reentrant, TLOAD and return value + .Op(Instruction.JUMPDEST) // PC = 78 + .StoreDataInTransientStorage(1, 9) + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(9)); + } - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; + /// + /// Successfully returned calls do not revert transient storage writes + /// + [Test] + public void tstore_from_reentrant_call_read_by_caller() + { + // If caller is self, TLOAD and return value (break recursion) + // Else, TSTORE and call self, return the response + byte[] contractCode = Prepare.EvmCode + // Check if caller is self + .Op(Instruction.CALLER) + .PushData(TestItem.AddressD) + .Op(Instruction.EQ) + .PushData(77) + .Op(Instruction.JUMPI) + + // Non-reentrant, call self after TSTORE + .StoreDataInTransientStorage(1, 8) + .Call(TestItem.AddressD, 50000) + // TLOAD and return value (should be 9) + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + + // Reentrant, TSTORE 9 + .Op(Instruction.JUMPDEST) // PC = 77 + .StoreDataInTransientStorage(1, 9) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(9)); + } - TestAllTracerWithOutput result = Execute(code); + /// + /// Revert undoes the transient storage write from the failed call + /// + [Test] + public void revert_resets_transient_state() + { + // If caller is self, TLOAD and return value (break recursion) + // Else, TSTORE and call self, return the response + byte[] contractCode = Prepare.EvmCode + // Check if caller is self + .Op(Instruction.CALLER) + .PushData(TestItem.AddressD) + .Op(Instruction.EQ) + .PushData(77) + .Op(Instruction.JUMPI) + + // Non-reentrant, call self after TSTORE + .StoreDataInTransientStorage(1, 8) + .Call(TestItem.AddressD, 50000) + // TLOAD and return value + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + + // Reentrant, TSTORE 9 but REVERT + .Op(Instruction.JUMPDEST) // PC = 77 + .StoreDataInTransientStorage(1, 9) + .Op(Instruction.REVERT) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + // Should be original TSTORE value + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); + } - // Should be original TSTORE value - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); - } + /// + /// Revert undoes all the transient storage writes to the same key from the failed call + /// + [Test] + public void revert_resets_all_transient_state() + { + // If caller is self, TLOAD and return value (break recursion) + // Else, TSTORE and call self, return the response + byte[] contractCode = Prepare.EvmCode + // Check if caller is self + .Op(Instruction.CALLER) + .PushData(TestItem.AddressD) + .Op(Instruction.EQ) + .PushData(77) + .Op(Instruction.JUMPI) + + // Non-reentrant, call self after TSTORE + .StoreDataInTransientStorage(1, 8) + .Call(TestItem.AddressD, 50000) + // TLOAD and return value + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + + // Reentrant, TSTORE 9 but REVERT + .Op(Instruction.JUMPDEST) // PC = 77 + .StoreDataInTransientStorage(1, 9) + .StoreDataInTransientStorage(1, 10) + .Op(Instruction.REVERT) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + // Should be original TSTORE value + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); + } - /// - /// Revert undoes transient storage writes from inner calls that successfully returned - /// - [Test] - public void revert_resets_transient_state_from_succesful_calls() - { - // If caller is self, TLOAD and return value (break recursion) - // Else, TSTORE and call self, return the response - byte[] contractCode = Prepare.EvmCode - // Check call depth - .PushData(0) - .Op(Instruction.CALLDATALOAD) - // Store input in mem and reload it to stack - .DataOnStackToMemory(5) + /// + /// Revert undoes transient storage writes from inner calls that successfully returned + /// + [Test] + public void revert_resets_transient_state_from_succesful_calls() + { + // If caller is self, TLOAD and return value (break recursion) + // Else, TSTORE and call self, return the response + byte[] contractCode = Prepare.EvmCode + // Check call depth + .PushData(0) + .Op(Instruction.CALLDATALOAD) + // Store input in mem and reload it to stack + .DataOnStackToMemory(5) + .PushData(5) + .Op(Instruction.MLOAD) + + // See if we're at call depth 1 + .PushData(1) + .Op(Instruction.EQ) + .PushData(84) + .Op(Instruction.JUMPI) + + // See if we're at call depth 2 + .PushData(5) + .Op(Instruction.MLOAD) + .PushData(2) + .Op(Instruction.EQ) + .PushData(135) + .Op(Instruction.JUMPI) + + // Call depth = 0, call self after TSTORE 8 + .StoreDataInTransientStorage(1, 8) + + // Recursive call with input + // Depth++ .PushData(5) .Op(Instruction.MLOAD) - - // See if we're at call depth 1 .PushData(1) - .Op(Instruction.EQ) - .PushData(84) - .Op(Instruction.JUMPI) - - // See if we're at call depth 2 - .PushData(5) - .Op(Instruction.MLOAD) - .PushData(2) - .Op(Instruction.EQ) - .PushData(135) - .Op(Instruction.JUMPI) - - // Call depth = 0, call self after TSTORE 8 - .StoreDataInTransientStorage(1, 8) - - // Recursive call with input - // Depth++ - .PushData(5) - .Op(Instruction.MLOAD) - .PushData(1) - .Op(Instruction.ADD) - - .CallWithInput(TestItem.AddressD, 50000) - - // TLOAD and return value - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - - // Call depth 1, TSTORE 9 but REVERT after recursion - .Op(Instruction.JUMPDEST) // PC = 84 - .StoreDataInTransientStorage(1, 9) - - // Recursive call with input - // Depth++ - .PushData(5) - .Op(Instruction.MLOAD) - .PushData(1) - .Op(Instruction.ADD) - - .CallWithInput(TestItem.AddressD, 50000) + .Op(Instruction.ADD) - .Op(Instruction.REVERT) + .CallWithInput(TestItem.AddressD, 50000) - // Call depth 2, TSTORE 10 and complete - .Op(Instruction.JUMPDEST) // PC = 135 - .StoreDataInTransientStorage(1, 10) - .Done; + // TLOAD and return value + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); - - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .CallWithInput(TestItem.AddressD, 50000, new byte[32]) - .ReturnInnerCallResult() - .Done; - - TestAllTracerWithOutput result = Execute(code); - - // Should be original TSTORE value - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); - } + // Call depth 1, TSTORE 9 but REVERT after recursion + .Op(Instruction.JUMPDEST) // PC = 84 + .StoreDataInTransientStorage(1, 9) - /// - /// Transient storage cannot be manipulated in a static context - /// - [TestCase(Instruction.CALL, 1)] - [TestCase(Instruction.STATICCALL, 0)] - public void tstore_in_staticcall(Instruction callType, int expectedResult) - { - byte[] contractCode = Prepare.EvmCode - .StoreDataInTransientStorage(1, 8) + // Recursive call with input + // Depth++ + .PushData(5) + .Op(Instruction.MLOAD) .PushData(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - .Done; + .Op(Instruction.ADD) - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + .CallWithInput(TestItem.AddressD, 50000) - // Return the result received from the contract (1 if successful) - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 7) - .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) - .ReturnInnerCallResult() - .Done; + .Op(Instruction.REVERT) - TestAllTracerWithOutput result = Execute(code); + // Call depth 2, TSTORE 10 and complete + .Op(Instruction.JUMPDEST) // PC = 135 + .StoreDataInTransientStorage(1, 10) + .Done; - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); - } + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); - /// - /// Transient storage cannot be manipulated in a static context when calling self - /// - [TestCase(Instruction.CALL, 9)] - [TestCase(Instruction.STATICCALL, 8)] - public void tstore_from_static_reentrant_call(Instruction callType, int expectedResult) - { - // If caller is self, TSTORE 9 and break recursion - // Else, TSTORE 8 and call self, return the result of TLOAD - byte[] contractCode = Prepare.EvmCode - // Check if caller is self - .Op(Instruction.CALLER) - .PushData(TestItem.AddressD) - .Op(Instruction.EQ) - .PushData(113) - .Op(Instruction.JUMPI) - - // Non-reentrant, call self after TSTORE 8 - .StoreDataInTransientStorage(1, 8) - .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) - // Return the TLOAD value - // Should be 8 if call fails, 9 if success - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - - // Reentrant, TSTORE 9 - .Op(Instruction.JUMPDEST) // PC = 113 - .StoreDataInTransientStorage(1, 9) - .Done; + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .CallWithInput(TestItem.AddressD, 50000, new byte[32]) + .ReturnInnerCallResult() + .Done; - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + TestAllTracerWithOutput result = Execute(code); - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; + // Should be original TSTORE value + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(8)); + } - TestAllTracerWithOutput result = Execute(code); + /// + /// Transient storage cannot be manipulated in a static context + /// + [TestCase(Instruction.CALL, 1)] + [TestCase(Instruction.STATICCALL, 0)] + public void tstore_in_staticcall(Instruction callType, int expectedResult) + { + byte[] contractCode = Prepare.EvmCode + .StoreDataInTransientStorage(1, 8) + .PushData(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract (1 if successful) + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 7) + .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); + } - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); - } + /// + /// Transient storage cannot be manipulated in a static context when calling self + /// + [TestCase(Instruction.CALL, 9)] + [TestCase(Instruction.STATICCALL, 8)] + public void tstore_from_static_reentrant_call(Instruction callType, int expectedResult) + { + // If caller is self, TSTORE 9 and break recursion + // Else, TSTORE 8 and call self, return the result of TLOAD + byte[] contractCode = Prepare.EvmCode + // Check if caller is self + .Op(Instruction.CALLER) + .PushData(TestItem.AddressD) + .Op(Instruction.EQ) + .PushData(113) + .Op(Instruction.JUMPI) + + // Non-reentrant, call self after TSTORE 8 + .StoreDataInTransientStorage(1, 8) + .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) + // Return the TLOAD value + // Should be 8 if call fails, 9 if success + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + + // Reentrant, TSTORE 9 + .Op(Instruction.JUMPDEST) // PC = 113 + .StoreDataInTransientStorage(1, 9) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); + } - /// - /// Transient storage cannot be manipulated in a nested static context - /// - [TestCase(Instruction.CALL, 10)] - [TestCase(Instruction.STATICCALL, 8)] - public void tstore_from_nonstatic_reentrant_call_with_static_intermediary(Instruction callType, int expectedResult) - { - // If caller is self, TLOAD and return value (break recursion) - // Else, TSTORE and call self, return the response - byte[] contractCode = Prepare.EvmCode - // Check call depth - .PushData(0) - .Op(Instruction.CALLDATALOAD) - // Store input in mem and reload it to stack - .DataOnStackToMemory(5) + /// + /// Transient storage cannot be manipulated in a nested static context + /// + [TestCase(Instruction.CALL, 10)] + [TestCase(Instruction.STATICCALL, 8)] + public void tstore_from_nonstatic_reentrant_call_with_static_intermediary(Instruction callType, int expectedResult) + { + // If caller is self, TLOAD and return value (break recursion) + // Else, TSTORE and call self, return the response + byte[] contractCode = Prepare.EvmCode + // Check call depth + .PushData(0) + .Op(Instruction.CALLDATALOAD) + // Store input in mem and reload it to stack + .DataOnStackToMemory(5) + .PushData(5) + .Op(Instruction.MLOAD) + + // See if we're at call depth 1 + .PushData(1) + .Op(Instruction.EQ) + .PushData(84) + .Op(Instruction.JUMPI) + + // See if we're at call depth 2 + .PushData(5) + .Op(Instruction.MLOAD) + .PushData(2) + .Op(Instruction.EQ) + .PushData(140) + .Op(Instruction.JUMPI) + + // Call depth = 0, call self after TSTORE 8 + .StoreDataInTransientStorage(1, 8) + + // Recursive call with input + // Depth++ .PushData(5) .Op(Instruction.MLOAD) - - // See if we're at call depth 1 .PushData(1) - .Op(Instruction.EQ) - .PushData(84) - .Op(Instruction.JUMPI) - - // See if we're at call depth 2 - .PushData(5) - .Op(Instruction.MLOAD) - .PushData(2) - .Op(Instruction.EQ) - .PushData(140) - .Op(Instruction.JUMPI) - - // Call depth = 0, call self after TSTORE 8 - .StoreDataInTransientStorage(1, 8) + .Op(Instruction.ADD) - // Recursive call with input - // Depth++ - .PushData(5) - .Op(Instruction.MLOAD) - .PushData(1) - .Op(Instruction.ADD) + .DynamicCallWithInput(callType, TestItem.AddressD, 50000) - .DynamicCallWithInput(callType, TestItem.AddressD, 50000) + // TLOAD and return value + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) - // TLOAD and return value - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) + // Call depth 1, TSTORE 9 but REVERT after recursion + .Op(Instruction.JUMPDEST) // PC = 84 - // Call depth 1, TSTORE 9 but REVERT after recursion - .Op(Instruction.JUMPDEST) // PC = 84 - - // Recursive call with input - // Depth++ - .PushData(5) - .Op(Instruction.MLOAD) - .PushData(1) - .Op(Instruction.ADD) - .CallWithInput(TestItem.AddressD, 50000) - - // TLOAD and return value - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - - // Call depth 2, TSTORE 10 and complete - .Op(Instruction.JUMPDEST) // PC = 140 - .StoreDataInTransientStorage(1, 10) // This will fail - .Done; - - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); - - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .CallWithInput(TestItem.AddressD, 50000, new byte[32]) - .ReturnInnerCallResult() - .Done; - - TestAllTracerWithOutput result = Execute(code); - - // Should be original TSTORE value - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); - } - - /// - /// Delegatecall manipulates transient storage in the context of the current address - /// - [TestCase(Instruction.CALL, 7)] - [TestCase(Instruction.DELEGATECALL, 8)] - public void tstore_in_delegatecall(Instruction callType, int expectedResult) - { - byte[] contractCode = Prepare.EvmCode - .StoreDataInTransientStorage(1, 8) - .Done; - - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + // Recursive call with input + // Depth++ + .PushData(5) + .Op(Instruction.MLOAD) + .PushData(1) + .Op(Instruction.ADD) + .CallWithInput(TestItem.AddressD, 50000) - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 7) - .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) // TLOAD and return value .LoadDataFromTransientStorage(1) .DataOnStackToMemory(0) .PushData(32) .PushData(0) .Op(Instruction.RETURN) - .Done; - - TestAllTracerWithOutput result = Execute(code); - - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); - } - - /// - /// Delegatecall reads transient storage in the context of the current address - /// - [TestCase(Instruction.CALL, 0)] - [TestCase(Instruction.DELEGATECALL, 7)] - public void tload_in_delegatecall(Instruction callType, int expectedResult) - { - byte[] contractCode = Prepare.EvmCode - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - .Done; - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + // Call depth 2, TSTORE 10 and complete + .Op(Instruction.JUMPDEST) // PC = 140 + .StoreDataInTransientStorage(1, 10) // This will fail + .Done; - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 7) - .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) - // Return response from nested call - .ReturnInnerCallResult() - .Done; + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); - TestAllTracerWithOutput result = Execute(code); - - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); - } - - /// - /// Zeroing out a transient storage slot does not result in gas refund - /// - [Test] - public void tstore_does_not_result_in_gasrefund() - { - byte[] code = Prepare.EvmCode - .StoreDataInTransientStorage(1, 7) - .StoreDataInTransientStorage(1, 0) - .Done; - - TestAllTracerWithOutput receipt = Execute(code); - Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 4 + GasCostOf.TStore * 2), "gas"); - } - - /// - /// Transient storage does not persist beyond a single transaction - /// - [Test] - public void transient_state_not_persisted_across_txs() - { - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .LoadDataFromTransientStorage(1) - // See if we're at call depth 1 - .PushData(1) - .Op(Instruction.EQ) - .PushData(24) - .Op(Instruction.JUMPI) - - // TSTORE 1 and Return 1 - .StoreDataInTransientStorage(1, 1) - .PushData(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .CallWithInput(TestItem.AddressD, 50000, new byte[32]) + .ReturnInnerCallResult() + .Done; - // Return 0 - .Op(Instruction.JUMPDEST) // PC = 24 - .PushData(0) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - .Done; + TestAllTracerWithOutput result = Execute(code); - TestAllTracerWithOutput result = Execute(code); - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(1)); + // Should be original TSTORE value + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); + } - // If transient state persisted across txs, calling again would return 0 - result = Execute(code); - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(1)); - } + /// + /// Delegatecall manipulates transient storage in the context of the current address + /// + [TestCase(Instruction.CALL, 7)] + [TestCase(Instruction.DELEGATECALL, 8)] + public void tstore_in_delegatecall(Instruction callType, int expectedResult) + { + byte[] contractCode = Prepare.EvmCode + .StoreDataInTransientStorage(1, 8) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 7) + .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) + // TLOAD and return value + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); + } + /// + /// Delegatecall reads transient storage in the context of the current address + /// + [TestCase(Instruction.CALL, 0)] + [TestCase(Instruction.DELEGATECALL, 7)] + public void tload_in_delegatecall(Instruction callType, int expectedResult) + { + byte[] contractCode = Prepare.EvmCode + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 7) + .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) + // Return response from nested call + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); + } - /// - /// Transient storage can be accessed in a static context when calling self - /// - [TestCase(Instruction.CALL, 8)] - [TestCase(Instruction.STATICCALL, 8)] - public void tload_from_static_reentrant_call(Instruction callType, int expectedResult) - { - // If caller is self, TLOAD and break recursion - // Else, TSTORE 8 and call self, return the result of the inner call - byte[] contractCode = Prepare.EvmCode - // Check if caller is self - .Op(Instruction.CALLER) - .PushData(TestItem.AddressD) - .Op(Instruction.EQ) - .PushData(114) - .Op(Instruction.JUMPI) - - // Non-reentrant, call self after TSTORE 8 - .StoreDataInTransientStorage(1, 8) - .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) - .ReturnInnerCallResult() - - // Reentrant, TLOAD and return - .Op(Instruction.JUMPDEST) // PC = 114 - .LoadDataFromTransientStorage(1) - .DataOnStackToMemory(0) - .PushData(32) - .PushData(0) - .Op(Instruction.RETURN) - .Done; + /// + /// Zeroing out a transient storage slot does not result in gas refund + /// + [Test] + public void tstore_does_not_result_in_gasrefund() + { + byte[] code = Prepare.EvmCode + .StoreDataInTransientStorage(1, 7) + .StoreDataInTransientStorage(1, 0) + .Done; - TestState.CreateAccount(TestItem.AddressD, 1.Ether()); - TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + TestAllTracerWithOutput receipt = Execute(code); + Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + GasCostOf.VeryLow * 4 + GasCostOf.TStore * 2), "gas"); + } - // Return the result received from the contract - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressD, 50000) - .ReturnInnerCallResult() - .Done; + /// + /// Transient storage does not persist beyond a single transaction + /// + [Test] + public void transient_state_not_persisted_across_txs() + { + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .LoadDataFromTransientStorage(1) + // See if we're at call depth 1 + .PushData(1) + .Op(Instruction.EQ) + .PushData(24) + .Op(Instruction.JUMPI) + + // TSTORE 1 and Return 1 + .StoreDataInTransientStorage(1, 1) + .PushData(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + + // Return 0 + .Op(Instruction.JUMPDEST) // PC = 24 + .PushData(0) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestAllTracerWithOutput result = Execute(code); + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(1)); + + // If transient state persisted across txs, calling again would return 0 + result = Execute(code); + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(1)); + } - TestAllTracerWithOutput result = Execute(code); - Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); - } + /// + /// Transient storage can be accessed in a static context when calling self + /// + [TestCase(Instruction.CALL, 8)] + [TestCase(Instruction.STATICCALL, 8)] + public void tload_from_static_reentrant_call(Instruction callType, int expectedResult) + { + // If caller is self, TLOAD and break recursion + // Else, TSTORE 8 and call self, return the result of the inner call + byte[] contractCode = Prepare.EvmCode + // Check if caller is self + .Op(Instruction.CALLER) + .PushData(TestItem.AddressD) + .Op(Instruction.EQ) + .PushData(114) + .Op(Instruction.JUMPI) + + // Non-reentrant, call self after TSTORE 8 + .StoreDataInTransientStorage(1, 8) + .DynamicCallWithInput(callType, TestItem.AddressD, 50000, new byte[32]) + .ReturnInnerCallResult() + + // Reentrant, TLOAD and return + .Op(Instruction.JUMPDEST) // PC = 114 + .LoadDataFromTransientStorage(1) + .DataOnStackToMemory(0) + .PushData(32) + .PushData(0) + .Op(Instruction.RETURN) + .Done; + + TestState.CreateAccount(TestItem.AddressD, 1.Ether()); + TestState.InsertCode(TestItem.AddressD, contractCode, Spec); + + // Return the result received from the contract + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressD, 50000) + .ReturnInnerCallResult() + .Done; + + TestAllTracerWithOutput result = Execute(code); + + Assert.That((int)result.ReturnValue.ToUInt256(), Is.EqualTo(expectedResult)); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs index ce523a422dc..b93be39bd7f 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs @@ -6,39 +6,38 @@ using Nethermind.Evm.Precompiles; using NUnit.Framework; -namespace Nethermind.Evm.Test +namespace Nethermind.Evm.Test; + +public class Eip152Tests : VirtualMachineTestsBase { - public class Eip152Tests : VirtualMachineTestsBase + private const int InputLength = 213; + protected override long BlockNumber => MainnetSpecProvider.IstanbulBlockNumber + _blockNumberAdjustment; + + private int _blockNumberAdjustment; + + [TearDown] + public override void TearDown() + { + base.TearDown(); + + _blockNumberAdjustment = 0; + } + + [Test] + public void before_istanbul() + { + _blockNumberAdjustment = -1; + Address precompileAddress = Blake2FPrecompile.Address; + Assert.That(precompileAddress.IsPrecompile(Spec), Is.False); + } + + [Test] + public void after_istanbul() { - private const int InputLength = 213; - protected override long BlockNumber => MainnetSpecProvider.IstanbulBlockNumber + _blockNumberAdjustment; - - private int _blockNumberAdjustment; - - [TearDown] - public override void TearDown() - { - base.TearDown(); - - _blockNumberAdjustment = 0; - } - - [Test] - public void before_istanbul() - { - _blockNumberAdjustment = -1; - Address precompileAddress = Blake2FPrecompile.Address; - Assert.False(precompileAddress.IsPrecompile(Spec)); - } - - [Test] - public void after_istanbul() - { - byte[] code = Prepare.EvmCode - .CallWithInput(Blake2FPrecompile.Address, 1000L, new byte[InputLength]) - .Done; - TestAllTracerWithOutput result = Execute(code); - Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); - } + byte[] code = Prepare.EvmCode + .CallWithInput(Blake2FPrecompile.Address, 1000L, new byte[InputLength]) + .Done; + TestAllTracerWithOutput result = Execute(code); + Assert.That(result.StatusCode, Is.EqualTo(StatusCode.Success)); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs index 69e75399a8f..33c7eb093cc 100644 --- a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs @@ -18,378 +18,375 @@ using Nethermind.Specs.Forks; using Nethermind.State; using Nethermind.Trie.Pruning; - using FluentAssertions; using NUnit.Framework; -namespace Nethermind.Evm.Test +namespace Nethermind.Evm.Test; + +public class EvmPooledMemoryTests : EvmMemoryTestsBase +{ + protected override IEvmMemory CreateEvmMemory() + { + return new EvmPooledMemory(); + } + + [TestCase(32, 1)] + [TestCase(0, 0)] + [TestCase(33, 2)] + [TestCase(64, 2)] + [TestCase(int.MaxValue, int.MaxValue / 32 + 1)] + public void Div32Ceiling(int input, int expectedResult) + { + long result = EvmPooledMemory.Div32Ceiling((ulong)input); + TestContext.Out.WriteLine($"Memory cost (gas): {result}"); + Assert.That(result, Is.EqualTo(expectedResult)); + } + + private const int MaxCodeSize = 24576; + + [TestCase(0, 0)] + [TestCase(0, 32)] + [TestCase(0, 256)] + [TestCase(0, 2048)] + [TestCase(0, MaxCodeSize)] + [TestCase(10 * MaxCodeSize, MaxCodeSize)] + [TestCase(100 * MaxCodeSize, MaxCodeSize)] + [TestCase(1000 * MaxCodeSize, MaxCodeSize)] + [TestCase(0, 1024 * 1024)] + [TestCase(0, Int32.MaxValue)] + public void MemoryCost(int destination, int memoryAllocation) + { + EvmPooledMemory memory = new(); + UInt256 dest = (UInt256)destination; + long result = memory.CalculateMemoryCost(in dest, (UInt256)memoryAllocation); + TestContext.Out.WriteLine($"Gas cost of allocating {memoryAllocation} starting from {dest}: {result}"); + } + + [Test] + public void Inspect_should_not_change_evm_memory() + { + EvmPooledMemory memory = new(); + memory.Save(3, TestItem.KeccakA.Bytes); + ulong initialSize = memory.Size; + ReadOnlyMemory result = memory.Inspect(initialSize + 32, 32); + Assert.That(memory.Size, Is.EqualTo(initialSize)); + Assert.That(result, Is.EqualTo(ReadOnlyMemory.Empty)); + } + + [Test] + public void Inspect_can_read_memory() + { + const int offset = 3; + byte[] expectedEmptyRead = new byte[32 - offset]; + byte[] expectedKeccakRead = TestItem.KeccakA.BytesToArray(); + EvmPooledMemory memory = new(); + memory.Save((UInt256)offset, expectedKeccakRead); + ulong initialSize = memory.Size; + ReadOnlyMemory actualKeccakMemoryRead = memory.Inspect((UInt256)offset, 32); + ReadOnlyMemory actualEmptyRead = memory.Inspect(32 + (UInt256)offset, 32 - (UInt256)offset); + Assert.That(memory.Size, Is.EqualTo(initialSize)); + Assert.That(actualKeccakMemoryRead.ToArray(), Is.EqualTo(expectedKeccakRead)); + Assert.That(actualEmptyRead.ToArray(), Is.EqualTo(expectedEmptyRead)); + } + + [Test] + public void Load_should_update_size_of_memory() + { + byte[] expectedResult = new byte[32]; + EvmPooledMemory memory = new(); + memory.Save(3, TestItem.KeccakA.Bytes); + ulong initialSize = memory.Size; + ReadOnlyMemory result = memory.Load(initialSize + 32, 32); + Assert.That(memory.Size, Is.Not.EqualTo(initialSize)); + Assert.That(result.ToArray(), Is.EqualTo(expectedResult)); + } + + [Test] + public void GetTrace_should_not_throw_on_not_initialized_memory() + { + EvmPooledMemory memory = new(); + memory.CalculateMemoryCost(0, 32); + memory.GetTrace().ToHexWordList().Should().BeEquivalentTo(new string[] { "0000000000000000000000000000000000000000000000000000000000000000" }); + } + + [Test] + public void GetTrace_memory_should_not_bleed_between_txs() + { + var first = new byte[] { + 0x5b, 0x38, 0x36, 0x59, 0x59, 0x59, 0x59, 0x52, 0x3a, 0x60, 0x05, 0x30, + 0xf4, 0x05, 0x56}; + var second = new byte[] { + 0x5b, 0x36, 0x59, 0x3a, 0x34, 0x60, 0x5b, 0x59, 0x05, 0x30, 0xf4, 0x3a, + 0x56}; + + var a = Run(second).ToString(); + Run(first); + var b = Run(second).ToString(); + + Assert.That(b, Is.EqualTo(a)); + } + + [Test] + public void GetTrace_memory_should_not_overflow() + { + var input = new byte[] { + 0x5b, 0x59, 0x60, 0x20, 0x59, 0x81, 0x91, 0x52, 0x44, 0x36, 0x5a, 0x3b, + 0x59, 0xf4, 0x5b, 0x31, 0x56, 0x08}; + Run(input); + } + + private static readonly PrivateKey PrivateKeyD = new("0000000000000000000000000000000000000000000000000000001000000000"); + private static readonly Address sender = new Address("0x59ede65f910076f60e07b2aeb189c72348525e72"); + + private static readonly Address to = new Address("0x000000000000000000000000636f6e7472616374"); + private static readonly Address coinbase = new Address("0x4444588443C3a91288c5002483449Aba1054192b"); + // for testing purposes, particular chain id does not matter. Maybe make random id so it captures the idea that signature should would irrespective of chain + private static readonly EthereumEcdsa ethereumEcdsa = new(BlockchainIds.GenericNonRealNetwork); + private static string Run(byte[] input) + { + long blocknr = 12965000; + long gas = 34218; + ulong ts = 123456; + MemDb stateDb = new(); + TrieStore trieStore = new( + stateDb, + LimboLogs.Instance); + IWorldState stateProvider = new WorldState( + trieStore, + new MemDb(), + LimboLogs.Instance); + ISpecProvider specProvider = new TestSpecProvider(London.Instance); + CodeInfoRepository codeInfoRepository = new(); + VirtualMachine virtualMachine = new( + new TestBlockhashProvider(specProvider), + specProvider, + codeInfoRepository, + LimboLogs.Instance); + TransactionProcessor transactionProcessor = new TransactionProcessor( + specProvider, + stateProvider, + virtualMachine, + codeInfoRepository, + LimboLogs.Instance); + + stateProvider.CreateAccount(to, 123); + stateProvider.InsertCode(to, input, specProvider.GenesisSpec); + + stateProvider.CreateAccount(sender, 40000000); + stateProvider.Commit(specProvider.GenesisSpec); + + stateProvider.CommitTree(0); + + Transaction tx = Build.A.Transaction. + WithData(input). + WithTo(to). + WithGasLimit(gas). + WithGasPrice(0). + WithValue(0). + SignedAndResolved(ethereumEcdsa, PrivateKeyD, true). + TestObject; + Block block = Build.A.Block. + WithBeneficiary(coinbase). + WithNumber(blocknr + 1). + WithTimestamp(ts). + WithTransactions(tx). + WithGasLimit(30000000). + WithDifficulty(0). + TestObject; + MyTracer tracer = new(); + transactionProcessor.Execute( + tx, + new BlockExecutionContext(block.Header), + tracer); + return tracer.lastmemline; + } +} + +public class MyTracer : ITxTracer, IDisposable { - [TestFixture] - public class EvmPooledMemoryTests : EvmMemoryTestsBase - { - protected override IEvmMemory CreateEvmMemory() - { - return new EvmPooledMemory(); - } - - [TestCase(32, 1)] - [TestCase(0, 0)] - [TestCase(33, 2)] - [TestCase(64, 2)] - [TestCase(int.MaxValue, int.MaxValue / 32 + 1)] - public void Div32Ceiling(int input, int expectedResult) - { - long result = EvmPooledMemory.Div32Ceiling((ulong)input); - TestContext.WriteLine($"Memory cost (gas): {result}"); - Assert.That(result, Is.EqualTo(expectedResult)); - } - - private const int MaxCodeSize = 24576; - - [TestCase(0, 0)] - [TestCase(0, 32)] - [TestCase(0, 256)] - [TestCase(0, 2048)] - [TestCase(0, MaxCodeSize)] - [TestCase(10 * MaxCodeSize, MaxCodeSize)] - [TestCase(100 * MaxCodeSize, MaxCodeSize)] - [TestCase(1000 * MaxCodeSize, MaxCodeSize)] - [TestCase(0, 1024 * 1024)] - [TestCase(0, Int32.MaxValue)] - public void MemoryCost(int destination, int memoryAllocation) - { - EvmPooledMemory memory = new(); - UInt256 dest = (UInt256)destination; - long result = memory.CalculateMemoryCost(in dest, (UInt256)memoryAllocation); - TestContext.WriteLine($"Gas cost of allocating {memoryAllocation} starting from {dest}: {result}"); - } - - [Test] - public void Inspect_should_not_change_evm_memory() - { - EvmPooledMemory memory = new(); - memory.Save(3, TestItem.KeccakA.Bytes); - ulong initialSize = memory.Size; - ReadOnlyMemory result = memory.Inspect(initialSize + 32, 32); - Assert.That(memory.Size, Is.EqualTo(initialSize)); - Assert.That(result, Is.EqualTo(ReadOnlyMemory.Empty)); - } - - [Test] - public void Inspect_can_read_memory() - { - const int offset = 3; - byte[] expectedEmptyRead = new byte[32 - offset]; - byte[] expectedKeccakRead = TestItem.KeccakA.BytesToArray(); - EvmPooledMemory memory = new(); - memory.Save((UInt256)offset, expectedKeccakRead); - ulong initialSize = memory.Size; - ReadOnlyMemory actualKeccakMemoryRead = memory.Inspect((UInt256)offset, 32); - ReadOnlyMemory actualEmptyRead = memory.Inspect(32 + (UInt256)offset, 32 - (UInt256)offset); - Assert.That(memory.Size, Is.EqualTo(initialSize)); - Assert.That(actualKeccakMemoryRead.ToArray(), Is.EqualTo(expectedKeccakRead)); - Assert.That(actualEmptyRead.ToArray(), Is.EqualTo(expectedEmptyRead)); - } - - [Test] - public void Load_should_update_size_of_memory() - { - byte[] expectedResult = new byte[32]; - EvmPooledMemory memory = new(); - memory.Save(3, TestItem.KeccakA.Bytes); - ulong initialSize = memory.Size; - ReadOnlyMemory result = memory.Load(initialSize + 32, 32); - Assert.That(memory.Size, Is.Not.EqualTo(initialSize)); - Assert.That(result.ToArray(), Is.EqualTo(expectedResult)); - } - - [Test] - public void GetTrace_should_not_throw_on_not_initialized_memory() - { - EvmPooledMemory memory = new(); - memory.CalculateMemoryCost(0, 32); - memory.GetTrace().ToHexWordList().Should().BeEquivalentTo(new string[] { "0000000000000000000000000000000000000000000000000000000000000000" }); - } - - [Test] - public void GetTrace_memory_should_not_bleed_between_txs() - { - var first = new byte[] { - 0x5b, 0x38, 0x36, 0x59, 0x59, 0x59, 0x59, 0x52, 0x3a, 0x60, 0x05, 0x30, - 0xf4, 0x05, 0x56}; - var second = new byte[] { - 0x5b, 0x36, 0x59, 0x3a, 0x34, 0x60, 0x5b, 0x59, 0x05, 0x30, 0xf4, 0x3a, - 0x56}; - - var a = Run(second).ToString(); - Run(first); - var b = Run(second).ToString(); - - Assert.That(b, Is.EqualTo(a)); - } - - [Test] - public void GetTrace_memory_should_not_overflow() - { - var input = new byte[] { - 0x5b, 0x59, 0x60, 0x20, 0x59, 0x81, 0x91, 0x52, 0x44, 0x36, 0x5a, 0x3b, - 0x59, 0xf4, 0x5b, 0x31, 0x56, 0x08}; - Run(input); - } - - private static readonly PrivateKey PrivateKeyD = new("0000000000000000000000000000000000000000000000000000001000000000"); - private static readonly Address sender = new Address("0x59ede65f910076f60e07b2aeb189c72348525e72"); - - private static readonly Address to = new Address("0x000000000000000000000000636f6e7472616374"); - private static readonly Address coinbase = new Address("0x4444588443C3a91288c5002483449Aba1054192b"); - // for testing purposes, particular chain id does not matter. Maybe make random id so it captures the idea that signature should would irrespective of chain - private static readonly EthereumEcdsa ethereumEcdsa = new(BlockchainIds.GenericNonRealNetwork); - private static string Run(byte[] input) - { - long blocknr = 12965000; - long gas = 34218; - ulong ts = 123456; - MemDb stateDb = new(); - TrieStore trieStore = new( - stateDb, - LimboLogs.Instance); - IWorldState stateProvider = new WorldState( - trieStore, - new MemDb(), - LimboLogs.Instance); - ISpecProvider specProvider = new TestSpecProvider(London.Instance); - CodeInfoRepository codeInfoRepository = new(); - VirtualMachine virtualMachine = new( - new TestBlockhashProvider(specProvider), - specProvider, - codeInfoRepository, - LimboLogs.Instance); - TransactionProcessor transactionProcessor = new TransactionProcessor( - specProvider, - stateProvider, - virtualMachine, - codeInfoRepository, - LimboLogs.Instance); - - stateProvider.CreateAccount(to, 123); - stateProvider.InsertCode(to, input, specProvider.GenesisSpec); - - stateProvider.CreateAccount(sender, 40000000); - stateProvider.Commit(specProvider.GenesisSpec); - - stateProvider.CommitTree(0); - - Transaction tx = Build.A.Transaction. - WithData(input). - WithTo(to). - WithGasLimit(gas). - WithGasPrice(0). - WithValue(0). - SignedAndResolved(ethereumEcdsa, PrivateKeyD, true). - TestObject; - Block block = Build.A.Block. - WithBeneficiary(coinbase). - WithNumber(blocknr + 1). - WithTimestamp(ts). - WithTransactions(tx). - WithGasLimit(30000000). - WithDifficulty(0). - TestObject; - MyTracer tracer = new(); - transactionProcessor.Execute( - tx, - new BlockExecutionContext(block.Header), - tracer); - return tracer.lastmemline; - } - } - - public class MyTracer : ITxTracer, IDisposable - { - public bool IsTracingReceipt => true; - public bool IsTracingActions => false; - public bool IsTracingOpLevelStorage => true; - public bool IsTracingMemory => true; - public bool IsTracingDetailedMemory { get; set; } = true; - public bool IsTracingInstructions => true; - public bool IsTracingRefunds { get; } = false; - public bool IsTracingCode => true; - public bool IsTracingStack { get; set; } = true; - public bool IsTracingState => false; - public bool IsTracingStorage => false; - public bool IsTracingBlockHash { get; } = false; - public bool IsTracingAccess { get; } = false; - public bool IsTracingFees => false; - public bool IsTracingLogs => false; - public bool IsTracing => IsTracingReceipt - || IsTracingActions - || IsTracingOpLevelStorage - || IsTracingMemory - || IsTracingInstructions - || IsTracingRefunds - || IsTracingCode - || IsTracingStack - || IsTracingBlockHash - || IsTracingAccess - || IsTracingFees - || IsTracingLogs; - - public string lastmemline; - - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256 stateRoot = null) - { - } - - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256 stateRoot = null) - { - } - - public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env) - { - } - - public void ReportOperationError(EvmExceptionType error) - { - } - - public void ReportOperationRemainingGas(long gas) - { - } - - public void ReportLog(LogEntry log) - { - } - - public void SetOperationStack(TraceStack stack) - { - } - - public void SetOperationMemory(TraceMemory memoryTrace) - { - lastmemline = string.Concat("0x", string.Join("", memoryTrace.ToHexWordList().Select(mt => mt.Replace("0x", string.Empty)))); - } - - public void SetOperationMemorySize(ulong newSize) - { - } - - public void ReportMemoryChange(long offset, in ReadOnlySpan data) - { - } - - public void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value) - { - } - - public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) - { - } - - public void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value) - { - } - - public void ReportSelfDestruct(Address address, UInt256 balance, Address refundAddress) - { - throw new NotSupportedException(); - } - - public void ReportBalanceChange(Address address, UInt256? before, UInt256? after) - { - throw new NotSupportedException(); - } - - public void ReportCodeChange(Address address, byte[] before, byte[] after) - { - throw new NotSupportedException(); - } - - public void ReportNonceChange(Address address, UInt256? before, UInt256? after) - { - throw new NotSupportedException(); - } - - public void ReportAccountRead(Address address) - { - throw new NotImplementedException(); - } - - public void ReportStorageChange(in StorageCell storageAddress, byte[] before, byte[] after) - { - throw new NotSupportedException(); - } - - public void ReportStorageRead(in StorageCell storageCell) - { - throw new NotImplementedException(); - } - - public void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false) - { - throw new NotSupportedException(); - } - - public void ReportActionEnd(long gas, ReadOnlyMemory output) - { - throw new NotSupportedException(); - } - - public void ReportActionError(EvmExceptionType exceptionType) - { - throw new NotSupportedException(); - } - - public void ReportActionRevert(long gas, ReadOnlyMemory output) - { - throw new NotSupportedException(); - } - - public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) - { - throw new NotSupportedException(); - } - - public void ReportBlockHash(Hash256 blockHash) - { - throw new NotImplementedException(); - } - - public void ReportByteCode(ReadOnlyMemory byteCode) - { - throw new NotSupportedException(); - } - - public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) - { - } - - public void ReportRefundForVmTrace(long refund, long gasAvailable) - { - } - - public void ReportRefund(long refund) - { - } - - public void ReportExtraGasPressure(long extraGasPressure) - { - throw new NotImplementedException(); - } - - public void ReportAccess(IReadOnlySet
accessedAddresses, IReadOnlySet accessedStorageCells) - { - throw new NotImplementedException(); - } - - public void ReportStackPush(in ReadOnlySpan stackItem) - { - } - - public void ReportFees(UInt256 fees, UInt256 burntFees) - { - throw new NotImplementedException(); - } - - public void Dispose() { } + public bool IsTracingReceipt => true; + public bool IsTracingActions => false; + public bool IsTracingOpLevelStorage => true; + public bool IsTracingMemory => true; + public bool IsTracingDetailedMemory { get; set; } = true; + public bool IsTracingInstructions => true; + public bool IsTracingRefunds { get; } = false; + public bool IsTracingCode => true; + public bool IsTracingStack { get; set; } = true; + public bool IsTracingState => false; + public bool IsTracingStorage => false; + public bool IsTracingBlockHash { get; } = false; + public bool IsTracingAccess { get; } = false; + public bool IsTracingFees => false; + public bool IsTracingLogs => false; + public bool IsTracing => IsTracingReceipt + || IsTracingActions + || IsTracingOpLevelStorage + || IsTracingMemory + || IsTracingInstructions + || IsTracingRefunds + || IsTracingCode + || IsTracingStack + || IsTracingBlockHash + || IsTracingAccess + || IsTracingFees + || IsTracingLogs; + + public string lastmemline; + + public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256 stateRoot = null) + { + } + + public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256 stateRoot = null) + { + } + + public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env) + { + } + + public void ReportOperationError(EvmExceptionType error) + { + } + + public void ReportOperationRemainingGas(long gas) + { + } + + public void ReportLog(LogEntry log) + { + } + + public void SetOperationStack(TraceStack stack) + { + } + + public void SetOperationMemory(TraceMemory memoryTrace) + { + lastmemline = string.Concat("0x", string.Join("", memoryTrace.ToHexWordList().Select(mt => mt.Replace("0x", string.Empty)))); + } + + public void SetOperationMemorySize(ulong newSize) + { + } + + public void ReportMemoryChange(long offset, in ReadOnlySpan data) + { + } + + public void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value) + { + } + + public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) + { + } + + public void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value) + { + } + + public void ReportSelfDestruct(Address address, UInt256 balance, Address refundAddress) + { + throw new NotSupportedException(); + } + + public void ReportBalanceChange(Address address, UInt256? before, UInt256? after) + { + throw new NotSupportedException(); + } + + public void ReportCodeChange(Address address, byte[] before, byte[] after) + { + throw new NotSupportedException(); + } + + public void ReportNonceChange(Address address, UInt256? before, UInt256? after) + { + throw new NotSupportedException(); + } + + public void ReportAccountRead(Address address) + { + throw new NotImplementedException(); + } + + public void ReportStorageChange(in StorageCell storageAddress, byte[] before, byte[] after) + { + throw new NotSupportedException(); + } + + public void ReportStorageRead(in StorageCell storageCell) + { + throw new NotImplementedException(); + } + + public void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false) + { + throw new NotSupportedException(); + } + + public void ReportActionEnd(long gas, ReadOnlyMemory output) + { + throw new NotSupportedException(); + } + + public void ReportActionError(EvmExceptionType exceptionType) + { + throw new NotSupportedException(); } + + public void ReportActionRevert(long gas, ReadOnlyMemory output) + { + throw new NotSupportedException(); + } + + public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) + { + throw new NotSupportedException(); + } + + public void ReportBlockHash(Hash256 blockHash) + { + throw new NotImplementedException(); + } + + public void ReportByteCode(ReadOnlyMemory byteCode) + { + throw new NotSupportedException(); + } + + public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) + { + } + + public void ReportRefundForVmTrace(long refund, long gasAvailable) + { + } + + public void ReportRefund(long refund) + { + } + + public void ReportExtraGasPressure(long extraGasPressure) + { + throw new NotImplementedException(); + } + + public void ReportAccess(IReadOnlySet
accessedAddresses, IReadOnlySet accessedStorageCells) + { + throw new NotImplementedException(); + } + + public void ReportStackPush(in ReadOnlySpan stackItem) + { + } + + public void ReportFees(UInt256 fees, UInt256 burntFees) + { + throw new NotImplementedException(); + } + + public void Dispose() { } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/DebugTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/DebugTracerTests.cs index 4a2a7140ee2..b2fd2017894 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/DebugTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/DebugTracerTests.cs @@ -67,7 +67,7 @@ public void Debugger_Halts_Execution_On_Breakpoint(string bytecodeHex) } - Assert.False(TestFailed); + Assert.That(TestFailed, Is.False); } [TestCase("0x5b601760005600")] @@ -119,7 +119,7 @@ public void Debugger_Halts_Execution_On_Breakpoint_If_Condition_Is_True(string b } } - Assert.False(TestFailed); + Assert.That(TestFailed, Is.False); } [TestCase("0x5b5b5b5b5b5b5b5b5b5b00")] @@ -251,7 +251,7 @@ public void Debugger_Can_Alter_Program_Counter(string bytecodeHex) // we check if bytecode execution failed var resultTraces = (tracer.InnerTracer as GethLikeTxMemoryTracer).BuildResult(); - Assert.IsFalse(resultTraces.Failed); + Assert.That(resultTraces.Failed, Is.False); } [TestCase("5b6017600160005700")] @@ -286,7 +286,7 @@ public void Debugger_Can_Alter_Data_Stack(string bytecodeHex) // we check if bytecode execution failed var resultTraces = (tracer.InnerTracer as GethLikeTxMemoryTracer).BuildResult(); - Assert.IsFalse(resultTraces.Failed); + Assert.That(resultTraces.Failed, Is.False); } [TestCase("6017806000526000511460005260206000f3")] @@ -319,7 +319,7 @@ public void Debugger_Can_Alter_Memory(string bytecodeHex) // we check if bytecode execution failed var resultTraces = (tracer.InnerTracer as GethLikeTxMemoryTracer).BuildResult(); - Assert.IsTrue(resultTraces.ReturnValue[31] == 0); + Assert.That(resultTraces.ReturnValue[31] == 0, Is.True); } [TestCase("6017806000526000511460005260206000f3")] @@ -386,7 +386,7 @@ public void Use_Debug_Tracer_To_Check_failure_status(string bytecodeHex) // we check if bytecode execution failed var resultTraces = (tracer.InnerTracer as GethLikeTxMemoryTracer).BuildResult(); - Assert.IsTrue(resultTraces.Failed); + Assert.That(resultTraces.Failed, Is.True); } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockMemoryTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockMemoryTracerTests.cs index d50b1756fa0..3809bd4bf84 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockMemoryTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockMemoryTracerTests.cs @@ -12,7 +12,6 @@ namespace Nethermind.Evm.Test.Tracing; -[TestFixture] public class GethLikeBlockMemoryTracerTests { [Test] @@ -20,7 +19,7 @@ public void Starts_with_trace_set_to_null() { Hash256 txHash = TestItem.KeccakA; GethLikeBlockMemoryTracer blockTracer = new(GethTraceOptions.Default with { TxHash = txHash }); - Assert.IsNull(blockTracer.BuildResult().SingleOrDefault(), $"starts with trace set to null"); + Assert.That(blockTracer.BuildResult().SingleOrDefault(), Is.Null, $"starts with trace set to null"); } [Test] @@ -56,9 +55,9 @@ public void Records_trace_properly() ((IBlockTracer)blockTracer).StartNewTxTrace(Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyC).TestObject); ((IBlockTracer)blockTracer).EndTxTrace(); - Assert.NotNull(blockTracer.BuildResult().First(), "0"); - Assert.NotNull(blockTracer.BuildResult().Skip(1).First(), "1"); - Assert.NotNull(blockTracer.BuildResult().Last(), "2"); + Assert.That(blockTracer.BuildResult().First(), Is.Not.Null, "0"); + Assert.That(blockTracer.BuildResult().Skip(1).First(), Is.Not.Null, "1"); + Assert.That(blockTracer.BuildResult().Last(), Is.Not.Null, "2"); } [Test] diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs index 3d84ab5a51d..8d3d7558be8 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeJavaScriptTracerTests.cs @@ -457,7 +457,7 @@ public void complex_tracer() MainnetSpecProvider.CancunActivation); GethLikeTxTrace traces = tracer.BuildResult().First(); - TestContext.WriteLine(GetEthereumJsonSerializer().Serialize(traces.CustomTracerResult)); + TestContext.Out.WriteLine(GetEthereumJsonSerializer().Serialize(traces.CustomTracerResult)); } [Test] @@ -469,7 +469,7 @@ public void complex_tracer_nested_call() MainnetSpecProvider.CancunActivation); GethLikeTxTrace traces = tracer.BuildResult().First(); - TestContext.WriteLine(GetEthereumJsonSerializer().Serialize(traces.CustomTracerResult)); + TestContext.Out.WriteLine(GetEthereumJsonSerializer().Serialize(traces.CustomTracerResult)); } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeNativeTracerFactoryTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeNativeTracerFactoryTests.cs index 10ecf070f0a..ed7a9faa399 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeNativeTracerFactoryTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeNativeTracerFactoryTests.cs @@ -7,7 +7,6 @@ using Nethermind.Evm.Tracing.GethStyle; using Nethermind.Evm.Tracing.GethStyle.Custom.Native; using Nethermind.Evm.Tracing.GethStyle.Custom.Native.FourByte; -using Nethermind.State; using NUnit.Framework; namespace Nethermind.Evm.Test.Tracing; @@ -24,7 +23,7 @@ public void CreateTracer_NativeTracerExists() GethLikeNativeTxTracer? nativeTracer = GethLikeNativeTracerFactory.CreateTracer(options, _block, _tx, null!); - Assert.True(nativeTracer is Native4ByteTracer); + Assert.That(nativeTracer is Native4ByteTracer, Is.True); } [Test] @@ -40,7 +39,7 @@ public void IsNativeTracer_TracerNameExists() { var isNativeTracer = GethLikeNativeTracerFactory.IsNativeTracer(Native4ByteTracer.FourByteTracer); - Assert.True(isNativeTracer); + Assert.That(isNativeTracer, Is.True); } [Test] @@ -48,7 +47,7 @@ public void IsNativeTracer_TracerNameDoesNotExist() { var isNativeTracer = GethLikeNativeTracerFactory.IsNativeTracer("nonExistentTracer"); - Assert.False(isNativeTracer); + Assert.That(isNativeTracer, Is.False); } [Test] @@ -56,7 +55,7 @@ public void CreateTracer_TracerNameIsEmpty() { var isNativeTracer = GethLikeNativeTracerFactory.IsNativeTracer(string.Empty); - Assert.False(isNativeTracer); + Assert.That(isNativeTracer, Is.False); } [Test] @@ -64,6 +63,6 @@ public void CreateTracer_TracerNameIsNull() { var isNativeTracer = GethLikeNativeTracerFactory.IsNativeTracer(null); - Assert.False(isNativeTracer); + Assert.That(isNativeTracer, Is.False); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs index a9a4e54b844..d60d54d02e7 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs @@ -15,836 +15,834 @@ using Nethermind.State; using NUnit.Framework; -namespace Nethermind.Evm.Test.Tracing +namespace Nethermind.Evm.Test.Tracing; + +public class ParityLikeTxTracerTests : VirtualMachineTestsBase { - [TestFixture] - public class ParityLikeTxTracerTests : VirtualMachineTestsBase + [Test] + public void On_failure_result_is_null() { - [Test] - public void On_failure_result_is_null() - { - byte[] code = Prepare.EvmCode - .Op(Instruction.ADD) - .Done; + byte[] code = Prepare.EvmCode + .Op(Instruction.ADD) + .Done; - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - Assert.IsNull(trace.Action.Result); - } + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.Result, Is.Null); + } - [Test] - public void On_failure_block_and_tx_fields_are_set() - { - byte[] code = Prepare.EvmCode - .Op(Instruction.ADD) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.From, Is.EqualTo(tx.SenderAddress), "from"); - Assert.That(trace.Action.To, Is.EqualTo(tx.To), "to"); - Assert.That(trace.BlockHash, Is.EqualTo(block.Hash), "hash"); - Assert.That(trace.BlockNumber, Is.EqualTo(block.Number), "number"); - Assert.That(trace.TransactionPosition, Is.EqualTo(0), "tx index"); - Assert.That(trace.TransactionHash, Is.EqualTo(tx.Hash), "tx hash"); - Assert.That(trace.Action.Gas, Is.EqualTo((long)tx.GasLimit - 21000), "gas"); - Assert.That(trace.Action.Value, Is.EqualTo(tx.Value), "value"); - Assert.That(trace.Action.Input, Is.EqualTo(tx.Data.AsArray()), "input"); - Assert.That(trace.Action.TraceAddress, Is.EqualTo(Array.Empty()), "trace address"); - } - - [Test] - public void Blockhash_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + [Test] + public void On_failure_block_and_tx_fields_are_set() + { + byte[] code = Prepare.EvmCode + .Op(Instruction.ADD) + .Done; + + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.From, Is.EqualTo(tx.SenderAddress), "from"); + Assert.That(trace.Action.To, Is.EqualTo(tx.To), "to"); + Assert.That(trace.BlockHash, Is.EqualTo(block.Hash), "hash"); + Assert.That(trace.BlockNumber, Is.EqualTo(block.Number), "number"); + Assert.That(trace.TransactionPosition, Is.EqualTo(0), "tx index"); + Assert.That(trace.TransactionHash, Is.EqualTo(tx.Hash), "tx hash"); + Assert.That(trace.Action.Gas, Is.EqualTo((long)tx.GasLimit - 21000), "gas"); + Assert.That(trace.Action.Value, Is.EqualTo(tx.Value), "value"); + Assert.That(trace.Action.Input, Is.EqualTo(tx.Data.AsArray()), "input"); + Assert.That(trace.Action.TraceAddress, Is.EqualTo(Array.Empty()), "trace address"); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.BlockHash, Is.EqualTo(block.Hash)); - } + [Test] + public void Blockhash_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - [Todo(Improve.TestCoverage, "Add scenario where tx index is not 0")] - public void Tx_index_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.BlockHash, Is.EqualTo(block.Hash)); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.TransactionPosition, Is.EqualTo(0)); - } + [Test] + [Todo(Improve.TestCoverage, "Add scenario where tx index is not 0")] + public void Tx_index_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Trace_address_is_valid_in_simple_cases() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.TransactionPosition, Is.EqualTo(0)); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.TraceAddress, Is.EqualTo(Array.Empty())); - } + [Test] + public void Trace_address_is_valid_in_simple_cases() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Tx_hash_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.TraceAddress, Is.EqualTo(Array.Empty())); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.TransactionHash, Is.EqualTo(tx.Hash)); - } + [Test] + public void Tx_hash_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Type_is_set_when_call() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.TransactionHash, Is.EqualTo(tx.Hash)); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.CallType, Is.EqualTo("call")); - } + [Test] + public void Type_is_set_when_call() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Type_is_set_when_init() - { - byte[] deployedCode = new byte[3]; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.CallType, Is.EqualTo("call")); + } - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; + [Test] + public void Type_is_set_when_init() + { + byte[] deployedCode = new byte[3]; - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteInitAndTraceParityCall(initCode); - Assert.That(trace.Action.CallType, Is.EqualTo("create")); - } + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; - [Test] - public void Action_gas_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteInitAndTraceParityCall(initCode); + Assert.That(trace.Action.CallType, Is.EqualTo("create")); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.Gas, Is.EqualTo(79000)); - } + [Test] + public void Action_gas_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Action_call_type_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.Gas, Is.EqualTo(79000)); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.CallType, Is.EqualTo("call")); - } + [Test] + public void Action_call_type_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Action_from_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.CallType, Is.EqualTo("call")); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.From, Is.EqualTo(Sender)); - } + [Test] + public void Action_from_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Action_to_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.From, Is.EqualTo(Sender)); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.To, Is.EqualTo(Recipient)); - } + [Test] + public void Action_to_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Action_input_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.To, Is.EqualTo(Recipient)); + } - byte[] input = Bytes.FromHexString(SampleHexData2); - UInt256 value = 1.Ether(); + [Test] + public void Action_input_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(input, value, code); - Assert.That(trace.Action.Input, Is.EqualTo(input)); - } + byte[] input = Bytes.FromHexString(SampleHexData2); + UInt256 value = 1.Ether(); - [Test] - public void Action_value_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(input, value, code); + Assert.That(trace.Action.Input, Is.EqualTo(input)); + } - byte[] input = Bytes.FromHexString(SampleHexData2); - UInt256 value = 1.Ether(); + [Test] + public void Action_value_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(input, value, code); - Assert.That(trace.Action.Value, Is.EqualTo(value)); - } + byte[] input = Bytes.FromHexString(SampleHexData2); + UInt256 value = 1.Ether(); - [Test] - public void Action_result_gas_is_set() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(input, value, code); + Assert.That(trace.Action.Value, Is.EqualTo(value)); + } - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.Result.GasUsed, Is.EqualTo(3)); - } + [Test] + public void Action_result_gas_is_set() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; - [Test] - public void Action_result_output_is_set() - { - byte[] code = Prepare.EvmCode - .StoreDataInMemory(0, SampleHexData1.PadLeft(64, '0')) - .PushData("0x20") - .PushData("0x0") - .Op(Instruction.RETURN) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.Result.Output, Is.EqualTo(Bytes.FromHexString(SampleHexData1.PadLeft(64, '0')))); - } - - [Test] - public void Can_trace_nested_calls() - { - byte[] deployedCode = new byte[3]; - - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; - - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressC, 50000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - int[] depths = new int[] - { - 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL - 3, 3, 3, 3, 3, 3, // CREATE - 2, // STOP - 1, // STOP - }; - - Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(1), "root subtraces"); - Assert.That(trace.Action.Subtraces[0].Subtraces.Count, Is.EqualTo(1), "[0] subtraces"); - Assert.That(trace.Action.Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0 }), "[0] address"); - Assert.That(trace.Action.Subtraces[0].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[0, 0] subtraces"); - Assert.That(trace.Action.Subtraces[0].Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0, 0 }), "[0, 0] address"); - } - - [Test] - public void Can_trace_delegate_calls() - { - byte[] deployedCode = new byte[3]; + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.Result.GasUsed, Is.EqualTo(3)); + } - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; + [Test] + public void Action_result_output_is_set() + { + byte[] code = Prepare.EvmCode + .StoreDataInMemory(0, SampleHexData1.PadLeft(64, '0')) + .PushData("0x20") + .PushData("0x0") + .Op(Instruction.RETURN) + .Done; + + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.Result.Output, Is.EqualTo(Bytes.FromHexString(SampleHexData1.PadLeft(64, '0')))); + } - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; + [Test] + public void Can_trace_nested_calls() + { + byte[] deployedCode = new byte[3]; + + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; + + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressC, 50000) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + int[] depths = new int[] + { + 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL + 3, 3, 3, 3, 3, 3, // CREATE + 2, // STOP + 1, // STOP + }; + + Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(1), "root subtraces"); + Assert.That(trace.Action.Subtraces[0].Subtraces.Count, Is.EqualTo(1), "[0] subtraces"); + Assert.That(trace.Action.Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0 }), "[0] address"); + Assert.That(trace.Action.Subtraces[0].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[0, 0] subtraces"); + Assert.That(trace.Action.Subtraces[0].Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0, 0 }), "[0, 0] address"); + } - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); + [Test] + public void Can_trace_delegate_calls() + { + byte[] deployedCode = new byte[3]; - byte[] code = Prepare.EvmCode - .DelegateCall(TestItem.AddressC, 50000) - .Op(Instruction.STOP) - .Done; + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - int[] depths = new int[] - { - 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL - 2, 2, 2, 2, 2, 2, 2, 2, 2, // DELEGATE CALL - 3, 3, 3, 3, 3, 3, // CREATE - 2, // STOP - 1, // STOP - }; + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; - Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("delegatecall"), "[0] type"); - } + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + byte[] code = Prepare.EvmCode + .DelegateCall(TestItem.AddressC, 50000) + .Op(Instruction.STOP) + .Done; - [Test] - public void Can_trace_call_code_calls() - { - byte[] deployedCode = new byte[3]; - - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; - - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .CallCode(TestItem.AddressC, 50000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - int[] depths = new int[] - { - 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL - 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL CODE - 3, 3, 3, 3, 3, 3, // CREATE - 2, // STOP - 1, // STOP - }; - - Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("callcode"), "[0] type"); - } - - [Test] - public void Can_trace_call_code_calls_with_large_data_offset() + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + int[] depths = new int[] { - byte[] deployedCode = new byte[3]; + 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL + 2, 2, 2, 2, 2, 2, 2, 2, 2, // DELEGATE CALL + 3, 3, 3, 3, 3, 3, // CREATE + 2, // STOP + 1, // STOP + }; - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; + Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("delegatecall"), "[0] type"); + } - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); + [Test] + public void Can_trace_call_code_calls() + { + byte[] deployedCode = new byte[3]; + + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; - byte[] code = Prepare.EvmCode - .CallCode(TestItem.AddressC, 50000, UInt256.MaxValue, ulong.MaxValue) - .Op(Instruction.STOP) - .Done; + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; - ParityLikeTxTrace trace = ExecuteAndTraceParityCall(code).trace; - trace.Action!.Error.Should().BeNullOrEmpty(); + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); - } + byte[] code = Prepare.EvmCode + .CallCode(TestItem.AddressC, 50000) + .Op(Instruction.STOP) + .Done; - [Test] - public void Can_trace_a_failing_static_call() + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + int[] depths = new int[] { - byte[] deployedCode = new byte[3]; + 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL + 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL CODE + 3, 3, 3, 3, 3, 3, // CREATE + 2, // STOP + 1, // STOP + }; - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; + Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("callcode"), "[0] type"); + } - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; + [Test] + public void Can_trace_call_code_calls_with_large_data_offset() + { + byte[] deployedCode = new byte[3]; - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; - byte[] code = Prepare.EvmCode - .CallWithValue(TestItem.AddressC, 50000, 1000000.Ether()) - .Done; + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); - Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(0), "subtraces count"); - Assert.That(trace.VmTrace.Operations.Last().Cost, Is.EqualTo(59700)); - Assert.That(trace.VmTrace.Operations.Last().Used, Is.EqualTo(71579)); - } + byte[] code = Prepare.EvmCode + .CallCode(TestItem.AddressC, 50000, UInt256.MaxValue, ulong.MaxValue) + .Op(Instruction.STOP) + .Done; - [Test] - public void Can_trace_memory_in_vm_trace() - { - string dataHex = "0x0102"; - string offsetHex = "0x01"; - - byte[] code = Prepare.EvmCode - .PushData(dataHex) - .PushData(offsetHex) - .Op(Instruction.MSTORE) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - ParityMemoryChangeTrace memory = trace.VmTrace.Operations[2].Memory; - Assert.That(memory.Data.WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(dataHex)); - Assert.That(memory.Offset, Is.EqualTo(1)); - } - - [Test] - public void Action_is_cleared_when_vm_trace_only() - { - byte[] code = Prepare.EvmCode - .Op(Instruction.STOP) - .Done; + ParityLikeTxTrace trace = ExecuteAndTraceParityCall(code).trace; + trace.Action!.Error.Should().BeNullOrEmpty(); - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(ParityTraceTypes.VmTrace, code); - Assert.Null(trace.Action); - } + } - [Test] - public void Can_trace_push_in_vm_trace() - { - string push1Hex = "0x01"; - string push2Hex = "0x0102"; - - byte[] code = Prepare.EvmCode - .PushData(push1Hex) - .PushData(push2Hex) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - byte[][] push1 = trace.VmTrace.Operations[0].Push; - byte[][] push2 = trace.VmTrace.Operations[1].Push; - Assert.That(push1[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); - Assert.That(push2[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); - } - - [Test] - public void Can_trace_dup_push_in_vm_trace() - { - string push1Hex = "0x01"; - string push2Hex = "0x0102"; - - byte[] code = Prepare.EvmCode - .PushData(push1Hex) - .PushData(push2Hex) - .Op(Instruction.DUP2) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - byte[][] dup = trace.VmTrace.Operations[2].Push; - Assert.That(dup[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); - Assert.That(dup[1].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); - } - - [Test] - public void Can_trace_swap_push_in_vm_trace() - { - string push1Hex = "0x01"; - string push2Hex = "0x0102"; - - byte[] code = Prepare.EvmCode - .PushData(push1Hex) - .PushData(push2Hex) - .Op(Instruction.SWAP1) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - byte[][] swap = trace.VmTrace.Operations[2].Push; - Assert.That(swap[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); - Assert.That(swap[1].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); - } - - [Test] - public void Can_trace_sstore_in_vm_trace() - { - string push1Hex = "0x01"; - string push2Hex = "0x0102"; - - byte[] code = Prepare.EvmCode - .PushData(push1Hex) - .PushData(push2Hex) - .Op(Instruction.SSTORE) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - ParityStorageChangeTrace sstore = trace.VmTrace.Operations[2].Store; - Assert.That(sstore.Key.WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); - Assert.That(sstore.Value.WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); - } - - [Test] - public void Can_trace_double_sstore() - { - string push1Hex = "0x01"; - string push2Hex = "0x0102"; - string push3Hex = "0x010203"; - - byte[] code = Prepare.EvmCode - .PushData(push2Hex) - .PushData(push1Hex) - .Op(Instruction.SSTORE) - .PushData(push3Hex) - .PushData(push1Hex) - .Op(Instruction.SSTORE) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - Assert.That(trace.StateChanges[TestItem.AddressB].Storage.Count, Is.EqualTo(1)); - } - - [Test] - public void Can_trace_self_destruct() - { - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.SELFDESTRUCT) - .Done; + [Test] + public void Can_trace_a_failing_static_call() + { + byte[] deployedCode = new byte[3]; - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - Assert.That(trace.Action.Subtraces[0].Type, Is.EqualTo("suicide")); - } + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; - [Test] - public void Can_trace_failed_action() - { - string push1Hex = "0x01"; - string push2Hex = "0x0102"; - - byte[] code = Prepare.EvmCode - .PushData(push1Hex) - .PushData(push2Hex) - .Done; - - UInt256 value = 2.Ether(); - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code, value); - Assert.Null(trace.VmTrace); - Assert.That(trace.Action.Value, Is.EqualTo(value)); - } - - [Test] - public void Can_trace_static_calls() - { - byte[] deployedCode = new byte[3]; - - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; - - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .StaticCall(TestItem.AddressC, 50000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - int[] depths = new int[] - { - 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL - 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL CODE - 3, 3, 3, 3, 3, 3, // CREATE - 2, // STOP - 1, // STOP - }; - - Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("staticcall"), "[0] type"); - } - - [Test] - public void Can_trace_precompile_calls() - { - byte[] code = Prepare.EvmCode - .Call(IdentityPrecompile.Address, 50000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - int[] depths = new int[] - { - 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL - 2, // STOP - 1, // STOP - }; - - Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(0), "Should ignore precompile"); - } - - [Test] - public void Can_ignore_precompile_calls_in_contract() - { - byte[] deployedCode = Prepare.EvmCode - .Call(IdentityPrecompile.Address, 50000) - .CallWithValue(IdentityPrecompile.Address, 50000, 1.Ether()) - .Op(Instruction.STOP) - .Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, deployedCode, Spec); - - byte[] code = Prepare.EvmCode - .Call(IdentityPrecompile.Address, 50000) - .Call(TestItem.AddressC, 40000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - - // call to AddressC and should ignore precompile - Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(1), "[] subtraces"); - Assert.That(trace.Action.CallType, Is.EqualTo("call"), "[] type"); - - // AddressC call - only one call - Assert.That(trace.Action.Subtraces[0].Subtraces.Count, Is.EqualTo(1), "[1] subtraces"); - Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("call"), "[1] type"); - - // Check the 2nd subtrace - a precompile call with value - must be included - Assert.That(trace.Action.Subtraces[0].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[1, 1] subtraces"); - Assert.That(trace.Action.Subtraces[0].Subtraces[0].CallType, Is.EqualTo("call"), "[1, 1] type"); - Assert.That(trace.Action.Subtraces[0].Subtraces[0].IncludeInTrace, Is.EqualTo(true), "[1, 1] type"); - } - - [Test] - public void Can_trace_same_level_calls() - { - byte[] deployedCode = new byte[3]; - - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; - - byte[] createCode = Prepare.EvmCode - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .Call(TestItem.AddressC, 40000) - .Call(TestItem.AddressC, 40000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); - int[] depths = new int[] - { - 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL - 3, 3, 3, 3, 3, 3, // CREATE - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL - 3, 3, 3, 3, 3, 3, // CREATE - 2, // STOP - 1, // STOP - }; - - Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(2), "[] subtraces"); - Assert.That(trace.Action.CallType, Is.EqualTo("call"), "[] type"); - - Assert.That(trace.Action.Subtraces[0].Subtraces.Count, Is.EqualTo(1), "[0] subtraces"); - Assert.That(trace.Action.Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0 }), "[0] address"); - Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("call"), "[0] type"); - - Assert.That(trace.Action.Subtraces[1].Subtraces.Count, Is.EqualTo(1), "[1] subtraces"); - Assert.That(trace.Action.Subtraces[1].TraceAddress, Is.EqualTo(new[] { 1 }), "[1] address"); - Assert.That(trace.Action.Subtraces[1].CallType, Is.EqualTo("call"), "[1] type"); - - Assert.That(trace.Action.Subtraces[0].Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0, 0 }), "[0, 0] address"); - Assert.That(trace.Action.Subtraces[0].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[0, 0] subtraces"); - Assert.That(trace.Action.Subtraces[1].Subtraces[0].CallType, Is.EqualTo("create"), "[0, 0] type"); - - Assert.That(trace.Action.Subtraces[1].Subtraces[0].TraceAddress, Is.EqualTo(new[] { 1, 0 }), "[1, 0] address"); - Assert.That(trace.Action.Subtraces[1].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[1, 0] subtraces"); - Assert.That(trace.Action.Subtraces[1].Subtraces[0].CallType, Is.EqualTo("create"), "[1, 0] type"); - } - - [Test] - public void Can_trace_storage_changes() - { - byte[] deployedCode = new byte[3]; - - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; - - byte[] createCode = Prepare.EvmCode - .PersistData("0x1", HexZero) // just to test if storage is restored - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .PersistData("0x2", SampleHexData1) - .PersistData("0x3", SampleHexData2) - .Call(TestItem.AddressC, 70000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - - Assert.That(trace.StateChanges.Count, Is.EqualTo(5), "state changes count"); - Assert.True(trace.StateChanges.ContainsKey(Sender), "sender"); - Assert.True(trace.StateChanges.ContainsKey(Recipient), "recipient"); - Assert.True(trace.StateChanges.ContainsKey(TestItem.AddressC), "address c"); - Assert.That(trace.StateChanges[Recipient].Storage.Count, Is.EqualTo(2), "recipient storage count"); - Assert.That(trace.StateChanges[Recipient].Storage[2].Before, Is.EqualTo(new byte[] { 0 }), "recipient storage[2]"); - Assert.That(trace.StateChanges[Recipient].Storage[2].After, Is.EqualTo(Bytes.FromHexString(SampleHexData1)), "recipient storage[2] after"); - Assert.That(trace.StateChanges[Recipient].Storage[3].Before, Is.EqualTo(new byte[] { 0 }), "recipient storage[3]"); - Assert.That(trace.StateChanges[Recipient].Storage[3].After, Is.EqualTo(Bytes.FromHexString(SampleHexData2)), "recipient storage[3] after"); - } - - [Test] - public void Can_trace_code_changes() - { - byte[] deployedCode = new byte[3]; - - byte[] initCode = Prepare.EvmCode - .ForInitOf(deployedCode) - .Done; - - byte[] createCode = Prepare.EvmCode - .PersistData("0x1", HexZero) // just to test if storage is restored - .Create(initCode, 0) - .Op(Instruction.STOP) - .Done; - - TestState.CreateAccount(TestItem.AddressC, 1.Ether()); - TestState.InsertCode(TestItem.AddressC, createCode, Spec); - - byte[] code = Prepare.EvmCode - .PersistData("0x2", SampleHexData1) - .PersistData("0x3", SampleHexData2) - .Call(TestItem.AddressC, 70000) - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - - Assert.That(trace.StateChanges.Count, Is.EqualTo(5), "state changes count"); - Assert.True(trace.StateChanges.ContainsKey(TestItem.AddressC), "call target"); - Assert.True(trace.StateChanges.ContainsKey(Sender), "sender"); - Assert.True(trace.StateChanges.ContainsKey(Recipient), "recipient"); - Assert.True(trace.StateChanges.ContainsKey(Miner), "miner"); - Assert.That(trace.StateChanges[Contract].Code.Before, Is.EqualTo(null), "code before"); - Assert.That(trace.StateChanges[Contract].Code.After, Is.EqualTo(deployedCode), "code after"); - } - - [Test] - public void Can_trace_balance_changes() - { - byte[] code = Prepare.EvmCode - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, _, Transaction tx) = ExecuteAndTraceParityCall(code); - - Assert.That(trace.StateChanges.Count, Is.EqualTo(3), "state changes count"); - Assert.True(trace.StateChanges.ContainsKey(Recipient), "recipient"); - Assert.True(trace.StateChanges.ContainsKey(Sender), "sender"); - Assert.True(trace.StateChanges.ContainsKey(Miner), "miner"); - Assert.That(trace.StateChanges[Sender].Balance.Before, Is.EqualTo(100.Ether()), "sender before"); - Assert.That(trace.StateChanges[Sender].Balance.After, Is.EqualTo(100.Ether() - 21001), "sender after"); - Assert.That(trace.StateChanges[Recipient].Balance.Before, Is.EqualTo(100.Ether()), "recipient before"); - Assert.That(trace.StateChanges[Recipient].Balance.After, Is.EqualTo(100.Ether() + 1), "recipient after"); - Assert.That(trace.StateChanges[Miner].Balance.Before, Is.EqualTo(null), "miner before"); - Assert.That(trace.StateChanges[Miner].Balance.After, Is.EqualTo((UInt256)21000), "miner after"); - } - - [Test] - public void Can_trace_nonce_changes() - { - byte[] code = Prepare.EvmCode - .Op(Instruction.STOP) - .Done; - - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - - Assert.That(trace.StateChanges.Count, Is.EqualTo(3), "state changes count"); - Assert.True(trace.StateChanges.ContainsKey(Sender), "sender"); - Assert.True(trace.StateChanges.ContainsKey(Recipient), "recipient"); - Assert.True(trace.StateChanges.ContainsKey(Miner), "miner"); - Assert.That(trace.StateChanges[Sender].Nonce.Before, Is.EqualTo(UInt256.Zero), "sender before"); - Assert.That(trace.StateChanges[Sender].Nonce.After, Is.EqualTo(UInt256.One), "sender after"); - } - - [Test] - public void Cannot_mark_as_failed_when_actions_stacked() - { - ParityLikeTxTracer tracer = new(Build.A.Block.TestObject, Build.A.Transaction.TestObject, ParityTraceTypes.All); - tracer.ReportAction(1000L, 10, Address.Zero, Address.Zero, Array.Empty(), ExecutionType.CALL, false); - Assert.Throws(() => tracer.MarkAsFailed(TestItem.AddressA, 21000, Array.Empty(), "Error")); - } + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; - [Test] - public void Cannot_mark_as_success_when_actions_stacked() - { - ParityLikeTxTracer tracer = new(Build.A.Block.TestObject, Build.A.Transaction.TestObject, ParityTraceTypes.All); - tracer.ReportAction(1000L, 10, Address.Zero, Address.Zero, Array.Empty(), ExecutionType.CALL, false); - Assert.Throws(() => tracer.MarkAsSuccess(TestItem.AddressA, 21000, Array.Empty(), new LogEntry[] { })); - } + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); - [Test] - public void Is_tracing_rewards_only_when_rewards_trace_type_selected() - { - ParityLikeBlockTracer tracer = new(ParityTraceTypes.All ^ ParityTraceTypes.Rewards); - Assert.False(tracer.IsTracingRewards); + byte[] code = Prepare.EvmCode + .CallWithValue(TestItem.AddressC, 50000, 1000000.Ether()) + .Done; - ParityLikeBlockTracer tracer2 = new(ParityTraceTypes.Rewards); - Assert.True(tracer2.IsTracingRewards); - } + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); - private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteInitAndTraceParityCall(params byte[] code) - { - (Block block, Transaction transaction) = PrepareInitTx((BlockNumber, Timestamp), 100000, code); - ParityLikeTxTracer tracer = new(block, transaction, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); - _processor.Execute(transaction, block.Header, tracer); - return (tracer.BuildResult(), block, transaction); - } + Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(0), "subtraces count"); + Assert.That(trace.VmTrace.Operations.Last().Cost, Is.EqualTo(59700)); + Assert.That(trace.VmTrace.Operations.Last().Used, Is.EqualTo(71579)); + } - private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteAndTraceParityCall(params byte[] code) - { - (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code); - ParityLikeTxTracer tracer = new(block, transaction, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff | ParityTraceTypes.VmTrace); - _processor.Execute(transaction, block.Header, tracer); - return (tracer.BuildResult(), block, transaction); - } + [Test] + public void Can_trace_memory_in_vm_trace() + { + string dataHex = "0x0102"; + string offsetHex = "0x01"; + + byte[] code = Prepare.EvmCode + .PushData(dataHex) + .PushData(offsetHex) + .Op(Instruction.MSTORE) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + ParityMemoryChangeTrace memory = trace.VmTrace.Operations[2].Memory; + Assert.That(memory.Data.WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(dataHex)); + Assert.That(memory.Offset, Is.EqualTo(1)); + } + + [Test] + public void Action_is_cleared_when_vm_trace_only() + { + byte[] code = Prepare.EvmCode + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(ParityTraceTypes.VmTrace, code); + Assert.That(trace.Action, Is.Null); + } + + [Test] + public void Can_trace_push_in_vm_trace() + { + string push1Hex = "0x01"; + string push2Hex = "0x0102"; + + byte[] code = Prepare.EvmCode + .PushData(push1Hex) + .PushData(push2Hex) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + byte[][] push1 = trace.VmTrace.Operations[0].Push; + byte[][] push2 = trace.VmTrace.Operations[1].Push; + Assert.That(push1[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); + Assert.That(push2[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); + } - private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteAndTraceParityCall(ParityTraceTypes traceTypes, params byte[] code) + [Test] + public void Can_trace_dup_push_in_vm_trace() + { + string push1Hex = "0x01"; + string push2Hex = "0x0102"; + + byte[] code = Prepare.EvmCode + .PushData(push1Hex) + .PushData(push2Hex) + .Op(Instruction.DUP2) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + byte[][] dup = trace.VmTrace.Operations[2].Push; + Assert.That(dup[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); + Assert.That(dup[1].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); + } + + [Test] + public void Can_trace_swap_push_in_vm_trace() + { + string push1Hex = "0x01"; + string push2Hex = "0x0102"; + + byte[] code = Prepare.EvmCode + .PushData(push1Hex) + .PushData(push2Hex) + .Op(Instruction.SWAP1) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + byte[][] swap = trace.VmTrace.Operations[2].Push; + Assert.That(swap[0].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); + Assert.That(swap[1].WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); + } + + [Test] + public void Can_trace_sstore_in_vm_trace() + { + string push1Hex = "0x01"; + string push2Hex = "0x0102"; + + byte[] code = Prepare.EvmCode + .PushData(push1Hex) + .PushData(push2Hex) + .Op(Instruction.SSTORE) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + ParityStorageChangeTrace sstore = trace.VmTrace.Operations[2].Store; + Assert.That(sstore.Key.WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push2Hex)); + Assert.That(sstore.Value.WithoutLeadingZeros().ToArray().ToHexString(true), Is.EqualTo(push1Hex)); + } + + [Test] + public void Can_trace_double_sstore() + { + string push1Hex = "0x01"; + string push2Hex = "0x0102"; + string push3Hex = "0x010203"; + + byte[] code = Prepare.EvmCode + .PushData(push2Hex) + .PushData(push1Hex) + .Op(Instruction.SSTORE) + .PushData(push3Hex) + .PushData(push1Hex) + .Op(Instruction.SSTORE) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + Assert.That(trace.StateChanges[TestItem.AddressB].Storage.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_trace_self_destruct() + { + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.SELFDESTRUCT) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + Assert.That(trace.Action.Subtraces[0].Type, Is.EqualTo("suicide")); + } + + [Test] + public void Can_trace_failed_action() + { + string push1Hex = "0x01"; + string push2Hex = "0x0102"; + + byte[] code = Prepare.EvmCode + .PushData(push1Hex) + .PushData(push2Hex) + .Done; + + UInt256 value = 2.Ether(); + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code, value); + Assert.That(trace.VmTrace, Is.Null); + Assert.That(trace.Action.Value, Is.EqualTo(value)); + } + + [Test] + public void Can_trace_static_calls() + { + byte[] deployedCode = new byte[3]; + + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; + + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + + byte[] code = Prepare.EvmCode + .StaticCall(TestItem.AddressC, 50000) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + int[] depths = new int[] { - (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code); - ParityLikeTxTracer tracer = new(block, transaction, traceTypes); - _processor.Execute(transaction, block.Header, tracer); - return (tracer.BuildResult(), block, transaction); - } + 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL + 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL CODE + 3, 3, 3, 3, 3, 3, // CREATE + 2, // STOP + 1, // STOP + }; - private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteAndTraceParityCall(byte[] input, UInt256 value, params byte[] code) + Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("staticcall"), "[0] type"); + } + + [Test] + public void Can_trace_precompile_calls() + { + byte[] code = Prepare.EvmCode + .Call(IdentityPrecompile.Address, 50000) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + int[] depths = new int[] { - (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code, input, value); - ParityLikeTxTracer tracer = new(block, transaction, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); - TransactionResult result = _processor.Execute(transaction, block.Header, tracer); - return (tracer.BuildResult(), block, transaction); - } + 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL + 2, // STOP + 1, // STOP + }; + + Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(0), "Should ignore precompile"); + } + + [Test] + public void Can_ignore_precompile_calls_in_contract() + { + byte[] deployedCode = Prepare.EvmCode + .Call(IdentityPrecompile.Address, 50000) + .CallWithValue(IdentityPrecompile.Address, 50000, 1.Ether()) + .Op(Instruction.STOP) + .Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, deployedCode, Spec); + + byte[] code = Prepare.EvmCode + .Call(IdentityPrecompile.Address, 50000) + .Call(TestItem.AddressC, 40000) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + + // call to AddressC and should ignore precompile + Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(1), "[] subtraces"); + Assert.That(trace.Action.CallType, Is.EqualTo("call"), "[] type"); + + // AddressC call - only one call + Assert.That(trace.Action.Subtraces[0].Subtraces.Count, Is.EqualTo(1), "[1] subtraces"); + Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("call"), "[1] type"); + + // Check the 2nd subtrace - a precompile call with value - must be included + Assert.That(trace.Action.Subtraces[0].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[1, 1] subtraces"); + Assert.That(trace.Action.Subtraces[0].Subtraces[0].CallType, Is.EqualTo("call"), "[1, 1] type"); + Assert.That(trace.Action.Subtraces[0].Subtraces[0].IncludeInTrace, Is.EqualTo(true), "[1, 1] type"); + } + + [Test] + public void Can_trace_same_level_calls() + { + byte[] deployedCode = new byte[3]; + + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; + + byte[] createCode = Prepare.EvmCode + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + + byte[] code = Prepare.EvmCode + .Call(TestItem.AddressC, 40000) + .Call(TestItem.AddressC, 40000) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(code); + int[] depths = new int[] + { + 1, 1, 1, 1, 1, 1, 1, 1, // STACK FOR CALL + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL + 3, 3, 3, 3, 3, 3, // CREATE + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // CALL + 3, 3, 3, 3, 3, 3, // CREATE + 2, // STOP + 1, // STOP + }; + + Assert.That(trace.Action.Subtraces.Count, Is.EqualTo(2), "[] subtraces"); + Assert.That(trace.Action.CallType, Is.EqualTo("call"), "[] type"); + + Assert.That(trace.Action.Subtraces[0].Subtraces.Count, Is.EqualTo(1), "[0] subtraces"); + Assert.That(trace.Action.Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0 }), "[0] address"); + Assert.That(trace.Action.Subtraces[0].CallType, Is.EqualTo("call"), "[0] type"); + + Assert.That(trace.Action.Subtraces[1].Subtraces.Count, Is.EqualTo(1), "[1] subtraces"); + Assert.That(trace.Action.Subtraces[1].TraceAddress, Is.EqualTo(new[] { 1 }), "[1] address"); + Assert.That(trace.Action.Subtraces[1].CallType, Is.EqualTo("call"), "[1] type"); + + Assert.That(trace.Action.Subtraces[0].Subtraces[0].TraceAddress, Is.EqualTo(new[] { 0, 0 }), "[0, 0] address"); + Assert.That(trace.Action.Subtraces[0].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[0, 0] subtraces"); + Assert.That(trace.Action.Subtraces[1].Subtraces[0].CallType, Is.EqualTo("create"), "[0, 0] type"); + + Assert.That(trace.Action.Subtraces[1].Subtraces[0].TraceAddress, Is.EqualTo(new[] { 1, 0 }), "[1, 0] address"); + Assert.That(trace.Action.Subtraces[1].Subtraces[0].Subtraces.Count, Is.EqualTo(0), "[1, 0] subtraces"); + Assert.That(trace.Action.Subtraces[1].Subtraces[0].CallType, Is.EqualTo("create"), "[1, 0] type"); + } + + [Test] + public void Can_trace_storage_changes() + { + byte[] deployedCode = new byte[3]; + + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; + + byte[] createCode = Prepare.EvmCode + .PersistData("0x1", HexZero) // just to test if storage is restored + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + + byte[] code = Prepare.EvmCode + .PersistData("0x2", SampleHexData1) + .PersistData("0x3", SampleHexData2) + .Call(TestItem.AddressC, 70000) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + + Assert.That(trace.StateChanges.Count, Is.EqualTo(5), "state changes count"); + Assert.That(trace.StateChanges.ContainsKey(Sender), Is.True, "sender"); + Assert.That(trace.StateChanges.ContainsKey(Recipient), Is.True, "recipient"); + Assert.That(trace.StateChanges.ContainsKey(TestItem.AddressC), Is.True, "address c"); + Assert.That(trace.StateChanges[Recipient].Storage.Count, Is.EqualTo(2), "recipient storage count"); + Assert.That(trace.StateChanges[Recipient].Storage[2].Before, Is.EqualTo(new byte[] { 0 }), "recipient storage[2]"); + Assert.That(trace.StateChanges[Recipient].Storage[2].After, Is.EqualTo(Bytes.FromHexString(SampleHexData1)), "recipient storage[2] after"); + Assert.That(trace.StateChanges[Recipient].Storage[3].Before, Is.EqualTo(new byte[] { 0 }), "recipient storage[3]"); + Assert.That(trace.StateChanges[Recipient].Storage[3].After, Is.EqualTo(Bytes.FromHexString(SampleHexData2)), "recipient storage[3] after"); + } + + [Test] + public void Can_trace_code_changes() + { + byte[] deployedCode = new byte[3]; + + byte[] initCode = Prepare.EvmCode + .ForInitOf(deployedCode) + .Done; + + byte[] createCode = Prepare.EvmCode + .PersistData("0x1", HexZero) // just to test if storage is restored + .Create(initCode, 0) + .Op(Instruction.STOP) + .Done; + + TestState.CreateAccount(TestItem.AddressC, 1.Ether()); + TestState.InsertCode(TestItem.AddressC, createCode, Spec); + + byte[] code = Prepare.EvmCode + .PersistData("0x2", SampleHexData1) + .PersistData("0x3", SampleHexData2) + .Call(TestItem.AddressC, 70000) + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + + Assert.That(trace.StateChanges.Count, Is.EqualTo(5), "state changes count"); + Assert.That(trace.StateChanges.ContainsKey(TestItem.AddressC), Is.True, "call target"); + Assert.That(trace.StateChanges.ContainsKey(Sender), Is.True, "sender"); + Assert.That(trace.StateChanges.ContainsKey(Recipient), Is.True, "recipient"); + Assert.That(trace.StateChanges.ContainsKey(Miner), Is.True, "miner"); + Assert.That(trace.StateChanges[Contract].Code.Before, Is.EqualTo(null), "code before"); + Assert.That(trace.StateChanges[Contract].Code.After, Is.EqualTo(deployedCode), "code after"); + } + + [Test] + public void Can_trace_balance_changes() + { + byte[] code = Prepare.EvmCode + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, _, Transaction tx) = ExecuteAndTraceParityCall(code); + + Assert.That(trace.StateChanges.Count, Is.EqualTo(3), "state changes count"); + Assert.That(trace.StateChanges.ContainsKey(Recipient), Is.True, "recipient"); + Assert.That(trace.StateChanges.ContainsKey(Sender), Is.True, "sender"); + Assert.That(trace.StateChanges.ContainsKey(Miner), Is.True, "miner"); + Assert.That(trace.StateChanges[Sender].Balance.Before, Is.EqualTo(100.Ether()), "sender before"); + Assert.That(trace.StateChanges[Sender].Balance.After, Is.EqualTo(100.Ether() - 21001), "sender after"); + Assert.That(trace.StateChanges[Recipient].Balance.Before, Is.EqualTo(100.Ether()), "recipient before"); + Assert.That(trace.StateChanges[Recipient].Balance.After, Is.EqualTo(100.Ether() + 1), "recipient after"); + Assert.That(trace.StateChanges[Miner].Balance.Before, Is.EqualTo(null), "miner before"); + Assert.That(trace.StateChanges[Miner].Balance.After, Is.EqualTo((UInt256)21000), "miner after"); + } + + [Test] + public void Can_trace_nonce_changes() + { + byte[] code = Prepare.EvmCode + .Op(Instruction.STOP) + .Done; + + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code); + + Assert.That(trace.StateChanges.Count, Is.EqualTo(3), "state changes count"); + Assert.That(trace.StateChanges.ContainsKey(Sender), Is.True, "sender"); + Assert.That(trace.StateChanges.ContainsKey(Recipient), Is.True, "recipient"); + Assert.That(trace.StateChanges.ContainsKey(Miner), Is.True, "miner"); + Assert.That(trace.StateChanges[Sender].Nonce.Before, Is.EqualTo(UInt256.Zero), "sender before"); + Assert.That(trace.StateChanges[Sender].Nonce.After, Is.EqualTo(UInt256.One), "sender after"); + } + + [Test] + public void Cannot_mark_as_failed_when_actions_stacked() + { + ParityLikeTxTracer tracer = new(Build.A.Block.TestObject, Build.A.Transaction.TestObject, ParityTraceTypes.All); + tracer.ReportAction(1000L, 10, Address.Zero, Address.Zero, Array.Empty(), ExecutionType.CALL, false); + Assert.Throws(() => tracer.MarkAsFailed(TestItem.AddressA, 21000, Array.Empty(), "Error")); + } + + [Test] + public void Cannot_mark_as_success_when_actions_stacked() + { + ParityLikeTxTracer tracer = new(Build.A.Block.TestObject, Build.A.Transaction.TestObject, ParityTraceTypes.All); + tracer.ReportAction(1000L, 10, Address.Zero, Address.Zero, Array.Empty(), ExecutionType.CALL, false); + Assert.Throws(() => tracer.MarkAsSuccess(TestItem.AddressA, 21000, Array.Empty(), new LogEntry[] { })); + } + + [Test] + public void Is_tracing_rewards_only_when_rewards_trace_type_selected() + { + ParityLikeBlockTracer tracer = new(ParityTraceTypes.All ^ ParityTraceTypes.Rewards); + Assert.That(tracer.IsTracingRewards, Is.False); + + ParityLikeBlockTracer tracer2 = new(ParityTraceTypes.Rewards); + Assert.That(tracer2.IsTracingRewards, Is.True); + } + + private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteInitAndTraceParityCall(params byte[] code) + { + (Block block, Transaction transaction) = PrepareInitTx((BlockNumber, Timestamp), 100000, code); + ParityLikeTxTracer tracer = new(block, transaction, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); + _processor.Execute(transaction, block.Header, tracer); + return (tracer.BuildResult(), block, transaction); + } + + private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteAndTraceParityCall(params byte[] code) + { + (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code); + ParityLikeTxTracer tracer = new(block, transaction, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff | ParityTraceTypes.VmTrace); + _processor.Execute(transaction, block.Header, tracer); + return (tracer.BuildResult(), block, transaction); + } + + private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteAndTraceParityCall(ParityTraceTypes traceTypes, params byte[] code) + { + (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code); + ParityLikeTxTracer tracer = new(block, transaction, traceTypes); + _processor.Execute(transaction, block.Header, tracer); + return (tracer.BuildResult(), block, transaction); + } + + private (ParityLikeTxTrace trace, Block block, Transaction tx) ExecuteAndTraceParityCall(byte[] input, UInt256 value, params byte[] code) + { + (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code, input, value); + ParityLikeTxTracer tracer = new(block, transaction, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); + TransactionResult result = _processor.Execute(transaction, block.Header, tracer); + return (tracer.BuildResult(), block, transaction); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs index 53201b141c4..77101430fce 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs @@ -7,284 +7,282 @@ using Nethermind.Evm.Tracing.Proofs; using NUnit.Framework; -namespace Nethermind.Evm.Test.Tracing +namespace Nethermind.Evm.Test.Tracing; + +[TestFixture(true)] +[TestFixture(false)] +[Parallelizable(ParallelScope.Self)] +public class ProofTxTracerTests : VirtualMachineTestsBase { - [TestFixture(true)] - [TestFixture(false)] - [Parallelizable(ParallelScope.Self)] - public class ProofTxTracerTests : VirtualMachineTestsBase + private readonly bool _treatSystemAccountDifferently; + + public ProofTxTracerTests(bool treatSystemAccountDifferently) + { + _treatSystemAccountDifferently = treatSystemAccountDifferently; + } + + [Test] + public void Can_trace_sender_recipient_miner() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Accounts.Count, Is.EqualTo(3), "count"); + Assert.That(trace.Accounts.Contains(Sender), Is.True); + Assert.That(trace.Accounts.Contains(Recipient), Is.True); + Assert.That(trace.Accounts.Contains(Miner), Is.True); + } + + [Test] + public void Can_trace_sender_recipient_miner_when_miner_and_sender_are_same() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; + + SenderRecipientAndMiner addresses = new(); + addresses.MinerKey = SenderKey; + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(addresses, code); + Assert.That(trace.Accounts.Count, Is.EqualTo(2), "count"); + Assert.That(trace.Accounts.Contains(Sender), Is.True); + } + + [Test] + public void Can_trace_sender_recipient_miner_when_miner_and_recipient_are_same() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .Done; + + SenderRecipientAndMiner addresses = new(); + addresses.MinerKey = addresses.RecipientKey; + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(addresses, code); + Assert.That(trace.Accounts.Count, Is.EqualTo(2), "count"); + Assert.That(trace.Accounts.Contains(Sender), Is.True); + } + + [Test] + public void Can_trace_touch_only_null_accounts() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .PushData(TestItem.AddressC.Bytes) + .Op(Instruction.BALANCE) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Accounts.Count, Is.EqualTo(4), "count"); + Assert.That(trace.Accounts.Contains(TestItem.AddressC), Is.True); + } + + [Test] + public void Can_trace_touch_only_preexisting_accounts() + { + TestState.CreateAccount(TestItem.AddressC, 100); + TestState.Commit(Spec); + + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .PushData(TestItem.AddressC.Bytes) + .Op(Instruction.BALANCE) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Accounts.Count, Is.EqualTo(4), "count"); + Assert.That(trace.Accounts.Contains(TestItem.AddressC), Is.True); + } + + [Test] + public void Can_trace_touch_only_null_miner_accounts() + { + byte[] code = Prepare.EvmCode + .PushData(SampleHexData1) + .PushData(SenderRecipientAndMiner.Default.Miner.Bytes) + .Op(Instruction.BALANCE) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Accounts.Count, Is.EqualTo(3), "count"); + } + + [Test] + public void Can_trace_blockhash() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.BlockHashes.Count, Is.EqualTo(1), "count"); + } + + [Test] + public void Can_trace_multiple_blockhash() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .PushData("0x02") + .Op(Instruction.BLOCKHASH) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.BlockHashes.Count, Is.EqualTo(2), "count"); + } + + [Test] + public void Can_trace_result() + { + byte[] code = Prepare.EvmCode + .PushData("0x03") + .PushData("0x00") + .Op(Instruction.RETURN) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Output.Length, Is.EqualTo(3)); + } + + [Test] + public void Can_trace_storage_read() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.SLOAD) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + + Assert.That(trace.Storages.Count, Is.EqualTo(1)); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1)), Is.True); + } + + [Test] + public void When_tracing_storage_the_account_will_always_be_already_added() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.SLOAD) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + + Assert.That(trace.Storages.Count, Is.EqualTo(1)); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1)), Is.True); + Assert.That(trace.Accounts.Contains(trace.Storages.First().Address), Is.True); + } + + [Test] + public void Can_trace_multiple_storage_reads_on_the_same_cell() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.SLOAD) + .PushData("0x01") + .Op(Instruction.SLOAD) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + + Assert.That(trace.Storages.Count, Is.EqualTo(1)); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1)), Is.True); + } + + [Test] + public void Can_trace_multiple_storage_reads() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.SLOAD) + .PushData("0x02") + .Op(Instruction.SLOAD) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + + Assert.That(trace.Storages.Count, Is.EqualTo(2)); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1)), Is.True); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2)), Is.True); + } + + [Test] + public void Can_trace_storage_write() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .PushData("0x02") + .Op(Instruction.SSTORE) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Storages.Count, Is.EqualTo(1)); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2)), Is.True); + } + + [Test] + public void Can_trace_multiple_storage_writes() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .PushData("0x02") + .Op(Instruction.SSTORE) + .PushData("0x03") + .PushData("0x04") + .Op(Instruction.SSTORE) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Storages.Count, Is.EqualTo(2)); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2)), Is.True); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 4)), Is.True); + } + + [Test] + public void Multiple_write_to_same_storage_can_be_traced_without_issues() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .PushData("0x02") + .Op(Instruction.SSTORE) + .PushData("0x01") + .PushData("0x02") + .Op(Instruction.SSTORE) + .Done; + + (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(trace.Storages.Count, Is.EqualTo(1)); + Assert.That(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2)), Is.True); + } + + [Test] + public void Can_trace_on_failure() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .PushData("0x02") + .Op(Instruction.SSTORE) + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .PushData(TestItem.AddressC) + .Op(Instruction.BALANCE) + .Op(Instruction.ADD) // stack underflow + .Done; + + (ProofTxTracer tracer, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); + Assert.That(tracer.Accounts.Count, Is.EqualTo(4)); + Assert.That(tracer.Output.Length, Is.EqualTo(0)); + Assert.That(tracer.BlockHashes.Count, Is.EqualTo(1)); + Assert.That(tracer.Storages.Count, Is.EqualTo(1)); + } + + protected (ProofTxTracer trace, Block block, Transaction transaction) ExecuteAndTraceProofCall(SenderRecipientAndMiner addresses, params byte[] code) { - private readonly bool _treatSystemAccountDifferently; - - public ProofTxTracerTests(bool treatSystemAccountDifferently) - { - _treatSystemAccountDifferently = treatSystemAccountDifferently; - } - - [Test] - public void Can_trace_sender_recipient_miner() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Accounts.Count, Is.EqualTo(3), "count"); - Assert.True(trace.Accounts.Contains(Sender)); - Assert.True(trace.Accounts.Contains(Recipient)); - Assert.True(trace.Accounts.Contains(Miner)); - } - - [Test] - public void Can_trace_sender_recipient_miner_when_miner_and_sender_are_same() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; - - SenderRecipientAndMiner addresses = new(); - addresses.MinerKey = SenderKey; - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(addresses, code); - Assert.That(trace.Accounts.Count, Is.EqualTo(2), "count"); - Assert.True(trace.Accounts.Contains(Sender)); - } - - [Test] - public void Can_trace_sender_recipient_miner_when_miner_and_recipient_are_same() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; - - SenderRecipientAndMiner addresses = new(); - addresses.MinerKey = addresses.RecipientKey; - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(addresses, code); - Assert.That(trace.Accounts.Count, Is.EqualTo(2), "count"); - Assert.True(trace.Accounts.Contains(Sender)); - } - - [Test] - public void Can_trace_touch_only_null_accounts() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .PushData(TestItem.AddressC.Bytes) - .Op(Instruction.BALANCE) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Accounts.Count, Is.EqualTo(4), "count"); - Assert.True(trace.Accounts.Contains(TestItem.AddressC)); - } - - [Test] - public void Can_trace_touch_only_preexisting_accounts() - { - TestState.CreateAccount(TestItem.AddressC, 100); - TestState.Commit(Spec); - - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .PushData(TestItem.AddressC.Bytes) - .Op(Instruction.BALANCE) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Accounts.Count, Is.EqualTo(4), "count"); - Assert.True(trace.Accounts.Contains(TestItem.AddressC)); - } - - [Test] - public void Can_trace_touch_only_null_miner_accounts() - { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .PushData(SenderRecipientAndMiner.Default.Miner.Bytes) - .Op(Instruction.BALANCE) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Accounts.Count, Is.EqualTo(3), "count"); - } - - [Test] - public void Can_trace_blockhash() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.BlockHashes.Count, Is.EqualTo(1), "count"); - } - - [Test] - public void Can_trace_multiple_blockhash() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .PushData("0x02") - .Op(Instruction.BLOCKHASH) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.BlockHashes.Count, Is.EqualTo(2), "count"); - } - - [Test] - public void Can_trace_result() - { - byte[] code = Prepare.EvmCode - .PushData("0x03") - .PushData("0x00") - .Op(Instruction.RETURN) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Output.Length, Is.EqualTo(3)); - } - - [Test] - public void Can_trace_storage_read() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.SLOAD) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - - Assert.That(trace.Storages.Count, Is.EqualTo(1)); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1))); - } - - [Test] - public void When_tracing_storage_the_account_will_always_be_already_added() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.SLOAD) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - - Assert.That(trace.Storages.Count, Is.EqualTo(1)); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1))); - - Assert.True(trace.Accounts.Contains(trace.Storages.First().Address)); - } - - [Test] - public void Can_trace_multiple_storage_reads_on_the_same_cell() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.SLOAD) - .PushData("0x01") - .Op(Instruction.SLOAD) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - - Assert.That(trace.Storages.Count, Is.EqualTo(1)); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1))); - } - - [Test] - public void Can_trace_multiple_storage_reads() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.SLOAD) - .PushData("0x02") - .Op(Instruction.SLOAD) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - - Assert.That(trace.Storages.Count, Is.EqualTo(2)); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 1))); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2))); - } - - [Test] - public void Can_trace_storage_write() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .PushData("0x02") - .Op(Instruction.SSTORE) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Storages.Count, Is.EqualTo(1)); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2))); - } - - [Test] - public void Can_trace_multiple_storage_writes() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .PushData("0x02") - .Op(Instruction.SSTORE) - .PushData("0x03") - .PushData("0x04") - .Op(Instruction.SSTORE) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Storages.Count, Is.EqualTo(2)); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2))); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 4))); - } - - [Test] - public void Multiple_write_to_same_storage_can_be_traced_without_issues() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .PushData("0x02") - .Op(Instruction.SSTORE) - .PushData("0x01") - .PushData("0x02") - .Op(Instruction.SSTORE) - .Done; - - (ProofTxTracer trace, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(trace.Storages.Count, Is.EqualTo(1)); - Assert.True(trace.Storages.Contains(new StorageCell(SenderRecipientAndMiner.Default.Recipient, 2))); - } - - [Test] - public void Can_trace_on_failure() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .PushData("0x02") - .Op(Instruction.SSTORE) - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .PushData(TestItem.AddressC) - .Op(Instruction.BALANCE) - .Op(Instruction.ADD) // stack underflow - .Done; - - (ProofTxTracer tracer, _, _) = ExecuteAndTraceProofCall(SenderRecipientAndMiner.Default, code); - Assert.That(tracer.Accounts.Count, Is.EqualTo(4)); - Assert.That(tracer.Output.Length, Is.EqualTo(0)); - Assert.That(tracer.BlockHashes.Count, Is.EqualTo(1)); - Assert.That(tracer.Storages.Count, Is.EqualTo(1)); - } - - protected (ProofTxTracer trace, Block block, Transaction transaction) ExecuteAndTraceProofCall(SenderRecipientAndMiner addresses, params byte[] code) - { - (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code, addresses); - ProofTxTracer tracer = new(_treatSystemAccountDifferently); - _processor.Execute(transaction, block.Header, tracer); - return (tracer, block, transaction); - } + (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code, addresses); + ProofTxTracer tracer = new(_treatSystemAccountDifferently); + _processor.Execute(transaction, block.Header, tracer); + return (tracer, block, transaction); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs index 59b07b4e72a..d21289e7aa6 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs @@ -94,11 +94,11 @@ public void Sets_state_root_on_receipts_before_eip658(bool withStateDiff, bool w if (_isEip155Enabled) // we use eip155 check just as a proxy on 658 { - Assert.Null(tracer.TxReceipts![0].PostTransactionState); + Assert.That(tracer.TxReceipts![0].PostTransactionState, Is.Null); } else { - Assert.NotNull(tracer.TxReceipts![0].PostTransactionState); + Assert.That(tracer.TxReceipts![0].PostTransactionState, Is.Not.Null); } } @@ -395,7 +395,7 @@ public void Can_estimate_with_refund() GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); - TestContext.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); + TestContext.Out.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); EstimateGasTracer tracer = new(); _transactionProcessor.CallAndRestore(tx, block.Header, tracer); @@ -440,7 +440,7 @@ public void Can_estimate_with_destroy_refund_and_below_intrinsic_pre_berlin() GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, tracer); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); - TestContext.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); + TestContext.Out.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); BlocksConfig blocksConfig = new(); GasEstimator estimator = new(_transactionProcessor, _stateProvider, _specProvider, blocksConfig); @@ -459,7 +459,7 @@ private void ConfirmEnoughEstimate(Transaction tx, Block block, long estimate) { CallOutputTracer outputTracer = new(); tx.GasLimit = estimate; - TestContext.WriteLine(tx.GasLimit); + TestContext.Out.WriteLine(tx.GasLimit); GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); @@ -470,13 +470,13 @@ private void ConfirmEnoughEstimate(Transaction tx, Block block, long estimate) outputTracer = new CallOutputTracer(); tx.GasLimit = Math.Min(estimate - 1, estimate * 63 / 64); - TestContext.WriteLine(tx.GasLimit); + TestContext.Out.WriteLine(tx.GasLimit); gethTracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); string traceOutOfGas = new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true); - TestContext.WriteLine(traceOutOfGas); + TestContext.Out.WriteLine(traceOutOfGas); _transactionProcessor.CallAndRestore(tx, block.Header, outputTracer); @@ -502,7 +502,7 @@ public void Can_estimate_with_stipend() GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); - TestContext.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); + TestContext.Out.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); EstimateGasTracer tracer = new(); _transactionProcessor.CallAndRestore(tx, block.Header, tracer); @@ -544,7 +544,7 @@ public void Can_estimate_with_stipend_and_refund() GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); - TestContext.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); + TestContext.Out.WriteLine(new EthereumJsonSerializer().Serialize(gethTracer.BuildResult(), true)); EstimateGasTracer tracer = new(); _transactionProcessor.CallAndRestore(tx, block.Header, tracer); diff --git a/src/Nethermind/Nethermind.Evm.Test/UInt256Tests.cs b/src/Nethermind/Nethermind.Evm.Test/UInt256Tests.cs index 315332c4684..8b9fc934e68 100644 --- a/src/Nethermind/Nethermind.Evm.Test/UInt256Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/UInt256Tests.cs @@ -7,36 +7,35 @@ using Nethermind.Int256; using NUnit.Framework; -namespace Nethermind.Evm.Test +namespace Nethermind.Evm.Test; + +public class UInt256Tests { - public class UInt256Tests + [Test] + public void IsOne() { - [Test] - public void IsOne() - { - Assert.True(UInt256.One.IsOne, "1"); - Assert.False(UInt256.Zero.IsOne, "0"); - Assert.False(((UInt256)BigInteger.Pow(2, 64)).IsOne, "2^64"); - Assert.False(((UInt256)BigInteger.Pow(2, 128)).IsOne, "2^128"); - Assert.False(((UInt256)BigInteger.Pow(2, 196)).IsOne, "2^196"); - } + Assert.That(UInt256.One.IsOne, Is.True, "1"); + Assert.That(UInt256.Zero.IsOne, Is.False, "0"); + Assert.That(((UInt256)BigInteger.Pow(2, 64)).IsOne, Is.False, "2^64"); + Assert.That(((UInt256)BigInteger.Pow(2, 128)).IsOne, Is.False, "2^128"); + Assert.That(((UInt256)BigInteger.Pow(2, 196)).IsOne, Is.False, "2^196"); + } - [Test] - public void To_big_endian_can_store_in_address() - { - Span target = stackalloc byte[20]; - UInt256 a = new(Bytes.FromHexString("0xA0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7D0D1D2D3D4D5D6D7").AsSpan(), true); - a.ToBigEndian(target); - Assert.That(target.ToHexString().ToUpperInvariant(), Is.EqualTo("b4b5b6b7c0c1c2c3c4c5c6c7d0d1d2d3d4d5d6d7".ToUpperInvariant())); - } + [Test] + public void To_big_endian_can_store_in_address() + { + Span target = stackalloc byte[20]; + UInt256 a = new(Bytes.FromHexString("0xA0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7D0D1D2D3D4D5D6D7").AsSpan(), true); + a.ToBigEndian(target); + Assert.That(target.ToHexString().ToUpperInvariant(), Is.EqualTo("b4b5b6b7c0c1c2c3c4c5c6c7d0d1d2d3d4d5d6d7".ToUpperInvariant())); + } - [Test] - public void To_big_endian_can_store_on_stack() - { - Span target = stackalloc byte[32]; - UInt256 a = new(Bytes.FromHexString("0xA0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7D0D1D2D3D4D5D6D7").AsSpan(), true); - a.ToBigEndian(target); - Assert.That(target.ToHexString().ToUpperInvariant(), Is.EqualTo("A0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7D0D1D2D3D4D5D6D7".ToUpperInvariant())); - } + [Test] + public void To_big_endian_can_store_on_stack() + { + Span target = stackalloc byte[32]; + UInt256 a = new(Bytes.FromHexString("0xA0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7D0D1D2D3D4D5D6D7").AsSpan(), true); + a.ToBigEndian(target); + Assert.That(target.ToHexString().ToUpperInvariant(), Is.EqualTo("A0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7D0D1D2D3D4D5D6D7".ToUpperInvariant())); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs index c035ac8c08c..19fb39617f3 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs @@ -12,7 +12,6 @@ namespace Nethermind.Evm.Test; -[TestFixture] [Parallelizable(ParallelScope.Self)] public class VirtualMachineTests : VirtualMachineTestsBase { @@ -61,7 +60,7 @@ public void Trace_vm_errors() 0, (byte)Instruction.SSTORE); - Assert.True(trace.Entries.Any(e => e.Error is not null)); + Assert.That(trace.Entries.Any(e => e.Error is not null), Is.True); } [Test] @@ -74,7 +73,7 @@ public void Trace_memory_out_of_gas_exception() GethLikeTxTrace trace = ExecuteAndTrace(1L, 21000L + 19000L, code); - Assert.True(trace.Entries.Any(e => e.Error is not null)); + Assert.That(trace.Entries.Any(e => e.Error is not null), Is.True); } [Test] @@ -88,7 +87,7 @@ public void Trace_invalid_jump_exception() GethLikeTxTrace trace = ExecuteAndTrace(1L, 21000L + 19000L, code); - Assert.True(trace.Entries.Any(e => e.Error is not null)); + Assert.That(trace.Entries.Any(e => e.Error is not null), Is.True); } [Test] @@ -103,7 +102,7 @@ public void Trace_invalid_jumpi_exception() GethLikeTxTrace trace = ExecuteAndTrace(1L, 21000L + 19000L, code); - Assert.True(trace.Entries.Any(e => e.Error is not null)); + Assert.That(trace.Entries.Any(e => e.Error is not null), Is.True); } [Test(Description = "Test a case where the trace is created for one transaction and subsequent untraced transactions keep adding entries to the first trace created.")] diff --git a/src/Nethermind/Nethermind.HealthChecks.Test/FreeDiskSpaceCheckerTests.cs b/src/Nethermind/Nethermind.HealthChecks.Test/FreeDiskSpaceCheckerTests.cs index 5be9df68c1c..c89be10b6e1 100644 --- a/src/Nethermind/Nethermind.HealthChecks.Test/FreeDiskSpaceCheckerTests.cs +++ b/src/Nethermind/Nethermind.HealthChecks.Test/FreeDiskSpaceCheckerTests.cs @@ -10,74 +10,73 @@ using System.Threading.Tasks; using Nethermind.Config; -namespace Nethermind.HealthChecks.Test +namespace Nethermind.HealthChecks.Test; + +public class FreeDiskSpaceCheckerTests { - public class FreeDiskSpaceCheckerTests - { - private static readonly long _freeSpaceBytes = (long)(1.GiB() * 1.2); + private static readonly long _freeSpaceBytes = (long)(1.GiB() * 1.2); - [Test] - [TestCase(1.5f, true)] //throw exception - min required 2.5% / available 1.5% - [TestCase(2.5f, false)] - public void free_disk_check_ensure_free_on_startup_no_wait(float availableDiskSpacePercent, bool exitExpected) + [Test] + [TestCase(1.5f, true)] //throw exception - min required 2.5% / available 1.5% + [TestCase(2.5f, false)] + public void free_disk_check_ensure_free_on_startup_no_wait(float availableDiskSpacePercent, bool exitExpected) + { + HealthChecksConfig hcConfig = new() { - HealthChecksConfig hcConfig = new() - { - LowStorageCheckAwaitOnStartup = false, - LowStorageSpaceShutdownThreshold = 1, - LowStorageSpaceWarningThreshold = 5 - }; - IProcessExitSource exitSource = Substitute.For(); - FreeDiskSpaceChecker freeDiskSpaceChecker = new( - hcConfig, - GetDriveInfos(availableDiskSpacePercent), - Core.Timers.TimerFactory.Default, - exitSource, - LimboTraceLogger.Instance); + LowStorageCheckAwaitOnStartup = false, + LowStorageSpaceShutdownThreshold = 1, + LowStorageSpaceWarningThreshold = 5 + }; + IProcessExitSource exitSource = Substitute.For(); + FreeDiskSpaceChecker freeDiskSpaceChecker = new( + hcConfig, + GetDriveInfos(availableDiskSpacePercent), + Core.Timers.TimerFactory.Default, + exitSource, + LimboTraceLogger.Instance); - freeDiskSpaceChecker.EnsureEnoughFreeSpaceOnStart(Core.Timers.TimerFactory.Default); - exitSource.Received(exitExpected ? 1 : 0).Exit(ExitCodes.LowDiskSpace); - } + freeDiskSpaceChecker.EnsureEnoughFreeSpaceOnStart(Core.Timers.TimerFactory.Default); + exitSource.Received(exitExpected ? 1 : 0).Exit(ExitCodes.LowDiskSpace); + } - [Test] - [TestCase(1.5f, true)] //wait until more space is free - [TestCase(2.5f, false)] //no wait - public void free_disk_check_ensure_free_on_startup_wait_until_enough(float availableDiskSpacePercent, bool awaitsForFreeSpace) + [Test] + [TestCase(1.5f, true)] //wait until more space is free + [TestCase(2.5f, false)] //no wait + public void free_disk_check_ensure_free_on_startup_wait_until_enough(float availableDiskSpacePercent, bool awaitsForFreeSpace) + { + TimeSpan ts = TimeSpan.FromMilliseconds(100); + HealthChecksConfig hcConfig = new() { - TimeSpan ts = TimeSpan.FromMilliseconds(100); - HealthChecksConfig hcConfig = new() - { - LowStorageCheckAwaitOnStartup = true, - LowStorageSpaceShutdownThreshold = 1, - LowStorageSpaceWarningThreshold = 5 - }; - IDriveInfo[] drives = GetDriveInfos(availableDiskSpacePercent); - drives[0].AvailableFreeSpace.Returns(a => _freeSpaceBytes, - a => 3 * _freeSpaceBytes); - FreeDiskSpaceChecker freeDiskSpaceChecker = new( - hcConfig, - drives, - Core.Timers.TimerFactory.Default, - Substitute.For(), - LimboTraceLogger.Instance, - ts.TotalMinutes); + LowStorageCheckAwaitOnStartup = true, + LowStorageSpaceShutdownThreshold = 1, + LowStorageSpaceWarningThreshold = 5 + }; + IDriveInfo[] drives = GetDriveInfos(availableDiskSpacePercent); + drives[0].AvailableFreeSpace.Returns(a => _freeSpaceBytes, + a => 3 * _freeSpaceBytes); + FreeDiskSpaceChecker freeDiskSpaceChecker = new( + hcConfig, + drives, + Core.Timers.TimerFactory.Default, + Substitute.For(), + LimboTraceLogger.Instance, + ts.TotalMinutes); - Task t = Task.Run(() => freeDiskSpaceChecker.EnsureEnoughFreeSpaceOnStart(Core.Timers.TimerFactory.Default)); - bool completed = t.Wait((int)ts.TotalMilliseconds * 2); + Task t = Task.Run(() => freeDiskSpaceChecker.EnsureEnoughFreeSpaceOnStart(Core.Timers.TimerFactory.Default)); + bool completed = t.Wait((int)ts.TotalMilliseconds * 2); - Assert.IsTrue(completed); + Assert.That(completed, Is.True); - _ = drives[0].Received(awaitsForFreeSpace ? 3 : 1).AvailableFreeSpace; - } + _ = drives[0].Received(awaitsForFreeSpace ? 3 : 1).AvailableFreeSpace; + } - private static IDriveInfo[] GetDriveInfos(float availableDiskSpacePercent) - { - IDriveInfo drive = Substitute.For(); - drive.AvailableFreeSpace.Returns(_freeSpaceBytes); - drive.TotalSize.Returns((long)(_freeSpaceBytes * 100.0 / availableDiskSpacePercent)); - drive.RootDirectory.FullName.Returns("C:/"); + private static IDriveInfo[] GetDriveInfos(float availableDiskSpacePercent) + { + IDriveInfo drive = Substitute.For(); + drive.AvailableFreeSpace.Returns(_freeSpaceBytes); + drive.TotalSize.Returns((long)(_freeSpaceBytes * 100.0 / availableDiskSpacePercent)); + drive.RootDirectory.FullName.Returns("C:/"); - return new[] { drive }; - } + return new[] { drive }; } } diff --git a/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs b/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs index c3336e8370a..92d9b5bce85 100644 --- a/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs +++ b/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs @@ -25,470 +25,469 @@ using Nethermind.Core.Extensions; using Nethermind.Synchronization.ParallelSync; -namespace Nethermind.HealthChecks.Test +namespace Nethermind.HealthChecks.Test; + +public class NodeHealthServiceTests { - public class NodeHealthServiceTests + private static readonly long _freeSpaceBytes = (int)(1.GiB() * 1.5); + + [Test] + public void CheckHealth_returns_expected_results([ValueSource(nameof(CheckHealthTestCases))] CheckHealthTest test) { - private static readonly long _freeSpaceBytes = (int)(1.GiB() * 1.5); + IBlockTree blockFinder = Substitute.For(); + ISyncServer syncServer = Substitute.For(); + IReceiptStorage receiptStorage = Substitute.For(); + IBlockchainProcessor blockchainProcessor = Substitute.For(); + IBlockProducerRunner blockProducerRunner = Substitute.For(); + ISyncConfig syncConfig = Substitute.For(); + IHealthHintService healthHintService = Substitute.For(); + INethermindApi api = Substitute.For(); + api.SpecProvider = Substitute.For(); + blockchainProcessor.IsProcessingBlocks(Arg.Any()).Returns(test.IsProcessingBlocks); + blockProducerRunner.IsProducingBlocks(Arg.Any()).Returns(test.IsProducingBlocks); + syncServer.GetPeerCount().Returns(test.PeerCount); - [Test] - public void CheckHealth_returns_expected_results([ValueSource(nameof(CheckHealthTestCases))] CheckHealthTest test) - { - IBlockTree blockFinder = Substitute.For(); - ISyncServer syncServer = Substitute.For(); - IReceiptStorage receiptStorage = Substitute.For(); - IBlockchainProcessor blockchainProcessor = Substitute.For(); - IBlockProducerRunner blockProducerRunner = Substitute.For(); - ISyncConfig syncConfig = Substitute.For(); - IHealthHintService healthHintService = Substitute.For(); - INethermindApi api = Substitute.For(); - api.SpecProvider = Substitute.For(); - blockchainProcessor.IsProcessingBlocks(Arg.Any()).Returns(test.IsProcessingBlocks); - blockProducerRunner.IsProducingBlocks(Arg.Any()).Returns(test.IsProducingBlocks); - syncServer.GetPeerCount().Returns(test.PeerCount); - - IDriveInfo drive = Substitute.For(); - drive.AvailableFreeSpace.Returns(_freeSpaceBytes); - drive.TotalSize.Returns((long)(_freeSpaceBytes * 100.0 / test.AvailableDiskSpacePercent)); - drive.RootDirectory.FullName.Returns("C:/"); - - BlockHeaderBuilder GetBlockHeader(int blockNumber) => Build.A.BlockHeader.WithNumber(blockNumber); - blockFinder.Head.Returns(new Block(GetBlockHeader(4).TestObject)); - if (test.IsSyncing) - { - blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(15).TestObject); - } - else - { - blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(2).TestObject); - } + IDriveInfo drive = Substitute.For(); + drive.AvailableFreeSpace.Returns(_freeSpaceBytes); + drive.TotalSize.Returns((long)(_freeSpaceBytes * 100.0 / test.AvailableDiskSpacePercent)); + drive.RootDirectory.FullName.Returns("C:/"); - IEthSyncingInfo ethSyncingInfo = new EthSyncingInfo(blockFinder, receiptStorage, syncConfig, Substitute.For(), Substitute.For(), LimboLogs.Instance); - NodeHealthService nodeHealthService = - new(syncServer, blockchainProcessor, blockProducerRunner, new HealthChecksConfig(), - healthHintService, ethSyncingInfo, new EngineRpcCapabilitiesProvider(api.SpecProvider), api, new[] { drive }, test.IsMining); - CheckHealthResult result = nodeHealthService.CheckHealth(); - Assert.That(result.Healthy, Is.EqualTo(test.ExpectedHealthy)); - Assert.That(FormatMessages(result.Messages.Select(x => x.Message)), Is.EqualTo(test.ExpectedMessage)); - Assert.That(FormatMessages(result.Messages.Select(x => x.LongMessage)), Is.EqualTo(test.ExpectedLongMessage)); - Assert.That(result.IsSyncing, Is.EqualTo(test.IsSyncing)); - CollectionAssert.AreEqual(test.ExpectedErrors, result.Errors); + BlockHeaderBuilder GetBlockHeader(int blockNumber) => Build.A.BlockHeader.WithNumber(blockNumber); + blockFinder.Head.Returns(new Block(GetBlockHeader(4).TestObject)); + if (test.IsSyncing) + { + blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(15).TestObject); } - - [Test] - public void post_merge_health_checks([ValueSource(nameof(CheckHealthPostMergeTestCases))] CheckHealthPostMergeTest test) + else { - Assert.That(test.EnabledCapabilitiesUpdatedCalls.Length, Is.EqualTo(test.EnabledCapabilities.Length)); - Assert.That(test.DisabledCapabilitiesUpdatedCalls.Length, Is.EqualTo(test.DisabledCapabilities.Length)); - - IBlockTree blockFinder = Substitute.For(); - ISyncServer syncServer = Substitute.For(); - IBlockchainProcessor blockchainProcessor = Substitute.For(); - IBlockProducerRunner blockProducerRunner = Substitute.For(); - IHealthHintService healthHintService = Substitute.For(); - ISyncModeSelector syncModeSelector = new StaticSelector(test.SyncMode); - INethermindApi api = Substitute.For(); - - ManualTimestamper timestamper = new(DateTime.Parse("18:23:00")); - api.Timestamper.Returns(timestamper); - api.JsonRpcLocalStats = Substitute.For(); - - MethodStats[] enabledMethodStats = new MethodStats[test.EnabledCapabilities.Length]; - for (int i = 0; i < enabledMethodStats.Length; i++) - { - enabledMethodStats[i] = new MethodStats(); - api.JsonRpcLocalStats!.GetMethodStats(test.EnabledCapabilities[i]).Returns(enabledMethodStats[i]); - } + blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(2).TestObject); + } - MethodStats[] disabledMethodStats = new MethodStats[test.DisabledCapabilities.Length]; - for (int i = 0; i < disabledMethodStats.Length; i++) - { - disabledMethodStats[i] = new MethodStats(); - api.JsonRpcLocalStats!.GetMethodStats(test.DisabledCapabilities[i]).Returns(disabledMethodStats[i]); - } + IEthSyncingInfo ethSyncingInfo = new EthSyncingInfo(blockFinder, receiptStorage, syncConfig, Substitute.For(), Substitute.For(), LimboLogs.Instance); + NodeHealthService nodeHealthService = + new(syncServer, blockchainProcessor, blockProducerRunner, new HealthChecksConfig(), + healthHintService, ethSyncingInfo, new EngineRpcCapabilitiesProvider(api.SpecProvider), api, new[] { drive }, test.IsMining); + CheckHealthResult result = nodeHealthService.CheckHealth(); + Assert.That(result.Healthy, Is.EqualTo(test.ExpectedHealthy)); + Assert.That(FormatMessages(result.Messages.Select(x => x.Message)), Is.EqualTo(test.ExpectedMessage)); + Assert.That(FormatMessages(result.Messages.Select(x => x.LongMessage)), Is.EqualTo(test.ExpectedLongMessage)); + Assert.That(result.IsSyncing, Is.EqualTo(test.IsSyncing)); + Assert.That(test.ExpectedErrors, Is.EqualTo(result.Errors).AsCollection); + } - syncServer.GetPeerCount().Returns(test.PeerCount); - IDriveInfo drive = Substitute.For(); - drive.AvailableFreeSpace.Returns(_freeSpaceBytes); - drive.TotalSize.Returns((long)(_freeSpaceBytes * 100.0 / test.AvailableDiskSpacePercent)); - drive.RootDirectory.FullName.Returns("C:/"); + [Test] + public void post_merge_health_checks([ValueSource(nameof(CheckHealthPostMergeTestCases))] CheckHealthPostMergeTest test) + { + Assert.That(test.EnabledCapabilitiesUpdatedCalls.Length, Is.EqualTo(test.EnabledCapabilities.Length)); + Assert.That(test.DisabledCapabilitiesUpdatedCalls.Length, Is.EqualTo(test.DisabledCapabilities.Length)); - api.SpecProvider = Substitute.For(); - api.SpecProvider.TerminalTotalDifficulty.Returns(UInt256.Zero); + IBlockTree blockFinder = Substitute.For(); + ISyncServer syncServer = Substitute.For(); + IBlockchainProcessor blockchainProcessor = Substitute.For(); + IBlockProducerRunner blockProducerRunner = Substitute.For(); + IHealthHintService healthHintService = Substitute.For(); + ISyncModeSelector syncModeSelector = new StaticSelector(test.SyncMode); + INethermindApi api = Substitute.For(); - BlockHeaderBuilder GetBlockHeader(int blockNumber) => Build.A.BlockHeader.WithNumber(blockNumber); + ManualTimestamper timestamper = new(DateTime.Parse("18:23:00")); + api.Timestamper.Returns(timestamper); + api.JsonRpcLocalStats = Substitute.For(); - blockFinder.Head.Returns(new Block(GetBlockHeader(4).WithDifficulty(0).TestObject)); - if (test.IsSyncing) - { - blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(15).TestObject); - } - else - { - blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(2).TestObject); - } + MethodStats[] enabledMethodStats = new MethodStats[test.EnabledCapabilities.Length]; + for (int i = 0; i < enabledMethodStats.Length; i++) + { + enabledMethodStats[i] = new MethodStats(); + api.JsonRpcLocalStats!.GetMethodStats(test.EnabledCapabilities[i]).Returns(enabledMethodStats[i]); + } - CustomRpcCapabilitiesProvider customProvider = - new(test.EnabledCapabilities, test.DisabledCapabilities); - IEthSyncingInfo ethSyncingInfo = new EthSyncingInfo(blockFinder, new InMemoryReceiptStorage(), - new SyncConfig(), syncModeSelector, Substitute.For(), new TestLogManager()); - NodeHealthService nodeHealthService = - new(syncServer, blockchainProcessor, blockProducerRunner, new HealthChecksConfig(), - healthHintService, ethSyncingInfo, customProvider, api, new[] { drive }, false); - nodeHealthService.CheckHealth(); - - timestamper.Add(TimeSpan.FromSeconds(test.TimeSpanSeconds)); - for (int i = 0; i < enabledMethodStats.Length; i++) - { - enabledMethodStats[i].Successes = test.EnabledCapabilitiesUpdatedCalls[i]; - } + MethodStats[] disabledMethodStats = new MethodStats[test.DisabledCapabilities.Length]; + for (int i = 0; i < disabledMethodStats.Length; i++) + { + disabledMethodStats[i] = new MethodStats(); + api.JsonRpcLocalStats!.GetMethodStats(test.DisabledCapabilities[i]).Returns(disabledMethodStats[i]); + } - for (int i = 0; i < disabledMethodStats.Length; i++) - { - disabledMethodStats[i].Successes = test.DisabledCapabilitiesUpdatedCalls[i]; - } + syncServer.GetPeerCount().Returns(test.PeerCount); + IDriveInfo drive = Substitute.For(); + drive.AvailableFreeSpace.Returns(_freeSpaceBytes); + drive.TotalSize.Returns((long)(_freeSpaceBytes * 100.0 / test.AvailableDiskSpacePercent)); + drive.RootDirectory.FullName.Returns("C:/"); + + api.SpecProvider = Substitute.For(); + api.SpecProvider.TerminalTotalDifficulty.Returns(UInt256.Zero); + + BlockHeaderBuilder GetBlockHeader(int blockNumber) => Build.A.BlockHeader.WithNumber(blockNumber); - CheckHealthResult result = nodeHealthService.CheckHealth(); - Assert.That(result.Healthy, Is.EqualTo(test.ExpectedHealthy)); - Assert.That(FormatMessages(result.Messages.Select(x => x.Message)), Is.EqualTo(test.ExpectedMessage)); - Assert.That(FormatMessages(result.Messages.Select(x => x.LongMessage)), Is.EqualTo(test.ExpectedLongMessage)); - Assert.That(result.IsSyncing, Is.EqualTo(test.IsSyncing)); - CollectionAssert.AreEqual(test.ExpectedErrors, result.Errors); + blockFinder.Head.Returns(new Block(GetBlockHeader(4).WithDifficulty(0).TestObject)); + if (test.IsSyncing) + { + blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(15).TestObject); + } + else + { + blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(2).TestObject); } - public class CheckHealthPostMergeTest + CustomRpcCapabilitiesProvider customProvider = + new(test.EnabledCapabilities, test.DisabledCapabilities); + IEthSyncingInfo ethSyncingInfo = new EthSyncingInfo(blockFinder, new InMemoryReceiptStorage(), + new SyncConfig(), syncModeSelector, Substitute.For(), new TestLogManager()); + NodeHealthService nodeHealthService = + new(syncServer, blockchainProcessor, blockProducerRunner, new HealthChecksConfig(), + healthHintService, ethSyncingInfo, customProvider, api, new[] { drive }, false); + nodeHealthService.CheckHealth(); + + timestamper.Add(TimeSpan.FromSeconds(test.TimeSpanSeconds)); + for (int i = 0; i < enabledMethodStats.Length; i++) { - public int Lp { get; set; } - public int PeerCount { get; set; } - public bool IsSyncing { get; set; } - public bool ExpectedHealthy { get; set; } - public string ExpectedMessage { get; set; } - public string ExpectedLongMessage { get; set; } - public int[] EnabledCapabilitiesUpdatedCalls { get; set; } - public int[] DisabledCapabilitiesUpdatedCalls { get; set; } = Array.Empty(); - public string[] EnabledCapabilities { get; set; } - public string[] DisabledCapabilities { get; set; } = Array.Empty(); - public string[] ExpectedErrors { get; set; } - public SyncMode SyncMode { get; set; } - public int TimeSpanSeconds { get; set; } - public double AvailableDiskSpacePercent { get; set; } = 11; - - public override string ToString() => - $"Lp: {Lp} ExpectedHealthy: {ExpectedHealthy}, ExpectedDescription: {ExpectedMessage}, ExpectedLongDescription: {ExpectedLongMessage}"; + enabledMethodStats[i].Successes = test.EnabledCapabilitiesUpdatedCalls[i]; } - public class CheckHealthTest + for (int i = 0; i < disabledMethodStats.Length; i++) { - public int Lp { get; set; } - public int PeerCount { get; set; } - public bool IsSyncing { get; set; } - public bool IsMining { get; set; } - public bool IsProducingBlocks { get; set; } - public bool IsProcessingBlocks { get; set; } - public double AvailableDiskSpacePercent { get; set; } = 11; - public bool ExpectedHealthy { get; set; } - public string ExpectedMessage { get; set; } - public string ExpectedLongMessage { get; set; } - public List ExpectedErrors { get; set; } - - public override string ToString() => - $"Lp: {Lp} ExpectedHealthy: {ExpectedHealthy}, ExpectedDescription: {ExpectedMessage}, ExpectedLongDescription: {ExpectedLongMessage}"; + disabledMethodStats[i].Successes = test.DisabledCapabilitiesUpdatedCalls[i]; } - public static IEnumerable CheckHealthTestCases + CheckHealthResult result = nodeHealthService.CheckHealth(); + Assert.That(result.Healthy, Is.EqualTo(test.ExpectedHealthy)); + Assert.That(FormatMessages(result.Messages.Select(x => x.Message)), Is.EqualTo(test.ExpectedMessage)); + Assert.That(FormatMessages(result.Messages.Select(x => x.LongMessage)), Is.EqualTo(test.ExpectedLongMessage)); + Assert.That(result.IsSyncing, Is.EqualTo(test.IsSyncing)); + Assert.That(test.ExpectedErrors, Is.EqualTo(result.Errors).AsCollection); + } + + public class CheckHealthPostMergeTest + { + public int Lp { get; set; } + public int PeerCount { get; set; } + public bool IsSyncing { get; set; } + public bool ExpectedHealthy { get; set; } + public string ExpectedMessage { get; set; } + public string ExpectedLongMessage { get; set; } + public int[] EnabledCapabilitiesUpdatedCalls { get; set; } + public int[] DisabledCapabilitiesUpdatedCalls { get; set; } = Array.Empty(); + public string[] EnabledCapabilities { get; set; } + public string[] DisabledCapabilities { get; set; } = Array.Empty(); + public string[] ExpectedErrors { get; set; } + public SyncMode SyncMode { get; set; } + public int TimeSpanSeconds { get; set; } + public double AvailableDiskSpacePercent { get; set; } = 11; + + public override string ToString() => + $"Lp: {Lp} ExpectedHealthy: {ExpectedHealthy}, ExpectedDescription: {ExpectedMessage}, ExpectedLongDescription: {ExpectedLongMessage}"; + } + + public class CheckHealthTest + { + public int Lp { get; set; } + public int PeerCount { get; set; } + public bool IsSyncing { get; set; } + public bool IsMining { get; set; } + public bool IsProducingBlocks { get; set; } + public bool IsProcessingBlocks { get; set; } + public double AvailableDiskSpacePercent { get; set; } = 11; + public bool ExpectedHealthy { get; set; } + public string ExpectedMessage { get; set; } + public string ExpectedLongMessage { get; set; } + public List ExpectedErrors { get; set; } + + public override string ToString() => + $"Lp: {Lp} ExpectedHealthy: {ExpectedHealthy}, ExpectedDescription: {ExpectedMessage}, ExpectedLongDescription: {ExpectedLongMessage}"; + } + + public static IEnumerable CheckHealthTestCases + { + get { - get + yield return new CheckHealthTest() { - yield return new CheckHealthTest() - { - Lp = 1, - IsSyncing = false, - IsProcessingBlocks = true, - PeerCount = 10, - ExpectedHealthy = true, - ExpectedErrors = new(), - ExpectedMessage = "Fully synced. Peers: 10.", - ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 10." - }; - yield return new CheckHealthTest() - { - Lp = 2, - IsSyncing = false, - IsProcessingBlocks = true, - PeerCount = 0, - ExpectedHealthy = false, - ExpectedErrors = new() { "NoPeers" }, - ExpectedMessage = "Fully synced. Node is not connected to any peers.", - ExpectedLongMessage = "The node is now fully synced with a network. Node is not connected to any peers." - }; - yield return new CheckHealthTest() - { - Lp = 3, - IsSyncing = true, - PeerCount = 7, - ExpectedHealthy = false, - ExpectedErrors = new(), - ExpectedMessage = "Still syncing. Peers: 7.", - ExpectedLongMessage = $"The node is still syncing, CurrentBlock: 4, HighestBlock: 15. The status will change to healthy once synced. Peers: 7." - }; - yield return new CheckHealthTest() - { - Lp = 4, - IsSyncing = false, - IsProcessingBlocks = false, - PeerCount = 7, - ExpectedHealthy = false, - ExpectedErrors = new() { "NotProcessingBlocks" }, - ExpectedMessage = "Fully synced. Peers: 7. Stopped processing blocks.", - ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 7. The node stopped processing blocks." - }; - yield return new CheckHealthTest() - { - Lp = 5, - IsSyncing = true, - IsMining = true, - IsProducingBlocks = false, - IsProcessingBlocks = false, - PeerCount = 4, - ExpectedHealthy = true, - ExpectedErrors = new(), - ExpectedMessage = "Still syncing. Peers: 4.", - ExpectedLongMessage = $"The node is still syncing, CurrentBlock: 4, HighestBlock: 15. The status will change to healthy once synced. Peers: 4." - }; - yield return new CheckHealthTest() - { - Lp = 6, - IsSyncing = true, - IsMining = true, - IsProducingBlocks = false, - IsProcessingBlocks = false, - PeerCount = 0, - ExpectedHealthy = false, - ExpectedErrors = new() { "NoPeers" }, - ExpectedMessage = "Still syncing. Node is not connected to any peers.", - ExpectedLongMessage = "The node is still syncing, CurrentBlock: 4, HighestBlock: 15. The status will change to healthy once synced. Node is not connected to any peers." - }; - yield return new CheckHealthTest() - { - Lp = 7, - IsSyncing = false, - IsMining = true, - IsProducingBlocks = false, - IsProcessingBlocks = false, - PeerCount = 1, - ExpectedHealthy = false, - ExpectedErrors = new() { "NotProcessingBlocks", "NotProducingBlocks" }, - ExpectedMessage = "Fully synced. Peers: 1. Stopped processing blocks. Stopped producing blocks.", - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 1. The node stopped processing blocks. The node stopped producing blocks." - }; - yield return new CheckHealthTest() - { - Lp = 8, - IsSyncing = false, - IsMining = true, - IsProducingBlocks = true, - IsProcessingBlocks = true, - PeerCount = 1, - ExpectedHealthy = true, - ExpectedErrors = new(), - ExpectedMessage = "Fully synced. Peers: 1.", - ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 1." - }; - yield return new CheckHealthTest() - { - Lp = 9, - IsSyncing = false, - IsMining = true, - IsProducingBlocks = true, - IsProcessingBlocks = true, - PeerCount = 1, - AvailableDiskSpacePercent = 4.73, - ExpectedHealthy = false, - ExpectedErrors = new() { "LowDiskSpace" }, - ExpectedMessage = "Fully synced. Peers: 1. Low free disk space.", - ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 1. The node is running out of free disk space in 'C:/' - only {1.5:F2} GB ({4.73:F2}%) left." - }; - } + Lp = 1, + IsSyncing = false, + IsProcessingBlocks = true, + PeerCount = 10, + ExpectedHealthy = true, + ExpectedErrors = new(), + ExpectedMessage = "Fully synced. Peers: 10.", + ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 10." + }; + yield return new CheckHealthTest() + { + Lp = 2, + IsSyncing = false, + IsProcessingBlocks = true, + PeerCount = 0, + ExpectedHealthy = false, + ExpectedErrors = new() { "NoPeers" }, + ExpectedMessage = "Fully synced. Node is not connected to any peers.", + ExpectedLongMessage = "The node is now fully synced with a network. Node is not connected to any peers." + }; + yield return new CheckHealthTest() + { + Lp = 3, + IsSyncing = true, + PeerCount = 7, + ExpectedHealthy = false, + ExpectedErrors = new(), + ExpectedMessage = "Still syncing. Peers: 7.", + ExpectedLongMessage = $"The node is still syncing, CurrentBlock: 4, HighestBlock: 15. The status will change to healthy once synced. Peers: 7." + }; + yield return new CheckHealthTest() + { + Lp = 4, + IsSyncing = false, + IsProcessingBlocks = false, + PeerCount = 7, + ExpectedHealthy = false, + ExpectedErrors = new() { "NotProcessingBlocks" }, + ExpectedMessage = "Fully synced. Peers: 7. Stopped processing blocks.", + ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 7. The node stopped processing blocks." + }; + yield return new CheckHealthTest() + { + Lp = 5, + IsSyncing = true, + IsMining = true, + IsProducingBlocks = false, + IsProcessingBlocks = false, + PeerCount = 4, + ExpectedHealthy = true, + ExpectedErrors = new(), + ExpectedMessage = "Still syncing. Peers: 4.", + ExpectedLongMessage = $"The node is still syncing, CurrentBlock: 4, HighestBlock: 15. The status will change to healthy once synced. Peers: 4." + }; + yield return new CheckHealthTest() + { + Lp = 6, + IsSyncing = true, + IsMining = true, + IsProducingBlocks = false, + IsProcessingBlocks = false, + PeerCount = 0, + ExpectedHealthy = false, + ExpectedErrors = new() { "NoPeers" }, + ExpectedMessage = "Still syncing. Node is not connected to any peers.", + ExpectedLongMessage = "The node is still syncing, CurrentBlock: 4, HighestBlock: 15. The status will change to healthy once synced. Node is not connected to any peers." + }; + yield return new CheckHealthTest() + { + Lp = 7, + IsSyncing = false, + IsMining = true, + IsProducingBlocks = false, + IsProcessingBlocks = false, + PeerCount = 1, + ExpectedHealthy = false, + ExpectedErrors = new() { "NotProcessingBlocks", "NotProducingBlocks" }, + ExpectedMessage = "Fully synced. Peers: 1. Stopped processing blocks. Stopped producing blocks.", + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 1. The node stopped processing blocks. The node stopped producing blocks." + }; + yield return new CheckHealthTest() + { + Lp = 8, + IsSyncing = false, + IsMining = true, + IsProducingBlocks = true, + IsProcessingBlocks = true, + PeerCount = 1, + ExpectedHealthy = true, + ExpectedErrors = new(), + ExpectedMessage = "Fully synced. Peers: 1.", + ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 1." + }; + yield return new CheckHealthTest() + { + Lp = 9, + IsSyncing = false, + IsMining = true, + IsProducingBlocks = true, + IsProcessingBlocks = true, + PeerCount = 1, + AvailableDiskSpacePercent = 4.73, + ExpectedHealthy = false, + ExpectedErrors = new() { "LowDiskSpace" }, + ExpectedMessage = "Fully synced. Peers: 1. Low free disk space.", + ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 1. The node is running out of free disk space in 'C:/' - only {1.5:F2} GB ({4.73:F2}%) left." + }; } + } - public static IEnumerable CheckHealthPostMergeTestCases + public static IEnumerable CheckHealthPostMergeTestCases + { + get { - get + yield return new CheckHealthPostMergeTest() { - yield return new CheckHealthPostMergeTest() - { - Lp = 1, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = false, - ExpectedMessage = "Fully synced. Peers: 10. No messages from CL.", - TimeSpanSeconds = 301, - ExpectedErrors = new[] { "ClUnavailable" }, - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10. No new messages from CL after last check." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 2, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = true, - ExpectedMessage = "Fully synced. Peers: 10.", - TimeSpanSeconds = 15, - ExpectedErrors = Array.Empty(), - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 3, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = true, - ExpectedMessage = "Fully synced. Peers: 10.", - TimeSpanSeconds = 301, - ExpectedErrors = Array.Empty(), - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 4, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = true, - ExpectedMessage = "Fully synced. Peers: 10.", - TimeSpanSeconds = 15, - ExpectedErrors = Array.Empty(), - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 5, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = false, - ExpectedMessage = "Fully synced. Peers: 10. No messages from CL.", - TimeSpanSeconds = 301, - ExpectedErrors = new[] { "ClUnavailable" }, - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, - DisabledCapabilities = new[] { "X", "Y", "Z" }, - DisabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10. No new messages from CL after last check." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 6, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = true, - ExpectedMessage = "Fully synced. Peers: 10.", - TimeSpanSeconds = 301, - ExpectedErrors = Array.Empty(), - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 0, 1, 0 }, - DisabledCapabilities = new[] { "X", "Y", "Z" }, - DisabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 7, - IsSyncing = true, - PeerCount = 10, - ExpectedHealthy = true, - ExpectedMessage = "Still syncing. Peers: 10.", - TimeSpanSeconds = 301, - ExpectedErrors = Array.Empty(), - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, - ExpectedLongMessage = "The node is still syncing, CurrentBlock: 4, HighestBlock: 15. Peers: 10." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 8, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = true, - ExpectedMessage = "Fully synced. Peers: 10.", - TimeSpanSeconds = 301, - ExpectedErrors = Array.Empty(), - EnabledCapabilities = new[] { "engine_forkchoiceUpdatedV999", "engine_newPayloadV999" }, - EnabledCapabilitiesUpdatedCalls = new[] { 1, 1 }, - ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 9, - IsSyncing = false, - PeerCount = 10, - ExpectedHealthy = false, - ExpectedMessage = "Fully synced. Peers: 10. Low free disk space.", - TimeSpanSeconds = 15, - ExpectedErrors = new[] { "LowDiskSpace" }, - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, - AvailableDiskSpacePercent = 4.73, - ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 10. The node is running out of free disk space in 'C:/' - only {1.50:F2} GB ({4.73:F2}%) left." - }; - yield return new CheckHealthPostMergeTest() - { - Lp = 10, - IsSyncing = true, - PeerCount = 10, - ExpectedHealthy = false, - ExpectedMessage = "Sync degraded. Peers: 10.", - TimeSpanSeconds = 301, - ExpectedErrors = new[] { "SyncDegraded" }, - SyncMode = SyncMode.Disconnected, - EnabledCapabilities = new[] { "A", "B", "C" }, - EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, - ExpectedLongMessage = "Sync degraded(no useful peers), CurrentBlock: 4, HighestBlock: 15. Peers: 10." - }; - } + Lp = 1, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = false, + ExpectedMessage = "Fully synced. Peers: 10. No messages from CL.", + TimeSpanSeconds = 301, + ExpectedErrors = new[] { "ClUnavailable" }, + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10. No new messages from CL after last check." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 2, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = true, + ExpectedMessage = "Fully synced. Peers: 10.", + TimeSpanSeconds = 15, + ExpectedErrors = Array.Empty(), + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 3, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = true, + ExpectedMessage = "Fully synced. Peers: 10.", + TimeSpanSeconds = 301, + ExpectedErrors = Array.Empty(), + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 4, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = true, + ExpectedMessage = "Fully synced. Peers: 10.", + TimeSpanSeconds = 15, + ExpectedErrors = Array.Empty(), + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 5, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = false, + ExpectedMessage = "Fully synced. Peers: 10. No messages from CL.", + TimeSpanSeconds = 301, + ExpectedErrors = new[] { "ClUnavailable" }, + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, + DisabledCapabilities = new[] { "X", "Y", "Z" }, + DisabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10. No new messages from CL after last check." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 6, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = true, + ExpectedMessage = "Fully synced. Peers: 10.", + TimeSpanSeconds = 301, + ExpectedErrors = Array.Empty(), + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 0, 1, 0 }, + DisabledCapabilities = new[] { "X", "Y", "Z" }, + DisabledCapabilitiesUpdatedCalls = new[] { 0, 0, 0 }, + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 7, + IsSyncing = true, + PeerCount = 10, + ExpectedHealthy = true, + ExpectedMessage = "Still syncing. Peers: 10.", + TimeSpanSeconds = 301, + ExpectedErrors = Array.Empty(), + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, + ExpectedLongMessage = "The node is still syncing, CurrentBlock: 4, HighestBlock: 15. Peers: 10." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 8, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = true, + ExpectedMessage = "Fully synced. Peers: 10.", + TimeSpanSeconds = 301, + ExpectedErrors = Array.Empty(), + EnabledCapabilities = new[] { "engine_forkchoiceUpdatedV999", "engine_newPayloadV999" }, + EnabledCapabilitiesUpdatedCalls = new[] { 1, 1 }, + ExpectedLongMessage = "The node is now fully synced with a network. Peers: 10." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 9, + IsSyncing = false, + PeerCount = 10, + ExpectedHealthy = false, + ExpectedMessage = "Fully synced. Peers: 10. Low free disk space.", + TimeSpanSeconds = 15, + ExpectedErrors = new[] { "LowDiskSpace" }, + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, + AvailableDiskSpacePercent = 4.73, + ExpectedLongMessage = $"The node is now fully synced with a network. Peers: 10. The node is running out of free disk space in 'C:/' - only {1.50:F2} GB ({4.73:F2}%) left." + }; + yield return new CheckHealthPostMergeTest() + { + Lp = 10, + IsSyncing = true, + PeerCount = 10, + ExpectedHealthy = false, + ExpectedMessage = "Sync degraded. Peers: 10.", + TimeSpanSeconds = 301, + ExpectedErrors = new[] { "SyncDegraded" }, + SyncMode = SyncMode.Disconnected, + EnabledCapabilities = new[] { "A", "B", "C" }, + EnabledCapabilitiesUpdatedCalls = new[] { 1, 1, 1 }, + ExpectedLongMessage = "Sync degraded(no useful peers), CurrentBlock: 4, HighestBlock: 15. Peers: 10." + }; } + } - private static string FormatMessages(IEnumerable messages) + private static string FormatMessages(IEnumerable messages) + { + if (messages.Any(x => !string.IsNullOrWhiteSpace(x))) { - if (messages.Any(x => !string.IsNullOrWhiteSpace(x))) + var joined = string.Join(". ", messages.Where(x => !string.IsNullOrWhiteSpace(x))); + if (!string.IsNullOrWhiteSpace(joined)) { - var joined = string.Join(". ", messages.Where(x => !string.IsNullOrWhiteSpace(x))); - if (!string.IsNullOrWhiteSpace(joined)) - { - return joined + "."; - } + return joined + "."; } - - return string.Empty; } - private class CustomRpcCapabilitiesProvider : IRpcCapabilitiesProvider - { - private readonly Dictionary _capabilities = new(); + return string.Empty; + } + + private class CustomRpcCapabilitiesProvider : IRpcCapabilitiesProvider + { + private readonly Dictionary _capabilities = new(); - public CustomRpcCapabilitiesProvider(IReadOnlyList enabledCapabilities, IReadOnlyList disabledCapabilities) + public CustomRpcCapabilitiesProvider(IReadOnlyList enabledCapabilities, IReadOnlyList disabledCapabilities) + { + foreach (string capability in enabledCapabilities) { - foreach (string capability in enabledCapabilities) - { - _capabilities[capability] = (true, true); - } - - foreach (string capability in disabledCapabilities) - { - _capabilities[capability] = (false, false); - } + _capabilities[capability] = (true, true); } - public IReadOnlyDictionary GetEngineCapabilities() + foreach (string capability in disabledCapabilities) { - return _capabilities; + _capabilities[capability] = (false, false); } } + + public IReadOnlyDictionary GetEngineCapabilities() + { + return _capabilities; + } } } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Data/SerializationTestBase.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Data/SerializationTestBase.cs index aafbb7d7496..9481c0e77d7 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Data/SerializationTestBase.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Data/SerializationTestBase.cs @@ -2,77 +2,75 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Collections; using System.Collections.Generic; using System.Text.Json.Serialization; using Nethermind.Serialization.Json; using NUnit.Framework; -namespace Nethermind.JsonRpc.Test.Data +namespace Nethermind.JsonRpc.Test.Data; + +public class SerializationTestBase { - public class SerializationTestBase + protected void TestRoundtrip(T item, Func? equalityComparer, JsonConverter? converter = null, string? description = null) { - protected void TestRoundtrip(T item, Func? equalityComparer, JsonConverter? converter = null, string? description = null) + IJsonSerializer serializer = BuildSerializer(); + + string result = serializer.Serialize(item); + T deserialized = serializer.Deserialize(result); + + if (equalityComparer is null) { - IJsonSerializer serializer = BuildSerializer(); - - string result = serializer.Serialize(item); - T deserialized = serializer.Deserialize(result); - - if (equalityComparer is null) - { - Assert.That(deserialized, Is.EqualTo(item), description); - } - else - { - Assert.True(equalityComparer(item, deserialized), description); - } + Assert.That(deserialized, Is.EqualTo(item), description); } - - protected void TestRoundtrip(Dictionary dictionary) - where TKey : notnull + else { - IJsonSerializer serializer = BuildSerializer(); + Assert.That(equalityComparer(item, deserialized), Is.True, description); + } + } - string result = serializer.Serialize(dictionary); - Dictionary deserialized = serializer.Deserialize>(result); + protected void TestRoundtrip(Dictionary dictionary) + where TKey : notnull + { + IJsonSerializer serializer = BuildSerializer(); - Assert.That(deserialized, Is.EquivalentTo(dictionary)); - } + string result = serializer.Serialize(dictionary); + Dictionary deserialized = serializer.Deserialize>(result); - protected void TestRoundtrip(T item, JsonConverter? converter = null, string? description = null) - { - TestRoundtrip(item, (a, b) => a!.Equals(b), converter, description); - } + Assert.That(deserialized, Is.EquivalentTo(dictionary)); + } - protected void TestRoundtrip(T item, string description) - { - TestRoundtrip(item, null, null, description); - } + protected void TestRoundtrip(T item, JsonConverter? converter = null, string? description = null) + { + TestRoundtrip(item, (a, b) => a!.Equals(b), converter, description); + } - protected void TestRoundtrip(T item, Func? equalityComparer, string? description = null) - { - TestRoundtrip(item, equalityComparer, null, description); - } + protected void TestRoundtrip(T item, string description) + { + TestRoundtrip(item, null, null, description); + } - protected void TestRoundtrip(string json, params JsonConverter[] converters) - { - IJsonSerializer serializer = BuildSerializer(converters); + protected void TestRoundtrip(T item, Func? equalityComparer, string? description = null) + { + TestRoundtrip(item, equalityComparer, null, description); + } - T deserialized = serializer.Deserialize(json); - string result = serializer.Serialize(deserialized); - Assert.That(result, Is.EqualTo(json)); - } + protected void TestRoundtrip(string json, params JsonConverter[] converters) + { + IJsonSerializer serializer = BuildSerializer(converters); - protected void TestToJson(T item, string expectedResult, params JsonConverter[] converters) - { - IJsonSerializer serializer = BuildSerializer(converters); + T deserialized = serializer.Deserialize(json); + string result = serializer.Serialize(deserialized); + Assert.That(result, Is.EqualTo(json)); + } - string result = serializer.Serialize(item); - Assert.That(result, Is.EqualTo(expectedResult.Replace("+", "\\u002B")), result.Replace("\"", "\\\"")); - } + protected void TestToJson(T item, string expectedResult, params JsonConverter[] converters) + { + IJsonSerializer serializer = BuildSerializer(converters); - private static IJsonSerializer BuildSerializer(params JsonConverter[] converters) => new EthereumJsonSerializer(converters); + string result = serializer.Serialize(item); + Assert.That(result, Is.EqualTo(expectedResult.Replace("+", "\\u002B")), result.Replace("\"", "\\\"")); } + + private static IJsonSerializer BuildSerializer(params JsonConverter[] converters) => new EthereumJsonSerializer(converters); } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcProcessorTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcProcessorTests.cs index 77ea1ccbba1..2bb1b14a1de 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcProcessorTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcProcessorTests.cs @@ -5,16 +5,13 @@ using System.Collections.Generic; using System.IO.Abstractions; using System.Linq; -using System.Numerics; using System.Text; using System.Threading; using System.Threading.Tasks; using FluentAssertions; using Nethermind.Core.Extensions; using Nethermind.Logging; -using Nethermind.Serialization.Json; using Nethermind.JsonRpc.Modules; - using NSubstitute; using NUnit.Framework; @@ -181,7 +178,7 @@ public async Task Can_process_batch_request_with_value_params() result[0].BatchedResponses.Should().NotBeNull(); var resultList = await result[0].BatchedResponses!.ToListAsync(); resultList.Should().HaveCount(2); - Assert.IsTrue(resultList.All(r => r.Response != _errorResponse)); + Assert.That(resultList.All(r => r.Response != _errorResponse), Is.True); result.DisposeItems(); } @@ -231,7 +228,7 @@ public async Task Can_process_batch_request_with_single_request_and_array_with_t result[1].BatchedResponses.Should().NotBeNull(); List resultList = await result[1].BatchedResponses!.ToListAsync(); resultList.Should().HaveCount(2); - Assert.IsTrue(resultList.All(r => r.Response != _errorResponse)); + Assert.That(resultList.All(r => r.Response != _errorResponse), Is.True); result.DisposeItems(); } @@ -355,7 +352,7 @@ public async Task Can_handle_empty_array_request() result.Should().HaveCount(1); result[0].Response.Should().BeNull(); result[0].BatchedResponses.Should().NotBeNull(); - Assert.IsTrue((await result[0].BatchedResponses!.ToListAsync()).All(r => r.Response != _errorResponse)); + Assert.That((await result[0].BatchedResponses!.ToListAsync()).All(r => r.Response != _errorResponse), Is.True); result.DisposeItems(); } @@ -379,7 +376,7 @@ public async Task Can_handle_array_of_empty_requests() result[0].BatchedResponses.Should().NotBeNull(); IList resultList = (await result[0].BatchedResponses!.ToListAsync()); resultList.Should().HaveCount(3); - Assert.IsTrue(resultList.All(r => r.Response != _errorResponse)); + Assert.That(resultList.All(r => r.Response != _errorResponse), Is.True); result.DisposeItems(); } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs index 00b2e77d735..272ad1d2a8e 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs @@ -231,7 +231,7 @@ public void NetVersionTest() netRpcModule.net_version().ReturnsForAnyArgs(x => ResultWrapper.Success("1")); JsonRpcSuccessResponse? response = TestRequest(netRpcModule, "net_version", null) as JsonRpcSuccessResponse; Assert.That(response?.Result, Is.EqualTo("1")); - Assert.IsNotInstanceOf(response); + Assert.That(response, Is.Not.InstanceOf()); } [Test] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcSocketsClientTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcSocketsClientTests.cs index c509ec7bec6..34b6648bf5e 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcSocketsClientTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcSocketsClientTests.cs @@ -234,7 +234,7 @@ async Task ReadMessages(Socket socket, IList receivedMessages, Canc int received = receiveMessages.Result; Assert.That(received, Is.EqualTo(sent)); - CollectionAssert.AreEqual(sentMessages, receivedMessages); + Assert.That(sentMessages, Is.EqualTo(receivedMessages).AsCollection); } private static async Task OneShotServer(IPEndPoint ipEndPoint, Func> func) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlCollectionTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlCollectionTests.cs index 864c5cacd70..1da47282ba1 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlCollectionTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlCollectionTests.cs @@ -8,252 +8,250 @@ using NUnit.Framework; using NSubstitute; -namespace Nethermind.JsonRpc.Test +namespace Nethermind.JsonRpc.Test; + +public class JsonRpcUrlCollectionTests { - [TestFixture] - public class JsonRpcUrlCollectionTests + [SetUp] + public void Initialize() { - [SetUp] - public void Initialize() - { - _enabledModules = new[] { ModuleType.Eth, ModuleType.Web3, ModuleType.Net }; - } + _enabledModules = [ModuleType.Eth, ModuleType.Web3, ModuleType.Net]; + } - private string[] _enabledModules = null!; + private string[] _enabledModules = null!; - [TearDown] - public void TearDown() - { - Environment.SetEnvironmentVariable("NETHERMIND_URL", null, EnvironmentVariableTarget.Process); - } + [TearDown] + public void TearDown() + { + Environment.SetEnvironmentVariable("NETHERMIND_URL", null, EnvironmentVariableTarget.Process); + } - [Test] - public void Empty_when_disabled() + [Test] + public void Empty_when_disabled() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { Enabled = false }; + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(urlCollection, Is.Empty); + } + + [Test] + public void Contains_single_default_url() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { Enabled = false }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.IsEmpty(urlCollection); - } + Enabled = true, + EnabledModules = _enabledModules + }; - [Test] - public void Contains_single_default_url() + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(new Dictionary() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules - }; + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) } + }, Is.EquivalentTo(urlCollection)); + } - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) } - }, urlCollection); - } + [Test] + public void Contains_single_default_url_overridden_by_environment_variable() + { + Environment.SetEnvironmentVariable("NETHERMIND_URL", "http://localhost:1234", EnvironmentVariableTarget.Process); - [Test] - public void Contains_single_default_url_overridden_by_environment_variable() + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - Environment.SetEnvironmentVariable("NETHERMIND_URL", "http://localhost:1234", EnvironmentVariableTarget.Process); - - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules - }; + Enabled = true, + EnabledModules = _enabledModules + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 1234, new JsonRpcUrl("http", "localhost", 1234, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) } - }, urlCollection); - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(new Dictionary() + { + { 1234, new JsonRpcUrl("http", "localhost", 1234, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) } + }, Is.EquivalentTo(urlCollection)); + } - [Test] - public void Contains_multiple_default_urls_with_different_ws_port() + [Test] + public void Contains_multiple_default_urls_with_different_ws_port() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - WebSocketsPort = 1234, - EnabledModules = _enabledModules - }; + Enabled = true, + WebSocketsPort = 1234, + EnabledModules = _enabledModules + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, - { 1234, new JsonRpcUrl("http", "127.0.0.1", 1234, RpcEndpoint.Ws, false, _enabledModules) } - }, urlCollection); - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, + { 1234, new JsonRpcUrl("http", "127.0.0.1", 1234, RpcEndpoint.Ws, false, _enabledModules) } + }, Is.EquivalentTo(urlCollection)); + } - [Test] - public void Contains_single_default_http_url_when_ws_disabled() + [Test] + public void Contains_single_default_http_url_when_ws_disabled() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - WebSocketsPort = 1234, - EnabledModules = _enabledModules - }; + Enabled = true, + WebSocketsPort = 1234, + EnabledModules = _enabledModules + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false,_enabledModules) }, - }, urlCollection); - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false,_enabledModules) }, + }, Is.EquivalentTo(urlCollection)); + } - [Test] - public void Contains_additional_urls() + [Test] + public void Contains_additional_urls() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules, - AdditionalRpcUrls = new[] { "https://localhost:1234|https;wss|admin;debug" } - }; + Enabled = true, + EnabledModules = _enabledModules, + AdditionalRpcUrls = ["https://localhost:1234|https;wss|admin;debug"] + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) }, - { 1234, new JsonRpcUrl("https", "localhost", 1234, RpcEndpoint.Https | RpcEndpoint.Wss, false, new[] { "admin", "debug" }) } - }, urlCollection); - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) }, + { 1234, new JsonRpcUrl("https", "localhost", 1234, RpcEndpoint.Https | RpcEndpoint.Wss, false, ["admin", "debug"]) } + }, Is.EquivalentTo(urlCollection)); + } - [Test] - public void Skips_additional_ws_only_urls_when_ws_disabled() + [Test] + public void Skips_additional_ws_only_urls_when_ws_disabled() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules, - AdditionalRpcUrls = new[] { "http://localhost:1234|ws|admin;debug" } - }; + Enabled = true, + EnabledModules = _enabledModules, + AdditionalRpcUrls = ["http://localhost:1234|ws|admin;debug"] + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) } - }, urlCollection); - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) } + }, Is.EquivalentTo(urlCollection)); + } - [Test] - public void Clears_flag_on_additional_ws_urls_when_ws_disabled() + [Test] + public void Clears_flag_on_additional_ws_urls_when_ws_disabled() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules, - AdditionalRpcUrls = new[] { "http://localhost:1234|http;ws|admin;debug" } - }; + Enabled = true, + EnabledModules = _enabledModules, + AdditionalRpcUrls = ["http://localhost:1234|http;ws|admin;debug"] + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, - { 1234, new JsonRpcUrl("http", "localhost", 1234, RpcEndpoint.Http, false, new [] { "admin", "debug" }) } - }, urlCollection); - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, + { 1234, new JsonRpcUrl("http", "localhost", 1234, RpcEndpoint.Http, false, ["admin", "debug"]) } + }, Is.EquivalentTo(urlCollection)); + } - [Test] - public void Skips_additional_urls_with_port_conficts() + [Test] + public void Skips_additional_urls_with_port_conficts() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules, - WebSocketsPort = 9876, - AdditionalRpcUrls = new[] - { - "http://localhost:8545|http;ws|admin;debug", - "https://127.0.0.1:1234|https;wss|eth;web3", - "https://127.0.0.1:9876|https;wss|net;proof", - "http://localhost:1234|http;ws|db;erc20" - } - }; + Enabled = true, + EnabledModules = _enabledModules, + WebSocketsPort = 9876, + AdditionalRpcUrls = + [ + "http://localhost:8545|http;ws|admin;debug", + "https://127.0.0.1:1234|https;wss|eth;web3", + "https://127.0.0.1:9876|https;wss|net;proof", + "http://localhost:1234|http;ws|db;erc20" + ] + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, - { 9876, new JsonRpcUrl("http", "127.0.0.1", 9876, RpcEndpoint.Ws,false, _enabledModules) }, - { 1234, new JsonRpcUrl("https", "127.0.0.1", 1234, RpcEndpoint.Https | RpcEndpoint.Wss, false, new [] { "eth", "web3" }) } - }, urlCollection); - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, + { 9876, new JsonRpcUrl("http", "127.0.0.1", 9876, RpcEndpoint.Ws,false, _enabledModules) }, + { 1234, new JsonRpcUrl("https", "127.0.0.1", 1234, RpcEndpoint.Https | RpcEndpoint.Wss, false, ["eth", "web3"]) } + }, Is.EquivalentTo(urlCollection)); + } - [Test] - public void Skips_additional_urls_when_invalid() + [Test] + public void Skips_additional_urls_when_invalid() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules, - AdditionalRpcUrls = new[] - { - string.Empty, - "test", - "http://localhost:1234|http|db;erc20;web3" - } - }; + Enabled = true, + EnabledModules = _enabledModules, + AdditionalRpcUrls = + [ + string.Empty, + "test", + "http://localhost:1234|http|db;erc20;web3" + ] + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) }, - { 1234, new JsonRpcUrl("http", "localhost", 1234, RpcEndpoint.Http, false, new [] { "db", "erc20", "web3" }) } - }, urlCollection); ; - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) }, + { 1234, new JsonRpcUrl("http", "localhost", 1234, RpcEndpoint.Http, false, ["db", "erc20", "web3"]) } + }, Is.EquivalentTo(urlCollection)); ; + } - [Test] - public void EngineHost_and_EnginePort_specified() + [Test] + public void EngineHost_and_EnginePort_specified() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules, - AdditionalRpcUrls = new[] - { - "http://127.0.0.1:8551|http|eth;web3;engine" - }, - EngineHost = "127.0.0.1", - EnginePort = 8551, - EngineEnabledModules = new[] { "eth" } - }; + Enabled = true, + EnabledModules = _enabledModules, + AdditionalRpcUrls = + [ + "http://127.0.0.1:8551|http|eth;web3;engine" + ], + EngineHost = "127.0.0.1", + EnginePort = 8551, + EngineEnabledModules = ["eth"] + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) }, - { 8551, new JsonRpcUrl("http", "127.0.0.1", 8551, RpcEndpoint.Http | RpcEndpoint.Ws, true, new [] { ModuleType.Eth, ModuleType.Engine }) }, - }, urlCollection); ; - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, true); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http | RpcEndpoint.Ws, false, _enabledModules) }, + { 8551, new JsonRpcUrl("http", "127.0.0.1", 8551, RpcEndpoint.Http | RpcEndpoint.Ws, true, [ModuleType.Eth, ModuleType.Engine]) }, + }, Is.EquivalentTo(urlCollection)); ; + } - [Test] - public void Skips_AdditionalUrl_with_engine_module_enabled_when_EngineUrl_specified() + [Test] + public void Skips_AdditionalUrl_with_engine_module_enabled_when_EngineUrl_specified() + { + JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { - JsonRpcConfig jsonRpcConfig = new JsonRpcConfig() - { - Enabled = true, - EnabledModules = _enabledModules, - AdditionalRpcUrls = new[] - { - "http://127.0.0.1:8551|http|eth;web3;engine", - "http://127.0.0.1:1234|http|eth;web3" - }, - EngineHost = "127.0.0.1", - EnginePort = 8552, - EngineEnabledModules = new[] { "eth" } - }; + Enabled = true, + EnabledModules = _enabledModules, + AdditionalRpcUrls = + [ + "http://127.0.0.1:8551|http|eth;web3;engine", + "http://127.0.0.1:1234|http|eth;web3" + ], + EngineHost = "127.0.0.1", + EnginePort = 8552, + EngineEnabledModules = ["eth"] + }; - JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); - CollectionAssert.AreEquivalent(new Dictionary() - { - { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, - { 8552, new JsonRpcUrl("http", "127.0.0.1", 8552, RpcEndpoint.Http, true, new [] { ModuleType.Eth, ModuleType.Engine }) }, - { 1234, new JsonRpcUrl("http", "127.0.0.1", 1234, RpcEndpoint.Http, false, new [] { ModuleType.Eth, ModuleType.Web3 })} - }, urlCollection); ; - } + JsonRpcUrlCollection urlCollection = new JsonRpcUrlCollection(Substitute.For(), jsonRpcConfig, false); + Assert.That(new Dictionary() + { + { 8545, new JsonRpcUrl("http", "127.0.0.1", 8545, RpcEndpoint.Http, false, _enabledModules) }, + { 8552, new JsonRpcUrl("http", "127.0.0.1", 8552, RpcEndpoint.Http, true, [ModuleType.Eth, ModuleType.Engine]) }, + { 1234, new JsonRpcUrl("http", "127.0.0.1", 1234, RpcEndpoint.Http, false, [ModuleType.Eth, ModuleType.Web3])} + }, Is.EquivalentTo(urlCollection)); } } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlTests.cs index b1eb2108dbb..cb88348b86e 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcUrlTests.cs @@ -5,37 +5,35 @@ using Nethermind.JsonRpc.Modules; using NUnit.Framework; -namespace Nethermind.JsonRpc.Test +namespace Nethermind.JsonRpc.Test; + +[Parallelizable(ParallelScope.All)] +public class JsonRpcUrlTests { - [Parallelizable(ParallelScope.All)] - [TestFixture] - public class JsonRpcUrlTests + [TestCase("http://127.0.0.1:1234|http|eth;web3;net", "http", "127.0.0.1", 1234, RpcEndpoint.Http, new string[] { "eth", "web3", "net" })] + [TestCase("http://0.0.0.0|ws|eth ;web3; net", "http", "0.0.0.0", 80, RpcEndpoint.Ws, new string[] { "eth", "web3", "net" })] + [TestCase("https://localhost:9876|HTTpS; wSs|eth;Web3;NET", "https", "localhost", 9876, RpcEndpoint.Http | RpcEndpoint.Ws, new string[] { "eth", "web3", "net" })] + public void Parse_success(string packedUrlValue, string expectedScheme, string expectedHost, int expectedPort, RpcEndpoint expectedRpcEndpoint, string[] expectedEnabledModules) { - [TestCase("http://127.0.0.1:1234|http|eth;web3;net", "http", "127.0.0.1", 1234, RpcEndpoint.Http, new string[] { "eth", "web3", "net" })] - [TestCase("http://0.0.0.0|ws|eth ;web3; net", "http", "0.0.0.0", 80, RpcEndpoint.Ws, new string[] { "eth", "web3", "net" })] - [TestCase("https://localhost:9876|HTTpS; wSs|eth;Web3;NET", "https", "localhost", 9876, RpcEndpoint.Http | RpcEndpoint.Ws, new string[] { "eth", "web3", "net" })] - public void Parse_success(string packedUrlValue, string expectedScheme, string expectedHost, int expectedPort, RpcEndpoint expectedRpcEndpoint, string[] expectedEnabledModules) - { - JsonRpcUrl url = JsonRpcUrl.Parse(packedUrlValue); - Assert.That(url.Scheme, Is.EqualTo(expectedScheme)); - Assert.That(url.Host, Is.EqualTo(expectedHost)); - Assert.That(url.Port, Is.EqualTo(expectedPort)); - Assert.That(url.RpcEndpoint, Is.EqualTo(expectedRpcEndpoint)); - CollectionAssert.AreEqual(expectedEnabledModules, url.EnabledModules, StringComparer.InvariantCultureIgnoreCase); - } - - [TestCase(null, typeof(ArgumentNullException))] - [TestCase("", typeof(FormatException))] - [TestCase("127.0.0.1:1234|a|a", typeof(FormatException))] - [TestCase("http://127.0.0.1:0|a|a", typeof(FormatException))] - [TestCase("http://127.0.0.1:-1|a|a", typeof(FormatException))] - [TestCase("http://127.0.0.1:1234||", typeof(FormatException))] - [TestCase("http://127.0.0.1:1234/test|a|a", typeof(FormatException))] - [TestCase("a://127.0.0.1:1234|a|a", typeof(FormatException))] - [TestCase("http://127.0.0.1:1234|a|a", typeof(FormatException))] - [TestCase("http://127.0.0.1:1234|ipc|a", typeof(FormatException))] - [TestCase("http://127.0.0.1:1234|http|", typeof(FormatException))] - public void Parse_fail(string? packedUrlValue, Type expectedExceptionType) => - Assert.Throws(expectedExceptionType, () => JsonRpcUrl.Parse(packedUrlValue!)); + JsonRpcUrl url = JsonRpcUrl.Parse(packedUrlValue); + Assert.That(url.Scheme, Is.EqualTo(expectedScheme)); + Assert.That(url.Host, Is.EqualTo(expectedHost)); + Assert.That(url.Port, Is.EqualTo(expectedPort)); + Assert.That(url.RpcEndpoint, Is.EqualTo(expectedRpcEndpoint)); + Assert.That(expectedEnabledModules, Is.EqualTo(url.EnabledModules).AsCollection.IgnoreCase); } + + [TestCase(null, typeof(ArgumentNullException))] + [TestCase("", typeof(FormatException))] + [TestCase("127.0.0.1:1234|a|a", typeof(FormatException))] + [TestCase("http://127.0.0.1:0|a|a", typeof(FormatException))] + [TestCase("http://127.0.0.1:-1|a|a", typeof(FormatException))] + [TestCase("http://127.0.0.1:1234||", typeof(FormatException))] + [TestCase("http://127.0.0.1:1234/test|a|a", typeof(FormatException))] + [TestCase("a://127.0.0.1:1234|a|a", typeof(FormatException))] + [TestCase("http://127.0.0.1:1234|a|a", typeof(FormatException))] + [TestCase("http://127.0.0.1:1234|ipc|a", typeof(FormatException))] + [TestCase("http://127.0.0.1:1234|http|", typeof(FormatException))] + public void Parse_fail(string? packedUrlValue, Type expectedExceptionType) => + Assert.Throws(expectedExceptionType, () => JsonRpcUrl.Parse(packedUrlValue!)); } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs index 00faf0cd169..234acd6e729 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs @@ -21,7 +21,6 @@ using Nethermind.Evm.Tracing.GethStyle.Custom; using Nethermind.Facade.Eth; using Nethermind.Int256; -using Nethermind.JsonRpc.Data; using Nethermind.JsonRpc.Modules.DebugModule; using Nethermind.JsonRpc.Modules.Eth; using Nethermind.Logging; @@ -33,7 +32,6 @@ namespace Nethermind.JsonRpc.Test.Modules; [Parallelizable(ParallelScope.Self)] -[TestFixture] public class DebugModuleTests { private readonly IJsonRpcConfig jsonRpcConfig = new JsonRpcConfig(); @@ -70,7 +68,7 @@ public async Task Get_from_db_null_value() await RpcTest.TestRequest(rpcModule, "debug_getFromDb", "STATE", key.ToHexString(true)) as JsonRpcSuccessResponse; - Assert.NotNull(response); + Assert.That(response, Is.Not.Null); } [TestCase("1")] @@ -89,7 +87,7 @@ public async Task Get_chain_level(string parameter) DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getChainLevel", parameter) as JsonRpcSuccessResponse; var chainLevel = response?.Result as ChainLevelForRpc; - Assert.NotNull(chainLevel); + Assert.That(chainLevel, Is.Not.Null); Assert.That(chainLevel?.HasBlockOnMainChain, Is.EqualTo(true)); Assert.That(chainLevel?.BlockInfos.Length, Is.EqualTo(2)); } @@ -402,7 +400,7 @@ public async Task Migrate_receipts() debugBridge.MigrateReceipts(Arg.Any()).Returns(true); IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_migrateReceipts", "100"); - Assert.NotNull(response); + Assert.That(response, Is.Not.Null); } [Test] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs index ed73767fcf1..060c4e855ad 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs @@ -9,7 +9,6 @@ using Nethermind.Core.Test.Builders; using Nethermind.Evm; using Nethermind.Facade.Eth; -using Nethermind.JsonRpc.Data; using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.Specs.Test; @@ -123,7 +122,7 @@ public async Task Eth_call_ethereum_recipient() string serialized = await ctx.Test.TestEthRpc("eth_call", "{\"data\":\"0x12\",\"from\":\"0x7301cfa0e1756b71869e93d4e4dca5c7d0eb0aa6\",\"to\":\"ethereum\"}", "latest"); - Assert.True(serialized.StartsWith("{\"jsonrpc\":\"2.0\",\"error\"")); + Assert.That(serialized.StartsWith("{\"jsonrpc\":\"2.0\",\"error\""), Is.True); } [Test] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs index 1a12d3e152f..076e792e566 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs @@ -20,14 +20,10 @@ using Nethermind.Core.Test.Builders; using Nethermind.Crypto; using Nethermind.Evm; -using Nethermind.Evm.Tracing; using Nethermind.Facade; using Nethermind.Facade.Eth; using Nethermind.Facade.Filters; using Nethermind.Int256; -using Nethermind.JsonRpc.Data; -using Nethermind.JsonRpc.Modules.Eth; -using Nethermind.Logging; using Nethermind.Serialization.Json; using Nethermind.Serialization.Rlp; using Nethermind.Specs; @@ -41,7 +37,6 @@ namespace Nethermind.JsonRpc.Test.Modules.Eth; [Parallelizable(ParallelScope.All)] -[TestFixture] [SetCulture("en-US")] public partial class EthRpcModuleTests { @@ -519,7 +514,7 @@ void HandleNewBlock(object? sender, BlockReplacementEventArgs e) using JsonRpcResponse? newFilterResp = await RpcTest.TestRequest(test.EthRpcModule, "eth_newFilter", $"{{\"fromBlock\":\"{blockHash}\"}}"); - Assert.IsTrue(newFilterResp is not null && newFilterResp is JsonRpcSuccessResponse); + Assert.That(newFilterResp is not null && newFilterResp is JsonRpcSuccessResponse, Is.True); string getFilterLogsSerialized = await test.TestEthRpc("eth_getFilterLogs", (newFilterResp as JsonRpcSuccessResponse)!.Result?.ToString() ?? "0x0"); @@ -764,7 +759,7 @@ public async Task Eth_get_block_by_number_empty_param() { using Context ctx = await Context.Create(); string serialized = await ctx.Test.TestEthRpc("eth_getBlockByNumber", "", "true"); - Assert.True(serialized.StartsWith("{\"jsonrpc\":\"2.0\",\"error\"")); + Assert.That(serialized.StartsWith("{\"jsonrpc\":\"2.0\",\"error\""), Is.True); } [Test] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthSimulateTestsPrecompilesWithRedirection.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthSimulateTestsPrecompilesWithRedirection.cs index 33d80a28d30..f25ebc9c145 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthSimulateTestsPrecompilesWithRedirection.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthSimulateTestsPrecompilesWithRedirection.cs @@ -16,7 +16,6 @@ using Nethermind.Facade.Eth; using Nethermind.Facade.Proxy.Models; using Nethermind.Facade.Proxy.Models.Simulate; -using Nethermind.JsonRpc.Data; using Nethermind.JsonRpc.Modules.Eth; using NUnit.Framework; @@ -68,7 +67,7 @@ public async Task Test_eth_simulate_create() //Check results byte[]? returnData = result.Data[0].Calls.First().ReturnData; - Assert.IsNotNull(returnData); + Assert.That(returnData, Is.Not.Null); } @@ -182,7 +181,7 @@ function ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public returns( SimulateTxExecutor executor = new(chain.Bridge, chain.BlockFinder, new JsonRpcConfig(), new BlocksConfig().SecondsPerSlot); Debug.Assert(contractAddress is not null, nameof(contractAddress) + " is not null"); - Assert.IsTrue(chain.State.AccountExists(contractAddress)); + Assert.That(chain.State.AccountExists(contractAddress), Is.True); ResultWrapper> result = executor.Execute(payload, BlockParameter.Latest); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs index 28a28e68803..e653e6914c2 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs @@ -16,7 +16,6 @@ using Nethermind.Facade.Proxy.Models; using Nethermind.Facade.Proxy.Models.Simulate; using Nethermind.Int256; -using Nethermind.JsonRpc.Data; using Nethermind.JsonRpc.Modules.Eth; using Nethermind.Serialization.Json; using NUnit.Framework; @@ -140,7 +139,7 @@ public async Task Test_eth_simulate_eth_moved() UInt256 before = chain.State.GetBalance(TestItem.AddressA); await chain.AddBlock(true, txMainnetAtoB); UInt256 after = chain.State.GetBalance(TestItem.AddressA); - Assert.Less(after, before); + Assert.That(after, Is.LessThan(before)); chain.Bridge.GetReceipt(txMainnetAtoB.Hash!); @@ -220,7 +219,7 @@ public async Task Test_eth_simulate_transactions_forced_fail() UInt256 before = chain.State.GetBalance(TestItem.AddressA); await chain.AddBlock(true, txMainnetAtoB); UInt256 after = chain.State.GetBalance(TestItem.AddressA); - Assert.Less(after, before); + Assert.That(after, Is.LessThan(before)); chain.Bridge.GetReceipt(txMainnetAtoB.Hash!); @@ -233,7 +232,7 @@ public async Task Test_eth_simulate_transactions_forced_fail() ResultWrapper> result = executor.Execute(payload, BlockParameter.Latest); - Assert.IsTrue(result.Result!.Error!.Contains("higher than sender balance")); + Assert.That(result.Result!.Error!.Contains("higher than sender balance"), Is.True); } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs index d0ab6c1e05c..16bd45f4f5d 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs @@ -7,7 +7,6 @@ using Nethermind.Blockchain.Find; using Nethermind.Facade.Eth; using Nethermind.Facade.Proxy.Models.Simulate; -using Nethermind.JsonRpc.Data; using Nethermind.Serialization.Json; using NUnit.Framework; using ResultType = Nethermind.Core.ResultType; @@ -78,6 +77,6 @@ public async Task TestsimulateHive(string name, string data) Console.WriteLine(); Assert.That(result.Result.ResultType, Is.EqualTo(ResultType.Success)); - Assert.IsNotNull(result.Data); + Assert.That(result.Data, Is.Not.Null); } } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs index 7f74b75145a..1d5dab0e6b9 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs @@ -13,7 +13,6 @@ using Nethermind.Db; using Nethermind.Int256; using Nethermind.Evm; -using Nethermind.JsonRpc.Data; using Nethermind.JsonRpc.Modules.Proof; using Nethermind.Logging; using Nethermind.Serialization.Json; @@ -33,884 +32,883 @@ using Nethermind.State.Tracing; using NSubstitute; -namespace Nethermind.JsonRpc.Test.Modules.Proof +namespace Nethermind.JsonRpc.Test.Modules.Proof; + +[Parallelizable(ParallelScope.None)] +// [TestFixture(true, true)] TODO fix or remove test? +[TestFixture(true, false)] +[TestFixture(false, false)] +public class ProofRpcModuleTests { - [Parallelizable(ParallelScope.None)] - // [TestFixture(true, true)] TODO fix or remove test? - [TestFixture(true, false)] - [TestFixture(false, false)] - public class ProofRpcModuleTests - { - private readonly bool _createSystemAccount; - private readonly bool _useNonZeroGasPrice; - private IProofRpcModule _proofRpcModule = null!; - private IBlockTree _blockTree = null!; - private IDbProvider _dbProvider = null!; - private TestSpecProvider _specProvider = null!; - private WorldStateManager _worldStateManager = null!; - - public ProofRpcModuleTests(bool createSystemAccount, bool useNonZeroGasPrice) + private readonly bool _createSystemAccount; + private readonly bool _useNonZeroGasPrice; + private IProofRpcModule _proofRpcModule = null!; + private IBlockTree _blockTree = null!; + private IDbProvider _dbProvider = null!; + private TestSpecProvider _specProvider = null!; + private WorldStateManager _worldStateManager = null!; + + public ProofRpcModuleTests(bool createSystemAccount, bool useNonZeroGasPrice) + { + _createSystemAccount = createSystemAccount; + _useNonZeroGasPrice = useNonZeroGasPrice; + } + + [SetUp] + public async Task Setup() + { + _dbProvider = await TestMemDbProvider.InitAsync(); + ITrieStore trieStore = new TrieStore(_dbProvider.StateDb, LimboLogs.Instance); + WorldState worldState = new WorldState(trieStore, _dbProvider.CodeDb, LimboLogs.Instance); + worldState.CreateAccount(TestItem.AddressA, 100000); + worldState.Commit(London.Instance); + worldState.CommitTree(0); + + InMemoryReceiptStorage receiptStorage = new(); + _specProvider = new TestSpecProvider(London.Instance); + _blockTree = Build.A.BlockTree(new Block(Build.A.BlockHeader.WithStateRoot(worldState.StateRoot).TestObject, new BlockBody()), _specProvider) + .WithTransactions(receiptStorage) + .OfChainLength(10) + .TestObject; + + _worldStateManager = new WorldStateManager(worldState, trieStore, _dbProvider, LimboLogs.Instance); + ProofModuleFactory moduleFactory = new( + _worldStateManager, + _blockTree, + new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(TestBlockchainIds.ChainId), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), + receiptStorage, + _specProvider, + LimboLogs.Instance); + + _proofRpcModule = moduleFactory.Create(); + } + + [TestCase(true)] + [TestCase(false)] + public async Task Can_get_transaction(bool withHeader) + { + Hash256 txHash = _blockTree.FindBlock(1)!.Transactions[0].Hash!; + TransactionWithProof txWithProof = _proofRpcModule.proof_getTransactionByHash(txHash, withHeader).Data; + Assert.That(txWithProof.Transaction, Is.Not.Null); + Assert.That(txWithProof.TxProof.Length, Is.EqualTo(2)); + if (withHeader) { - _createSystemAccount = createSystemAccount; - _useNonZeroGasPrice = useNonZeroGasPrice; + Assert.That(txWithProof.BlockHeader, Is.Not.Null); } - - [SetUp] - public async Task Setup() + else { - _dbProvider = await TestMemDbProvider.InitAsync(); - ITrieStore trieStore = new TrieStore(_dbProvider.StateDb, LimboLogs.Instance); - WorldState worldState = new WorldState(trieStore, _dbProvider.CodeDb, LimboLogs.Instance); - worldState.CreateAccount(TestItem.AddressA, 100000); - worldState.Commit(London.Instance); - worldState.CommitTree(0); - - InMemoryReceiptStorage receiptStorage = new(); - _specProvider = new TestSpecProvider(London.Instance); - _blockTree = Build.A.BlockTree(new Block(Build.A.BlockHeader.WithStateRoot(worldState.StateRoot).TestObject, new BlockBody()), _specProvider) - .WithTransactions(receiptStorage) - .OfChainLength(10) - .TestObject; - - _worldStateManager = new WorldStateManager(worldState, trieStore, _dbProvider, LimboLogs.Instance); - ProofModuleFactory moduleFactory = new( - _worldStateManager, - _blockTree, - new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(TestBlockchainIds.ChainId), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), - receiptStorage, - _specProvider, - LimboLogs.Instance); - - _proofRpcModule = moduleFactory.Create(); + Assert.That(txWithProof.BlockHeader, Is.Null); } - [TestCase(true)] - [TestCase(false)] - public async Task Can_get_transaction(bool withHeader) - { - Hash256 txHash = _blockTree.FindBlock(1)!.Transactions[0].Hash!; - TransactionWithProof txWithProof = _proofRpcModule.proof_getTransactionByHash(txHash, withHeader).Data; - Assert.NotNull(txWithProof.Transaction); - Assert.That(txWithProof.TxProof.Length, Is.EqualTo(2)); - if (withHeader) - { - Assert.NotNull(txWithProof.BlockHeader); - } - else - { - Assert.Null(txWithProof.BlockHeader); - } + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}", $"{withHeader}"); + Assert.That(response.Contains("\"result\""), Is.True); + } - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}", $"{withHeader}"); - Assert.True(response.Contains("\"result\"")); - } + [TestCase(true)] + [TestCase(false)] + public async Task When_getting_non_existing_tx_correct_error_code_is_returned(bool withHeader) + { + Hash256 txHash = TestItem.KeccakH; + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}", $"{withHeader}"); + Assert.That(response.Contains($"{ErrorCodes.ResourceNotFound}"), Is.True); + } - [TestCase(true)] - [TestCase(false)] - public async Task When_getting_non_existing_tx_correct_error_code_is_returned(bool withHeader) - { - Hash256 txHash = TestItem.KeccakH; - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}", $"{withHeader}"); - Assert.True(response.Contains($"{ErrorCodes.ResourceNotFound}")); - } + [TestCase(true)] + [TestCase(false)] + public async Task When_getting_non_existing_receipt_correct_error_code_is_returned(bool withHeader) + { + Hash256 txHash = TestItem.KeccakH; + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); + Assert.That(response.Contains($"{ErrorCodes.ResourceNotFound}"), Is.True); + } - [TestCase(true)] - [TestCase(false)] - public async Task When_getting_non_existing_receipt_correct_error_code_is_returned(bool withHeader) - { - Hash256 txHash = TestItem.KeccakH; - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); - Assert.True(response.Contains($"{ErrorCodes.ResourceNotFound}")); - } + [TestCase] + public async Task On_incorrect_params_returns_correct_error_code() + { + Hash256 txHash = TestItem.KeccakH; - [TestCase] - public async Task On_incorrect_params_returns_correct_error_code() - { - Hash256 txHash = TestItem.KeccakH; + // missing with header + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}"); + Assert.That(response.Contains($"{ErrorCodes.InvalidParams}"), Is.True, "missing"); + + // too many + response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", "true", "false"); + Assert.That(response.Contains($"{ErrorCodes.InvalidParams}"), Is.True, "too many"); - // missing with header - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}"); - Assert.True(response.Contains($"{ErrorCodes.InvalidParams}"), "missing"); + // missing with header + response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}"); + Assert.That(response.Contains($"{ErrorCodes.InvalidParams}"), Is.True, "missing"); - // too many - response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", "true", "false"); - Assert.True(response.Contains($"{ErrorCodes.InvalidParams}"), "too many"); + // too many + response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}", "true", "false"); + Assert.That(response.Contains($"{ErrorCodes.InvalidParams}"), Is.True, "too many"); - // missing with header - response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}"); - Assert.True(response.Contains($"{ErrorCodes.InvalidParams}"), "missing"); + // all wrong + response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{txHash}"); + Assert.That(response.Contains($"{ErrorCodes.InvalidParams}"), Is.True, "missing"); + } - // too many - response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionByHash", $"{txHash}", "true", "false"); - Assert.True(response.Contains($"{ErrorCodes.InvalidParams}"), "too many"); + [TestCase(true, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x9d335cdd632432bc4181dabfc07b9a614f1fcf9f0d2c0c1340e35a403875fdb1\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x0\",\"gasUsed\":\"0x0\",\"effectiveGasPrice\":\"0x1\",\"to\":null,\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86530b862f860800182a41094000000000000000000000000000000000000000001818026a0e4830571029d291f22478cbb60a04115f783fb687f9c3a98bf9d4a008f909817a010f0f7a1c274747616522ea29771cb026bf153362227563e2657d25fa57816bd\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d30b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"],\"blockHeader\":\"0xf901f9a0a3e31eb259593976b3717142a5a9e90637f614d33e2ad13f01134ea00c24ca5aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a009e11c477e0a0dfdfe036492b9bce7131991eb23bcf9575f9bff1e4016f90447a0e1b1585a222beceb3887dc6701802facccf186c2d0f6aa69e26ae0c431fc2b5db9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424001833d090080830f424183010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8\"},\"id\":67}")] + [TestCase(false, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x9d335cdd632432bc4181dabfc07b9a614f1fcf9f0d2c0c1340e35a403875fdb1\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x0\",\"gasUsed\":\"0x0\",\"effectiveGasPrice\":\"0x1\",\"to\":null,\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86530b862f860800182a41094000000000000000000000000000000000000000001818026a0e4830571029d291f22478cbb60a04115f783fb687f9c3a98bf9d4a008f909817a010f0f7a1c274747616522ea29771cb026bf153362227563e2657d25fa57816bd\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d30b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"]},\"id\":67}")] + public async Task Can_get_receipt(bool withHeader, string expectedResult) + { + Hash256 txHash = _blockTree.FindBlock(1)!.Transactions[0].Hash!; + ReceiptWithProof receiptWithProof = _proofRpcModule.proof_getTransactionReceipt(txHash, withHeader).Data; + Assert.That(receiptWithProof.Receipt, Is.Not.Null); + Assert.That(receiptWithProof.ReceiptProof.Length, Is.EqualTo(2)); - // all wrong - response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{txHash}"); - Assert.True(response.Contains($"{ErrorCodes.InvalidParams}"), "missing"); + if (withHeader) + { + Assert.That(receiptWithProof.BlockHeader, Is.Not.Null); } - - [TestCase(true, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x9d335cdd632432bc4181dabfc07b9a614f1fcf9f0d2c0c1340e35a403875fdb1\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x0\",\"gasUsed\":\"0x0\",\"effectiveGasPrice\":\"0x1\",\"to\":null,\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86530b862f860800182a41094000000000000000000000000000000000000000001818026a0e4830571029d291f22478cbb60a04115f783fb687f9c3a98bf9d4a008f909817a010f0f7a1c274747616522ea29771cb026bf153362227563e2657d25fa57816bd\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d30b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"],\"blockHeader\":\"0xf901f9a0a3e31eb259593976b3717142a5a9e90637f614d33e2ad13f01134ea00c24ca5aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a009e11c477e0a0dfdfe036492b9bce7131991eb23bcf9575f9bff1e4016f90447a0e1b1585a222beceb3887dc6701802facccf186c2d0f6aa69e26ae0c431fc2b5db9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424001833d090080830f424183010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8\"},\"id\":67}")] - [TestCase(false, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x9d335cdd632432bc4181dabfc07b9a614f1fcf9f0d2c0c1340e35a403875fdb1\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x0\",\"gasUsed\":\"0x0\",\"effectiveGasPrice\":\"0x1\",\"to\":null,\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86530b862f860800182a41094000000000000000000000000000000000000000001818026a0e4830571029d291f22478cbb60a04115f783fb687f9c3a98bf9d4a008f909817a010f0f7a1c274747616522ea29771cb026bf153362227563e2657d25fa57816bd\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d30b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"]},\"id\":67}")] - public async Task Can_get_receipt(bool withHeader, string expectedResult) + else { - Hash256 txHash = _blockTree.FindBlock(1)!.Transactions[0].Hash!; - ReceiptWithProof receiptWithProof = _proofRpcModule.proof_getTransactionReceipt(txHash, withHeader).Data; - Assert.NotNull(receiptWithProof.Receipt); - Assert.That(receiptWithProof.ReceiptProof.Length, Is.EqualTo(2)); + Assert.That(receiptWithProof.BlockHeader, Is.Null); + } - if (withHeader) - { - Assert.NotNull(receiptWithProof.BlockHeader); - } - else - { - Assert.Null(receiptWithProof.BlockHeader); - } + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); + response.Should().Be(expectedResult); + } - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); - response.Should().Be(expectedResult); - } + [TestCase(true, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"transactionIndex\":\"0x1\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x7d0\",\"gasUsed\":\"0x3e8\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"to\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x2\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x3\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86431b861f85f010182a410940000000000000000000000000000000000000000020126a0872929cb57ab6d88d0004a60f00df3dd9e0755860549aea25e559bce3d4a66dba01c06266ee2085ae815c258dd9dbb601bfc08c35c13b7cc9cd4ed88a16c3eb3f0\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d31b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"],\"blockHeader\":\"0xf901f9a0a3e31eb259593976b3717142a5a9e90637f614d33e2ad13f01134ea00c24ca5aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a009e11c477e0a0dfdfe036492b9bce7131991eb23bcf9575f9bff1e4016f90447a0e1b1585a222beceb3887dc6701802facccf186c2d0f6aa69e26ae0c431fc2b5db9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424001833d090080830f424183010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8\"},\"id\":67}")] + [TestCase(false, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"transactionIndex\":\"0x1\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x7d0\",\"gasUsed\":\"0x3e8\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"to\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x2\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x3\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86431b861f85f010182a410940000000000000000000000000000000000000000020126a0872929cb57ab6d88d0004a60f00df3dd9e0755860549aea25e559bce3d4a66dba01c06266ee2085ae815c258dd9dbb601bfc08c35c13b7cc9cd4ed88a16c3eb3f0\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d31b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"]},\"id\":67}")] + public async Task Get_receipt_when_block_has_few_receipts(bool withHeader, string expectedResult) + { + IReceiptFinder _receiptFinder = Substitute.For(); + LogEntry[] logEntries = new[] { Build.A.LogEntry.TestObject, Build.A.LogEntry.TestObject }; + + TxReceipt receipt1 = new TxReceipt() + { + Bloom = new Bloom(logEntries), + Index = 0, + Recipient = TestItem.AddressA, + Sender = TestItem.AddressB, + BlockHash = _blockTree.FindBlock(1)!.Hash, + BlockNumber = 1, + ContractAddress = TestItem.AddressC, + GasUsed = 1000, + TxHash = _blockTree.FindBlock(1)!.Transactions[0].Hash, + StatusCode = 0, + GasUsedTotal = 2000, + Logs = logEntries + }; + + TxReceipt receipt2 = new TxReceipt() + { + Bloom = new Bloom(logEntries), + Index = 1, + Recipient = TestItem.AddressC, + Sender = TestItem.AddressD, + BlockHash = _blockTree.FindBlock(1)!.Hash, + BlockNumber = 1, + ContractAddress = TestItem.AddressC, + GasUsed = 1000, + TxHash = _blockTree.FindBlock(1)!.Transactions[1].Hash, + StatusCode = 0, + GasUsedTotal = 2000, + Logs = logEntries + }; + + Block block = _blockTree.FindBlock(1)!; + Hash256 txHash = _blockTree.FindBlock(1)!.Transactions[1].Hash!; + TxReceipt[] receipts = { receipt1, receipt2 }; + _receiptFinder.Get(Arg.Any()).Returns(receipts); + _receiptFinder.Get(Arg.Any()).Returns(receipts); + _receiptFinder.FindBlockHash(Arg.Any()).Returns(_blockTree.FindBlock(1)!.Hash); + + ProofModuleFactory moduleFactory = new ProofModuleFactory( + _worldStateManager, + _blockTree, + new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(TestBlockchainIds.ChainId), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), + _receiptFinder, + _specProvider, + LimboLogs.Instance); + + _proofRpcModule = moduleFactory.Create(); + ReceiptWithProof receiptWithProof = _proofRpcModule.proof_getTransactionReceipt(txHash, withHeader).Data; + + if (withHeader) + { + Assert.That(receiptWithProof.BlockHeader, Is.Not.Null); + } + else + { + Assert.That(receiptWithProof.BlockHeader, Is.Null); + } + + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); + response.Should().Be(expectedResult); + } - [TestCase(true, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"transactionIndex\":\"0x1\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x7d0\",\"gasUsed\":\"0x3e8\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"to\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x2\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x3\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86431b861f85f010182a410940000000000000000000000000000000000000000020126a0872929cb57ab6d88d0004a60f00df3dd9e0755860549aea25e559bce3d4a66dba01c06266ee2085ae815c258dd9dbb601bfc08c35c13b7cc9cd4ed88a16c3eb3f0\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d31b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"],\"blockHeader\":\"0xf901f9a0a3e31eb259593976b3717142a5a9e90637f614d33e2ad13f01134ea00c24ca5aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a009e11c477e0a0dfdfe036492b9bce7131991eb23bcf9575f9bff1e4016f90447a0e1b1585a222beceb3887dc6701802facccf186c2d0f6aa69e26ae0c431fc2b5db9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424001833d090080830f424183010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8\"},\"id\":67}")] - [TestCase(false, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"transactionIndex\":\"0x1\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x7d0\",\"gasUsed\":\"0x3e8\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"to\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x2\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x3\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x4901390ae91e8a4286f7ae9053440c48eb5c2bca11ca83439f0088a4af90ceb8\",\"blockHash\":\"0xda4b917515655b1aabcc9b01125df34a76c6ebb3e7e2f2b060d4daa70d9f813d\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0eb9c9ef295ba68ff22c85763176dabc05773d58ef77ce34e4a23bf9516c706bc80808080808080a0850e08970f6beee9bd3687c74e591429cf6f65d5faf9db298ddc627ac4a26a1b8080808080808080\",\"0xf86431b861f85f010182a410940000000000000000000000000000000000000000020126a0872929cb57ab6d88d0004a60f00df3dd9e0755860549aea25e559bce3d4a66dba01c06266ee2085ae815c258dd9dbb601bfc08c35c13b7cc9cd4ed88a16c3eb3f0\"],\"receiptProof\":[\"0xf851a0460919cda4f025e4e91b9540e4a0fb8a2cf07e4ad8b2379a053efe2f98b1789980808080808080a0bc8717240b46db28e32bc834f8c34f4d70c2e9ba880eb68de904351fd5ef158f8080808080808080\",\"0xf9010d31b90109f901060180b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"]},\"id\":67}")] - public async Task Get_receipt_when_block_has_few_receipts(bool withHeader, string expectedResult) - { - IReceiptFinder _receiptFinder = Substitute.For(); - LogEntry[] logEntries = new[] { Build.A.LogEntry.TestObject, Build.A.LogEntry.TestObject }; + [TestCase] + public async Task Can_call() + { + WorldState stateProvider = CreateInitialState(null); - TxReceipt receipt1 = new TxReceipt() - { - Bloom = new Bloom(logEntries), - Index = 0, - Recipient = TestItem.AddressA, - Sender = TestItem.AddressB, - BlockHash = _blockTree.FindBlock(1)!.Hash, - BlockNumber = 1, - ContractAddress = TestItem.AddressC, - GasUsed = 1000, - TxHash = _blockTree.FindBlock(1)!.Transactions[0].Hash, - StatusCode = 0, - GasUsedTotal = 2000, - Logs = logEntries - }; - - TxReceipt receipt2 = new TxReceipt() - { - Bloom = new Bloom(logEntries), - Index = 1, - Recipient = TestItem.AddressC, - Sender = TestItem.AddressD, - BlockHash = _blockTree.FindBlock(1)!.Hash, - BlockNumber = 1, - ContractAddress = TestItem.AddressC, - GasUsed = 1000, - TxHash = _blockTree.FindBlock(1)!.Transactions[1].Hash, - StatusCode = 0, - GasUsedTotal = 2000, - Logs = logEntries - }; - - Block block = _blockTree.FindBlock(1)!; - Hash256 txHash = _blockTree.FindBlock(1)!.Transactions[1].Hash!; - TxReceipt[] receipts = { receipt1, receipt2 }; - _receiptFinder.Get(Arg.Any()).Returns(receipts); - _receiptFinder.Get(Arg.Any()).Returns(receipts); - _receiptFinder.FindBlockHash(Arg.Any()).Returns(_blockTree.FindBlock(1)!.Hash); - - ProofModuleFactory moduleFactory = new ProofModuleFactory( - _worldStateManager, - _blockTree, - new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(TestBlockchainIds.ChainId), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), - _receiptFinder, - _specProvider, - LimboLogs.Instance); - - _proofRpcModule = moduleFactory.Create(); - ReceiptWithProof receiptWithProof = _proofRpcModule.proof_getTransactionReceipt(txHash, withHeader).Data; - - if (withHeader) - { - Assert.NotNull(receiptWithProof.BlockHeader); - } - else - { - Assert.Null(receiptWithProof.BlockHeader); - } + Hash256 root = stateProvider.StateRoot; + Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).TestObject; + BlockTreeBuilder.AddBlock(_blockTree, block); - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); - response.Should().Be(expectedResult); - } + // would need to setup state root somehow... - [TestCase] - public async Task Can_call() + TransactionForRpc tx = new() { - WorldState stateProvider = CreateInitialState(null); + From = TestItem.AddressA, + To = TestItem.AddressB, + GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 + }; - Hash256 root = stateProvider.StateRoot; - Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).TestObject; - BlockTreeBuilder.AddBlock(_blockTree, block); + _proofRpcModule.proof_call(tx, new BlockParameter(block.Number)); - // would need to setup state root somehow... + EthereumJsonSerializer serializer = new(); + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{block.Number}"); + Assert.That(response.Contains("\"result\""), Is.True); + } - TransactionForRpc tx = new() - { - From = TestItem.AddressA, - To = TestItem.AddressB, - GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 - }; + [TestCase] + public async Task Can_call_by_hash() + { + WorldState stateProvider = CreateInitialState(null); - _proofRpcModule.proof_call(tx, new BlockParameter(block.Number)); + Hash256 root = stateProvider.StateRoot; + Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).TestObject; + BlockTreeBuilder.AddBlock(_blockTree, block); - EthereumJsonSerializer serializer = new(); - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{block.Number}"); - Assert.True(response.Contains("\"result\"")); - } + // would need to setup state root somehow... - [TestCase] - public async Task Can_call_by_hash() + TransactionForRpc tx = new() { - WorldState stateProvider = CreateInitialState(null); + From = TestItem.AddressA, + To = TestItem.AddressB, + GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 + }; + _proofRpcModule.proof_call(tx, new BlockParameter(block.Hash!)); - Hash256 root = stateProvider.StateRoot; - Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).TestObject; - BlockTreeBuilder.AddBlock(_blockTree, block); + EthereumJsonSerializer serializer = new(); + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{block.Hash}"); + Assert.That(response.Contains("\"result\""), Is.True); + } - // would need to setup state root somehow... + [TestCase] + public async Task Can_call_by_hash_canonical() + { + Block lastHead = _blockTree.Head!; + Block block = Build.A.Block.WithParent(lastHead).TestObject; + Block newBlockOnMain = Build.A.Block.WithParent(lastHead).WithDifficulty(block.Difficulty + 1).TestObject; + BlockTreeBuilder.AddBlock(_blockTree, block); + BlockTreeBuilder.AddBlock(_blockTree, newBlockOnMain); - TransactionForRpc tx = new() - { - From = TestItem.AddressA, - To = TestItem.AddressB, - GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 - }; - _proofRpcModule.proof_call(tx, new BlockParameter(block.Hash!)); - - EthereumJsonSerializer serializer = new(); - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{block.Hash}"); - Assert.True(response.Contains("\"result\"")); - } + // would need to setup state root somehow... - [TestCase] - public async Task Can_call_by_hash_canonical() + TransactionForRpc tx = new() { - Block lastHead = _blockTree.Head!; - Block block = Build.A.Block.WithParent(lastHead).TestObject; - Block newBlockOnMain = Build.A.Block.WithParent(lastHead).WithDifficulty(block.Difficulty + 1).TestObject; - BlockTreeBuilder.AddBlock(_blockTree, block); - BlockTreeBuilder.AddBlock(_blockTree, newBlockOnMain); + From = TestItem.AddressA, + To = TestItem.AddressB, + GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 + }; - // would need to setup state root somehow... + EthereumJsonSerializer serializer = new(); + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{{\"blockHash\" : \"{block.Hash}\", \"requireCanonical\" : true}}"); + Assert.That(response.Contains("-32000"), Is.True); - TransactionForRpc tx = new() - { - From = TestItem.AddressA, - To = TestItem.AddressB, - GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 - }; + response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{{\"blockHash\" : \"{TestItem.KeccakG}\", \"requireCanonical\" : true}}"); + Assert.That(response.Contains("-32001"), Is.True); + } - EthereumJsonSerializer serializer = new(); - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{{\"blockHash\" : \"{block.Hash}\", \"requireCanonical\" : true}}"); - Assert.True(response.Contains("-32000")); + [TestCase] + public async Task Can_call_with_block_hashes() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.BlockHeaders.Length, Is.EqualTo(2)); + } - response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{{\"blockHash\" : \"{TestItem.KeccakG}\", \"requireCanonical\" : true}}"); - Assert.True(response.Contains("-32001")); - } + [TestCase] + public async Task Can_call_with_many_block_hashes() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .PushData("0x02") + .Op(Instruction.BLOCKHASH) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.BlockHeaders.Length, Is.EqualTo(3)); + } - [TestCase] - public async Task Can_call_with_block_hashes() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.BlockHeaders.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_same_block_hash_many_time() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.BlockHeaders.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_many_block_hashes() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .PushData("0x02") - .Op(Instruction.BLOCKHASH) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.BlockHeaders.Length, Is.EqualTo(3)); - } + [TestCase] + public async Task Can_call_with_storage_load() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.SLOAD) + .Done; - [TestCase] - public async Task Can_call_with_same_block_hash_many_time() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.BlockHeaders.Length, Is.EqualTo(2)); - } + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_storage_load() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.SLOAD) - .Done; + [TestCase] + public async Task Can_call_with_many_storage_loads() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .Op(Instruction.SLOAD) + .PushData("0x02") + .Op(Instruction.SLOAD) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + } - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_storage_write() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .PushData("0x01") + .Op(Instruction.SSTORE) + .Done; + + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_many_storage_loads() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .Op(Instruction.SLOAD) - .PushData("0x02") - .Op(Instruction.SLOAD) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_extcodecopy() + { + byte[] code = Prepare.EvmCode + .PushData("0x20") + .PushData("0x00") + .PushData("0x00") + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODECOPY) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_storage_write() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .PushData("0x01") - .Op(Instruction.SSTORE) - .Done; - - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_extcodecopy_to_system_account() + { + byte[] code = Prepare.EvmCode + .PushData("0x20") + .PushData("0x00") + .PushData("0x00") + .PushData(Address.SystemUser) + .Op(Instruction.EXTCODECOPY) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_extcodecopy() - { - byte[] code = Prepare.EvmCode - .PushData("0x20") - .PushData("0x00") - .PushData("0x00") - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODECOPY) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_extcodesize() + { + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODESIZE) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_extcodecopy_to_system_account() - { - byte[] code = Prepare.EvmCode - .PushData("0x20") - .PushData("0x00") - .PushData("0x00") - .PushData(Address.SystemUser) - .Op(Instruction.EXTCODECOPY) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_extcodesize_to_system_account() + { + byte[] code = Prepare.EvmCode + .PushData(Address.SystemUser) + .Op(Instruction.EXTCODESIZE) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_extcodesize() - { - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODESIZE) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_extcodehash() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.EXTCODEHASH) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_extcodesize_to_system_account() - { - byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) - .Op(Instruction.EXTCODESIZE) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_extcodehash_to_system_account() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(Address.SystemUser) + .Op(Instruction.EXTCODEHASH) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_extcodehash() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.EXTCODEHASH) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_just_basic_addresses() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .Op(Instruction.STOP) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_extcodehash_to_system_account() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) - .Op(Instruction.EXTCODEHASH) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_balance() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.BALANCE) + .Done; + + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_just_basic_addresses() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .Op(Instruction.STOP) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_self_balance() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .Op(Instruction.SELFBALANCE) + .Done; - [TestCase] - public async Task Can_call_with_balance() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.BALANCE) - .Done; - - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_self_balance() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .Op(Instruction.SELFBALANCE) - .Done; + [TestCase] + public async Task Can_call_with_balance_of_system_account() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(Address.SystemUser) + .Op(Instruction.BALANCE) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_call_to_system_account_with_zero_value() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(Address.SystemUser) + .PushData(1000000) + .Op(Instruction.CALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_balance_of_system_account() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) - .Op(Instruction.BALANCE) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_static_call_to_system_account() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(Address.SystemUser) + .PushData(1000000) + .Op(Instruction.STATICCALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_call_to_system_account_with_zero_value() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(Address.SystemUser) - .PushData(1000000) - .Op(Instruction.CALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_delegate_call_to_system_account() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(Address.SystemUser) + .PushData(1000000) + .Op(Instruction.DELEGATECALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_static_call_to_system_account() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(Address.SystemUser) - .PushData(1000000) - .Op(Instruction.STATICCALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_call_to_system_account_with_non_zero_value() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(1) + .PushData(Address.SystemUser) + .PushData(1000000) + .Op(Instruction.CALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_delegate_call_to_system_account() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(Address.SystemUser) - .PushData(1000000) - .Op(Instruction.DELEGATECALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_call_with_zero_value() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(TestItem.AddressC) + .PushData(1000000) + .Op(Instruction.CALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_call_to_system_account_with_non_zero_value() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(1) - .PushData(Address.SystemUser) - .PushData(1000000) - .Op(Instruction.CALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_static_call() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(TestItem.AddressC) + .PushData(1000000) + .Op(Instruction.STATICCALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_call_with_zero_value() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(TestItem.AddressC) - .PushData(1000000) - .Op(Instruction.CALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_delegate_call() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(TestItem.AddressC) + .PushData(1000000) + .Op(Instruction.DELEGATECALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(_createSystemAccount && _useNonZeroGasPrice ? 3 : 2)); + } - [TestCase] - public async Task Can_call_with_static_call() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(TestItem.AddressC) - .PushData(1000000) - .Op(Instruction.STATICCALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_call_with_non_zero_value() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(0) + .PushData(1) + .PushData(TestItem.AddressC) + .PushData(1000000) + .Op(Instruction.CALL) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_delegate_call() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(TestItem.AddressC) - .PushData(1000000) - .Op(Instruction.DELEGATECALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(_createSystemAccount && _useNonZeroGasPrice ? 3 : 2)); - } + [TestCase] + public async Task Can_call_with_self_destruct() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.SELFDESTRUCT) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + + Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + } - [TestCase] - public async Task Can_call_with_call_with_non_zero_value() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(0) - .PushData(1) - .PushData(TestItem.AddressC) - .PushData(1000000) - .Op(Instruction.CALL) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_self_destruct_to_system_account() + { + _specProvider.SpecToReturn = MuirGlacier.Instance; + byte[] code = Prepare.EvmCode + .PushData(Address.SystemUser) + .Op(Instruction.SELFDESTRUCT) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); + } - [TestCase] - public async Task Can_call_with_self_destruct() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.SELFDESTRUCT) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); - } - [TestCase] - public async Task Can_call_with_self_destruct_to_system_account() - { - _specProvider.SpecToReturn = MuirGlacier.Instance; - byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) - .Op(Instruction.SELFDESTRUCT) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2)); - } + [TestCase] + public async Task Can_call_with_many_storage_writes() + { + byte[] code = Prepare.EvmCode + .PushData("0x01") + .PushData("0x01") + .Op(Instruction.SSTORE) + .PushData("0x02") + .PushData("0x02") + .Op(Instruction.SSTORE) + .Done; + CallResultWithProof result = await TestCallWithCode(code); + Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + } + [TestCase] + public async Task Can_call_with_mix_of_everything() + { + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.BALANCE) + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .PushData("0x02") + .Op(Instruction.BLOCKHASH) + .PushData("0x01") + .Op(Instruction.SLOAD) + .PushData("0x02") + .Op(Instruction.SLOAD) + .PushData("0x01") + .PushData("0x01") + .Op(Instruction.SSTORE) + .PushData("0x03") + .PushData("0x03") + .Op(Instruction.SSTORE) + .Done; + + await TestCallWithCode(code); + } - [TestCase] - public async Task Can_call_with_many_storage_writes() - { - byte[] code = Prepare.EvmCode - .PushData("0x01") - .PushData("0x01") - .Op(Instruction.SSTORE) - .PushData("0x02") - .PushData("0x02") - .Op(Instruction.SSTORE) - .Done; - CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); - } + [TestCase] + public async Task Can_call_with_mix_of_everything_and_storage() + { + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.BALANCE) + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .PushData("0x02") + .Op(Instruction.BLOCKHASH) + .PushData("0x01") + .Op(Instruction.SLOAD) + .PushData("0x02") + .Op(Instruction.SLOAD) + .PushData("0x01") + .PushData("0x01") + .Op(Instruction.SSTORE) + .PushData("0x03") + .PushData("0x03") + .Op(Instruction.SSTORE) + .Done; + + await TestCallWithStorageAndCode(code, _useNonZeroGasPrice ? 10.GWei() : 0); + } - [TestCase] - public async Task Can_call_with_mix_of_everything() - { - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.BALANCE) - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .PushData("0x02") - .Op(Instruction.BLOCKHASH) - .PushData("0x01") - .Op(Instruction.SLOAD) - .PushData("0x02") - .Op(Instruction.SLOAD) - .PushData("0x01") - .PushData("0x01") - .Op(Instruction.SSTORE) - .PushData("0x03") - .PushData("0x03") - .Op(Instruction.SSTORE) - .Done; - - await TestCallWithCode(code); - } + [TestCase] + public async Task Can_call_with_mix_of_everything_and_storage_from_another_account_wrong_nonce() + { + byte[] code = Prepare.EvmCode + .PushData(TestItem.AddressC) + .Op(Instruction.BALANCE) + .PushData("0x01") + .Op(Instruction.BLOCKHASH) + .PushData("0x02") + .Op(Instruction.BLOCKHASH) + .PushData("0x01") + .Op(Instruction.SLOAD) + .PushData("0x02") + .Op(Instruction.SLOAD) + .PushData("0x01") + .PushData("0x01") + .Op(Instruction.SSTORE) + .PushData("0x03") + .PushData("0x03") + .Op(Instruction.SSTORE) + .Done; + + await TestCallWithStorageAndCode(code, 0, TestItem.AddressD); + } - [TestCase] - public async Task Can_call_with_mix_of_everything_and_storage() - { - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.BALANCE) - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .PushData("0x02") - .Op(Instruction.BLOCKHASH) - .PushData("0x01") - .Op(Instruction.SLOAD) - .PushData("0x02") - .Op(Instruction.SLOAD) - .PushData("0x01") - .PushData("0x01") - .Op(Instruction.SSTORE) - .PushData("0x03") - .PushData("0x03") - .Op(Instruction.SSTORE) - .Done; - - await TestCallWithStorageAndCode(code, _useNonZeroGasPrice ? 10.GWei() : 0); - } + private async Task TestCallWithCode(byte[] code, Address? from = null) + { + WorldState stateProvider = CreateInitialState(code); - [TestCase] - public async Task Can_call_with_mix_of_everything_and_storage_from_another_account_wrong_nonce() - { - byte[] code = Prepare.EvmCode - .PushData(TestItem.AddressC) - .Op(Instruction.BALANCE) - .PushData("0x01") - .Op(Instruction.BLOCKHASH) - .PushData("0x02") - .Op(Instruction.BLOCKHASH) - .PushData("0x01") - .Op(Instruction.SLOAD) - .PushData("0x02") - .Op(Instruction.SLOAD) - .PushData("0x01") - .PushData("0x01") - .Op(Instruction.SSTORE) - .PushData("0x03") - .PushData("0x03") - .Op(Instruction.SSTORE) - .Done; - - await TestCallWithStorageAndCode(code, 0, TestItem.AddressD); - } + Hash256 root = stateProvider.StateRoot; + Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).WithBeneficiary(TestItem.AddressD).TestObject; + BlockTreeBuilder.AddBlock(_blockTree, block); + Block blockOnTop = Build.A.Block.WithParent(block).WithStateRoot(root).WithBeneficiary(TestItem.AddressD).TestObject; + BlockTreeBuilder.AddBlock(_blockTree, blockOnTop); - private async Task TestCallWithCode(byte[] code, Address? from = null) - { - WorldState stateProvider = CreateInitialState(code); + // would need to setup state root somehow... - Hash256 root = stateProvider.StateRoot; - Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).WithBeneficiary(TestItem.AddressD).TestObject; - BlockTreeBuilder.AddBlock(_blockTree, block); - Block blockOnTop = Build.A.Block.WithParent(block).WithStateRoot(root).WithBeneficiary(TestItem.AddressD).TestObject; - BlockTreeBuilder.AddBlock(_blockTree, blockOnTop); + TransactionForRpc tx = new() + { + From = from, + To = TestItem.AddressB, + GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 + }; - // would need to setup state root somehow... + CallResultWithProof callResultWithProof = _proofRpcModule.proof_call(tx, new BlockParameter(blockOnTop.Number)).Data; + Assert.That(callResultWithProof.Accounts.Length, Is.GreaterThan(0)); - TransactionForRpc tx = new() + foreach (AccountProof accountProof in callResultWithProof.Accounts) + { + ProofVerifier.VerifyOneProof(accountProof.Proof!, block.StateRoot!); + foreach (StorageProof storageProof in accountProof.StorageProofs!) { - From = from, - To = TestItem.AddressB, - GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 - }; + ProofVerifier.VerifyOneProof(storageProof.Proof!, accountProof.StorageRoot); + } + } - CallResultWithProof callResultWithProof = _proofRpcModule.proof_call(tx, new BlockParameter(blockOnTop.Number)).Data; - Assert.Greater(callResultWithProof.Accounts.Length, 0); + EthereumJsonSerializer serializer = new(); + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{blockOnTop.Number}"); + Assert.That(response.Contains("\"result\""), Is.True); - foreach (AccountProof accountProof in callResultWithProof.Accounts) - { - ProofVerifier.VerifyOneProof(accountProof.Proof!, block.StateRoot!); - foreach (StorageProof storageProof in accountProof.StorageProofs!) - { - ProofVerifier.VerifyOneProof(storageProof.Proof!, accountProof.StorageRoot); - } - } + return callResultWithProof; + } - EthereumJsonSerializer serializer = new(); - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{blockOnTop.Number}"); - Assert.True(response.Contains("\"result\"")); + private async Task TestCallWithStorageAndCode(byte[] code, UInt256 gasPrice, Address? from = null) + { + WorldState stateProvider = CreateInitialState(code); - return callResultWithProof; + for (int i = 0; i < 10000; i++) + { + stateProvider.Set(new StorageCell(TestItem.AddressB, (UInt256)i), i.ToBigEndianByteArray()); } - private async Task TestCallWithStorageAndCode(byte[] code, UInt256 gasPrice, Address? from = null) - { - WorldState stateProvider = CreateInitialState(code); + stateProvider.Commit(MainnetSpecProvider.Instance.GenesisSpec, NullStateTracer.Instance); + stateProvider.CommitTree(0); - for (int i = 0; i < 10000; i++) - { - stateProvider.Set(new StorageCell(TestItem.AddressB, (UInt256)i), i.ToBigEndianByteArray()); - } + Hash256 root = stateProvider.StateRoot; - stateProvider.Commit(MainnetSpecProvider.Instance.GenesisSpec, NullStateTracer.Instance); - stateProvider.CommitTree(0); + Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).TestObject; + BlockTreeBuilder.AddBlock(_blockTree, block); + Block blockOnTop = Build.A.Block.WithParent(block).WithStateRoot(root).TestObject; + BlockTreeBuilder.AddBlock(_blockTree, blockOnTop); - Hash256 root = stateProvider.StateRoot; + // would need to setup state root somehow... - Block block = Build.A.Block.WithParent(_blockTree.Head!).WithStateRoot(root).TestObject; - BlockTreeBuilder.AddBlock(_blockTree, block); - Block blockOnTop = Build.A.Block.WithParent(block).WithStateRoot(root).TestObject; - BlockTreeBuilder.AddBlock(_blockTree, blockOnTop); + TransactionForRpc tx = new() + { + // we are testing system transaction here when From is null + From = from, + To = TestItem.AddressB, + GasPrice = gasPrice, + Nonce = 1000 + }; - // would need to setup state root somehow... + CallResultWithProof callResultWithProof = _proofRpcModule.proof_call(tx, new BlockParameter(blockOnTop.Number)).Data; + Assert.That(callResultWithProof.Accounts.Length, Is.GreaterThan(0)); - TransactionForRpc tx = new() - { - // we are testing system transaction here when From is null - From = from, - To = TestItem.AddressB, - GasPrice = gasPrice, - Nonce = 1000 - }; - - CallResultWithProof callResultWithProof = _proofRpcModule.proof_call(tx, new BlockParameter(blockOnTop.Number)).Data; - Assert.Greater(callResultWithProof.Accounts.Length, 0); - - // just the keys for debugging - byte[] span = new byte[32]; - new UInt256(0).ToBigEndian(span); - Hash256 unused = Keccak.Compute(span); - - // just the keys for debugging - new UInt256(1).ToBigEndian(span); - Hash256 unused1 = Keccak.Compute(span); - - // just the keys for debugging - new UInt256(2).ToBigEndian(span); - Hash256 unused2 = Keccak.Compute(span); - - foreach (AccountProof accountProof in callResultWithProof.Accounts) - { - // this is here for diagnostics - so you can read what happens in the test - // generally the account here should be consistent with the values inside the proof - // the exception will be thrown if the account did not exist before the call - try - { - CappedArray verifyOneProof = ProofVerifier.VerifyOneProof(accountProof.Proof!, block.StateRoot!); - new AccountDecoder().Decode(verifyOneProof.AsSpan()); - } - catch (Exception) - { - // ignored - } - - foreach (StorageProof storageProof in accountProof.StorageProofs!) - { - // we read the values here just to allow easier debugging so you can confirm that the value is same as the one in the proof and in the trie - ProofVerifier.VerifyOneProof(storageProof.Proof!, accountProof.StorageRoot); - } - } + // just the keys for debugging + byte[] span = new byte[32]; + new UInt256(0).ToBigEndian(span); + Hash256 unused = Keccak.Compute(span); - EthereumJsonSerializer serializer = new(); - string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{blockOnTop.Number}"); - Assert.True(response.Contains("\"result\"")); - } + // just the keys for debugging + new UInt256(1).ToBigEndian(span); + Hash256 unused1 = Keccak.Compute(span); - private WorldState CreateInitialState(byte[]? code) - { - WorldState stateProvider = new(new TrieStore(_dbProvider.StateDb, LimboLogs.Instance), _dbProvider.CodeDb, LimboLogs.Instance); - AddAccount(stateProvider, TestItem.AddressA, 1.Ether()); - AddAccount(stateProvider, TestItem.AddressB, 1.Ether()); + // just the keys for debugging + new UInt256(2).ToBigEndian(span); + Hash256 unused2 = Keccak.Compute(span); - if (code is not null) + foreach (AccountProof accountProof in callResultWithProof.Accounts) + { + // this is here for diagnostics - so you can read what happens in the test + // generally the account here should be consistent with the values inside the proof + // the exception will be thrown if the account did not exist before the call + try + { + CappedArray verifyOneProof = ProofVerifier.VerifyOneProof(accountProof.Proof!, block.StateRoot!); + new AccountDecoder().Decode(verifyOneProof.AsSpan()); + } + catch (Exception) { - AddCode(stateProvider, TestItem.AddressB, code); + // ignored } - if (_createSystemAccount) + foreach (StorageProof storageProof in accountProof.StorageProofs!) { - AddAccount(stateProvider, Address.SystemUser, 1.Ether()); + // we read the values here just to allow easier debugging so you can confirm that the value is same as the one in the proof and in the trie + ProofVerifier.VerifyOneProof(storageProof.Proof!, accountProof.StorageRoot); } + } - stateProvider.CommitTree(0); + EthereumJsonSerializer serializer = new(); + string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_call", $"{serializer.Serialize(tx)}", $"{blockOnTop.Number}"); + Assert.That(response.Contains("\"result\""), Is.True); + } - return stateProvider; - } + private WorldState CreateInitialState(byte[]? code) + { + WorldState stateProvider = new(new TrieStore(_dbProvider.StateDb, LimboLogs.Instance), _dbProvider.CodeDb, LimboLogs.Instance); + AddAccount(stateProvider, TestItem.AddressA, 1.Ether()); + AddAccount(stateProvider, TestItem.AddressB, 1.Ether()); - private void AddAccount(WorldState stateProvider, Address account, UInt256 initialBalance) + if (code is not null) { - stateProvider.CreateAccount(account, initialBalance); - stateProvider.Commit(MuirGlacier.Instance, NullStateTracer.Instance); + AddCode(stateProvider, TestItem.AddressB, code); } - private void AddCode(WorldState stateProvider, Address account, byte[] code) + if (_createSystemAccount) { - stateProvider.InsertCode(account, code, MuirGlacier.Instance); - stateProvider.Commit(MainnetSpecProvider.Instance.GenesisSpec, NullStateTracer.Instance); + AddAccount(stateProvider, Address.SystemUser, 1.Ether()); } + + stateProvider.CommitTree(0); + + return stateProvider; + } + + private void AddAccount(WorldState stateProvider, Address account, UInt256 initialBalance) + { + stateProvider.CreateAccount(account, initialBalance); + stateProvider.Commit(MuirGlacier.Instance, NullStateTracer.Instance); + } + + private void AddCode(WorldState stateProvider, Address account, byte[] code) + { + stateProvider.InsertCode(account, code, MuirGlacier.Instance); + stateProvider.Commit(MainnetSpecProvider.Instance.GenesisSpec, NullStateTracer.Instance); } } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs index e34f98389d9..f9b10675107 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs @@ -8,7 +8,6 @@ using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; -using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Rewards; @@ -26,110 +25,106 @@ using Nethermind.Logging; using Nethermind.Specs; using Nethermind.State; -using Nethermind.State.Repositories; -using Nethermind.Db.Blooms; using Nethermind.TxPool; using NUnit.Framework; using Nethermind.Evm.TransactionProcessing; using Nethermind.Trie.Pruning; using NSubstitute; -namespace Nethermind.JsonRpc.Test.Modules.Trace +namespace Nethermind.JsonRpc.Test.Modules.Trace; + +[Parallelizable(ParallelScope.Self)] +public class ParityStyleTracerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class ParityStyleTracerTests + private BlockchainProcessor? _processor; + private BlockTree? _blockTree; + private Tracer? _tracer; + private IPoSSwitcher? _poSSwitcher; + private IStateReader _stateReader; + private readonly IJsonRpcConfig _jsonRpcConfig = new JsonRpcConfig(); + + [SetUp] + public void Setup() { - private BlockchainProcessor? _processor; - private BlockTree? _blockTree; - private Tracer? _tracer; - private IPoSSwitcher? _poSSwitcher; - private IStateReader _stateReader; - private readonly IJsonRpcConfig _jsonRpcConfig = new JsonRpcConfig(); - - [SetUp] - public void Setup() - { - ISpecProvider specProvider = MainnetSpecProvider.Instance; - - _blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithSpecProvider(specProvider) - .TestObject; - - MemDb stateDb = new(); - MemDb codeDb = new(); - ITrieStore trieStore = new TrieStore(stateDb, LimboLogs.Instance).AsReadOnly(); - WorldState stateProvider = new(trieStore, codeDb, LimboLogs.Instance); - _stateReader = new StateReader(trieStore, codeDb, LimboLogs.Instance); - - BlockhashProvider blockhashProvider = new(_blockTree, specProvider, stateProvider, LimboLogs.Instance); - CodeInfoRepository codeInfoRepository = new(); - VirtualMachine virtualMachine = new(blockhashProvider, specProvider, codeInfoRepository, LimboLogs.Instance); - TransactionProcessor transactionProcessor = new(specProvider, stateProvider, virtualMachine, codeInfoRepository, LimboLogs.Instance); - - _poSSwitcher = Substitute.For(); - BlockProcessor blockProcessor = new( - specProvider, - Always.Valid, - new MergeRpcRewardCalculator(NoBlockRewards.Instance, _poSSwitcher), - new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), - stateProvider, - NullReceiptStorage.Instance, - transactionProcessor, - new BeaconBlockRootHandler(transactionProcessor), - new BlockhashStore(specProvider, stateProvider), - LimboLogs.Instance); - - RecoverSignatures txRecovery = new(new EthereumEcdsa(TestBlockchainIds.ChainId), NullTxPool.Instance, specProvider, LimboLogs.Instance); - _processor = new BlockchainProcessor(_blockTree, blockProcessor, txRecovery, _stateReader, LimboLogs.Instance, BlockchainProcessor.Options.NoReceipts); - - Block genesis = Build.A.Block.Genesis.TestObject; - _blockTree.SuggestBlock(genesis); - _processor.Process(genesis, ProcessingOptions.None, NullBlockTracer.Instance); - - _tracer = new Tracer(stateProvider, _processor, _processor); - } + ISpecProvider specProvider = MainnetSpecProvider.Instance; - [TearDown] - public void TearDown() => _processor?.Dispose(); + _blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithSpecProvider(specProvider) + .TestObject; - [Test] - public void Can_trace_raw_parity_style() - { - TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); - ResultWrapper result = traceRpcModule.trace_rawTransaction(Bytes.FromHexString("f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f"), new[] { "trace" }); - Assert.NotNull(result.Data); - } + MemDb stateDb = new(); + MemDb codeDb = new(); + ITrieStore trieStore = new TrieStore(stateDb, LimboLogs.Instance).AsReadOnly(); + WorldState stateProvider = new(trieStore, codeDb, LimboLogs.Instance); + _stateReader = new StateReader(trieStore, codeDb, LimboLogs.Instance); + + BlockhashProvider blockhashProvider = new(_blockTree, specProvider, stateProvider, LimboLogs.Instance); + CodeInfoRepository codeInfoRepository = new(); + VirtualMachine virtualMachine = new(blockhashProvider, specProvider, codeInfoRepository, LimboLogs.Instance); + TransactionProcessor transactionProcessor = new(specProvider, stateProvider, virtualMachine, codeInfoRepository, LimboLogs.Instance); + + _poSSwitcher = Substitute.For(); + BlockProcessor blockProcessor = new( + specProvider, + Always.Valid, + new MergeRpcRewardCalculator(NoBlockRewards.Instance, _poSSwitcher), + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), + stateProvider, + NullReceiptStorage.Instance, + transactionProcessor, + new BeaconBlockRootHandler(transactionProcessor), + new BlockhashStore(specProvider, stateProvider), + LimboLogs.Instance); + + RecoverSignatures txRecovery = new(new EthereumEcdsa(TestBlockchainIds.ChainId), NullTxPool.Instance, specProvider, LimboLogs.Instance); + _processor = new BlockchainProcessor(_blockTree, blockProcessor, txRecovery, _stateReader, LimboLogs.Instance, BlockchainProcessor.Options.NoReceipts); + + Block genesis = Build.A.Block.Genesis.TestObject; + _blockTree.SuggestBlock(genesis); + _processor.Process(genesis, ProcessingOptions.None, NullBlockTracer.Instance); + + _tracer = new Tracer(stateProvider, _processor, _processor); + } + + [TearDown] + public void TearDown() => _processor?.Dispose(); + + [Test] + public void Can_trace_raw_parity_style() + { + TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); + ResultWrapper result = traceRpcModule.trace_rawTransaction(Bytes.FromHexString("f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f"), new[] { "trace" }); + Assert.That(result.Data, Is.Not.Null); + } - [Test] - public void Can_trace_raw_parity_style_berlin_tx() + [Test] + public void Can_trace_raw_parity_style_berlin_tx() + { + TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); + ResultWrapper result = traceRpcModule.trace_rawTransaction(Bytes.FromHexString("01f85b821e8e8204d7847735940083030d408080853a60005500c080a0f43e70c79190701347517e283ef63753f6143a5225cbb500b14d98eadfb7616ba070893923d8a1fc97499f426524f9e82f8e0322dfac7c3d7e8a9eee515f0bcdc4"), new[] { "trace" }); + Assert.That(result.Data, Is.Not.Null); + } + + [TestCase(true)] + [TestCase(false)] + public void Should_return_correct_block_reward(bool isPostMerge) + { + Block block = Build.A.Block.WithParent(Build.A.Block.Genesis.TestObject).TestObject; + _blockTree!.SuggestBlock(block).Should().Be(AddBlockResult.Added); + _poSSwitcher!.IsPostMerge(Arg.Any()).Returns(isPostMerge); + + TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); + ParityTxTraceFromStore[] result = traceRpcModule.trace_block(new BlockParameter(block.Number)).Data.ToArray(); + if (isPostMerge) { - TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); - ResultWrapper result = traceRpcModule.trace_rawTransaction(Bytes.FromHexString("01f85b821e8e8204d7847735940083030d408080853a60005500c080a0f43e70c79190701347517e283ef63753f6143a5225cbb500b14d98eadfb7616ba070893923d8a1fc97499f426524f9e82f8e0322dfac7c3d7e8a9eee515f0bcdc4"), new[] { "trace" }); - Assert.NotNull(result.Data); + result.Length.Should().Be(1); + result[0].Action.Author.Should().Be(block.Beneficiary!); + result[0].Action.Value.Should().Be(0); } - - [TestCase(true)] - [TestCase(false)] - public void Should_return_correct_block_reward(bool isPostMerge) + else { - Block block = Build.A.Block.WithParent(Build.A.Block.Genesis.TestObject).TestObject; - _blockTree!.SuggestBlock(block).Should().Be(AddBlockResult.Added); - _poSSwitcher!.IsPostMerge(Arg.Any()).Returns(isPostMerge); - - TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); - ParityTxTraceFromStore[] result = traceRpcModule.trace_block(new BlockParameter(block.Number)).Data.ToArray(); - if (isPostMerge) - { - result.Length.Should().Be(1); - result[0].Action.Author.Should().Be(block.Beneficiary!); - result[0].Action.Value.Should().Be(0); - } - else - { - result.Length.Should().Be(0); - } + result.Length.Should().Be(0); } } } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index 966b34dfb53..6b264462616 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -33,7 +33,6 @@ namespace Nethermind.JsonRpc.Test.Modules; -[TestFixture] public class TraceRpcModuleTests { private class Context @@ -584,7 +583,7 @@ public async Task Trace_replayTransaction_test() Assert.That(traces.Data.Action!.From, Is.EqualTo(TestItem.AddressB)); Assert.That(traces.Data.Action.To, Is.EqualTo(TestItem.AddressC)); Assert.That(traces.Data.Action.CallType, Is.EqualTo("call")); - Assert.IsTrue(traces.Result.ResultType == ResultType.Success); + Assert.That(traces.Result.ResultType == ResultType.Success, Is.True); } [Test] @@ -612,7 +611,7 @@ public async Task Trace_replayTransaction_reward_test() ResultWrapper traces = context.TraceRpcModule.trace_replayTransaction(transaction.Hash!, traceTypes); Assert.That(traces.Data.Action!.CallType, Is.EqualTo("reward")); Assert.That(traces.Data.Action.Value, Is.EqualTo(UInt256.Parse("2000000000000000000"))); - Assert.IsTrue(traces.Result.ResultType == ResultType.Success); + Assert.That(traces.Result.ResultType == ResultType.Success, Is.True); } [Test] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/StandardConfigTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/StandardConfigTests.cs index 342412553e5..8554db4e7e1 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/StandardConfigTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/StandardConfigTests.cs @@ -23,7 +23,7 @@ private static void ForEachMethod(Action verifier) .OrderBy(n => n).ToArray(); foreach (string dll in dlls) { - TestContext.WriteLine($"Verifying {nameof(StandardJsonRpcTests)} on {Path.GetFileName(dll)}"); + TestContext.Out.WriteLine($"Verifying {nameof(StandardJsonRpcTests)} on {Path.GetFileName(dll)}"); Assembly assembly = Assembly.LoadFile(dll); Type[] modules = assembly.GetExportedTypes().Where(FilterTypes).ToArray(); diff --git a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcLocalStats.cs b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcLocalStats.cs index 160adfd1082..1e1431b75f6 100644 --- a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcLocalStats.cs +++ b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcLocalStats.cs @@ -3,25 +3,24 @@ using System.Threading.Tasks; -namespace Nethermind.JsonRpc +namespace Nethermind.JsonRpc; + +public class MethodStats { - public class MethodStats - { - public int Successes { get; set; } - public int Errors { get; set; } - public decimal AvgTimeOfErrors { get; set; } - public decimal AvgTimeOfSuccesses { get; set; } - public long MaxTimeOfError { get; set; } - public long MaxTimeOfSuccess { get; set; } - public decimal TotalSize { get; set; } - public decimal AvgSize => Calls == 0 ? 0 : TotalSize / Calls; - public int Calls => Successes + Errors; - } + public int Successes { get; set; } + public int Errors { get; set; } + public decimal AvgTimeOfErrors { get; set; } + public decimal AvgTimeOfSuccesses { get; set; } + public long MaxTimeOfError { get; set; } + public long MaxTimeOfSuccess { get; set; } + public decimal TotalSize { get; set; } + public decimal AvgSize => Calls == 0 ? 0 : TotalSize / Calls; + public int Calls => Successes + Errors; +} - public interface IJsonRpcLocalStats - { - Task ReportCall(RpcReport report, long elapsedMicroseconds = 0, long? size = null); +public interface IJsonRpcLocalStats +{ + Task ReportCall(RpcReport report, long elapsedMicroseconds = 0, long? size = null); - MethodStats GetMethodStats(string methodName); - } + MethodStats GetMethodStats(string methodName); } diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcLocalStats.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcLocalStats.cs index adb920c7675..c258777700e 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcLocalStats.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcLocalStats.cs @@ -12,180 +12,179 @@ using Nethermind.Core; using Nethermind.Logging; -namespace Nethermind.JsonRpc +namespace Nethermind.JsonRpc; + +public class JsonRpcLocalStats : IJsonRpcLocalStats { - public class JsonRpcLocalStats : IJsonRpcLocalStats + private readonly ITimestamper _timestamper; + private readonly TimeSpan _reportingInterval; + private ConcurrentDictionary _currentStats = new(); + private ConcurrentDictionary _previousStats = new(); + private readonly ConcurrentDictionary _allTimeStats = new(); + private DateTime _lastReport; + private readonly ILogger _logger; + private readonly StringBuilder _reportStringBuilder = new(); + + public JsonRpcLocalStats(ITimestamper timestamper, IJsonRpcConfig jsonRpcConfig, ILogManager logManager) { - private readonly ITimestamper _timestamper; - private readonly TimeSpan _reportingInterval; - private ConcurrentDictionary _currentStats = new(); - private ConcurrentDictionary _previousStats = new(); - private readonly ConcurrentDictionary _allTimeStats = new(); - private DateTime _lastReport; - private readonly ILogger _logger; - private readonly StringBuilder _reportStringBuilder = new(); - - public JsonRpcLocalStats(ITimestamper timestamper, IJsonRpcConfig jsonRpcConfig, ILogManager logManager) + _timestamper = timestamper ?? throw new ArgumentNullException(nameof(timestamper)); + _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); + _reportingInterval = TimeSpan.FromSeconds(jsonRpcConfig.ReportIntervalSeconds); + _lastReport = timestamper.UtcNow; + } + + public MethodStats GetMethodStats(string methodName) => _allTimeStats.GetValueOrDefault(methodName, new MethodStats()); + + public Task ReportCall(string method, long handlingTimeMicroseconds, bool success) => + ReportCall(new RpcReport(method, handlingTimeMicroseconds, success)); + + public Task ReportCall(RpcReport report, long elapsedMicroseconds = 0, long? size = null) + { + if (string.IsNullOrWhiteSpace(report.Method)) + { + return Task.CompletedTask; + } + + if (!_logger.IsInfo) { - _timestamper = timestamper ?? throw new ArgumentNullException(nameof(timestamper)); - _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - _reportingInterval = TimeSpan.FromSeconds(jsonRpcConfig.ReportIntervalSeconds); - _lastReport = timestamper.UtcNow; + return Task.CompletedTask; } - public MethodStats GetMethodStats(string methodName) => _allTimeStats.GetValueOrDefault(methodName, new MethodStats()); + return ReportCallInternal(report, elapsedMicroseconds, size); + } + + private async Task ReportCallInternal(RpcReport report, long elapsedMicroseconds, long? size) + { + // we don't want to block RPC calls any longer than required + await Task.Yield(); + + BuildReport(); + + MethodStats methodStats = _currentStats.GetOrAdd(report.Method, _ => new MethodStats()); + MethodStats allTimeMethodStats = _allTimeStats.GetOrAdd(report.Method, _ => new MethodStats()); - public Task ReportCall(string method, long handlingTimeMicroseconds, bool success) => - ReportCall(new RpcReport(method, handlingTimeMicroseconds, success)); + long reportHandlingTimeMicroseconds = elapsedMicroseconds == 0 ? report.HandlingTimeMicroseconds : elapsedMicroseconds; - public Task ReportCall(RpcReport report, long elapsedMicroseconds = 0, long? size = null) + decimal sizeDec = size ?? 0; + + lock (methodStats) { - if (string.IsNullOrWhiteSpace(report.Method)) + if (report.Success) { - return Task.CompletedTask; + methodStats.AvgTimeOfSuccesses = + (methodStats.Successes * methodStats.AvgTimeOfSuccesses + reportHandlingTimeMicroseconds) / + ++methodStats.Successes; + methodStats.MaxTimeOfSuccess = + Math.Max(methodStats.MaxTimeOfSuccess, reportHandlingTimeMicroseconds); + + allTimeMethodStats.AvgTimeOfSuccesses = + (allTimeMethodStats.Successes * allTimeMethodStats.AvgTimeOfSuccesses + + reportHandlingTimeMicroseconds) / + ++allTimeMethodStats.Successes; + allTimeMethodStats.MaxTimeOfSuccess = + Math.Max(allTimeMethodStats.MaxTimeOfSuccess, reportHandlingTimeMicroseconds); } - - if (!_logger.IsInfo) + else { - return Task.CompletedTask; + methodStats.AvgTimeOfErrors = + (methodStats.Errors * methodStats.AvgTimeOfErrors + reportHandlingTimeMicroseconds) / + ++methodStats.Errors; + methodStats.MaxTimeOfError = Math.Max(methodStats.MaxTimeOfError, reportHandlingTimeMicroseconds); + + allTimeMethodStats.AvgTimeOfErrors = + (allTimeMethodStats.Errors * allTimeMethodStats.AvgTimeOfErrors + reportHandlingTimeMicroseconds) / + ++allTimeMethodStats.Errors; + allTimeMethodStats.MaxTimeOfError = Math.Max(allTimeMethodStats.MaxTimeOfError, reportHandlingTimeMicroseconds); } - return ReportCallInternal(report, elapsedMicroseconds, size); + methodStats.TotalSize += sizeDec; + allTimeMethodStats.TotalSize += sizeDec; } + } - private async Task ReportCallInternal(RpcReport report, long elapsedMicroseconds, long? size) - { - // we don't want to block RPC calls any longer than required - await Task.Yield(); - - BuildReport(); - - MethodStats methodStats = _currentStats.GetOrAdd(report.Method, _ => new MethodStats()); - MethodStats allTimeMethodStats = _allTimeStats.GetOrAdd(report.Method, _ => new MethodStats()); + private const string ReportHeader = "method | " + + "successes | " + + " avg (ms) | " + + " max (ms) | " + + " errors | " + + " avg (ms) | " + + " max (ms) |" + + " avg size B |" + + " total (kB) |"; - long reportHandlingTimeMicroseconds = elapsedMicroseconds == 0 ? report.HandlingTimeMicroseconds : elapsedMicroseconds; + private static readonly string _divider = new('-', ReportHeader.Length); - decimal sizeDec = size ?? 0; + private void BuildReport() + { + DateTime thisTime = _timestamper.UtcNow; + if (thisTime - _lastReport <= _reportingInterval) + { + return; + } - lock (methodStats) + lock (_logger.UnderlyingLogger) + { + if (thisTime - _lastReport <= _reportingInterval) { - if (report.Success) - { - methodStats.AvgTimeOfSuccesses = - (methodStats.Successes * methodStats.AvgTimeOfSuccesses + reportHandlingTimeMicroseconds) / - ++methodStats.Successes; - methodStats.MaxTimeOfSuccess = - Math.Max(methodStats.MaxTimeOfSuccess, reportHandlingTimeMicroseconds); - - allTimeMethodStats.AvgTimeOfSuccesses = - (allTimeMethodStats.Successes * allTimeMethodStats.AvgTimeOfSuccesses + - reportHandlingTimeMicroseconds) / - ++allTimeMethodStats.Successes; - allTimeMethodStats.MaxTimeOfSuccess = - Math.Max(allTimeMethodStats.MaxTimeOfSuccess, reportHandlingTimeMicroseconds); - } - else - { - methodStats.AvgTimeOfErrors = - (methodStats.Errors * methodStats.AvgTimeOfErrors + reportHandlingTimeMicroseconds) / - ++methodStats.Errors; - methodStats.MaxTimeOfError = Math.Max(methodStats.MaxTimeOfError, reportHandlingTimeMicroseconds); - - allTimeMethodStats.AvgTimeOfErrors = - (allTimeMethodStats.Errors * allTimeMethodStats.AvgTimeOfErrors + reportHandlingTimeMicroseconds) / - ++allTimeMethodStats.Errors; - allTimeMethodStats.MaxTimeOfError = Math.Max(allTimeMethodStats.MaxTimeOfError, reportHandlingTimeMicroseconds); - } - - methodStats.TotalSize += sizeDec; - allTimeMethodStats.TotalSize += sizeDec; + return; } - } - private const string ReportHeader = "method | " + - "successes | " + - " avg (ms) | " + - " max (ms) | " + - " errors | " + - " avg (ms) | " + - " max (ms) |" + - " avg size B |" + - " total (kB) |"; + _lastReport = thisTime; - private static readonly string _divider = new('-', ReportHeader.Length); + Swap(); - private void BuildReport() - { - DateTime thisTime = _timestamper.UtcNow; - if (thisTime - _lastReport <= _reportingInterval) + if (_previousStats.IsEmpty) { return; } - lock (_logger.UnderlyingLogger) + _reportStringBuilder.AppendLine("***** JSON RPC report *****"); + _reportStringBuilder.AppendLine(_divider); + _reportStringBuilder.AppendLine(ReportHeader); + _reportStringBuilder.AppendLine(_divider); + MethodStats total = new(); + foreach (KeyValuePair methodStats in _previousStats.OrderBy(kv => kv.Key)) { - if (thisTime - _lastReport <= _reportingInterval) - { - return; - } - - _lastReport = thisTime; - - Swap(); - - if (_previousStats.IsEmpty) - { - return; - } - - _reportStringBuilder.AppendLine("***** JSON RPC report *****"); - _reportStringBuilder.AppendLine(_divider); - _reportStringBuilder.AppendLine(ReportHeader); - _reportStringBuilder.AppendLine(_divider); - MethodStats total = new(); - foreach (KeyValuePair methodStats in _previousStats.OrderBy(kv => kv.Key)) - { - total.AvgTimeOfSuccesses = total.Successes + methodStats.Value.Successes == 0 - ? 0 - : (total.AvgTimeOfSuccesses * total.Successes + methodStats.Value.Successes * methodStats.Value.AvgTimeOfSuccesses) - / (total.Successes + methodStats.Value.Successes); - total.AvgTimeOfErrors = total.Errors + methodStats.Value.Errors == 0 - ? 0 - : (total.AvgTimeOfErrors * total.Errors + methodStats.Value.Errors * methodStats.Value.AvgTimeOfErrors) - / (total.Errors + methodStats.Value.Errors); - total.Successes += methodStats.Value.Successes; - total.Errors += methodStats.Value.Errors; - total.MaxTimeOfSuccess = Math.Max(total.MaxTimeOfSuccess, methodStats.Value.MaxTimeOfSuccess); - total.MaxTimeOfError = Math.Max(total.MaxTimeOfError, methodStats.Value.MaxTimeOfError); - total.TotalSize += methodStats.Value.TotalSize; - _reportStringBuilder.AppendLine(PrepareReportLine(methodStats.Key, methodStats.Value)); - } - - _reportStringBuilder.AppendLine(_divider); - _reportStringBuilder.AppendLine(PrepareReportLine("TOTAL", total)); - _reportStringBuilder.AppendLine(_divider); - - _logger.Info(_reportStringBuilder.ToString()); - _reportStringBuilder.Clear(); - _previousStats.Clear(); + total.AvgTimeOfSuccesses = total.Successes + methodStats.Value.Successes == 0 + ? 0 + : (total.AvgTimeOfSuccesses * total.Successes + methodStats.Value.Successes * methodStats.Value.AvgTimeOfSuccesses) + / (total.Successes + methodStats.Value.Successes); + total.AvgTimeOfErrors = total.Errors + methodStats.Value.Errors == 0 + ? 0 + : (total.AvgTimeOfErrors * total.Errors + methodStats.Value.Errors * methodStats.Value.AvgTimeOfErrors) + / (total.Errors + methodStats.Value.Errors); + total.Successes += methodStats.Value.Successes; + total.Errors += methodStats.Value.Errors; + total.MaxTimeOfSuccess = Math.Max(total.MaxTimeOfSuccess, methodStats.Value.MaxTimeOfSuccess); + total.MaxTimeOfError = Math.Max(total.MaxTimeOfError, methodStats.Value.MaxTimeOfError); + total.TotalSize += methodStats.Value.TotalSize; + _reportStringBuilder.AppendLine(PrepareReportLine(methodStats.Key, methodStats.Value)); } - } - private void Swap() - { - (_currentStats, _previousStats) = (_previousStats, _currentStats); + _reportStringBuilder.AppendLine(_divider); + _reportStringBuilder.AppendLine(PrepareReportLine("TOTAL", total)); + _reportStringBuilder.AppendLine(_divider); + + _logger.Info(_reportStringBuilder.ToString()); + _reportStringBuilder.Clear(); + _previousStats.Clear(); } + } - [Pure] - private static string PrepareReportLine(in string key, MethodStats methodStats) => - $"{key,-40}| " + - $"{methodStats.Successes.ToString(),9} | " + - $"{((double)methodStats.AvgTimeOfSuccesses / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + - $"{((double)methodStats.MaxTimeOfSuccess / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + - $"{methodStats.Errors.ToString(),9} | " + - $"{((double)methodStats.AvgTimeOfErrors / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + - $"{((double)methodStats.MaxTimeOfError / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + - $"{methodStats.AvgSize.ToString("0", CultureInfo.InvariantCulture),10} | " + - $"{((double)methodStats.TotalSize / 1024.0).ToString("0.00", CultureInfo.InvariantCulture),10} | "; + private void Swap() + { + (_currentStats, _previousStats) = (_previousStats, _currentStats); } + + [Pure] + private static string PrepareReportLine(in string key, MethodStats methodStats) => + $"{key,-40}| " + + $"{methodStats.Successes.ToString(),9} | " + + $"{((double)methodStats.AvgTimeOfSuccesses / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + + $"{((double)methodStats.MaxTimeOfSuccess / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + + $"{methodStats.Errors.ToString(),9} | " + + $"{((double)methodStats.AvgTimeOfErrors / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + + $"{((double)methodStats.MaxTimeOfError / 1000.0).ToString("0.000", CultureInfo.InvariantCulture),10} | " + + $"{methodStats.AvgSize.ToString("0", CultureInfo.InvariantCulture),10} | " + + $"{((double)methodStats.TotalSize / 1024.0).ToString("0.00", CultureInfo.InvariantCulture),10} | "; } diff --git a/src/Nethermind/Nethermind.KeyStore.Test/ConsolePasswordProviderTests.cs b/src/Nethermind/Nethermind.KeyStore.Test/ConsolePasswordProviderTests.cs index 370675895c5..0ddbb64cd6b 100644 --- a/src/Nethermind/Nethermind.KeyStore.Test/ConsolePasswordProviderTests.cs +++ b/src/Nethermind/Nethermind.KeyStore.Test/ConsolePasswordProviderTests.cs @@ -9,106 +9,105 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.KeyStore.Test +namespace Nethermind.KeyStore.Test; + +public class ConsolePasswordProviderTests { - public class ConsolePasswordProviderTests + [Test] + public void Alternative_provider_sets_correctly() { - [Test] - public void Alternative_provider_sets_correctly() - { - var emptyPasswordProvider = new FilePasswordProvider(address => string.Empty); - var consolePasswordProvider1 = emptyPasswordProvider - .OrReadFromConsole("Test1"); + var emptyPasswordProvider = new FilePasswordProvider(address => string.Empty); + var consolePasswordProvider1 = emptyPasswordProvider + .OrReadFromConsole("Test1"); - Assert.IsTrue(consolePasswordProvider1 is FilePasswordProvider); - Assert.That(((ConsolePasswordProvider)consolePasswordProvider1.AlternativeProvider).Message, Is.EqualTo("Test1")); + Assert.That(consolePasswordProvider1 is FilePasswordProvider, Is.True); + Assert.That(((ConsolePasswordProvider)consolePasswordProvider1.AlternativeProvider).Message, Is.EqualTo("Test1")); - var consolePasswordProvider2 = consolePasswordProvider1 - .OrReadFromConsole("Test2"); + var consolePasswordProvider2 = consolePasswordProvider1 + .OrReadFromConsole("Test2"); - Assert.IsTrue(consolePasswordProvider2 is FilePasswordProvider); - Assert.That(((ConsolePasswordProvider)consolePasswordProvider2.AlternativeProvider).Message, Is.EqualTo("Test2")); - } + Assert.That(consolePasswordProvider2 is FilePasswordProvider, Is.True); + Assert.That(((ConsolePasswordProvider)consolePasswordProvider2.AlternativeProvider).Message, Is.EqualTo("Test2")); + } - [Test] - public void GetPassword([ValueSource(nameof(PasswordProviderTestCases))] ConsolePasswordProviderTest test) + [Test] + public void GetPassword([ValueSource(nameof(PasswordProviderTestCases))] ConsolePasswordProviderTest test) + { + IConsoleWrapper consoleWrapper = Substitute.For(); + var chars = test.InputChars; + var iterator = 0; + consoleWrapper.ReadKey(true).Returns(s => { - IConsoleWrapper consoleWrapper = Substitute.For(); - var chars = test.InputChars; - var iterator = 0; - consoleWrapper.ReadKey(true).Returns(s => - { - ConsoleKeyInfo key = chars[iterator]; - ++iterator; - return key; - }); - var passwordProvider = new ConsolePasswordProvider(new ConsoleUtils(consoleWrapper)); - var password = passwordProvider.GetPassword(Address.Zero); - Assert.IsTrue(password.IsReadOnly()); - Assert.That(password.Unsecure(), Is.EqualTo(test.ExpectedPassword)); - } + ConsoleKeyInfo key = chars[iterator]; + ++iterator; + return key; + }); + var passwordProvider = new ConsolePasswordProvider(new ConsoleUtils(consoleWrapper)); + var password = passwordProvider.GetPassword(Address.Zero); + Assert.That(password.IsReadOnly(), Is.True); + Assert.That(password.Unsecure(), Is.EqualTo(test.ExpectedPassword)); + } - public static IEnumerable PasswordProviderTestCases + public static IEnumerable PasswordProviderTestCases + { + get { - get + yield return new ConsolePasswordProviderTest() { - yield return new ConsolePasswordProviderTest() + ExpectedPassword = "T", + InputChars = new ConsoleKeyInfo[] { - ExpectedPassword = "T", - InputChars = new ConsoleKeyInfo[] - { - new ConsoleKeyInfo('T', ConsoleKey.T, false, false, false), - new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) - }, - }; - yield return new ConsolePasswordProviderTest() + new ConsoleKeyInfo('T', ConsoleKey.T, false, false, false), + new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) + }, + }; + yield return new ConsolePasswordProviderTest() + { + ExpectedPassword = "Asx", + InputChars = new ConsoleKeyInfo[] { - ExpectedPassword = "Asx", - InputChars = new ConsoleKeyInfo[] - { - new ConsoleKeyInfo('A', ConsoleKey.A, false, false, false), - new ConsoleKeyInfo('s', ConsoleKey.S, false, false, false), - new ConsoleKeyInfo('x', ConsoleKey.X, false, false, false), - new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) - }, - }; - yield return new ConsolePasswordProviderTest() + new ConsoleKeyInfo('A', ConsoleKey.A, false, false, false), + new ConsoleKeyInfo('s', ConsoleKey.S, false, false, false), + new ConsoleKeyInfo('x', ConsoleKey.X, false, false, false), + new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) + }, + }; + yield return new ConsolePasswordProviderTest() + { + ExpectedPassword = "rd", + InputChars = new ConsoleKeyInfo[] { - ExpectedPassword = "rd", - InputChars = new ConsoleKeyInfo[] - { - new ConsoleKeyInfo('A', ConsoleKey.A, false, false, false), - new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), - new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false), - new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false), - new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) - }, - }; - yield return new ConsolePasswordProviderTest() + new ConsoleKeyInfo('A', ConsoleKey.A, false, false, false), + new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), + new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false), + new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false), + new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) + }, + }; + yield return new ConsolePasswordProviderTest() + { + ExpectedPassword = "po", + InputChars = new ConsoleKeyInfo[] { - ExpectedPassword = "po", - InputChars = new ConsoleKeyInfo[] - { - new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), - new ConsoleKeyInfo('j', ConsoleKey.A, false, false, false), - new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), - new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), - new ConsoleKeyInfo('p', ConsoleKey.R, false, false, false), - new ConsoleKeyInfo('o', ConsoleKey.D, false, false, false), - new ConsoleKeyInfo('o', ConsoleKey.D, false, false, false), - new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), - new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) - }, - }; - } + new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), + new ConsoleKeyInfo('j', ConsoleKey.A, false, false, false), + new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), + new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), + new ConsoleKeyInfo('p', ConsoleKey.R, false, false, false), + new ConsoleKeyInfo('o', ConsoleKey.D, false, false, false), + new ConsoleKeyInfo('o', ConsoleKey.D, false, false, false), + new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false), + new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false) + }, + }; } + } - public class ConsolePasswordProviderTest - { - public ConsoleKeyInfo[] InputChars { get; set; } = Array.Empty(); - public string ExpectedPassword { get; set; } + public class ConsolePasswordProviderTest + { + public ConsoleKeyInfo[] InputChars { get; set; } = Array.Empty(); + public string ExpectedPassword { get; set; } - public override string ToString() => string.Join("; ", ExpectedPassword); - } + public override string ToString() => string.Join("; ", ExpectedPassword); } } diff --git a/src/Nethermind/Nethermind.KeyStore.Test/FilePasswordProviderTests.cs b/src/Nethermind/Nethermind.KeyStore.Test/FilePasswordProviderTests.cs index 917b147286e..04a80bff652 100644 --- a/src/Nethermind/Nethermind.KeyStore.Test/FilePasswordProviderTests.cs +++ b/src/Nethermind/Nethermind.KeyStore.Test/FilePasswordProviderTests.cs @@ -7,119 +7,118 @@ using Nethermind.Crypto; using NUnit.Framework; -namespace Nethermind.KeyStore.Test +namespace Nethermind.KeyStore.Test; + +public class FilePasswordProviderTests { - public class FilePasswordProviderTests + private static readonly List<(string Name, string Content)> _files = new List<(string Name, string Content)>() { - private static readonly List<(string Name, string Content)> _files = new List<(string Name, string Content)>() - { - ("TestingPasswordProviderFileF1", "PF1"), - ("TestingPasswordProviderFileF2", "P F2"), - ("TestingPasswordProviderFileF3", " P F3 ") - }; + ("TestingPasswordProviderFileF1", "PF1"), + ("TestingPasswordProviderFileF2", "P F2"), + ("TestingPasswordProviderFileF3", " P F3 ") + }; - private string TestDir => TestContext.CurrentContext.WorkDirectory; + private string TestDir => TestContext.CurrentContext.WorkDirectory; - [SetUp] - public void SetUp() + [SetUp] + public void SetUp() + { + foreach (var file in _files) { - foreach (var file in _files) + var filePath = Path.Combine(TestDir, file.Name); + if (!File.Exists(filePath)) { - var filePath = Path.Combine(TestDir, file.Name); - if (!File.Exists(filePath)) - { - File.Create(filePath).Close(); - File.WriteAllText(filePath, file.Content); - } + File.Create(filePath).Close(); + File.WriteAllText(filePath, file.Content); } } + } - [TearDown] - public void TearDown() + [TearDown] + public void TearDown() + { + foreach (var file in _files) { - foreach (var file in _files) + var filePath = Path.Combine(TestDir, file.Name); + if (File.Exists(filePath)) { - var filePath = Path.Combine(TestDir, file.Name); - if (File.Exists(filePath)) - { - File.Delete(filePath); - } + File.Delete(filePath); } } + } - [Test] - public void GetPassword([ValueSource(nameof(PasswordProviderTestCases))] - FilePasswordProviderTest test) - { - var passwordProvider = new FilePasswordProvider(address => Path.Combine(TestDir, test.FileName)); + [Test] + public void GetPassword([ValueSource(nameof(PasswordProviderTestCases))] + FilePasswordProviderTest test) + { + var passwordProvider = new FilePasswordProvider(address => Path.Combine(TestDir, test.FileName)); - var password = passwordProvider.GetPassword(Address.Zero); - Assert.IsTrue(password.IsReadOnly()); - Assert.That(password.Unsecure(), Is.EqualTo(test.ExpectedPassword)); - } + var password = passwordProvider.GetPassword(Address.Zero); + Assert.That(password.IsReadOnly(), Is.True); + Assert.That(password.Unsecure(), Is.EqualTo(test.ExpectedPassword)); + } - [Test] - public void Return_null_when_file_not_exists() + [Test] + public void Return_null_when_file_not_exists() + { + var passwordProvider = new FilePasswordProvider(address => { - var passwordProvider = new FilePasswordProvider(address => + if (address == Address.Zero) { - if (address == Address.Zero) - { - return string.Empty; - } - else - { - return "NotExistingFile"; - } - }); - - var password = passwordProvider.GetPassword(Address.Zero); - Assert.That(password, Is.EqualTo(null)); - password = passwordProvider.GetPassword(Address.Zero); - Assert.That(password, Is.EqualTo(null)); - } + return string.Empty; + } + else + { + return "NotExistingFile"; + } + }); - [Test] - public void Correctly_use_alternative_provider() - { - var passwordProvider = new FilePasswordProvider(a => string.Empty) - .OrReadFromFile(Path.Combine(TestDir, _files[0].Name)); + var password = passwordProvider.GetPassword(Address.Zero); + Assert.That(password, Is.EqualTo(null)); + password = passwordProvider.GetPassword(Address.Zero); + Assert.That(password, Is.EqualTo(null)); + } - var password = passwordProvider.GetPassword(Address.Zero); - Assert.IsTrue(password.IsReadOnly()); - Assert.That(password.Unsecure(), Is.EqualTo(_files[0].Content.Trim())); - } + [Test] + public void Correctly_use_alternative_provider() + { + var passwordProvider = new FilePasswordProvider(a => string.Empty) + .OrReadFromFile(Path.Combine(TestDir, _files[0].Name)); + + var password = passwordProvider.GetPassword(Address.Zero); + Assert.That(password.IsReadOnly(), Is.True); + Assert.That(password.Unsecure(), Is.EqualTo(_files[0].Content.Trim())); + } - public static IEnumerable PasswordProviderTestCases + public static IEnumerable PasswordProviderTestCases + { + get { - get + yield return new FilePasswordProviderTest() { - yield return new FilePasswordProviderTest() - { - FileName = _files[0].Name, - ExpectedPassword = _files[0].Content.Trim() - }; - - yield return new FilePasswordProviderTest() - { - FileName = _files[1].Name, - ExpectedPassword = _files[1].Content.Trim() - }; - - yield return new FilePasswordProviderTest() - { - FileName = _files[2].Name, - ExpectedPassword = _files[2].Content.Trim() - }; - } - } + FileName = _files[0].Name, + ExpectedPassword = _files[0].Content.Trim() + }; - public class FilePasswordProviderTest - { - public string FileName { get; set; } - public string ExpectedPassword { get; set; } + yield return new FilePasswordProviderTest() + { + FileName = _files[1].Name, + ExpectedPassword = _files[1].Content.Trim() + }; - public override string ToString() => string.Join("; ", ExpectedPassword); + yield return new FilePasswordProviderTest() + { + FileName = _files[2].Name, + ExpectedPassword = _files[2].Content.Trim() + }; } } + + public class FilePasswordProviderTest + { + public string FileName { get; set; } + public string ExpectedPassword { get; set; } + + public override string ToString() => string.Join("; ", ExpectedPassword); + } } diff --git a/src/Nethermind/Nethermind.KeyStore.Test/KeyStorePasswordProviderTests.cs b/src/Nethermind/Nethermind.KeyStore.Test/KeyStorePasswordProviderTests.cs index 4d664ac4a35..1f75e2927b0 100644 --- a/src/Nethermind/Nethermind.KeyStore.Test/KeyStorePasswordProviderTests.cs +++ b/src/Nethermind/Nethermind.KeyStore.Test/KeyStorePasswordProviderTests.cs @@ -14,138 +14,137 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.KeyStore.Test +namespace Nethermind.KeyStore.Test; + +public class KeyStorePasswordProviderTests { - public class KeyStorePasswordProviderTests + private static readonly List<(string Name, string Content)> _files = new List<(string Name, string Content)>() { - private static readonly List<(string Name, string Content)> _files = new List<(string Name, string Content)>() - { - ("TestingPasswordProviderFileF1", "PF1"), - ("TestingPasswordProviderFileF2", "P F2"), - ("TestingPasswordProviderFileF3", " P F3 ") - }; + ("TestingPasswordProviderFileF1", "PF1"), + ("TestingPasswordProviderFileF2", "P F2"), + ("TestingPasswordProviderFileF3", " P F3 ") + }; - private string TestDir => TestContext.CurrentContext.WorkDirectory; + private string TestDir => TestContext.CurrentContext.WorkDirectory; - [SetUp] - public void SetUp() + [SetUp] + public void SetUp() + { + foreach (var file in _files) { - foreach (var file in _files) + var filePath = Path.Combine(TestDir, file.Name); + if (!File.Exists(filePath)) { - var filePath = Path.Combine(TestDir, file.Name); - if (!File.Exists(filePath)) - { - File.Create(filePath).Close(); - File.WriteAllText(filePath, file.Content); - } + File.Create(filePath).Close(); + File.WriteAllText(filePath, file.Content); } } + } - [TearDown] - public void TearDown() + [TearDown] + public void TearDown() + { + foreach (var file in _files) { - foreach (var file in _files) + var filePath = Path.Combine(TestDir, file.Name); + if (File.Exists(filePath)) { - var filePath = Path.Combine(TestDir, file.Name); - if (File.Exists(filePath)) - { - File.Delete(filePath); - } + File.Delete(filePath); } } + } - public static IEnumerable PasswordProviderTestCases + public static IEnumerable PasswordProviderTestCases + { + get { - get + yield return new KeyStorePasswordProviderTest() { - yield return new KeyStorePasswordProviderTest() - { - TestName = "A B both from same file", - UnlockAccounts = new[] { TestItem.AddressA, TestItem.AddressB }, - Passwords = new[] { "A", "B" }, - PasswordFiles = new List { _files[0].Name }, - ExpectedPasswords = new[] { _files[0].Content.Trim(), _files[0].Content.Trim() }, - BlockAuthorAccount = TestItem.AddressA, - ExpectedBlockAuthorAccountPassword = _files[0].Content.Trim() - }; - - yield return new KeyStorePasswordProviderTest() - { - TestName = "A B two different files", - UnlockAccounts = new[] { TestItem.AddressA, TestItem.AddressB }, - Passwords = new[] { "A", "B" }, - PasswordFiles = new List { _files[0].Name, _files[1].Name }, - ExpectedPasswords = new[] { _files[0].Content.Trim(), _files[1].Content.Trim() }, - BlockAuthorAccount = TestItem.AddressB, - ExpectedBlockAuthorAccountPassword = _files[1].Content.Trim() - }; - - yield return new KeyStorePasswordProviderTest() - { - TestName = "A B from password directly", - UnlockAccounts = new[] { TestItem.AddressA, TestItem.AddressB }, - Passwords = new[] { "A", "B" }, - ExpectedPasswords = new[] { "A", "B" }, - BlockAuthorAccount = TestItem.AddressB, - ExpectedBlockAuthorAccountPassword = "B" - }; + TestName = "A B both from same file", + UnlockAccounts = new[] { TestItem.AddressA, TestItem.AddressB }, + Passwords = new[] { "A", "B" }, + PasswordFiles = new List { _files[0].Name }, + ExpectedPasswords = new[] { _files[0].Content.Trim(), _files[0].Content.Trim() }, + BlockAuthorAccount = TestItem.AddressA, + ExpectedBlockAuthorAccountPassword = _files[0].Content.Trim() + }; - yield return new KeyStorePasswordProviderTest() - { - TestName = "A B from same file but file needs to be trimmed", - UnlockAccounts = new[] { TestItem.AddressA }, - Passwords = new[] { "A", "B" }, - PasswordFiles = new List { _files[2].Name }, - ExpectedPasswords = new[] { _files[2].Content.Trim() }, - BlockAuthorAccount = TestItem.AddressA, - ExpectedBlockAuthorAccountPassword = _files[2].Content.Trim() - }; - } - } + yield return new KeyStorePasswordProviderTest() + { + TestName = "A B two different files", + UnlockAccounts = new[] { TestItem.AddressA, TestItem.AddressB }, + Passwords = new[] { "A", "B" }, + PasswordFiles = new List { _files[0].Name, _files[1].Name }, + ExpectedPasswords = new[] { _files[0].Content.Trim(), _files[1].Content.Trim() }, + BlockAuthorAccount = TestItem.AddressB, + ExpectedBlockAuthorAccountPassword = _files[1].Content.Trim() + }; - [Test] - public void GetPassword([ValueSource(nameof(PasswordProviderTestCases))] KeyStorePasswordProviderTest test) - { - IKeyStoreConfig keyStoreConfig = Substitute.For(); - keyStoreConfig.Passwords.Returns(test.Passwords); - keyStoreConfig.UnlockAccounts.Returns(test.UnlockAccounts.Select(a => a.ToString()).ToArray()); - keyStoreConfig.PasswordFiles.Returns(_files.Where(x => test.PasswordFiles.Contains(x.Name)).Select(x => x.Name).ToArray()); - var passwordProvider = new KeyStorePasswordProvider(keyStoreConfig); + yield return new KeyStorePasswordProviderTest() + { + TestName = "A B from password directly", + UnlockAccounts = new[] { TestItem.AddressA, TestItem.AddressB }, + Passwords = new[] { "A", "B" }, + ExpectedPasswords = new[] { "A", "B" }, + BlockAuthorAccount = TestItem.AddressB, + ExpectedBlockAuthorAccountPassword = "B" + }; - for (var index = 0; index < test.PasswordFiles.Count; ++index) + yield return new KeyStorePasswordProviderTest() { - var actualPassword = passwordProvider.GetPassword(test.UnlockAccounts[index]); - var expectedPassword = test.ExpectedPasswords[index]; - Assert.IsTrue(actualPassword.IsReadOnly()); - Assert.That(actualPassword.Unsecure(), Is.EqualTo(expectedPassword)); - } + TestName = "A B from same file but file needs to be trimmed", + UnlockAccounts = new[] { TestItem.AddressA }, + Passwords = new[] { "A", "B" }, + PasswordFiles = new List { _files[2].Name }, + ExpectedPasswords = new[] { _files[2].Content.Trim() }, + BlockAuthorAccount = TestItem.AddressA, + ExpectedBlockAuthorAccountPassword = _files[2].Content.Trim() + }; } + } + + [Test] + public void GetPassword([ValueSource(nameof(PasswordProviderTestCases))] KeyStorePasswordProviderTest test) + { + IKeyStoreConfig keyStoreConfig = Substitute.For(); + keyStoreConfig.Passwords.Returns(test.Passwords); + keyStoreConfig.UnlockAccounts.Returns(test.UnlockAccounts.Select(a => a.ToString()).ToArray()); + keyStoreConfig.PasswordFiles.Returns(_files.Where(x => test.PasswordFiles.Contains(x.Name)).Select(x => x.Name).ToArray()); + var passwordProvider = new KeyStorePasswordProvider(keyStoreConfig); - [Test] - public void GetBlockAuthorPassword([ValueSource(nameof(PasswordProviderTestCases))] KeyStorePasswordProviderTest test) + for (var index = 0; index < test.PasswordFiles.Count; ++index) { - IKeyStoreConfig keyStoreConfig = Substitute.For(); - keyStoreConfig.Passwords.Returns(test.Passwords); - keyStoreConfig.PasswordFiles.Returns(_files.Where(x => test.PasswordFiles.Contains(x.Name)).Select(x => x.Name).ToArray()); - keyStoreConfig.BlockAuthorAccount.Returns(test.BlockAuthorAccount.ToString()); - keyStoreConfig.UnlockAccounts.Returns(test.UnlockAccounts.Select(a => a.ToString()).ToArray()); - var passwordProvider = new KeyStorePasswordProvider(keyStoreConfig); - var blockAuthorPassword = passwordProvider.GetPassword(new Address(Bytes.FromHexString(keyStoreConfig.BlockAuthorAccount))); - Assert.IsTrue(blockAuthorPassword.IsReadOnly()); - blockAuthorPassword.Unsecure().Should().Be(test.ExpectedBlockAuthorAccountPassword, test.TestName); + var actualPassword = passwordProvider.GetPassword(test.UnlockAccounts[index]); + var expectedPassword = test.ExpectedPasswords[index]; + Assert.That(actualPassword.IsReadOnly(), Is.True); + Assert.That(actualPassword.Unsecure(), Is.EqualTo(expectedPassword)); } } - public class KeyStorePasswordProviderTest + [Test] + public void GetBlockAuthorPassword([ValueSource(nameof(PasswordProviderTestCases))] KeyStorePasswordProviderTest test) { - public string TestName { get; set; } = string.Empty; - public string[] Passwords { get; set; } = Array.Empty(); - public List PasswordFiles { get; set; } = new List(); - public string[] ExpectedPasswords { get; set; } = Array.Empty(); - public Address[] UnlockAccounts { get; set; } = Array.Empty
(); - public Address BlockAuthorAccount { get; set; } - public string ExpectedBlockAuthorAccountPassword { get; set; } - - public override string ToString() => TestName + " " + string.Join("; ", ExpectedPasswords); + IKeyStoreConfig keyStoreConfig = Substitute.For(); + keyStoreConfig.Passwords.Returns(test.Passwords); + keyStoreConfig.PasswordFiles.Returns(_files.Where(x => test.PasswordFiles.Contains(x.Name)).Select(x => x.Name).ToArray()); + keyStoreConfig.BlockAuthorAccount.Returns(test.BlockAuthorAccount.ToString()); + keyStoreConfig.UnlockAccounts.Returns(test.UnlockAccounts.Select(a => a.ToString()).ToArray()); + var passwordProvider = new KeyStorePasswordProvider(keyStoreConfig); + var blockAuthorPassword = passwordProvider.GetPassword(new Address(Bytes.FromHexString(keyStoreConfig.BlockAuthorAccount))); + Assert.That(blockAuthorPassword.IsReadOnly(), Is.True); + blockAuthorPassword.Unsecure().Should().Be(test.ExpectedBlockAuthorAccountPassword, test.TestName); } } + +public class KeyStorePasswordProviderTest +{ + public string TestName { get; set; } = string.Empty; + public string[] Passwords { get; set; } = Array.Empty(); + public List PasswordFiles { get; set; } = new List(); + public string[] ExpectedPasswords { get; set; } = Array.Empty(); + public Address[] UnlockAccounts { get; set; } = Array.Empty
(); + public Address BlockAuthorAccount { get; set; } + public string ExpectedBlockAuthorAccountPassword { get; set; } + + public override string ToString() => TestName + " " + string.Join("; ", ExpectedPasswords); +} diff --git a/src/Nethermind/Nethermind.KeyStore.Test/KeyStoreTests.cs b/src/Nethermind/Nethermind.KeyStore.Test/KeyStoreTests.cs index 5abdfcff083..edde63978be 100644 --- a/src/Nethermind/Nethermind.KeyStore.Test/KeyStoreTests.cs +++ b/src/Nethermind/Nethermind.KeyStore.Test/KeyStoreTests.cs @@ -14,246 +14,244 @@ using Nethermind.Serialization.Json; using NUnit.Framework; -namespace Nethermind.KeyStore.Test +namespace Nethermind.KeyStore.Test; + +[Parallelizable(ParallelScope.All)] +public class KeyStoreTests { - [Parallelizable(ParallelScope.All)] - [TestFixture] - public class KeyStoreTests + private class TestContext { - private class TestContext + public FileKeyStore Store { get; } + public IJsonSerializer Serializer { get; } + public IKeyStoreConfig KeyStoreConfig { get; } + public ICryptoRandom CryptoRandom { get; } + public SecureString TestPasswordSecured { get; } + public SecureString WrongPasswordSecured { get; } + public const string TestPassword = "testpassword"; + + public TestContext() { - public FileKeyStore Store { get; } - public IJsonSerializer Serializer { get; } - public IKeyStoreConfig KeyStoreConfig { get; } - public ICryptoRandom CryptoRandom { get; } - public SecureString TestPasswordSecured { get; } - public SecureString WrongPasswordSecured { get; } - public const string TestPassword = "testpassword"; - - public TestContext() - { - KeyStoreConfig = new KeyStoreConfig(); - KeyStoreConfig.KeyStoreDirectory = NUnit.Framework.TestContext.CurrentContext.WorkDirectory; + KeyStoreConfig = new KeyStoreConfig(); + KeyStoreConfig.KeyStoreDirectory = NUnit.Framework.TestContext.CurrentContext.WorkDirectory; - TestPasswordSecured = new SecureString(); - WrongPasswordSecured = new SecureString(); + TestPasswordSecured = new SecureString(); + WrongPasswordSecured = new SecureString(); - for (int i = 0; i < TestPassword.Length; i++) - { - TestPasswordSecured.AppendChar(TestPassword[i]); - WrongPasswordSecured.AppendChar('*'); - } + for (int i = 0; i < TestPassword.Length; i++) + { + TestPasswordSecured.AppendChar(TestPassword[i]); + WrongPasswordSecured.AppendChar('*'); + } - TestPasswordSecured.MakeReadOnly(); - WrongPasswordSecured.MakeReadOnly(); + TestPasswordSecured.MakeReadOnly(); + WrongPasswordSecured.MakeReadOnly(); - ILogManager logger = LimboLogs.Instance; - Serializer = new EthereumJsonSerializer(); - CryptoRandom = new CryptoRandom(); - Store = new FileKeyStore(KeyStoreConfig, Serializer, new AesEncrypter(KeyStoreConfig, logger), CryptoRandom, logger, new PrivateKeyStoreIOSettingsProvider(KeyStoreConfig)); - } + ILogManager logger = LimboLogs.Instance; + Serializer = new EthereumJsonSerializer(); + CryptoRandom = new CryptoRandom(); + Store = new FileKeyStore(KeyStoreConfig, Serializer, new AesEncrypter(KeyStoreConfig, logger), CryptoRandom, logger, new PrivateKeyStoreIOSettingsProvider(KeyStoreConfig)); } + } - [TestCase("{\"address\":\"20b2e4bb8688a44729780d15dc64adb42f9f5a0a\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"d30cbb0f5b30ef86e57b7fa111307398b911b8c0a3eab4ac4edc4b2c8839afbe\",\"cipherparams\":{\"iv\":\"1e29e79023d73be3f3bb065ca9ddc078\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"fffcd979c3223b3cdfcb2cf21b07bd4313e6f8d02af8a79a5c5dc879a25680d3\"},\"mac\":\"3ac5a539775c33bd73adfd2c0d4ef8c9154e4b404e2a15c77b0e6c78cb90df20\"},\"id\":\"68462de1-4114-4f92-828b-883fae5f779c\",\"version\":3}")] - [TestCase("{\"address\":\"746526c3a59db995b914a319306cd7ae35dc50c5\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"644b1af45188b23f6195abd2b0563d7b079ff6622e5ac61767cd81cbd621a13e\",\"cipherparams\":{\"iv\":\"844c895835de8571409b8a76a75672b2\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"e7df76e322e444ed61314fa5261cf0ac02b9c057fe626a74a37c5255c16a8d61\"},\"mac\":\"48f26081eec397b818ed4e2cb3b1c04908c671a81d6b183e9965d869bd001862\"},\"id\":\"6ee56be1-367f-4b41-a25d-f60e0a7bfe42\",\"version\":3}")] - [TestCase("{\"address\":\"aa42104423e00a862b616f2f712a1b17d308bbc9\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"450c341ab64c39237039a30a8d84cc112dfbdda889caa19201b0cf8473680936\",\"cipherparams\":{\"iv\":\"923d950dcdba710a0c8e240441e0a227\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"101185ea81a1067591bce5323d75648b753f71becc22a4ebd55256593a705698\"},\"mac\":\"dc0a3bc555ac8f22d84115968b5fde6f50eb065ff7fe47a1da30de668a5ca864\"},\"id\":\"339ef573-a7d5-4bd0-86b2-3b1e420439d7\",\"version\":3}")] - [TestCase("{\"address\":\"25dead29c683c5db3e0fabcf8f3757cdb0abe549\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"4fd59f3a3fa1bed32774b29a40886d5489c0c06a8da014cb44b25792f6c32cb2\",\"cipherparams\":{\"iv\":\"6b850162043a0a879726839cfca55220\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"cafbe520e0d711cf32d9a2e6b2ecbd231cc7aed09018c5032c637436e02754d1\"},\"mac\":\"379f51c673f1f355a6ffc92b31b37381670eea2e0e23604a2572f5df650d148e\"},\"id\":\"fc7ff6bf-c51e-4e02-bb7c-0c91a3eeab4c\",\"version\":3}")] - public void Can_unlock_test_accounts(string keyJson) - { - TestContext test = new TestContext(); - EthereumJsonSerializer serializer = new EthereumJsonSerializer(); - KeyStoreItem item = serializer.Deserialize(keyJson); + [TestCase("{\"address\":\"20b2e4bb8688a44729780d15dc64adb42f9f5a0a\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"d30cbb0f5b30ef86e57b7fa111307398b911b8c0a3eab4ac4edc4b2c8839afbe\",\"cipherparams\":{\"iv\":\"1e29e79023d73be3f3bb065ca9ddc078\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"fffcd979c3223b3cdfcb2cf21b07bd4313e6f8d02af8a79a5c5dc879a25680d3\"},\"mac\":\"3ac5a539775c33bd73adfd2c0d4ef8c9154e4b404e2a15c77b0e6c78cb90df20\"},\"id\":\"68462de1-4114-4f92-828b-883fae5f779c\",\"version\":3}")] + [TestCase("{\"address\":\"746526c3a59db995b914a319306cd7ae35dc50c5\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"644b1af45188b23f6195abd2b0563d7b079ff6622e5ac61767cd81cbd621a13e\",\"cipherparams\":{\"iv\":\"844c895835de8571409b8a76a75672b2\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"e7df76e322e444ed61314fa5261cf0ac02b9c057fe626a74a37c5255c16a8d61\"},\"mac\":\"48f26081eec397b818ed4e2cb3b1c04908c671a81d6b183e9965d869bd001862\"},\"id\":\"6ee56be1-367f-4b41-a25d-f60e0a7bfe42\",\"version\":3}")] + [TestCase("{\"address\":\"aa42104423e00a862b616f2f712a1b17d308bbc9\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"450c341ab64c39237039a30a8d84cc112dfbdda889caa19201b0cf8473680936\",\"cipherparams\":{\"iv\":\"923d950dcdba710a0c8e240441e0a227\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"101185ea81a1067591bce5323d75648b753f71becc22a4ebd55256593a705698\"},\"mac\":\"dc0a3bc555ac8f22d84115968b5fde6f50eb065ff7fe47a1da30de668a5ca864\"},\"id\":\"339ef573-a7d5-4bd0-86b2-3b1e420439d7\",\"version\":3}")] + [TestCase("{\"address\":\"25dead29c683c5db3e0fabcf8f3757cdb0abe549\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"4fd59f3a3fa1bed32774b29a40886d5489c0c06a8da014cb44b25792f6c32cb2\",\"cipherparams\":{\"iv\":\"6b850162043a0a879726839cfca55220\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"cafbe520e0d711cf32d9a2e6b2ecbd231cc7aed09018c5032c637436e02754d1\"},\"mac\":\"379f51c673f1f355a6ffc92b31b37381670eea2e0e23604a2572f5df650d148e\"},\"id\":\"fc7ff6bf-c51e-4e02-bb7c-0c91a3eeab4c\",\"version\":3}")] + public void Can_unlock_test_accounts(string keyJson) + { + TestContext test = new TestContext(); + EthereumJsonSerializer serializer = new EthereumJsonSerializer(); + KeyStoreItem item = serializer.Deserialize(keyJson); - SecureString securePassword = new SecureString(); - string password = "testpuppeth"; - for (int i = 0; i < password.Length; i++) - { - securePassword.AppendChar(password[i]); - } + SecureString securePassword = new SecureString(); + string password = "testpuppeth"; + for (int i = 0; i < password.Length; i++) + { + securePassword.AppendChar(password[i]); + } - securePassword.MakeReadOnly(); + securePassword.MakeReadOnly(); - test.Store.StoreKey(new Address(item.Address), item); - try - { - (PrivateKey key, Result result) = test.Store.GetKey(new Address(item.Address), securePassword); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), item.Address + " " + result.Error); - Assert.That(item.Address, Is.EqualTo(key.Address.ToString(false, false))); - } - finally - { - test.Store.DeleteKey(new Address(item.Address)); - } + test.Store.StoreKey(new Address(item.Address), item); + try + { + (PrivateKey key, Result result) = test.Store.GetKey(new Address(item.Address), securePassword); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), item.Address + " " + result.Error); + Assert.That(item.Address, Is.EqualTo(key.Address.ToString(false, false))); } - - [TestCase("{\"address\":\"20b2e4bb8688a44729780d15dc64adb42f9f5a0a\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"d30cbb0f5b30ef86e57b7fa111307398b911b8c0a3eab4ac4edc4b2c8839afbe\",\"cipherparams\":{\"iv\":\"1e29e79023d73be3f3bb065ca9ddc078\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"fffcd979c3223b3cdfcb2cf21b07bd4313e6f8d02af8a79a5c5dc879a25680d3\"},\"mac\":\"3ac5a539775c33bd73adfd2c0d4ef8c9154e4b404e2a15c77b0e6c78cb90df20\"},\"id\":\"68462de1-4114-4f92-828b-883fae5f779c\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] - [TestCase("{\"address\":\"746526c3a59db995b914a319306cd7ae35dc50c5\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"644b1af45188b23f6195abd2b0563d7b079ff6622e5ac61767cd81cbd621a13e\",\"cipherparams\":{\"iv\":\"844c895835de8571409b8a76a75672b2\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"e7df76e322e444ed61314fa5261cf0ac02b9c057fe626a74a37c5255c16a8d61\"},\"mac\":\"48f26081eec397b818ed4e2cb3b1c04908c671a81d6b183e9965d869bd001862\"},\"id\":\"6ee56be1-367f-4b41-a25d-f60e0a7bfe42\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] - [TestCase("{\"address\":\"aa42104423e00a862b616f2f712a1b17d308bbc9\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"450c341ab64c39237039a30a8d84cc112dfbdda889caa19201b0cf8473680936\",\"cipherparams\":{\"iv\":\"923d950dcdba710a0c8e240441e0a227\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"101185ea81a1067591bce5323d75648b753f71becc22a4ebd55256593a705698\"},\"mac\":\"dc0a3bc555ac8f22d84115968b5fde6f50eb065ff7fe47a1da30de668a5ca864\"},\"id\":\"339ef573-a7d5-4bd0-86b2-3b1e420439d7\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] - [TestCase("{\"address\":\"25dead29c683c5db3e0fabcf8f3757cdb0abe549\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"4fd59f3a3fa1bed32774b29a40886d5489c0c06a8da014cb44b25792f6c32cb2\",\"cipherparams\":{\"iv\":\"6b850162043a0a879726839cfca55220\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"cafbe520e0d711cf32d9a2e6b2ecbd231cc7aed09018c5032c637436e02754d1\"},\"mac\":\"379f51c673f1f355a6ffc92b31b37381670eea2e0e23604a2572f5df650d148e\"},\"id\":\"fc7ff6bf-c51e-4e02-bb7c-0c91a3eeab4c\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] - public void Same_storage_format_as_in_geth(string keyJson) + finally { - TestContext test = new TestContext(); - EthereumJsonSerializer serializer = new EthereumJsonSerializer(); - KeyStoreItem item = serializer.Deserialize(keyJson); - - SecureString securePassword = new SecureString(); - string password = "testpuppeth"; - for (int i = 0; i < password.Length; i++) - { - securePassword.AppendChar(password[i]); - } + test.Store.DeleteKey(new Address(item.Address)); + } + } - Address address = new Address(item.Address); - test.Store.StoreKey(address, item); + [TestCase("{\"address\":\"20b2e4bb8688a44729780d15dc64adb42f9f5a0a\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"d30cbb0f5b30ef86e57b7fa111307398b911b8c0a3eab4ac4edc4b2c8839afbe\",\"cipherparams\":{\"iv\":\"1e29e79023d73be3f3bb065ca9ddc078\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"fffcd979c3223b3cdfcb2cf21b07bd4313e6f8d02af8a79a5c5dc879a25680d3\"},\"mac\":\"3ac5a539775c33bd73adfd2c0d4ef8c9154e4b404e2a15c77b0e6c78cb90df20\"},\"id\":\"68462de1-4114-4f92-828b-883fae5f779c\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] + [TestCase("{\"address\":\"746526c3a59db995b914a319306cd7ae35dc50c5\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"644b1af45188b23f6195abd2b0563d7b079ff6622e5ac61767cd81cbd621a13e\",\"cipherparams\":{\"iv\":\"844c895835de8571409b8a76a75672b2\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"e7df76e322e444ed61314fa5261cf0ac02b9c057fe626a74a37c5255c16a8d61\"},\"mac\":\"48f26081eec397b818ed4e2cb3b1c04908c671a81d6b183e9965d869bd001862\"},\"id\":\"6ee56be1-367f-4b41-a25d-f60e0a7bfe42\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] + [TestCase("{\"address\":\"aa42104423e00a862b616f2f712a1b17d308bbc9\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"450c341ab64c39237039a30a8d84cc112dfbdda889caa19201b0cf8473680936\",\"cipherparams\":{\"iv\":\"923d950dcdba710a0c8e240441e0a227\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"101185ea81a1067591bce5323d75648b753f71becc22a4ebd55256593a705698\"},\"mac\":\"dc0a3bc555ac8f22d84115968b5fde6f50eb065ff7fe47a1da30de668a5ca864\"},\"id\":\"339ef573-a7d5-4bd0-86b2-3b1e420439d7\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] + [TestCase("{\"address\":\"25dead29c683c5db3e0fabcf8f3757cdb0abe549\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"4fd59f3a3fa1bed32774b29a40886d5489c0c06a8da014cb44b25792f6c32cb2\",\"cipherparams\":{\"iv\":\"6b850162043a0a879726839cfca55220\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"cafbe520e0d711cf32d9a2e6b2ecbd231cc7aed09018c5032c637436e02754d1\"},\"mac\":\"379f51c673f1f355a6ffc92b31b37381670eea2e0e23604a2572f5df650d148e\"},\"id\":\"fc7ff6bf-c51e-4e02-bb7c-0c91a3eeab4c\",\"version\":3}", Ignore = "Order of fields changed from geth to mycryptowallet.")] + public void Same_storage_format_as_in_geth(string keyJson) + { + TestContext test = new TestContext(); + EthereumJsonSerializer serializer = new EthereumJsonSerializer(); + KeyStoreItem item = serializer.Deserialize(keyJson); - try - { - string[] files = test.Store.FindKeyFiles(address); - Assert.That(files.Length, Is.EqualTo(1)); - string text = File.ReadAllText(files[0]); - Assert.That(text, Is.EqualTo(keyJson), "same json"); - } - finally - { - test.Store.DeleteKey(new Address(item.Address)); - } + SecureString securePassword = new SecureString(); + string password = "testpuppeth"; + for (int i = 0; i < password.Length; i++) + { + securePassword.AppendChar(password[i]); } - [Test] - public void GenerateKeyAddressesTest() + Address address = new Address(item.Address); + test.Store.StoreKey(address, item); + + try { - TestContext test = new TestContext(); + string[] files = test.Store.FindKeyFiles(address); + Assert.That(files.Length, Is.EqualTo(1)); + string text = File.ReadAllText(files[0]); + Assert.That(text, Is.EqualTo(keyJson), "same json"); + } + finally + { + test.Store.DeleteKey(new Address(item.Address)); + } + } - PrivateKey key1; - PrivateKey key2; + [Test] + public void GenerateKeyAddressesTest() + { + TestContext test = new TestContext(); - string notAKeyPath = Path.Combine(test.KeyStoreConfig.KeyStoreDirectory, "not_a_key"); + PrivateKey key1; + PrivateKey key2; - using (var stream = File.Create(notAKeyPath)) - { - } + string notAKeyPath = Path.Combine(test.KeyStoreConfig.KeyStoreDirectory, "not_a_key"); - try - { - Result result; - (key1, result) = test.Store.GenerateKey(test.TestPasswordSecured); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "generate key 1"); + using (var stream = File.Create(notAKeyPath)) + { + } - (key2, result) = test.Store.GenerateKey(test.TestPasswordSecured); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "generate key 2"); + try + { + Result result; + (key1, result) = test.Store.GenerateKey(test.TestPasswordSecured); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "generate key 1"); - (IReadOnlyCollection
addresses, Result getAllResult) = test.Store.GetKeyAddresses(); - Assert.That(getAllResult.ResultType, Is.EqualTo(ResultType.Success), "get key"); - Assert.IsTrue(addresses.Count() >= 2); - Assert.IsNotNull(addresses.FirstOrDefault(x => x.Equals(key1.Address)), "key 1 not null"); - Assert.IsNotNull(addresses.FirstOrDefault(x => x.Equals(key2.Address)), "key 2 not null"); + (key2, result) = test.Store.GenerateKey(test.TestPasswordSecured); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "generate key 2"); - result = test.Store.DeleteKey(key1.Address); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "delete key 1"); + (IReadOnlyCollection
addresses, Result getAllResult) = test.Store.GetKeyAddresses(); + Assert.That(getAllResult.ResultType, Is.EqualTo(ResultType.Success), "get key"); + Assert.That(addresses.Count() >= 2, Is.True); + Assert.That(addresses.FirstOrDefault(x => x.Equals(key1.Address)), Is.Not.Null, "key 1 not null"); + Assert.That(addresses.FirstOrDefault(x => x.Equals(key2.Address)), Is.Not.Null, "key 2 not null"); - result = test.Store.DeleteKey(key2.Address); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "delete key 2"); - } - finally - { - File.Delete(notAKeyPath); - } - } + result = test.Store.DeleteKey(key1.Address); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "delete key 1"); - [Test] - public void GenerateKeyTest() + result = test.Store.DeleteKey(key2.Address); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "delete key 2"); + } + finally { - TestContext test = new TestContext(); - (PrivateKey, Result) key = test.Store.GenerateKey(test.TestPasswordSecured); - Assert.That(key.Item2.ResultType, Is.EqualTo(ResultType.Success)); + File.Delete(notAKeyPath); + } + } - (PrivateKey, Result) persistedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); - Assert.That(persistedKey.Item2.ResultType, Is.EqualTo(ResultType.Success)); - Assert.IsTrue(Bytes.AreEqual(key.Item1.KeyBytes, persistedKey.Item1.KeyBytes)); + [Test] + public void GenerateKeyTest() + { + TestContext test = new TestContext(); + (PrivateKey, Result) key = test.Store.GenerateKey(test.TestPasswordSecured); + Assert.That(key.Item2.ResultType, Is.EqualTo(ResultType.Success)); - Result result = test.Store.DeleteKey(key.Item1.Address); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success)); + (PrivateKey, Result) persistedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); + Assert.That(persistedKey.Item2.ResultType, Is.EqualTo(ResultType.Success)); + Assert.That(Bytes.AreEqual(key.Item1.KeyBytes, persistedKey.Item1.KeyBytes), Is.True); - (PrivateKey, Result) deletedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); - Assert.That(deletedKey.Item2.ResultType, Is.EqualTo(ResultType.Failure)); - } + Result result = test.Store.DeleteKey(key.Item1.Address); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success)); - [Test] - public void Salt32Test() - { - TestContext test = new TestContext(); - (PrivateKey, Result) key = test.Store.GenerateKey(test.TestPasswordSecured); - Assert.That(key.Item2.ResultType, Is.EqualTo(ResultType.Success)); + (PrivateKey, Result) deletedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); + Assert.That(deletedKey.Item2.ResultType, Is.EqualTo(ResultType.Failure)); + } - (PrivateKey, Result) persistedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); - Assert.That(persistedKey.Item2.ResultType, Is.EqualTo(ResultType.Success)); - Assert.IsTrue(Bytes.AreEqual(key.Item1.KeyBytes, persistedKey.Item1.KeyBytes)); + [Test] + public void Salt32Test() + { + TestContext test = new TestContext(); + (PrivateKey, Result) key = test.Store.GenerateKey(test.TestPasswordSecured); + Assert.That(key.Item2.ResultType, Is.EqualTo(ResultType.Success)); - Result result = test.Store.DeleteKey(key.Item1.Address); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success)); + (PrivateKey, Result) persistedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); + Assert.That(persistedKey.Item2.ResultType, Is.EqualTo(ResultType.Success)); + Assert.That(Bytes.AreEqual(key.Item1.KeyBytes, persistedKey.Item1.KeyBytes), Is.True); - (PrivateKey, Result) deletedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); - Assert.That(deletedKey.Item2.ResultType, Is.EqualTo(ResultType.Failure)); - } + Result result = test.Store.DeleteKey(key.Item1.Address); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success)); - [Test] - public void KeyStoreVersionMismatchTest() - { - TestContext test = new TestContext(); - //generate key - (PrivateKey key, Result storeResult) = test.Store.GenerateKey(test.TestPasswordSecured); - Assert.That(storeResult.ResultType, Is.EqualTo(ResultType.Success), "generate result"); + (PrivateKey, Result) deletedKey = test.Store.GetKey(key.Item1.Address, test.TestPasswordSecured); + Assert.That(deletedKey.Item2.ResultType, Is.EqualTo(ResultType.Failure)); + } - (KeyStoreItem keyData, Result result) = test.Store.GetKeyData(key.Address); - Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "load result"); + [Test] + public void KeyStoreVersionMismatchTest() + { + TestContext test = new TestContext(); + //generate key + (PrivateKey key, Result storeResult) = test.Store.GenerateKey(test.TestPasswordSecured); + Assert.That(storeResult.ResultType, Is.EqualTo(ResultType.Success), "generate result"); - Result deleteResult = test.Store.DeleteKey(key.Address); - Assert.That(deleteResult.ResultType, Is.EqualTo(ResultType.Success), "delete result"); + (KeyStoreItem keyData, Result result) = test.Store.GetKeyData(key.Address); + Assert.That(result.ResultType, Is.EqualTo(ResultType.Success), "load result"); - keyData.Version = 0; - test.Store.StoreKey(key.Address, keyData); + Result deleteResult = test.Store.DeleteKey(key.Address); + Assert.That(deleteResult.ResultType, Is.EqualTo(ResultType.Success), "delete result"); - (_, Result loadResult) = test.Store.GetKey(key.Address, test.TestPasswordSecured); - Assert.That(loadResult.ResultType, Is.EqualTo(ResultType.Failure), "bad load result"); - Assert.That(loadResult.Error, Is.EqualTo("KeyStore version mismatch")); + keyData.Version = 0; + test.Store.StoreKey(key.Address, keyData); - test.Store.DeleteKey(key.Address); - } + (_, Result loadResult) = test.Store.GetKey(key.Address, test.TestPasswordSecured); + Assert.That(loadResult.ResultType, Is.EqualTo(ResultType.Failure), "bad load result"); + Assert.That(loadResult.Error, Is.EqualTo("KeyStore version mismatch")); - [Test] - public void WrongPasswordTest() - { - TestContext test = new TestContext(); - (PrivateKey key, Result generateResult) = test.Store.GenerateKey(test.TestPasswordSecured); - Assert.That(generateResult.ResultType, Is.EqualTo(ResultType.Success)); + test.Store.DeleteKey(key.Address); + } - (PrivateKey keyRestored, Result getResult) = test.Store.GetKey(key.Address, test.TestPasswordSecured); - Assert.That(getResult.ResultType, Is.EqualTo(ResultType.Success)); - Assert.IsTrue(Bytes.AreEqual(key.KeyBytes, keyRestored.KeyBytes)); + [Test] + public void WrongPasswordTest() + { + TestContext test = new TestContext(); + (PrivateKey key, Result generateResult) = test.Store.GenerateKey(test.TestPasswordSecured); + Assert.That(generateResult.ResultType, Is.EqualTo(ResultType.Success)); - (PrivateKey _, Result wrongResult) = test.Store.GetKey(key.Address, test.WrongPasswordSecured); - Assert.That(wrongResult.ResultType, Is.EqualTo(ResultType.Failure)); - Assert.That(wrongResult.Error, Is.EqualTo("Incorrect MAC")); + (PrivateKey keyRestored, Result getResult) = test.Store.GetKey(key.Address, test.TestPasswordSecured); + Assert.That(getResult.ResultType, Is.EqualTo(ResultType.Success)); + Assert.That(Bytes.AreEqual(key.KeyBytes, keyRestored.KeyBytes), Is.True); - Result deleteResult = test.Store.DeleteKey(key.Address); - Assert.That(deleteResult.ResultType, Is.EqualTo(ResultType.Success)); - } + (PrivateKey _, Result wrongResult) = test.Store.GetKey(key.Address, test.WrongPasswordSecured); + Assert.That(wrongResult.ResultType, Is.EqualTo(ResultType.Failure)); + Assert.That(wrongResult.Error, Is.EqualTo("Incorrect MAC")); - [Test] - public void ShouldSaveFileWithoutBom() - { - TestContext test = new TestContext(); - const string bomBytesHex = "efbbbf"; - const string validBytesHex = "7b2276"; - var (key, _) = test.Store.GenerateKey(test.TestPasswordSecured); - var directory = test.KeyStoreConfig.KeyStoreDirectory.GetApplicationResourcePath(); - var addressHex = key.Address.ToString(false, false); - var file = Directory.GetFiles(directory).SingleOrDefault(f => f.Contains(addressHex)); - var bytes = File.ReadAllBytes(file); - test.Store.DeleteKey(key.Address); - var bytesHex = bytes.ToHexString(); - bytesHex.Should().NotStartWith(bomBytesHex); - bytesHex.Should().StartWith(validBytesHex); - } + Result deleteResult = test.Store.DeleteKey(key.Address); + Assert.That(deleteResult.ResultType, Is.EqualTo(ResultType.Success)); + } + + [Test] + public void ShouldSaveFileWithoutBom() + { + TestContext test = new TestContext(); + const string bomBytesHex = "efbbbf"; + const string validBytesHex = "7b2276"; + var (key, _) = test.Store.GenerateKey(test.TestPasswordSecured); + var directory = test.KeyStoreConfig.KeyStoreDirectory.GetApplicationResourcePath(); + var addressHex = key.Address.ToString(false, false); + var file = Directory.GetFiles(directory).SingleOrDefault(f => f.Contains(addressHex)); + var bytes = File.ReadAllBytes(file); + test.Store.DeleteKey(key.Address); + var bytesHex = bytes.ToHexString(); + bytesHex.Should().NotStartWith(bomBytesHex); + bytesHex.Should().StartWith(validBytesHex); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs index a801e17ed89..2e1873f021a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs @@ -79,11 +79,11 @@ public void Can_suggest_terminal_block_correctly() PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, new ChainSpec(), LimboLogs.Instance); Block? block8 = tree.FindBlock(8, BlockTreeLookupOptions.None); - Assert.False(block8!.IsTerminalBlock(specProvider)); + Assert.That(block8!.IsTerminalBlock(specProvider), Is.False); Assert.That(tree.BestKnownNumber, Is.EqualTo(9)); Assert.That(tree.BestSuggestedBody!.Number, Is.EqualTo(9)); Assert.That(tree.Head!.Number, Is.EqualTo(9)); - Assert.True(tree.Head.IsTerminalBlock(specProvider)); + Assert.That(tree.Head.IsTerminalBlock(specProvider), Is.True); } [Test] @@ -105,11 +105,11 @@ public void Suggest_terminal_block_with_lower_number_and_lower_total_difficulty( .WithNumber(block7!.Number + 1).WithDifficulty(1999950).TestObject; // current Head TD: 10000000, block7 TD: 8000000, TTD 9999900, newTerminalBlock 9999950 tree.SuggestBlock(newTerminalBlock); - Assert.True(newTerminalBlock.IsTerminalBlock(specProvider)); + Assert.That(newTerminalBlock.IsTerminalBlock(specProvider), Is.True); Assert.That(tree.BestKnownNumber, Is.EqualTo(9)); Assert.That(tree.BestSuggestedBody!.Number, Is.EqualTo(9)); Assert.That(tree.Head!.Number, Is.EqualTo(9)); - Assert.True(tree.Head.IsTerminalBlock(specProvider)); + Assert.That(tree.Head.IsTerminalBlock(specProvider), Is.True); } [Test] @@ -127,11 +127,11 @@ public void Cannot_change_best_suggested_to_terminal_block_after_merge_block() PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, new ChainSpec(), LimboLogs.Instance); Block? block8 = tree.FindBlock(8, BlockTreeLookupOptions.None); - Assert.False(block8!.Header.IsTerminalBlock(specProvider)); + Assert.That(block8!.Header.IsTerminalBlock(specProvider), Is.False); Assert.That(tree.BestKnownNumber, Is.EqualTo(9)); Assert.That(tree.BestSuggestedBody!.Number, Is.EqualTo(9)); Assert.That(tree.Head!.Number, Is.EqualTo(9)); - Assert.True(tree.Head.IsTerminalBlock(specProvider)); + Assert.That(tree.Head.IsTerminalBlock(specProvider), Is.True); Block firstPoSBlock = Build.A.Block .WithHeader(Build.A.BlockHeader.WithParent(tree.Head!.Header).TestObject) @@ -148,7 +148,7 @@ public void Cannot_change_best_suggested_to_terminal_block_after_merge_block() .WithParent(block8!) .WithTotalDifficulty((UInt256)10000001) .WithNumber(block8!.Number + 1).WithDifficulty(2000001).TestObject; - Assert.True(newTerminalBlock.IsTerminalBlock(specProvider)); + Assert.That(newTerminalBlock.IsTerminalBlock(specProvider), Is.True); tree.SuggestBlock(newTerminalBlock); Assert.That(tree.BestKnownNumber, Is.EqualTo(10)); Assert.That(tree.BestSuggestedBody!.Number, Is.EqualTo(10)); @@ -228,7 +228,7 @@ public void FindHeader_will_not_change_total_difficulty_when_it_is_zero() Assert.That(insertResult, Is.EqualTo(insertOutcome)); BlockHeader? headerToCheck = notSyncedTree.FindHeader(beaconHeader.Hash, BlockTreeLookupOptions.None); - Assert.IsNull(headerToCheck!.TotalDifficulty); + Assert.That(headerToCheck!.TotalDifficulty, Is.Null); } [Test] @@ -246,7 +246,7 @@ public void FindBlock_will_not_change_total_difficulty_when_it_is_zero() Assert.That(insertResult, Is.EqualTo(insertOutcome)); Block? blockToCheck = notSyncedTree.FindBlock(beaconBlock2.Hash, BlockTreeLookupOptions.None); - Assert.IsNull(blockToCheck!.TotalDifficulty); + Assert.That(blockToCheck!.TotalDifficulty, Is.Null); } @@ -365,7 +365,7 @@ public ScenarioBuilder SuggestBlocksUsingChainLevels(int maxCount = 2, long maxH } AddBlockResult insertResult = NotSyncedTree.SuggestBlock(beaconBlock, BlockTreeSuggestOptions.ShouldProcess | BlockTreeSuggestOptions.FillBeaconBlock | BlockTreeSuggestOptions.ForceSetAsMain); - Assert.True(AddBlockResult.Added == insertResult, $"BeaconBlock {beaconBlock!.ToString(Block.Format.FullHashAndNumber)} result {insertResult}"); + Assert.That(AddBlockResult.Added == insertResult, Is.True, $"BeaconBlock {beaconBlock!.ToString(Block.Format.FullHashAndNumber)} result {insertResult}"); } headers = _chainLevelHelper!.GetNextHeaders(maxCount, maxHeaderNumber, 0)!; @@ -514,8 +514,8 @@ public ScenarioBuilder AssertMetadata(int startNumber, int finalNumber, BlockMet public ScenarioBuilder AssertLowestInsertedBeaconHeader(long expected) { - Assert.IsNotNull(NotSyncedTree); - Assert.IsNotNull(NotSyncedTree!.LowestInsertedBeaconHeader); + Assert.That(NotSyncedTree, Is.Not.Null); + Assert.That(NotSyncedTree!.LowestInsertedBeaconHeader, Is.Not.Null); Assert.That(NotSyncedTree!.LowestInsertedBeaconHeader!.Number, Is.EqualTo(expected)); Console.WriteLine("LowestInsertedBeaconHeader:" + NotSyncedTree!.LowestInsertedBeaconHeader!.Number); return this; @@ -543,16 +543,16 @@ public ScenarioBuilder InsertToBlockDb(Block block) public ScenarioBuilder AssertBestBeaconHeader(long expected) { - Assert.IsNotNull(NotSyncedTree); - Assert.IsNotNull(NotSyncedTree.BestSuggestedBeaconHeader); + Assert.That(NotSyncedTree, Is.Not.Null); + Assert.That(NotSyncedTree.BestSuggestedBeaconHeader, Is.Not.Null); Assert.That(NotSyncedTree.BestSuggestedBeaconHeader?.Number, Is.EqualTo(expected)); return this; } public ScenarioBuilder AssertBestBeaconBody(long expected) { - Assert.IsNotNull(NotSyncedTree); - Assert.IsNotNull(NotSyncedTree.BestSuggestedBeaconBody); + Assert.That(NotSyncedTree, Is.Not.Null); + Assert.That(NotSyncedTree.BestSuggestedBeaconBody, Is.Not.Null); Assert.That(NotSyncedTree.BestSuggestedBeaconBody?.Number, Is.EqualTo(expected)); return this; } @@ -802,7 +802,7 @@ public void MarkChainAsProcessed_does_not_change_main_chain() AddBlockResult addBlockResult = blockTree.SuggestBlock(newBlock); Assert.That(addBlockResult, Is.EqualTo(AddBlockResult.Added)); blockTree.MarkChainAsProcessed(new[] { newBlock }); - Assert.False(blockTree.IsMainChain(newBlock.Header)); + Assert.That(blockTree.IsMainChain(newBlock.Header), Is.False); } [Test] diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs index 51d7571ec21..5501820429f 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.IO; -using System.Linq; using Nethermind.Core.Specs; using Nethermind.Int256; using Nethermind.Serialization.Json; @@ -42,9 +41,9 @@ public void Correctly_read_merge_parameters_from_file() Assert.That(chainSpec.TerminalTotalDifficulty, Is.EqualTo((UInt256)10)); Assert.That(chainSpec.MergeForkIdBlockNumber, Is.EqualTo(72)); - Assert.True(provider.TransitionActivations.ToList().Contains((ForkActivation)72)); // MergeForkIdBlockNumber should affect transition blocks - Assert.False(provider.TransitionActivations.ToList().Contains((ForkActivation)100)); // merge block number shouldn't affect transition blocks - Assert.False(provider.TransitionActivations.ToList().Contains((ForkActivation)101)); // merge block number shouldn't affect transition blocks + Assert.That(provider.TransitionActivations, Has.Member((ForkActivation)72)); // MergeForkIdBlockNumber should affect transition blocks + Assert.That(provider.TransitionActivations, Has.No.Member((ForkActivation)100)); // merge block number shouldn't affect transition blocks + Assert.That(provider.TransitionActivations, Has.No.Member((ForkActivation)101)); // merge block number shouldn't affect transition blocks } [Test] diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs index c3c2f884436..da2e62ef01a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs @@ -974,14 +974,14 @@ public async Task Invalid_block_can_create_invalid_best_state_issue_but_recalcul response.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); // invalid best state calculation - Assert.True(chain.BlockTree.BestSuggestedBody!.Number < chain.BlockTree.Head!.Number); - Assert.True(chain.BlockTree.BestSuggestedHeader!.Number < chain.BlockTree.Head!.Number); + Assert.That(chain.BlockTree.BestSuggestedBody!.Number, Is.LessThan(chain.BlockTree.Head!.Number)); + Assert.That(chain.BlockTree.BestSuggestedHeader!.Number, Is.LessThan(chain.BlockTree.Head!.Number)); // autofix chain.BlockTree.RecalculateTreeLevels(); - Assert.True(chain.BlockTree.BestSuggestedBody!.Number >= chain.BlockTree.Head!.Number); - Assert.True(chain.BlockTree.BestSuggestedHeader!.Number >= chain.BlockTree.Head!.Number); + Assert.That(chain.BlockTree.BestSuggestedBody!.Number, Is.GreaterThanOrEqualTo(chain.BlockTree.Head!.Number)); + Assert.That(chain.BlockTree.BestSuggestedHeader!.Number, Is.GreaterThanOrEqualTo(chain.BlockTree.Head!.Number)); } [Test] @@ -1011,14 +1011,14 @@ public async Task MultiSyncModeSelector_should_fix_block_tree_levels_if_needed() response.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); // invalid best state calculation - Assert.True(chain.BlockTree.BestSuggestedBody!.Number < chain.BlockTree.Head!.Number); - Assert.True(chain.BlockTree.BestSuggestedHeader!.Number < chain.BlockTree.Head!.Number); + Assert.That(chain.BlockTree.BestSuggestedBody!.Number, Is.LessThan(chain.BlockTree.Head!.Number)); + Assert.That(chain.BlockTree.BestSuggestedHeader!.Number, Is.LessThan(chain.BlockTree.Head!.Number)); MultiSyncModeSelector multiSyncModeSelector = CreateMultiSyncModeSelector(chain); multiSyncModeSelector.Update(); - Assert.True(chain.BlockTree.BestSuggestedBody!.Number >= chain.BlockTree.Head!.Number); - Assert.True(chain.BlockTree.BestSuggestedHeader!.Number >= chain.BlockTree.Head!.Number); + Assert.That(chain.BlockTree.BestSuggestedBody!.Number, Is.GreaterThanOrEqualTo(chain.BlockTree.Head!.Number)); + Assert.That(chain.BlockTree.BestSuggestedHeader!.Number, Is.GreaterThanOrEqualTo(chain.BlockTree.Head!.Number)); } private MultiSyncModeSelector CreateMultiSyncModeSelector(MergeTestBlockchain chain) diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs index 35e46353acd..83af60a8eff 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs @@ -25,7 +25,6 @@ using Nethermind.Int256; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; -using Nethermind.JsonRpc.Modules.Eth; using Nethermind.JsonRpc.Test; using Nethermind.JsonRpc.Test.Modules; using Nethermind.Logging; @@ -36,8 +35,6 @@ using Nethermind.Specs.ChainSpecStyle; using Nethermind.Specs.Forks; using Nethermind.State; -using Nethermind.Trie; - using NSubstitute; using NUnit.Framework; @@ -1081,7 +1078,7 @@ public async Task executePayloadV1_transactions_produce_receipts() chain.StateReader.HasStateForRoot(executionPayload.StateRoot).Should().BeTrue(); UInt256 fromBalanceAfter = chain.StateReader.GetBalance(executionPayload.StateRoot, from.Address); - Assert.True(fromBalanceAfter < fromBalance - toBalanceAfter); + Assert.That(fromBalanceAfter, Is.LessThan(fromBalance - toBalanceAfter)); chain.StateReader.GetBalance(executionPayload.StateRoot, to).Should().Be(toBalanceAfter); Block findBlock = chain.BlockTree.FindBlock(executionPayload.BlockHash, BlockTreeLookupOptions.None)!; TxReceipt[]? receipts = chain.ReceiptStorage.Get(findBlock); @@ -1490,7 +1487,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1, forkchoiceUpdatedResult2.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); Hash256 currentBlockHash = chain.BlockTree.Head!.Hash!; - Assert.True(currentBlockHash == executionPayloadV12.BlockHash); + Assert.That(currentBlockHash == executionPayloadV12.BlockHash, Is.True); } // re-org @@ -1512,9 +1509,9 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1, forkchoiceUpdatedResult3.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); Hash256 currentBlockHash = chain.BlockTree.Head!.Hash!; - Assert.False(currentBlockHash != forkChoiceState3.HeadBlockHash || + Assert.That(currentBlockHash != forkChoiceState3.HeadBlockHash || currentBlockHash == forkChoiceState3.SafeBlockHash || - currentBlockHash == forkChoiceState3.FinalizedBlockHash); + currentBlockHash == forkChoiceState3.FinalizedBlockHash, Is.False); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/ExternalRpcIntegrationTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/ExternalRpcIntegrationTests.cs index 23b20746b5b..1317e380c1b 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/ExternalRpcIntegrationTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/ExternalRpcIntegrationTests.cs @@ -6,69 +6,67 @@ using Nethermind.Core.Extensions; using Nethermind.Facade.Eth; using Nethermind.Int256; -using Nethermind.JsonRpc.Modules.Eth; using Nethermind.Overseer.Test.JsonRpc; using Nethermind.Serialization.Json; using Newtonsoft.Json.Linq; using NUnit.Framework; -namespace Nethermind.Merge.Plugin.Test +namespace Nethermind.Merge.Plugin.Test; + +public class ExternalRpcIntegrationTests { - public class ExternalRpcIntegrationTests + // don't want to change default BlockForRpc constructor to public + class BlockForRpcForTest : BlockForRpc { - // don't want to change default BlockForRpc constructor to public - class BlockForRpcForTest : BlockForRpc - { - } + } - [Test] - [Ignore("You need specify rpc for this test")] - public async Task CanonicalTreeIsConsistent() + [Test] + [Ignore("You need specify rpc for this test")] + public async Task CanonicalTreeIsConsistent() + { + IJsonSerializer jsonSerializer = new EthereumJsonSerializer(); + int destinationBlockNumber = 5000; + long? currentBlockNumber = null; + Hash256? currentHash = null; + JsonRpcClient? client = new($"http://127.0.0.1:8545"); + do { - IJsonSerializer jsonSerializer = new EthereumJsonSerializer(); - int destinationBlockNumber = 5000; - long? currentBlockNumber = null; - Hash256? currentHash = null; - JsonRpcClient? client = new($"http://127.0.0.1:8545"); - do + string? requestedBlockNumber = currentBlockNumber is null ? "latest" : currentBlockNumber.Value.ToHexString(false); + JsonRpcResponse? requestResponse = + await client.PostAsync("eth_getBlockByNumber", new object[] { requestedBlockNumber!, false }); + BlockForRpcForTest? block = jsonSerializer.Deserialize(requestResponse.Result.ToString()); + if (currentHash is not null) { - string? requestedBlockNumber = currentBlockNumber is null ? "latest" : currentBlockNumber.Value.ToHexString(false); - JsonRpcResponse? requestResponse = - await client.PostAsync("eth_getBlockByNumber", new object[] { requestedBlockNumber!, false }); - BlockForRpcForTest? block = jsonSerializer.Deserialize(requestResponse.Result.ToString()); - if (currentHash is not null) - { - Assert.That(block.Hash, Is.EqualTo(currentHash), $"incorrect block hash found {block}"); - } + Assert.That(block.Hash, Is.EqualTo(currentHash), $"incorrect block hash found {block}"); + } - currentHash = block.ParentHash; - currentBlockNumber = block.Number!.Value - 1; - } while (currentBlockNumber != destinationBlockNumber); - } + currentHash = block.ParentHash; + currentBlockNumber = block.Number!.Value - 1; + } while (currentBlockNumber != destinationBlockNumber); + } - [Test] - [Ignore("You need specify rpc for this test")] - public async Task ParentTimestampIsAlwaysLowerThanChildTimestamp() + [Test] + [Ignore("You need specify rpc for this test")] + public async Task ParentTimestampIsAlwaysLowerThanChildTimestamp() + { + IJsonSerializer jsonSerializer = new EthereumJsonSerializer(); + int destinationBlockNumber = 5000; + long? currentBlockNumber = null; + UInt256? childTimestamp = null; + JsonRpcClient? client = new($"http://127.0.0.1:8545"); + do { - IJsonSerializer jsonSerializer = new EthereumJsonSerializer(); - int destinationBlockNumber = 5000; - long? currentBlockNumber = null; - UInt256? childTimestamp = null; - JsonRpcClient? client = new($"http://127.0.0.1:8545"); - do + string? requestedBlockNumber = currentBlockNumber is null ? "latest" : currentBlockNumber.Value.ToHexString(false); + JsonRpcResponse? requestResponse = + await client.PostAsync("eth_getBlockByNumber", [requestedBlockNumber!, false]); + BlockForRpcForTest? block = jsonSerializer.Deserialize(requestResponse.Result.ToString()); + if (childTimestamp is not null) { - string? requestedBlockNumber = currentBlockNumber is null ? "latest" : currentBlockNumber.Value.ToHexString(false); - JsonRpcResponse? requestResponse = - await client.PostAsync("eth_getBlockByNumber", new object[] { requestedBlockNumber!, false }); - BlockForRpcForTest? block = jsonSerializer.Deserialize(requestResponse.Result.ToString()); - if (childTimestamp is not null) - { - Assert.True(childTimestamp > block.Timestamp, $"incorrect timestamp for block {block}"); - } + Assert.That(childTimestamp, Is.GreaterThan(block.Timestamp), $"incorrect timestamp for block {block}"); + } - childTimestamp = block.Timestamp; - currentBlockNumber = block.Number!.Value - 1; - } while (currentBlockNumber != destinationBlockNumber); - } + childTimestamp = block.Timestamp; + currentBlockNumber = block.Number!.Value - 1; + } while (currentBlockNumber != destinationBlockNumber); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs index ae09a209b5c..d93e6c8a649 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs @@ -34,7 +34,7 @@ public void Setup() { _mergeConfig = new MergeConfig() { TerminalTotalDifficulty = "0" }; BlocksConfig? miningConfig = new(); - IJsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { Enabled = true, EnabledModules = new[] { ModuleType.Engine } }; + IJsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { Enabled = true, EnabledModules = [ModuleType.Engine] }; _context = Build.ContextWithMocks(); _context.SealEngineType = SealEngineType.Clique; @@ -109,10 +109,10 @@ public async Task Initializes_correctly() await _plugin.InitSynchronization(); await _plugin.InitNetworkProtocol(); ISyncConfig syncConfig = _context.Config(); - Assert.IsTrue(syncConfig.NetworkingEnabled); - Assert.IsTrue(_context.GossipPolicy.CanGossipBlocks); + Assert.That(syncConfig.NetworkingEnabled, Is.True); + Assert.That(_context.GossipPolicy.CanGossipBlocks, Is.True); _plugin.InitBlockProducer(_consensusPlugin!, null); - Assert.IsInstanceOf(_context.BlockProducer); + Assert.That(_context.BlockProducer, Is.InstanceOf()); await _plugin.InitRpcModules(); _context.RpcModuleProvider!.Received().Register(Arg.Is>(m => m is SingletonModulePool)); await _plugin.DisposeAsync(); diff --git a/src/Nethermind/Nethermind.Mining.Test/EthashSealEngineTests.cs b/src/Nethermind/Nethermind.Mining.Test/EthashSealEngineTests.cs index c0fdf9a0392..ae6029abff9 100644 --- a/src/Nethermind/Nethermind.Mining.Test/EthashSealEngineTests.cs +++ b/src/Nethermind/Nethermind.Mining.Test/EthashSealEngineTests.cs @@ -14,75 +14,73 @@ using Nethermind.Logging; using NUnit.Framework; -namespace Nethermind.Mining.Test +namespace Nethermind.Mining.Test; + +[Parallelizable(ParallelScope.Self)] +public class EthashSealEngineTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class EthashSealEngineTests + [Test] + public async Task Can_mine() { - [Test] - public async Task Can_mine() - { - ulong validNonce = 971086423715460064; - - BlockHeader header = new(Keccak.Zero, Keccak.OfAnEmptySequenceRlp, Address.Zero, 27, 1, 21000, 1, new byte[] { 1, 2, 3 }); - header.TxRoot = Keccak.Zero; - header.ReceiptsRoot = Keccak.Zero; - header.UnclesHash = Keccak.Zero; - header.StateRoot = Keccak.Zero; - header.Bloom = Bloom.Empty; + ulong validNonce = 971086423715460064; - Block block = new(header); - EthashSealer ethashSealer = new(new Ethash(LimboLogs.Instance), NullSigner.Instance, LimboLogs.Instance); - using CancellationTokenSource cancellationTokenSource = new(TimeSpan.FromSeconds(600)); - await ethashSealer.MineAsync(cancellationTokenSource.Token, block, validNonce - 3); + BlockHeader header = new(Keccak.Zero, Keccak.OfAnEmptySequenceRlp, Address.Zero, 27, 1, 21000, 1, new byte[] { 1, 2, 3 }); + header.TxRoot = Keccak.Zero; + header.ReceiptsRoot = Keccak.Zero; + header.UnclesHash = Keccak.Zero; + header.StateRoot = Keccak.Zero; + header.Bloom = Bloom.Empty; - Assert.That(block.Header.Nonce, Is.EqualTo(validNonce)); - Assert.That(block.Header.MixHash, Is.EqualTo(new Hash256("0x52b96cf62447129c6bd81f835721ee145b948ae3b05ef6eae454cbf69a5bc05d"))); - } + Block block = new(header); + EthashSealer ethashSealer = new(new Ethash(LimboLogs.Instance), NullSigner.Instance, LimboLogs.Instance); + using CancellationTokenSource cancellationTokenSource = new(TimeSpan.FromSeconds(600)); + await ethashSealer.MineAsync(cancellationTokenSource.Token, block, validNonce - 3); - [Test] - public async Task Can_cancel() - { - ulong badNonce = 971086423715459953; // change if valid + Assert.That(block.Header.Nonce, Is.EqualTo(validNonce)); + Assert.That(block.Header.MixHash, Is.EqualTo(new Hash256("0x52b96cf62447129c6bd81f835721ee145b948ae3b05ef6eae454cbf69a5bc05d"))); + } - BlockHeader header = new(Keccak.Zero, Keccak.OfAnEmptySequenceRlp, Address.Zero, (UInt256)BigInteger.Pow(2, 32), 1, 21000, 1, new byte[] { 1, 2, 3 }); - header.TxRoot = Keccak.Zero; - header.ReceiptsRoot = Keccak.Zero; - header.UnclesHash = Keccak.Zero; - header.StateRoot = Keccak.Zero; - header.Bloom = Bloom.Empty; + [Test] + public async Task Can_cancel() + { + ulong badNonce = 971086423715459953; // change if valid - Block block = new(header); - EthashSealer ethashSealer = new(new Ethash(LimboLogs.Instance), NullSigner.Instance, LimboLogs.Instance); - using CancellationTokenSource cancellationTokenSource = new(TimeSpan.FromMilliseconds(2000)); - await ethashSealer.MineAsync(cancellationTokenSource.Token, block, badNonce).ContinueWith(t => - { - Assert.True(t.IsCanceled); - }); - } + BlockHeader header = new(Keccak.Zero, Keccak.OfAnEmptySequenceRlp, Address.Zero, (UInt256)BigInteger.Pow(2, 32), 1, 21000, 1, new byte[] { 1, 2, 3 }); + header.TxRoot = Keccak.Zero; + header.ReceiptsRoot = Keccak.Zero; + header.UnclesHash = Keccak.Zero; + header.StateRoot = Keccak.Zero; + header.Bloom = Bloom.Empty; - [Test] - [Explicit("use just for finding nonces for other tests")] - public async Task Find_nonce() + Block block = new(header); + EthashSealer ethashSealer = new(new Ethash(LimboLogs.Instance), NullSigner.Instance, LimboLogs.Instance); + using CancellationTokenSource cancellationTokenSource = new(TimeSpan.FromMilliseconds(2000)); + await ethashSealer.MineAsync(cancellationTokenSource.Token, block, badNonce).ContinueWith(t => { - BlockHeader parentHeader = new(Keccak.Zero, Keccak.OfAnEmptySequenceRlp, Address.Zero, 131072, 0, 21000, 0, new byte[] { }); - parentHeader.Hash = parentHeader.CalculateHash(); + Assert.That(t.IsCanceled, Is.True); + }); + } + + [Test] + [Explicit("use just for finding nonces for other tests")] + public async Task Find_nonce() + { + BlockHeader parentHeader = new(Keccak.Zero, Keccak.OfAnEmptySequenceRlp, Address.Zero, 131072, 0, 21000, 0, new byte[] { }); + parentHeader.Hash = parentHeader.CalculateHash(); - BlockHeader blockHeader = new(parentHeader.Hash, Keccak.OfAnEmptySequenceRlp, Address.Zero, 131136, 1, 21000, 1, new byte[] { }); - blockHeader.Nonce = 7217048144105167954; - blockHeader.MixHash = new Hash256("0x37d9fb46a55e9dbbffc428f3a1be6f191b3f8eaf52f2b6f53c4b9bae62937105"); - blockHeader.Hash = blockHeader.CalculateHash(); - Block block = new(blockHeader); + BlockHeader blockHeader = new(parentHeader.Hash, Keccak.OfAnEmptySequenceRlp, Address.Zero, 131136, 1, 21000, 1, new byte[] { }); + blockHeader.Nonce = 7217048144105167954; + blockHeader.MixHash = new Hash256("0x37d9fb46a55e9dbbffc428f3a1be6f191b3f8eaf52f2b6f53c4b9bae62937105"); + blockHeader.Hash = blockHeader.CalculateHash(); + Block block = new(blockHeader); - IEthash ethash = new Ethash(LimboLogs.Instance); - EthashSealer ethashSealer = new(ethash, NullSigner.Instance, LimboLogs.Instance); - await ethashSealer.MineAsync(CancellationToken.None, block, 7217048144105167954); + IEthash ethash = new Ethash(LimboLogs.Instance); + EthashSealer ethashSealer = new(ethash, NullSigner.Instance, LimboLogs.Instance); + await ethashSealer.MineAsync(CancellationToken.None, block, 7217048144105167954); - Assert.True(ethash.Validate(block.Header)); + Assert.That(ethash.Validate(block.Header), Is.True); - Console.WriteLine(block.Header.Nonce); - Console.WriteLine(block.Header.MixHash); - } + Console.WriteLine(block.Header.Nonce); + Console.WriteLine(block.Header.MixHash); } } diff --git a/src/Nethermind/Nethermind.Mining.Test/EthashTests.cs b/src/Nethermind/Nethermind.Mining.Test/EthashTests.cs index c68eb031272..4232fea1417 100644 --- a/src/Nethermind/Nethermind.Mining.Test/EthashTests.cs +++ b/src/Nethermind/Nethermind.Mining.Test/EthashTests.cs @@ -13,848 +13,846 @@ using Nethermind.Specs; using NUnit.Framework; -namespace Nethermind.Mining.Test +namespace Nethermind.Mining.Test; + +[Parallelizable(ParallelScope.All)] +public class EthashTests { - [Parallelizable(ParallelScope.All)] - [TestFixture] - public class EthashTests + private readonly uint[] _cacheSizes = new uint[] { - private readonly uint[] _cacheSizes = new uint[] - { - 16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072, - 17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088, - 18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208, - 19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968, - 20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216, - 21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104, - 22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096, - 23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112, - 24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488, - 25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096, - 25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472, - 26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744, - 27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504, - 28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752, - 29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976, - 30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248, - 31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392, - 32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768, - 33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992, - 34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984, - 35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976, - 36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656, - 36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904, - 37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672, - 38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632, - 39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032, - 40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304, - 41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912, - 42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696, - 43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432, - 44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448, - 45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208, - 46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328, - 47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936, - 47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312, - 48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712, - 49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472, - 50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848, - 51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968, - 52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576, - 53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744, - 54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248, - 55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856, - 56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488, - 57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632, - 58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984, - 58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512, - 59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968, - 60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752, - 61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512, - 62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656, - 63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392, - 64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792, - 65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296, - 66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672, - 67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304, - 68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912, - 69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184, - 69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816, - 70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168, - 71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568, - 72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944, - 73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832, - 74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544, - 75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072, - 76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832, - 77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336, - 78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664, - 79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472, - 80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848, - 81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304, - 81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984, - 82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464, - 83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608, - 84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496, - 85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112, - 86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632, - 87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264, - 88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384, - 89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376, - 90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776, - 91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384, - 92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912, - 92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136, - 93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896, - 94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016, - 95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544, - 96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536, - 97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168, - 98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928, - 99352384, 99482816, 99614272, 99745472, 99876416, 100007104, - 100138048, 100267072, 100401088, 100529984, 100662592, 100791872, - 100925248, 101056064, 101187392, 101317952, 101449408, 101580608, - 101711296, 101841728, 101973824, 102104896, 102235712, 102366016, - 102498112, 102628672, 102760384, 102890432, 103021888, 103153472, - 103284032, 103415744, 103545152, 103677248, 103808576, 103939648, - 104070976, 104201792, 104332736, 104462528, 104594752, 104725952, - 104854592, 104988608, 105118912, 105247808, 105381184, 105511232, - 105643072, 105774784, 105903296, 106037056, 106167872, 106298944, - 106429504, 106561472, 106691392, 106822592, 106954304, 107085376, - 107216576, 107346368, 107478464, 107609792, 107739712, 107872192, - 108003136, 108131392, 108265408, 108396224, 108527168, 108657344, - 108789568, 108920384, 109049792, 109182272, 109312576, 109444928, - 109572928, 109706944, 109837888, 109969088, 110099648, 110230976, - 110362432, 110492992, 110624704, 110755264, 110886208, 111017408, - 111148864, 111279296, 111410752, 111541952, 111673024, 111803456, - 111933632, 112066496, 112196416, 112328512, 112457792, 112590784, - 112715968, 112852672, 112983616, 113114944, 113244224, 113376448, - 113505472, 113639104, 113770304, 113901376, 114031552, 114163264, - 114294592, 114425536, 114556864, 114687424, 114818624, 114948544, - 115080512, 115212224, 115343296, 115473472, 115605184, 115736128, - 115867072, 115997248, 116128576, 116260288, 116391488, 116522944, - 116652992, 116784704, 116915648, 117046208, 117178304, 117308608, - 117440192, 117569728, 117701824, 117833024, 117964096, 118094656, - 118225984, 118357312, 118489024, 118617536, 118749632, 118882112, - 119012416, 119144384, 119275328, 119406016, 119537344, 119668672, - 119798464, 119928896, 120061376, 120192832, 120321728, 120454336, - 120584512, 120716608, 120848192, 120979136, 121109056, 121241408, - 121372352, 121502912, 121634752, 121764416, 121895744, 122027072, - 122157632, 122289088, 122421184, 122550592, 122682944, 122813888, - 122945344, 123075776, 123207488, 123338048, 123468736, 123600704, - 123731264, 123861952, 123993664, 124124608, 124256192, 124386368, - 124518208, 124649024, 124778048, 124911296, 125041088, 125173696, - 125303744, 125432896, 125566912, 125696576, 125829056, 125958592, - 126090304, 126221248, 126352832, 126483776, 126615232, 126746432, - 126876608, 127008704, 127139392, 127270336, 127401152, 127532224, - 127663552, 127794752, 127925696, 128055232, 128188096, 128319424, - 128449856, 128581312, 128712256, 128843584, 128973632, 129103808, - 129236288, 129365696, 129498944, 129629888, 129760832, 129892288, - 130023104, 130154048, 130283968, 130416448, 130547008, 130678336, - 130807616, 130939456, 131071552, 131202112, 131331776, 131464384, - 131594048, 131727296, 131858368, 131987392, 132120256, 132250816, - 132382528, 132513728, 132644672, 132774976, 132905792, 133038016, - 133168832, 133299392, 133429312, 133562048, 133692992, 133823296, - 133954624, 134086336, 134217152, 134348608, 134479808, 134607296, - 134741056, 134872384, 135002944, 135134144, 135265472, 135396544, - 135527872, 135659072, 135787712, 135921472, 136052416, 136182848, - 136313792, 136444864, 136576448, 136707904, 136837952, 136970048, - 137099584, 137232064, 137363392, 137494208, 137625536, 137755712, - 137887424, 138018368, 138149824, 138280256, 138411584, 138539584, - 138672832, 138804928, 138936128, 139066688, 139196864, 139328704, - 139460032, 139590208, 139721024, 139852864, 139984576, 140115776, - 140245696, 140376512, 140508352, 140640064, 140769856, 140902336, - 141032768, 141162688, 141294016, 141426496, 141556544, 141687488, - 141819584, 141949888, 142080448, 142212544, 142342336, 142474432, - 142606144, 142736192, 142868288, 142997824, 143129408, 143258944, - 143392448, 143523136, 143653696, 143785024, 143916992, 144045632, - 144177856, 144309184, 144440768, 144570688, 144701888, 144832448, - 144965056, 145096384, 145227584, 145358656, 145489856, 145620928, - 145751488, 145883072, 146011456, 146144704, 146275264, 146407232, - 146538176, 146668736, 146800448, 146931392, 147062336, 147193664, - 147324224, 147455936, 147586624, 147717056, 147848768, 147979456, - 148110784, 148242368, 148373312, 148503232, 148635584, 148766144, - 148897088, 149028416, 149159488, 149290688, 149420224, 149551552, - 149683136, 149814976, 149943616, 150076352, 150208064, 150338624, - 150470464, 150600256, 150732224, 150862784, 150993088, 151125952, - 151254976, 151388096, 151519168, 151649728, 151778752, 151911104, - 152042944, 152174144, 152304704, 152435648, 152567488, 152698816, - 152828992, 152960576, 153091648, 153222976, 153353792, 153484096, - 153616192, 153747008, 153878336, 154008256, 154139968, 154270912, - 154402624, 154533824, 154663616, 154795712, 154926272, 155057984, - 155188928, 155319872, 155450816, 155580608, 155712064, 155843392, - 155971136, 156106688, 156237376, 156367424, 156499264, 156630976, - 156761536, 156892352, 157024064, 157155008, 157284416, 157415872, - 157545536, 157677248, 157810496, 157938112, 158071744, 158203328, - 158334656, 158464832, 158596288, 158727616, 158858048, 158988992, - 159121216, 159252416, 159381568, 159513152, 159645632, 159776192, - 159906496, 160038464, 160169536, 160300352, 160430656, 160563008, - 160693952, 160822208, 160956352, 161086784, 161217344, 161349184, - 161480512, 161611456, 161742272, 161873216, 162002752, 162135872, - 162266432, 162397888, 162529216, 162660032, 162790976, 162922048, - 163052096, 163184576, 163314752, 163446592, 163577408, 163707968, - 163839296, 163969984, 164100928, 164233024, 164364224, 164494912, - 164625856, 164756672, 164887616, 165019072, 165150016, 165280064, - 165412672, 165543104, 165674944, 165805888, 165936832, 166067648, - 166198336, 166330048, 166461248, 166591552, 166722496, 166854208, - 166985408, 167116736, 167246656, 167378368, 167508416, 167641024, - 167771584, 167903168, 168034112, 168164032, 168295744, 168427456, - 168557632, 168688448, 168819136, 168951616, 169082176, 169213504, - 169344832, 169475648, 169605952, 169738048, 169866304, 169999552, - 170131264, 170262464, 170393536, 170524352, 170655424, 170782016, - 170917696, 171048896, 171179072, 171310784, 171439936, 171573184, - 171702976, 171835072, 171966272, 172097216, 172228288, 172359232, - 172489664, 172621376, 172747712, 172883264, 173014208, 173144512, - 173275072, 173407424, 173539136, 173669696, 173800768, 173931712, - 174063424, 174193472, 174325696, 174455744, 174586816, 174718912, - 174849728, 174977728, 175109696, 175242688, 175374272, 175504832, - 175636288, 175765696, 175898432, 176028992, 176159936, 176291264, - 176422592, 176552512, 176684864, 176815424, 176946496, 177076544, - 177209152, 177340096, 177470528, 177600704, 177731648, 177864256, - 177994816, 178126528, 178257472, 178387648, 178518464, 178650176, - 178781888, 178912064, 179044288, 179174848, 179305024, 179436736, - 179568448, 179698496, 179830208, 179960512, 180092608, 180223808, - 180354752, 180485696, 180617152, 180748096, 180877504, 181009984, - 181139264, 181272512, 181402688, 181532608, 181663168, 181795136, - 181926592, 182057536, 182190016, 182320192, 182451904, 182582336, - 182713792, 182843072, 182976064, 183107264, 183237056, 183368384, - 183494848, 183631424, 183762752, 183893824, 184024768, 184154816, - 184286656, 184417984, 184548928, 184680128, 184810816, 184941248, - 185072704, 185203904, 185335616, 185465408, 185596352, 185727296, - 185859904, 185989696, 186121664, 186252992, 186383552, 186514112, - 186645952, 186777152, 186907328, 187037504, 187170112, 187301824, - 187429184, 187562048, 187693504, 187825472, 187957184, 188087104, - 188218304, 188349376, 188481344, 188609728, 188743616, 188874304, - 189005248, 189136448, 189265088, 189396544, 189528128, 189660992, - 189791936, 189923264, 190054208, 190182848, 190315072, 190447424, - 190577984, 190709312, 190840768, 190971328, 191102656, 191233472, - 191364032, 191495872, 191626816, 191758016, 191888192, 192020288, - 192148928, 192282176, 192413504, 192542528, 192674752, 192805952, - 192937792, 193068608, 193198912, 193330496, 193462208, 193592384, - 193723456, 193854272, 193985984, 194116672, 194247232, 194379712, - 194508352, 194641856, 194772544, 194900672, 195035072, 195166016, - 195296704, 195428032, 195558592, 195690304, 195818176, 195952576, - 196083392, 196214336, 196345792, 196476736, 196607552, 196739008, - 196869952, 197000768, 197130688, 197262784, 197394368, 197523904, - 197656384, 197787584, 197916608, 198049472, 198180544, 198310208, - 198442432, 198573632, 198705088, 198834368, 198967232, 199097792, - 199228352, 199360192, 199491392, 199621696, 199751744, 199883968, - 200014016, 200146624, 200276672, 200408128, 200540096, 200671168, - 200801984, 200933312, 201062464, 201194944, 201326144, 201457472, - 201588544, 201719744, 201850816, 201981632, 202111552, 202244032, - 202374464, 202505152, 202636352, 202767808, 202898368, 203030336, - 203159872, 203292608, 203423296, 203553472, 203685824, 203816896, - 203947712, 204078272, 204208192, 204341056, 204472256, 204603328, - 204733888, 204864448, 204996544, 205125568, 205258304, 205388864, - 205517632, 205650112, 205782208, 205913536, 206044736, 206176192, - 206307008, 206434496, 206569024, 206700224, 206831168, 206961856, - 207093056, 207223616, 207355328, 207486784, 207616832, 207749056, - 207879104, 208010048, 208141888, 208273216, 208404032, 208534336, - 208666048, 208796864, 208927424, 209059264, 209189824, 209321792, - 209451584, 209582656, 209715136, 209845568, 209976896, 210106432, - 210239296, 210370112, 210501568, 210630976, 210763712, 210894272, - 211024832, 211156672, 211287616, 211418176, 211549376, 211679296, - 211812032, 211942592, 212074432, 212204864, 212334016, 212467648, - 212597824, 212727616, 212860352, 212991424, 213120832, 213253952, - 213385024, 213515584, 213645632, 213777728, 213909184, 214040128, - 214170688, 214302656, 214433728, 214564544, 214695232, 214826048, - 214956992, 215089088, 215219776, 215350592, 215482304, 215613248, - 215743552, 215874752, 216005312, 216137024, 216267328, 216399296, - 216530752, 216661696, 216790592, 216923968, 217054528, 217183168, - 217316672, 217448128, 217579072, 217709504, 217838912, 217972672, - 218102848, 218233024, 218364736, 218496832, 218627776, 218759104, - 218888896, 219021248, 219151936, 219281728, 219413056, 219545024, - 219675968, 219807296, 219938624, 220069312, 220200128, 220331456, - 220461632, 220592704, 220725184, 220855744, 220987072, 221117888, - 221249216, 221378368, 221510336, 221642048, 221772736, 221904832, - 222031808, 222166976, 222297536, 222428992, 222559936, 222690368, - 222820672, 222953152, 223083968, 223213376, 223345984, 223476928, - 223608512, 223738688, 223869376, 224001472, 224132672, 224262848, - 224394944, 224524864, 224657344, 224788288, 224919488, 225050432, - 225181504, 225312704, 225443776, 225574592, 225704768, 225834176, - 225966784, 226097216, 226229824, 226360384, 226491712, 226623424, - 226754368, 226885312, 227015104, 227147456, 227278528, 227409472, - 227539904, 227669696, 227802944, 227932352, 228065216, 228196288, - 228326464, 228457792, 228588736, 228720064, 228850112, 228981056, - 229113152, 229243328, 229375936, 229505344, 229636928, 229769152, - 229894976, 230030272, 230162368, 230292416, 230424512, 230553152, - 230684864, 230816704, 230948416, 231079616, 231210944, 231342016, - 231472448, 231603776, 231733952, 231866176, 231996736, 232127296, - 232259392, 232388672, 232521664, 232652608, 232782272, 232914496, - 233043904, 233175616, 233306816, 233438528, 233569984, 233699776, - 233830592, 233962688, 234092224, 234221888, 234353984, 234485312, - 234618304, 234749888, 234880832, 235011776, 235142464, 235274048, - 235403456, 235535936, 235667392, 235797568, 235928768, 236057152, - 236190272, 236322752, 236453312, 236583616, 236715712, 236846528, - 236976448, 237108544, 237239104, 237371072, 237501632, 237630784, - 237764416, 237895232, 238026688, 238157632, 238286912, 238419392, - 238548032, 238681024, 238812608, 238941632, 239075008, 239206336, - 239335232, 239466944, 239599168, 239730496, 239861312, 239992384, - 240122816, 240254656, 240385856, 240516928, 240647872, 240779072, - 240909632, 241040704, 241171904, 241302848, 241433408, 241565248, - 241696192, 241825984, 241958848, 242088256, 242220224, 242352064, - 242481856, 242611648, 242744896, 242876224, 243005632, 243138496, - 243268672, 243400384, 243531712, 243662656, 243793856, 243924544, - 244054592, 244187072, 244316608, 244448704, 244580032, 244710976, - 244841536, 244972864, 245104448, 245233984, 245365312, 245497792, - 245628736, 245759936, 245889856, 246021056, 246152512, 246284224, - 246415168, 246545344, 246675904, 246808384, 246939584, 247070144, - 247199552, 247331648, 247463872, 247593536, 247726016, 247857088, - 247987648, 248116928, 248249536, 248380736, 248512064, 248643008, - 248773312, 248901056, 249036608, 249167552, 249298624, 249429184, - 249560512, 249692096, 249822784, 249954112, 250085312, 250215488, - 250345792, 250478528, 250608704, 250739264, 250870976, 251002816, - 251133632, 251263552, 251395136, 251523904, 251657792, 251789248, - 251919424, 252051392, 252182464, 252313408, 252444224, 252575552, - 252706624, 252836032, 252968512, 253099712, 253227584, 253361728, - 253493056, 253623488, 253754432, 253885504, 254017216, 254148032, - 254279488, 254410432, 254541376, 254672576, 254803264, 254933824, - 255065792, 255196736, 255326528, 255458752, 255589952, 255721408, - 255851072, 255983296, 256114624, 256244416, 256374208, 256507712, - 256636096, 256768832, 256900544, 257031616, 257162176, 257294272, - 257424448, 257555776, 257686976, 257818432, 257949632, 258079552, - 258211136, 258342464, 258473408, 258603712, 258734656, 258867008, - 258996544, 259127744, 259260224, 259391296, 259522112, 259651904, - 259784384, 259915328, 260045888, 260175424, 260308544, 260438336, - 260570944, 260700992, 260832448, 260963776, 261092672, 261226304, - 261356864, 261487936, 261619648, 261750592, 261879872, 262011968, - 262143424, 262274752, 262404416, 262537024, 262667968, 262799296, - 262928704, 263061184, 263191744, 263322944, 263454656, 263585216, - 263716672, 263847872, 263978944, 264108608, 264241088, 264371648, - 264501184, 264632768, 264764096, 264895936, 265024576, 265158464, - 265287488, 265418432, 265550528, 265681216, 265813312, 265943488, - 266075968, 266206144, 266337728, 266468032, 266600384, 266731072, - 266862272, 266993344, 267124288, 267255616, 267386432, 267516992, - 267648704, 267777728, 267910592, 268040512, 268172096, 268302784, - 268435264, 268566208, 268696256, 268828096, 268959296, 269090368, - 269221312, 269352256, 269482688, 269614784, 269745856, 269876416, - 270007616, 270139328, 270270272, 270401216, 270531904, 270663616, - 270791744, 270924736, 271056832, 271186112, 271317184, 271449536, - 271580992, 271711936, 271843136, 271973056, 272105408, 272236352, - 272367296, 272498368, 272629568, 272759488, 272891456, 273022784, - 273153856, 273284672, 273415616, 273547072, 273677632, 273808448, - 273937088, 274071488, 274200896, 274332992, 274463296, 274595392, - 274726208, 274857536, 274988992, 275118656, 275250496, 275382208, - 275513024, 275643968, 275775296, 275906368, 276037184, 276167872, - 276297664, 276429376, 276560576, 276692672, 276822976, 276955072, - 277085632, 277216832, 277347008, 277478848, 277609664, 277740992, - 277868608, 278002624, 278134336, 278265536, 278395328, 278526784, - 278657728, 278789824, 278921152, 279052096, 279182912, 279313088, - 279443776, 279576256, 279706048, 279838528, 279969728, 280099648, - 280230976, 280361408, 280493632, 280622528, 280755392, 280887104, - 281018176, 281147968, 281278912, 281411392, 281542592, 281673152, - 281803712, 281935552, 282066496, 282197312, 282329024, 282458816, - 282590272, 282720832, 282853184, 282983744, 283115072, 283246144, - 283377344, 283508416, 283639744, 283770304, 283901504, 284032576, - 284163136, 284294848, 284426176, 284556992, 284687296, 284819264, - 284950208, 285081536 - }; + 16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072, + 17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088, + 18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208, + 19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968, + 20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216, + 21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104, + 22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096, + 23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112, + 24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488, + 25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096, + 25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472, + 26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744, + 27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504, + 28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752, + 29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976, + 30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248, + 31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392, + 32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768, + 33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992, + 34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984, + 35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976, + 36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656, + 36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904, + 37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672, + 38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632, + 39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032, + 40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304, + 41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912, + 42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696, + 43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432, + 44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448, + 45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208, + 46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328, + 47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936, + 47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312, + 48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712, + 49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472, + 50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848, + 51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968, + 52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576, + 53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744, + 54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248, + 55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856, + 56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488, + 57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632, + 58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984, + 58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512, + 59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968, + 60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752, + 61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512, + 62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656, + 63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392, + 64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792, + 65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296, + 66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672, + 67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304, + 68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912, + 69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184, + 69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816, + 70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168, + 71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568, + 72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944, + 73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832, + 74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544, + 75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072, + 76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832, + 77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336, + 78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664, + 79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472, + 80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848, + 81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304, + 81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984, + 82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464, + 83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608, + 84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496, + 85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112, + 86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632, + 87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264, + 88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384, + 89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376, + 90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776, + 91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384, + 92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912, + 92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136, + 93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896, + 94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016, + 95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544, + 96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536, + 97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168, + 98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928, + 99352384, 99482816, 99614272, 99745472, 99876416, 100007104, + 100138048, 100267072, 100401088, 100529984, 100662592, 100791872, + 100925248, 101056064, 101187392, 101317952, 101449408, 101580608, + 101711296, 101841728, 101973824, 102104896, 102235712, 102366016, + 102498112, 102628672, 102760384, 102890432, 103021888, 103153472, + 103284032, 103415744, 103545152, 103677248, 103808576, 103939648, + 104070976, 104201792, 104332736, 104462528, 104594752, 104725952, + 104854592, 104988608, 105118912, 105247808, 105381184, 105511232, + 105643072, 105774784, 105903296, 106037056, 106167872, 106298944, + 106429504, 106561472, 106691392, 106822592, 106954304, 107085376, + 107216576, 107346368, 107478464, 107609792, 107739712, 107872192, + 108003136, 108131392, 108265408, 108396224, 108527168, 108657344, + 108789568, 108920384, 109049792, 109182272, 109312576, 109444928, + 109572928, 109706944, 109837888, 109969088, 110099648, 110230976, + 110362432, 110492992, 110624704, 110755264, 110886208, 111017408, + 111148864, 111279296, 111410752, 111541952, 111673024, 111803456, + 111933632, 112066496, 112196416, 112328512, 112457792, 112590784, + 112715968, 112852672, 112983616, 113114944, 113244224, 113376448, + 113505472, 113639104, 113770304, 113901376, 114031552, 114163264, + 114294592, 114425536, 114556864, 114687424, 114818624, 114948544, + 115080512, 115212224, 115343296, 115473472, 115605184, 115736128, + 115867072, 115997248, 116128576, 116260288, 116391488, 116522944, + 116652992, 116784704, 116915648, 117046208, 117178304, 117308608, + 117440192, 117569728, 117701824, 117833024, 117964096, 118094656, + 118225984, 118357312, 118489024, 118617536, 118749632, 118882112, + 119012416, 119144384, 119275328, 119406016, 119537344, 119668672, + 119798464, 119928896, 120061376, 120192832, 120321728, 120454336, + 120584512, 120716608, 120848192, 120979136, 121109056, 121241408, + 121372352, 121502912, 121634752, 121764416, 121895744, 122027072, + 122157632, 122289088, 122421184, 122550592, 122682944, 122813888, + 122945344, 123075776, 123207488, 123338048, 123468736, 123600704, + 123731264, 123861952, 123993664, 124124608, 124256192, 124386368, + 124518208, 124649024, 124778048, 124911296, 125041088, 125173696, + 125303744, 125432896, 125566912, 125696576, 125829056, 125958592, + 126090304, 126221248, 126352832, 126483776, 126615232, 126746432, + 126876608, 127008704, 127139392, 127270336, 127401152, 127532224, + 127663552, 127794752, 127925696, 128055232, 128188096, 128319424, + 128449856, 128581312, 128712256, 128843584, 128973632, 129103808, + 129236288, 129365696, 129498944, 129629888, 129760832, 129892288, + 130023104, 130154048, 130283968, 130416448, 130547008, 130678336, + 130807616, 130939456, 131071552, 131202112, 131331776, 131464384, + 131594048, 131727296, 131858368, 131987392, 132120256, 132250816, + 132382528, 132513728, 132644672, 132774976, 132905792, 133038016, + 133168832, 133299392, 133429312, 133562048, 133692992, 133823296, + 133954624, 134086336, 134217152, 134348608, 134479808, 134607296, + 134741056, 134872384, 135002944, 135134144, 135265472, 135396544, + 135527872, 135659072, 135787712, 135921472, 136052416, 136182848, + 136313792, 136444864, 136576448, 136707904, 136837952, 136970048, + 137099584, 137232064, 137363392, 137494208, 137625536, 137755712, + 137887424, 138018368, 138149824, 138280256, 138411584, 138539584, + 138672832, 138804928, 138936128, 139066688, 139196864, 139328704, + 139460032, 139590208, 139721024, 139852864, 139984576, 140115776, + 140245696, 140376512, 140508352, 140640064, 140769856, 140902336, + 141032768, 141162688, 141294016, 141426496, 141556544, 141687488, + 141819584, 141949888, 142080448, 142212544, 142342336, 142474432, + 142606144, 142736192, 142868288, 142997824, 143129408, 143258944, + 143392448, 143523136, 143653696, 143785024, 143916992, 144045632, + 144177856, 144309184, 144440768, 144570688, 144701888, 144832448, + 144965056, 145096384, 145227584, 145358656, 145489856, 145620928, + 145751488, 145883072, 146011456, 146144704, 146275264, 146407232, + 146538176, 146668736, 146800448, 146931392, 147062336, 147193664, + 147324224, 147455936, 147586624, 147717056, 147848768, 147979456, + 148110784, 148242368, 148373312, 148503232, 148635584, 148766144, + 148897088, 149028416, 149159488, 149290688, 149420224, 149551552, + 149683136, 149814976, 149943616, 150076352, 150208064, 150338624, + 150470464, 150600256, 150732224, 150862784, 150993088, 151125952, + 151254976, 151388096, 151519168, 151649728, 151778752, 151911104, + 152042944, 152174144, 152304704, 152435648, 152567488, 152698816, + 152828992, 152960576, 153091648, 153222976, 153353792, 153484096, + 153616192, 153747008, 153878336, 154008256, 154139968, 154270912, + 154402624, 154533824, 154663616, 154795712, 154926272, 155057984, + 155188928, 155319872, 155450816, 155580608, 155712064, 155843392, + 155971136, 156106688, 156237376, 156367424, 156499264, 156630976, + 156761536, 156892352, 157024064, 157155008, 157284416, 157415872, + 157545536, 157677248, 157810496, 157938112, 158071744, 158203328, + 158334656, 158464832, 158596288, 158727616, 158858048, 158988992, + 159121216, 159252416, 159381568, 159513152, 159645632, 159776192, + 159906496, 160038464, 160169536, 160300352, 160430656, 160563008, + 160693952, 160822208, 160956352, 161086784, 161217344, 161349184, + 161480512, 161611456, 161742272, 161873216, 162002752, 162135872, + 162266432, 162397888, 162529216, 162660032, 162790976, 162922048, + 163052096, 163184576, 163314752, 163446592, 163577408, 163707968, + 163839296, 163969984, 164100928, 164233024, 164364224, 164494912, + 164625856, 164756672, 164887616, 165019072, 165150016, 165280064, + 165412672, 165543104, 165674944, 165805888, 165936832, 166067648, + 166198336, 166330048, 166461248, 166591552, 166722496, 166854208, + 166985408, 167116736, 167246656, 167378368, 167508416, 167641024, + 167771584, 167903168, 168034112, 168164032, 168295744, 168427456, + 168557632, 168688448, 168819136, 168951616, 169082176, 169213504, + 169344832, 169475648, 169605952, 169738048, 169866304, 169999552, + 170131264, 170262464, 170393536, 170524352, 170655424, 170782016, + 170917696, 171048896, 171179072, 171310784, 171439936, 171573184, + 171702976, 171835072, 171966272, 172097216, 172228288, 172359232, + 172489664, 172621376, 172747712, 172883264, 173014208, 173144512, + 173275072, 173407424, 173539136, 173669696, 173800768, 173931712, + 174063424, 174193472, 174325696, 174455744, 174586816, 174718912, + 174849728, 174977728, 175109696, 175242688, 175374272, 175504832, + 175636288, 175765696, 175898432, 176028992, 176159936, 176291264, + 176422592, 176552512, 176684864, 176815424, 176946496, 177076544, + 177209152, 177340096, 177470528, 177600704, 177731648, 177864256, + 177994816, 178126528, 178257472, 178387648, 178518464, 178650176, + 178781888, 178912064, 179044288, 179174848, 179305024, 179436736, + 179568448, 179698496, 179830208, 179960512, 180092608, 180223808, + 180354752, 180485696, 180617152, 180748096, 180877504, 181009984, + 181139264, 181272512, 181402688, 181532608, 181663168, 181795136, + 181926592, 182057536, 182190016, 182320192, 182451904, 182582336, + 182713792, 182843072, 182976064, 183107264, 183237056, 183368384, + 183494848, 183631424, 183762752, 183893824, 184024768, 184154816, + 184286656, 184417984, 184548928, 184680128, 184810816, 184941248, + 185072704, 185203904, 185335616, 185465408, 185596352, 185727296, + 185859904, 185989696, 186121664, 186252992, 186383552, 186514112, + 186645952, 186777152, 186907328, 187037504, 187170112, 187301824, + 187429184, 187562048, 187693504, 187825472, 187957184, 188087104, + 188218304, 188349376, 188481344, 188609728, 188743616, 188874304, + 189005248, 189136448, 189265088, 189396544, 189528128, 189660992, + 189791936, 189923264, 190054208, 190182848, 190315072, 190447424, + 190577984, 190709312, 190840768, 190971328, 191102656, 191233472, + 191364032, 191495872, 191626816, 191758016, 191888192, 192020288, + 192148928, 192282176, 192413504, 192542528, 192674752, 192805952, + 192937792, 193068608, 193198912, 193330496, 193462208, 193592384, + 193723456, 193854272, 193985984, 194116672, 194247232, 194379712, + 194508352, 194641856, 194772544, 194900672, 195035072, 195166016, + 195296704, 195428032, 195558592, 195690304, 195818176, 195952576, + 196083392, 196214336, 196345792, 196476736, 196607552, 196739008, + 196869952, 197000768, 197130688, 197262784, 197394368, 197523904, + 197656384, 197787584, 197916608, 198049472, 198180544, 198310208, + 198442432, 198573632, 198705088, 198834368, 198967232, 199097792, + 199228352, 199360192, 199491392, 199621696, 199751744, 199883968, + 200014016, 200146624, 200276672, 200408128, 200540096, 200671168, + 200801984, 200933312, 201062464, 201194944, 201326144, 201457472, + 201588544, 201719744, 201850816, 201981632, 202111552, 202244032, + 202374464, 202505152, 202636352, 202767808, 202898368, 203030336, + 203159872, 203292608, 203423296, 203553472, 203685824, 203816896, + 203947712, 204078272, 204208192, 204341056, 204472256, 204603328, + 204733888, 204864448, 204996544, 205125568, 205258304, 205388864, + 205517632, 205650112, 205782208, 205913536, 206044736, 206176192, + 206307008, 206434496, 206569024, 206700224, 206831168, 206961856, + 207093056, 207223616, 207355328, 207486784, 207616832, 207749056, + 207879104, 208010048, 208141888, 208273216, 208404032, 208534336, + 208666048, 208796864, 208927424, 209059264, 209189824, 209321792, + 209451584, 209582656, 209715136, 209845568, 209976896, 210106432, + 210239296, 210370112, 210501568, 210630976, 210763712, 210894272, + 211024832, 211156672, 211287616, 211418176, 211549376, 211679296, + 211812032, 211942592, 212074432, 212204864, 212334016, 212467648, + 212597824, 212727616, 212860352, 212991424, 213120832, 213253952, + 213385024, 213515584, 213645632, 213777728, 213909184, 214040128, + 214170688, 214302656, 214433728, 214564544, 214695232, 214826048, + 214956992, 215089088, 215219776, 215350592, 215482304, 215613248, + 215743552, 215874752, 216005312, 216137024, 216267328, 216399296, + 216530752, 216661696, 216790592, 216923968, 217054528, 217183168, + 217316672, 217448128, 217579072, 217709504, 217838912, 217972672, + 218102848, 218233024, 218364736, 218496832, 218627776, 218759104, + 218888896, 219021248, 219151936, 219281728, 219413056, 219545024, + 219675968, 219807296, 219938624, 220069312, 220200128, 220331456, + 220461632, 220592704, 220725184, 220855744, 220987072, 221117888, + 221249216, 221378368, 221510336, 221642048, 221772736, 221904832, + 222031808, 222166976, 222297536, 222428992, 222559936, 222690368, + 222820672, 222953152, 223083968, 223213376, 223345984, 223476928, + 223608512, 223738688, 223869376, 224001472, 224132672, 224262848, + 224394944, 224524864, 224657344, 224788288, 224919488, 225050432, + 225181504, 225312704, 225443776, 225574592, 225704768, 225834176, + 225966784, 226097216, 226229824, 226360384, 226491712, 226623424, + 226754368, 226885312, 227015104, 227147456, 227278528, 227409472, + 227539904, 227669696, 227802944, 227932352, 228065216, 228196288, + 228326464, 228457792, 228588736, 228720064, 228850112, 228981056, + 229113152, 229243328, 229375936, 229505344, 229636928, 229769152, + 229894976, 230030272, 230162368, 230292416, 230424512, 230553152, + 230684864, 230816704, 230948416, 231079616, 231210944, 231342016, + 231472448, 231603776, 231733952, 231866176, 231996736, 232127296, + 232259392, 232388672, 232521664, 232652608, 232782272, 232914496, + 233043904, 233175616, 233306816, 233438528, 233569984, 233699776, + 233830592, 233962688, 234092224, 234221888, 234353984, 234485312, + 234618304, 234749888, 234880832, 235011776, 235142464, 235274048, + 235403456, 235535936, 235667392, 235797568, 235928768, 236057152, + 236190272, 236322752, 236453312, 236583616, 236715712, 236846528, + 236976448, 237108544, 237239104, 237371072, 237501632, 237630784, + 237764416, 237895232, 238026688, 238157632, 238286912, 238419392, + 238548032, 238681024, 238812608, 238941632, 239075008, 239206336, + 239335232, 239466944, 239599168, 239730496, 239861312, 239992384, + 240122816, 240254656, 240385856, 240516928, 240647872, 240779072, + 240909632, 241040704, 241171904, 241302848, 241433408, 241565248, + 241696192, 241825984, 241958848, 242088256, 242220224, 242352064, + 242481856, 242611648, 242744896, 242876224, 243005632, 243138496, + 243268672, 243400384, 243531712, 243662656, 243793856, 243924544, + 244054592, 244187072, 244316608, 244448704, 244580032, 244710976, + 244841536, 244972864, 245104448, 245233984, 245365312, 245497792, + 245628736, 245759936, 245889856, 246021056, 246152512, 246284224, + 246415168, 246545344, 246675904, 246808384, 246939584, 247070144, + 247199552, 247331648, 247463872, 247593536, 247726016, 247857088, + 247987648, 248116928, 248249536, 248380736, 248512064, 248643008, + 248773312, 248901056, 249036608, 249167552, 249298624, 249429184, + 249560512, 249692096, 249822784, 249954112, 250085312, 250215488, + 250345792, 250478528, 250608704, 250739264, 250870976, 251002816, + 251133632, 251263552, 251395136, 251523904, 251657792, 251789248, + 251919424, 252051392, 252182464, 252313408, 252444224, 252575552, + 252706624, 252836032, 252968512, 253099712, 253227584, 253361728, + 253493056, 253623488, 253754432, 253885504, 254017216, 254148032, + 254279488, 254410432, 254541376, 254672576, 254803264, 254933824, + 255065792, 255196736, 255326528, 255458752, 255589952, 255721408, + 255851072, 255983296, 256114624, 256244416, 256374208, 256507712, + 256636096, 256768832, 256900544, 257031616, 257162176, 257294272, + 257424448, 257555776, 257686976, 257818432, 257949632, 258079552, + 258211136, 258342464, 258473408, 258603712, 258734656, 258867008, + 258996544, 259127744, 259260224, 259391296, 259522112, 259651904, + 259784384, 259915328, 260045888, 260175424, 260308544, 260438336, + 260570944, 260700992, 260832448, 260963776, 261092672, 261226304, + 261356864, 261487936, 261619648, 261750592, 261879872, 262011968, + 262143424, 262274752, 262404416, 262537024, 262667968, 262799296, + 262928704, 263061184, 263191744, 263322944, 263454656, 263585216, + 263716672, 263847872, 263978944, 264108608, 264241088, 264371648, + 264501184, 264632768, 264764096, 264895936, 265024576, 265158464, + 265287488, 265418432, 265550528, 265681216, 265813312, 265943488, + 266075968, 266206144, 266337728, 266468032, 266600384, 266731072, + 266862272, 266993344, 267124288, 267255616, 267386432, 267516992, + 267648704, 267777728, 267910592, 268040512, 268172096, 268302784, + 268435264, 268566208, 268696256, 268828096, 268959296, 269090368, + 269221312, 269352256, 269482688, 269614784, 269745856, 269876416, + 270007616, 270139328, 270270272, 270401216, 270531904, 270663616, + 270791744, 270924736, 271056832, 271186112, 271317184, 271449536, + 271580992, 271711936, 271843136, 271973056, 272105408, 272236352, + 272367296, 272498368, 272629568, 272759488, 272891456, 273022784, + 273153856, 273284672, 273415616, 273547072, 273677632, 273808448, + 273937088, 274071488, 274200896, 274332992, 274463296, 274595392, + 274726208, 274857536, 274988992, 275118656, 275250496, 275382208, + 275513024, 275643968, 275775296, 275906368, 276037184, 276167872, + 276297664, 276429376, 276560576, 276692672, 276822976, 276955072, + 277085632, 277216832, 277347008, 277478848, 277609664, 277740992, + 277868608, 278002624, 278134336, 278265536, 278395328, 278526784, + 278657728, 278789824, 278921152, 279052096, 279182912, 279313088, + 279443776, 279576256, 279706048, 279838528, 279969728, 280099648, + 280230976, 280361408, 280493632, 280622528, 280755392, 280887104, + 281018176, 281147968, 281278912, 281411392, 281542592, 281673152, + 281803712, 281935552, 282066496, 282197312, 282329024, 282458816, + 282590272, 282720832, 282853184, 282983744, 283115072, 283246144, + 283377344, 283508416, 283639744, 283770304, 283901504, 284032576, + 284163136, 284294848, 284426176, 284556992, 284687296, 284819264, + 284950208, 285081536 + }; - private readonly ulong[] _dataSizes = new ulong[] - { - 1073739904, 1082130304, 1090514816, 1098906752, 1107293056, - 1115684224, 1124070016, 1132461952, 1140849536, 1149232768, - 1157627776, 1166013824, 1174404736, 1182786944, 1191180416, - 1199568512, 1207958912, 1216345216, 1224732032, 1233124736, - 1241513344, 1249902464, 1258290304, 1266673792, 1275067264, - 1283453312, 1291844992, 1300234112, 1308619904, 1317010048, - 1325397376, 1333787776, 1342176128, 1350561664, 1358954368, - 1367339392, 1375731584, 1384118144, 1392507008, 1400897408, - 1409284736, 1417673344, 1426062464, 1434451072, 1442839168, - 1451229056, 1459615616, 1468006016, 1476394112, 1484782976, - 1493171584, 1501559168, 1509948032, 1518337664, 1526726528, - 1535114624, 1543503488, 1551892096, 1560278656, 1568669056, - 1577056384, 1585446272, 1593831296, 1602219392, 1610610304, - 1619000192, 1627386752, 1635773824, 1644164224, 1652555648, - 1660943488, 1669332608, 1677721216, 1686109312, 1694497664, - 1702886272, 1711274624, 1719661184, 1728047744, 1736434816, - 1744829056, 1753218944, 1761606272, 1769995904, 1778382464, - 1786772864, 1795157888, 1803550592, 1811937664, 1820327552, - 1828711552, 1837102976, 1845488768, 1853879936, 1862269312, - 1870656896, 1879048064, 1887431552, 1895825024, 1904212096, - 1912601216, 1920988544, 1929379456, 1937765504, 1946156672, - 1954543232, 1962932096, 1971321728, 1979707264, 1988093056, - 1996487552, 2004874624, 2013262208, 2021653888, 2030039936, - 2038430848, 2046819968, 2055208576, 2063596672, 2071981952, - 2080373632, 2088762752, 2097149056, 2105539712, 2113928576, - 2122315136, 2130700672, 2139092608, 2147483264, 2155872128, - 2164257664, 2172642176, 2181035392, 2189426048, 2197814912, - 2206203008, 2214587264, 2222979712, 2231367808, 2239758208, - 2248145024, 2256527744, 2264922752, 2273312128, 2281701248, - 2290086272, 2298476672, 2306867072, 2315251072, 2323639168, - 2332032128, 2340420224, 2348808064, 2357196416, 2365580416, - 2373966976, 2382363008, 2390748544, 2399139968, 2407530368, - 2415918976, 2424307328, 2432695424, 2441084288, 2449472384, - 2457861248, 2466247808, 2474637184, 2483026816, 2491414144, - 2499803776, 2508191872, 2516582272, 2524970368, 2533359232, - 2541743488, 2550134144, 2558525056, 2566913408, 2575301504, - 2583686528, 2592073856, 2600467328, 2608856192, 2617240448, - 2625631616, 2634022016, 2642407552, 2650796416, 2659188352, - 2667574912, 2675965312, 2684352896, 2692738688, 2701130624, - 2709518464, 2717907328, 2726293376, 2734685056, 2743073152, - 2751462016, 2759851648, 2768232832, 2776625536, 2785017728, - 2793401984, 2801794432, 2810182016, 2818571648, 2826959488, - 2835349376, 2843734144, 2852121472, 2860514432, 2868900992, - 2877286784, 2885676928, 2894069632, 2902451584, 2910843008, - 2919234688, 2927622784, 2936011648, 2944400768, 2952789376, - 2961177728, 2969565568, 2977951616, 2986338944, 2994731392, - 3003120256, 3011508352, 3019895936, 3028287104, 3036675968, - 3045063808, 3053452928, 3061837696, 3070228352, 3078615424, - 3087003776, 3095394944, 3103782272, 3112173184, 3120562048, - 3128944768, 3137339264, 3145725056, 3154109312, 3162505088, - 3170893184, 3179280256, 3187669376, 3196056704, 3204445568, - 3212836736, 3221224064, 3229612928, 3238002304, 3246391168, - 3254778496, 3263165824, 3271556224, 3279944576, 3288332416, - 3296719232, 3305110912, 3313500032, 3321887104, 3330273152, - 3338658944, 3347053184, 3355440512, 3363827072, 3372220288, - 3380608384, 3388997504, 3397384576, 3405774208, 3414163072, - 3422551936, 3430937984, 3439328384, 3447714176, 3456104576, - 3464493952, 3472883584, 3481268864, 3489655168, 3498048896, - 3506434432, 3514826368, 3523213952, 3531603584, 3539987072, - 3548380288, 3556763264, 3565157248, 3573545344, 3581934464, - 3590324096, 3598712704, 3607098752, 3615488384, 3623877248, - 3632265856, 3640646528, 3649043584, 3657430144, 3665821568, - 3674207872, 3682597504, 3690984832, 3699367808, 3707764352, - 3716152448, 3724541056, 3732925568, 3741318016, 3749706368, - 3758091136, 3766481536, 3774872704, 3783260032, 3791650432, - 3800036224, 3808427648, 3816815488, 3825204608, 3833592704, - 3841981568, 3850370432, 3858755968, 3867147904, 3875536256, - 3883920512, 3892313728, 3900702592, 3909087872, 3917478784, - 3925868416, 3934256512, 3942645376, 3951032192, 3959422336, - 3967809152, 3976200064, 3984588416, 3992974976, 4001363584, - 4009751168, 4018141312, 4026530432, 4034911616, 4043308928, - 4051695488, 4060084352, 4068472448, 4076862848, 4085249408, - 4093640576, 4102028416, 4110413696, 4118805632, 4127194496, - 4135583104, 4143971968, 4152360832, 4160746112, 4169135744, - 4177525888, 4185912704, 4194303616, 4202691968, 4211076736, - 4219463552, 4227855488, 4236246656, 4244633728, 4253022848, - 4261412224, 4269799808, 4278184832, 4286578048, 4294962304, - 4303349632, 4311743104, 4320130432, 4328521088, 4336909184, - 4345295488, 4353687424, 4362073472, 4370458496, 4378852736, - 4387238528, 4395630208, 4404019072, 4412407424, 4420790656, - 4429182848, 4437571456, 4445962112, 4454344064, 4462738048, - 4471119232, 4479516544, 4487904128, 4496289664, 4504682368, - 4513068416, 4521459584, 4529846144, 4538232704, 4546619776, - 4555010176, 4563402112, 4571790208, 4580174464, 4588567936, - 4596957056, 4605344896, 4613734016, 4622119808, 4630511488, - 4638898816, 4647287936, 4655675264, 4664065664, 4672451968, - 4680842624, 4689231488, 4697620352, 4706007424, 4714397056, - 4722786176, 4731173248, 4739562368, 4747951744, 4756340608, - 4764727936, 4773114496, 4781504384, 4789894784, 4798283648, - 4806667648, 4815059584, 4823449472, 4831835776, 4840226176, - 4848612224, 4857003392, 4865391488, 4873780096, 4882169728, - 4890557312, 4898946944, 4907333248, 4915722368, 4924110976, - 4932499328, 4940889728, 4949276032, 4957666432, 4966054784, - 4974438016, 4982831488, 4991221376, 4999607168, 5007998848, - 5016386432, 5024763776, 5033164672, 5041544576, 5049941888, - 5058329728, 5066717056, 5075107456, 5083494272, 5091883904, - 5100273536, 5108662144, 5117048192, 5125436032, 5133827456, - 5142215296, 5150605184, 5158993024, 5167382144, 5175769472, - 5184157568, 5192543872, 5200936064, 5209324928, 5217711232, - 5226102656, 5234490496, 5242877312, 5251263872, 5259654016, - 5268040832, 5276434304, 5284819328, 5293209728, 5301598592, - 5309986688, 5318374784, 5326764416, 5335151488, 5343542144, - 5351929472, 5360319872, 5368706944, 5377096576, 5385484928, - 5393871232, 5402263424, 5410650496, 5419040384, 5427426944, - 5435816576, 5444205952, 5452594816, 5460981376, 5469367936, - 5477760896, 5486148736, 5494536832, 5502925952, 5511315328, - 5519703424, 5528089984, 5536481152, 5544869504, 5553256064, - 5561645696, 5570032768, 5578423936, 5586811264, 5595193216, - 5603585408, 5611972736, 5620366208, 5628750464, 5637143936, - 5645528192, 5653921408, 5662310272, 5670694784, 5679082624, - 5687474048, 5695864448, 5704251008, 5712641408, 5721030272, - 5729416832, 5737806208, 5746194304, 5754583936, 5762969984, - 5771358592, 5779748224, 5788137856, 5796527488, 5804911232, - 5813300608, 5821692544, 5830082176, 5838468992, 5846855552, - 5855247488, 5863636096, 5872024448, 5880411008, 5888799872, - 5897186432, 5905576832, 5913966976, 5922352768, 5930744704, - 5939132288, 5947522432, 5955911296, 5964299392, 5972688256, - 5981074304, 5989465472, 5997851008, 6006241408, 6014627968, - 6023015552, 6031408256, 6039796096, 6048185216, 6056574848, - 6064963456, 6073351808, 6081736064, 6090128768, 6098517632, - 6106906496, 6115289216, 6123680896, 6132070016, 6140459648, - 6148849024, 6157237376, 6165624704, 6174009728, 6182403712, - 6190792064, 6199176064, 6207569792, 6215952256, 6224345216, - 6232732544, 6241124224, 6249510272, 6257899136, 6266287744, - 6274676864, 6283065728, 6291454336, 6299843456, 6308232064, - 6316620928, 6325006208, 6333395584, 6341784704, 6350174848, - 6358562176, 6366951296, 6375337856, 6383729536, 6392119168, - 6400504192, 6408895616, 6417283456, 6425673344, 6434059136, - 6442444672, 6450837376, 6459223424, 6467613056, 6476004224, - 6484393088, 6492781952, 6501170048, 6509555072, 6517947008, - 6526336384, 6534725504, 6543112832, 6551500672, 6559888768, - 6568278656, 6576662912, 6585055616, 6593443456, 6601834112, - 6610219648, 6618610304, 6626999168, 6635385472, 6643777408, - 6652164224, 6660552832, 6668941952, 6677330048, 6685719424, - 6694107776, 6702493568, 6710882176, 6719274112, 6727662976, - 6736052096, 6744437632, 6752825984, 6761213824, 6769604224, - 6777993856, 6786383488, 6794770816, 6803158144, 6811549312, - 6819937664, 6828326528, 6836706176, 6845101696, 6853491328, - 6861880448, 6870269312, 6878655104, 6887046272, 6895433344, - 6903822208, 6912212864, 6920596864, 6928988288, 6937377152, - 6945764992, 6954149248, 6962544256, 6970928768, 6979317376, - 6987709312, 6996093824, 7004487296, 7012875392, 7021258624, - 7029652352, 7038038912, 7046427776, 7054818944, 7063207808, - 7071595136, 7079980928, 7088372608, 7096759424, 7105149824, - 7113536896, 7121928064, 7130315392, 7138699648, 7147092352, - 7155479168, 7163865728, 7172249984, 7180648064, 7189036672, - 7197424768, 7205810816, 7214196608, 7222589824, 7230975104, - 7239367552, 7247755904, 7256145536, 7264533376, 7272921472, - 7281308032, 7289694848, 7298088832, 7306471808, 7314864512, - 7323253888, 7331643008, 7340029568, 7348419712, 7356808832, - 7365196672, 7373585792, 7381973888, 7390362752, 7398750592, - 7407138944, 7415528576, 7423915648, 7432302208, 7440690304, - 7449080192, 7457472128, 7465860992, 7474249088, 7482635648, - 7491023744, 7499412608, 7507803008, 7516192384, 7524579968, - 7532967296, 7541358464, 7549745792, 7558134656, 7566524032, - 7574912896, 7583300992, 7591690112, 7600075136, 7608466816, - 7616854912, 7625244544, 7633629824, 7642020992, 7650410368, - 7658794112, 7667187328, 7675574912, 7683961984, 7692349568, - 7700739712, 7709130368, 7717519232, 7725905536, 7734295424, - 7742683264, 7751069056, 7759457408, 7767849088, 7776238208, - 7784626816, 7793014912, 7801405312, 7809792128, 7818179968, - 7826571136, 7834957184, 7843347328, 7851732352, 7860124544, - 7868512384, 7876902016, 7885287808, 7893679744, 7902067072, - 7910455936, 7918844288, 7927230848, 7935622784, 7944009344, - 7952400256, 7960786048, 7969176704, 7977565312, 7985953408, - 7994339968, 8002730368, 8011119488, 8019508096, 8027896192, - 8036285056, 8044674688, 8053062272, 8061448832, 8069838464, - 8078227328, 8086616704, 8095006592, 8103393664, 8111783552, - 8120171392, 8128560256, 8136949376, 8145336704, 8153726848, - 8162114944, 8170503296, 8178891904, 8187280768, 8195669632, - 8204058496, 8212444544, 8220834176, 8229222272, 8237612672, - 8246000768, 8254389376, 8262775168, 8271167104, 8279553664, - 8287944064, 8296333184, 8304715136, 8313108352, 8321497984, - 8329885568, 8338274432, 8346663296, 8355052928, 8363441536, - 8371828352, 8380217984, 8388606592, 8396996224, 8405384576, - 8413772672, 8422161536, 8430549376, 8438939008, 8447326592, - 8455715456, 8464104832, 8472492928, 8480882048, 8489270656, - 8497659776, 8506045312, 8514434944, 8522823808, 8531208832, - 8539602304, 8547990656, 8556378752, 8564768384, 8573154176, - 8581542784, 8589933952, 8598322816, 8606705024, 8615099264, - 8623487872, 8631876992, 8640264064, 8648653952, 8657040256, - 8665430656, 8673820544, 8682209152, 8690592128, 8698977152, - 8707374464, 8715763328, 8724151424, 8732540032, 8740928384, - 8749315712, 8757704576, 8766089344, 8774480768, 8782871936, - 8791260032, 8799645824, 8808034432, 8816426368, 8824812928, - 8833199488, 8841591424, 8849976448, 8858366336, 8866757248, - 8875147136, 8883532928, 8891923328, 8900306816, 8908700288, - 8917088384, 8925478784, 8933867392, 8942250368, 8950644608, - 8959032704, 8967420544, 8975809664, 8984197504, 8992584064, - 9000976256, 9009362048, 9017752448, 9026141312, 9034530688, - 9042917504, 9051307904, 9059694208, 9068084864, 9076471424, - 9084861824, 9093250688, 9101638528, 9110027648, 9118416512, - 9126803584, 9135188096, 9143581312, 9151969664, 9160356224, - 9168747136, 9177134464, 9185525632, 9193910144, 9202302848, - 9210690688, 9219079552, 9227465344, 9235854464, 9244244864, - 9252633472, 9261021824, 9269411456, 9277799296, 9286188928, - 9294574208, 9302965888, 9311351936, 9319740032, 9328131968, - 9336516736, 9344907392, 9353296768, 9361685888, 9370074752, - 9378463616, 9386849408, 9395239808, 9403629184, 9412016512, - 9420405376, 9428795008, 9437181568, 9445570688, 9453960832, - 9462346624, 9470738048, 9479121536, 9487515008, 9495903616, - 9504289664, 9512678528, 9521067904, 9529456256, 9537843584, - 9546233728, 9554621312, 9563011456, 9571398784, 9579788672, - 9588178304, 9596567168, 9604954496, 9613343104, 9621732992, - 9630121856, 9638508416, 9646898816, 9655283584, 9663675776, - 9672061312, 9680449664, 9688840064, 9697230464, 9705617536, - 9714003584, 9722393984, 9730772608, 9739172224, 9747561088, - 9755945344, 9764338816, 9772726144, 9781116544, 9789503872, - 9797892992, 9806282624, 9814670464, 9823056512, 9831439232, - 9839833984, 9848224384, 9856613504, 9865000576, 9873391232, - 9881772416, 9890162816, 9898556288, 9906940544, 9915333248, - 9923721088, 9932108672, 9940496512, 9948888448, 9957276544, - 9965666176, 9974048384, 9982441088, 9990830464, 9999219584, - 10007602816, 10015996544, 10024385152, 10032774016, 10041163648, - 10049548928, 10057940096, 10066329472, 10074717824, 10083105152, - 10091495296, 10099878784, 10108272256, 10116660608, 10125049216, - 10133437312, 10141825664, 10150213504, 10158601088, 10166991232, - 10175378816, 10183766144, 10192157312, 10200545408, 10208935552, - 10217322112, 10225712768, 10234099328, 10242489472, 10250876032, - 10259264896, 10267656064, 10276042624, 10284429184, 10292820352, - 10301209472, 10309598848, 10317987712, 10326375296, 10334763392, - 10343153536, 10351541632, 10359930752, 10368318592, 10376707456, - 10385096576, 10393484672, 10401867136, 10410262144, 10418647424, - 10427039104, 10435425664, 10443810176, 10452203648, 10460589952, - 10468982144, 10477369472, 10485759104, 10494147712, 10502533504, - 10510923392, 10519313536, 10527702656, 10536091264, 10544478592, - 10552867712, 10561255808, 10569642368, 10578032768, 10586423168, - 10594805632, 10603200128, 10611588992, 10619976064, 10628361344, - 10636754048, 10645143424, 10653531776, 10661920384, 10670307968, - 10678696832, 10687086464, 10695475072, 10703863168, 10712246144, - 10720639616, 10729026688, 10737414784, 10745806208, 10754190976, - 10762581376, 10770971264, 10779356288, 10787747456, 10796135552, - 10804525184, 10812915584, 10821301888, 10829692288, 10838078336, - 10846469248, 10854858368, 10863247232, 10871631488, 10880023424, - 10888412032, 10896799616, 10905188992, 10913574016, 10921964672, - 10930352768, 10938742912, 10947132544, 10955518592, 10963909504, - 10972298368, 10980687488, 10989074816, 10997462912, 11005851776, - 11014241152, 11022627712, 11031017344, 11039403904, 11047793024, - 11056184704, 11064570752, 11072960896, 11081343872, 11089737856, - 11098128256, 11106514816, 11114904448, 11123293568, 11131680128, - 11140065152, 11148458368, 11156845696, 11165236864, 11173624192, - 11182013824, 11190402688, 11198790784, 11207179136, 11215568768, - 11223957376, 11232345728, 11240734592, 11249122688, 11257511296, - 11265899648, 11274285952, 11282675584, 11291065472, 11299452544, - 11307842432, 11316231296, 11324616832, 11333009024, 11341395584, - 11349782656, 11358172288, 11366560384, 11374950016, 11383339648, - 11391721856, 11400117376, 11408504192, 11416893568, 11425283456, - 11433671552, 11442061184, 11450444672, 11458837888, 11467226752, - 11475611776, 11484003968, 11492392064, 11500780672, 11509169024, - 11517550976, 11525944448, 11534335616, 11542724224, 11551111808, - 11559500672, 11567890304, 11576277376, 11584667008, 11593056128, - 11601443456, 11609830016, 11618221952, 11626607488, 11634995072, - 11643387776, 11651775104, 11660161664, 11668552576, 11676940928, - 11685330304, 11693718656, 11702106496, 11710496128, 11718882688, - 11727273088, 11735660416, 11744050048, 11752437376, 11760824704, - 11769216128, 11777604736, 11785991296, 11794381952, 11802770048, - 11811157888, 11819548544, 11827932544, 11836324736, 11844713344, - 11853100928, 11861486464, 11869879936, 11878268032, 11886656896, - 11895044992, 11903433088, 11911822976, 11920210816, 11928600448, - 11936987264, 11945375872, 11953761152, 11962151296, 11970543488, - 11978928512, 11987320448, 11995708288, 12004095104, 12012486272, - 12020875136, 12029255552, 12037652096, 12046039168, 12054429568, - 12062813824, 12071206528, 12079594624, 12087983744, 12096371072, - 12104759936, 12113147264, 12121534592, 12129924992, 12138314624, - 12146703232, 12155091584, 12163481216, 12171864704, 12180255872, - 12188643968, 12197034112, 12205424512, 12213811328, 12222199424, - 12230590336, 12238977664, 12247365248, 12255755392, 12264143488, - 12272531584, 12280920448, 12289309568, 12297694592, 12306086528, - 12314475392, 12322865024, 12331253632, 12339640448, 12348029312, - 12356418944, 12364805248, 12373196672, 12381580928, 12389969024, - 12398357632, 12406750592, 12415138432, 12423527552, 12431916416, - 12440304512, 12448692352, 12457081216, 12465467776, 12473859968, - 12482245504, 12490636672, 12499025536, 12507411584, 12515801728, - 12524190592, 12532577152, 12540966272, 12549354368, 12557743232, - 12566129536, 12574523264, 12582911872, 12591299456, 12599688064, - 12608074624, 12616463488, 12624845696, 12633239936, 12641631616, - 12650019968, 12658407296, 12666795136, 12675183232, 12683574656, - 12691960192, 12700350592, 12708740224, 12717128576, 12725515904, - 12733906816, 12742295168, 12750680192, 12759071872, 12767460736, - 12775848832, 12784236928, 12792626816, 12801014656, 12809404288, - 12817789312, 12826181504, 12834568832, 12842954624, 12851345792, - 12859732352, 12868122496, 12876512128, 12884901248, 12893289088, - 12901672832, 12910067584, 12918455168, 12926842496, 12935232896, - 12943620736, 12952009856, 12960396928, 12968786816, 12977176192, - 12985563776, 12993951104, 13002341504, 13010730368, 13019115392, - 13027506304, 13035895168, 13044272512, 13052673152, 13061062528, - 13069446272, 13077838976, 13086227072, 13094613632, 13103000192, - 13111393664, 13119782528, 13128157568, 13136559232, 13144945024, - 13153329536, 13161724288, 13170111872, 13178502784, 13186884736, - 13195279744, 13203667072, 13212057472, 13220445824, 13228832128, - 13237221248, 13245610624, 13254000512, 13262388352, 13270777472, - 13279166336, 13287553408, 13295943296, 13304331904, 13312719488, - 13321108096, 13329494656, 13337885824, 13346274944, 13354663808, - 13363051136, 13371439232, 13379825024, 13388210816, 13396605056, - 13404995456, 13413380224, 13421771392, 13430159744, 13438546048, - 13446937216, 13455326848, 13463708288, 13472103808, 13480492672, - 13488875648, 13497269888, 13505657728, 13514045312, 13522435712, - 13530824576, 13539210112, 13547599232, 13555989376, 13564379008, - 13572766336, 13581154432, 13589544832, 13597932928, 13606320512, - 13614710656, 13623097472, 13631477632, 13639874944, 13648264064, - 13656652928, 13665041792, 13673430656, 13681818496, 13690207616, - 13698595712, 13706982272, 13715373184, 13723762048, 13732150144, - 13740536704, 13748926592, 13757316224, 13765700992, 13774090112, - 13782477952, 13790869376, 13799259008, 13807647872, 13816036736, - 13824425344, 13832814208, 13841202304, 13849591424, 13857978752, - 13866368896, 13874754688, 13883145344, 13891533184, 13899919232, - 13908311168, 13916692096, 13925085056, 13933473152, 13941866368, - 13950253696, 13958643584, 13967032192, 13975417216, 13983807616, - 13992197504, 14000582272, 14008973696, 14017363072, 14025752192, - 14034137984, 14042528384, 14050918016, 14059301504, 14067691648, - 14076083584, 14084470144, 14092852352, 14101249664, 14109635968, - 14118024832, 14126407552, 14134804352, 14143188608, 14151577984, - 14159968384, 14168357248, 14176741504, 14185127296, 14193521024, - 14201911424, 14210301824, 14218685056, 14227067264, 14235467392, - 14243855488, 14252243072, 14260630144, 14269021568, 14277409408, - 14285799296, 14294187904, 14302571392, 14310961792, 14319353728, - 14327738752, 14336130944, 14344518784, 14352906368, 14361296512, - 14369685376, 14378071424, 14386462592, 14394848128, 14403230848, - 14411627392, 14420013952, 14428402304, 14436793472, 14445181568, - 14453569664, 14461959808, 14470347904, 14478737024, 14487122816, - 14495511424, 14503901824, 14512291712, 14520677504, 14529064832, - 14537456768, 14545845632, 14554234496, 14562618496, 14571011456, - 14579398784, 14587789184, 14596172672, 14604564608, 14612953984, - 14621341312, 14629724288, 14638120832, 14646503296, 14654897536, - 14663284864, 14671675264, 14680061056, 14688447616, 14696835968, - 14705228416, 14713616768, 14722003328, 14730392192, 14738784128, - 14747172736, 14755561088, 14763947648, 14772336512, 14780725376, - 14789110144, 14797499776, 14805892736, 14814276992, 14822670208, - 14831056256, 14839444352, 14847836032, 14856222848, 14864612992, - 14872997504, 14881388672, 14889775744, 14898165376, 14906553472, - 14914944896, 14923329664, 14931721856, 14940109696, 14948497024, - 14956887424, 14965276544, 14973663616, 14982053248, 14990439808, - 14998830976, 15007216768, 15015605888, 15023995264, 15032385152, - 15040768384, 15049154944, 15057549184, 15065939072, 15074328448, - 15082715008, 15091104128, 15099493504, 15107879296, 15116269184, - 15124659584, 15133042304, 15141431936, 15149824384, 15158214272, - 15166602368, 15174991232, 15183378304, 15191760512, 15200154496, - 15208542592, 15216931712, 15225323392, 15233708416, 15242098048, - 15250489216, 15258875264, 15267265408, 15275654528, 15284043136, - 15292431488, 15300819584, 15309208192, 15317596544, 15325986176, - 15334374784, 15342763648, 15351151744, 15359540608, 15367929728, - 15376318336, 15384706432, 15393092992, 15401481856, 15409869952, - 15418258816, 15426649984, 15435037568, 15443425664, 15451815296, - 15460203392, 15468589184, 15476979328, 15485369216, 15493755776, - 15502146944, 15510534272, 15518924416, 15527311232, 15535699072, - 15544089472, 15552478336, 15560866688, 15569254528, 15577642624, - 15586031488, 15594419072, 15602809472, 15611199104, 15619586432, - 15627975296, 15636364928, 15644753792, 15653141888, 15661529216, - 15669918848, 15678305152, 15686696576, 15695083136, 15703474048, - 15711861632, 15720251264, 15728636288, 15737027456, 15745417088, - 15753804928, 15762194048, 15770582656, 15778971008, 15787358336, - 15795747712, 15804132224, 15812523392, 15820909696, 15829300096, - 15837691264, 15846071936, 15854466944, 15862855808, 15871244672, - 15879634816, 15888020608, 15896409728, 15904799104, 15913185152, - 15921577088, 15929966464, 15938354816, 15946743424, 15955129472, - 15963519872, 15971907968, 15980296064, 15988684928, 15997073024, - 16005460864, 16013851264, 16022241152, 16030629248, 16039012736, - 16047406976, 16055794816, 16064181376, 16072571264, 16080957824, - 16089346688, 16097737856, 16106125184, 16114514816, 16122904192, - 16131292544, 16139678848, 16148066944, 16156453504, 16164839552, - 16173236096, 16181623424, 16190012032, 16198401152, 16206790528, - 16215177344, 16223567744, 16231956352, 16240344704, 16248731008, - 16257117824, 16265504384, 16273898624, 16282281856, 16290668672, - 16299064192, 16307449216, 16315842176, 16324230016, 16332613504, - 16341006464, 16349394304, 16357783168, 16366172288, 16374561664, - 16382951296, 16391337856, 16399726208, 16408116352, 16416505472, - 16424892032, 16433282176, 16441668224, 16450058624, 16458448768, - 16466836864, 16475224448, 16483613056, 16492001408, 16500391808, - 16508779648, 16517166976, 16525555328, 16533944192, 16542330752, - 16550719616, 16559110528, 16567497088, 16575888512, 16584274816, - 16592665472, 16601051008, 16609442944, 16617832064, 16626218624, - 16634607488, 16642996096, 16651385728, 16659773824, 16668163712, - 16676552576, 16684938112, 16693328768, 16701718144, 16710095488, - 16718492288, 16726883968, 16735272832, 16743661184, 16752049792, - 16760436608, 16768827008, 16777214336, 16785599104, 16793992832, - 16802381696, 16810768768, 16819151744, 16827542656, 16835934848, - 16844323712, 16852711552, 16861101952, 16869489536, 16877876864, - 16886265728, 16894653056, 16903044736, 16911431296, 16919821696, - 16928207488, 16936592768, 16944987776, 16953375616, 16961763968, - 16970152832, 16978540928, 16986929536, 16995319168, 17003704448, - 17012096896, 17020481152, 17028870784, 17037262208, 17045649536, - 17054039936, 17062426496, 17070814336, 17079205504, 17087592064, - 17095978112, 17104369024, 17112759424, 17121147776, 17129536384, - 17137926016, 17146314368, 17154700928, 17163089792, 17171480192, - 17179864192, 17188256896, 17196644992, 17205033856, 17213423488, - 17221811072, 17230198912, 17238588032, 17246976896, 17255360384, - 17263754624, 17272143232, 17280530048, 17288918912, 17297309312, - 17305696384, 17314085504, 17322475136, 17330863744, 17339252096, - 17347640192, 17356026496, 17364413824, 17372796544, 17381190016, - 17389583488, 17397972608, 17406360704, 17414748544, 17423135872, - 17431527296, 17439915904, 17448303232, 17456691584, 17465081728, - 17473468288, 17481857408, 17490247552, 17498635904, 17507022464, - 17515409024, 17523801728, 17532189824, 17540577664, 17548966016, - 17557353344, 17565741184, 17574131584, 17582519168, 17590907008, - 17599296128, 17607687808, 17616076672, 17624455808, 17632852352, - 17641238656, 17649630848, 17658018944, 17666403968, 17674794112, - 17683178368, 17691573376, 17699962496, 17708350592, 17716739968, - 17725126528, 17733517184, 17741898112, 17750293888, 17758673024, - 17767070336, 17775458432, 17783848832, 17792236928, 17800625536, - 17809012352, 17817402752, 17825785984, 17834178944, 17842563968, - 17850955648, 17859344512, 17867732864, 17876119424, 17884511872, - 17892900224, 17901287296, 17909677696, 17918058112, 17926451072, - 17934843776, 17943230848, 17951609216, 17960008576, 17968397696, - 17976784256, 17985175424, 17993564032, 18001952128, 18010339712, - 18018728576, 18027116672, 18035503232, 18043894144, 18052283264, - 18060672128, 18069056384, 18077449856, 18085837184, 18094225792, - 18102613376, 18111004544, 18119388544, 18127781248, 18136170368, - 18144558976, 18152947328, 18161336192, 18169724288, 18178108544, - 18186498944, 18194886784, 18203275648, 18211666048, 18220048768, - 18228444544, 18236833408, 18245220736 - }; + private readonly ulong[] _dataSizes = new ulong[] + { + 1073739904, 1082130304, 1090514816, 1098906752, 1107293056, + 1115684224, 1124070016, 1132461952, 1140849536, 1149232768, + 1157627776, 1166013824, 1174404736, 1182786944, 1191180416, + 1199568512, 1207958912, 1216345216, 1224732032, 1233124736, + 1241513344, 1249902464, 1258290304, 1266673792, 1275067264, + 1283453312, 1291844992, 1300234112, 1308619904, 1317010048, + 1325397376, 1333787776, 1342176128, 1350561664, 1358954368, + 1367339392, 1375731584, 1384118144, 1392507008, 1400897408, + 1409284736, 1417673344, 1426062464, 1434451072, 1442839168, + 1451229056, 1459615616, 1468006016, 1476394112, 1484782976, + 1493171584, 1501559168, 1509948032, 1518337664, 1526726528, + 1535114624, 1543503488, 1551892096, 1560278656, 1568669056, + 1577056384, 1585446272, 1593831296, 1602219392, 1610610304, + 1619000192, 1627386752, 1635773824, 1644164224, 1652555648, + 1660943488, 1669332608, 1677721216, 1686109312, 1694497664, + 1702886272, 1711274624, 1719661184, 1728047744, 1736434816, + 1744829056, 1753218944, 1761606272, 1769995904, 1778382464, + 1786772864, 1795157888, 1803550592, 1811937664, 1820327552, + 1828711552, 1837102976, 1845488768, 1853879936, 1862269312, + 1870656896, 1879048064, 1887431552, 1895825024, 1904212096, + 1912601216, 1920988544, 1929379456, 1937765504, 1946156672, + 1954543232, 1962932096, 1971321728, 1979707264, 1988093056, + 1996487552, 2004874624, 2013262208, 2021653888, 2030039936, + 2038430848, 2046819968, 2055208576, 2063596672, 2071981952, + 2080373632, 2088762752, 2097149056, 2105539712, 2113928576, + 2122315136, 2130700672, 2139092608, 2147483264, 2155872128, + 2164257664, 2172642176, 2181035392, 2189426048, 2197814912, + 2206203008, 2214587264, 2222979712, 2231367808, 2239758208, + 2248145024, 2256527744, 2264922752, 2273312128, 2281701248, + 2290086272, 2298476672, 2306867072, 2315251072, 2323639168, + 2332032128, 2340420224, 2348808064, 2357196416, 2365580416, + 2373966976, 2382363008, 2390748544, 2399139968, 2407530368, + 2415918976, 2424307328, 2432695424, 2441084288, 2449472384, + 2457861248, 2466247808, 2474637184, 2483026816, 2491414144, + 2499803776, 2508191872, 2516582272, 2524970368, 2533359232, + 2541743488, 2550134144, 2558525056, 2566913408, 2575301504, + 2583686528, 2592073856, 2600467328, 2608856192, 2617240448, + 2625631616, 2634022016, 2642407552, 2650796416, 2659188352, + 2667574912, 2675965312, 2684352896, 2692738688, 2701130624, + 2709518464, 2717907328, 2726293376, 2734685056, 2743073152, + 2751462016, 2759851648, 2768232832, 2776625536, 2785017728, + 2793401984, 2801794432, 2810182016, 2818571648, 2826959488, + 2835349376, 2843734144, 2852121472, 2860514432, 2868900992, + 2877286784, 2885676928, 2894069632, 2902451584, 2910843008, + 2919234688, 2927622784, 2936011648, 2944400768, 2952789376, + 2961177728, 2969565568, 2977951616, 2986338944, 2994731392, + 3003120256, 3011508352, 3019895936, 3028287104, 3036675968, + 3045063808, 3053452928, 3061837696, 3070228352, 3078615424, + 3087003776, 3095394944, 3103782272, 3112173184, 3120562048, + 3128944768, 3137339264, 3145725056, 3154109312, 3162505088, + 3170893184, 3179280256, 3187669376, 3196056704, 3204445568, + 3212836736, 3221224064, 3229612928, 3238002304, 3246391168, + 3254778496, 3263165824, 3271556224, 3279944576, 3288332416, + 3296719232, 3305110912, 3313500032, 3321887104, 3330273152, + 3338658944, 3347053184, 3355440512, 3363827072, 3372220288, + 3380608384, 3388997504, 3397384576, 3405774208, 3414163072, + 3422551936, 3430937984, 3439328384, 3447714176, 3456104576, + 3464493952, 3472883584, 3481268864, 3489655168, 3498048896, + 3506434432, 3514826368, 3523213952, 3531603584, 3539987072, + 3548380288, 3556763264, 3565157248, 3573545344, 3581934464, + 3590324096, 3598712704, 3607098752, 3615488384, 3623877248, + 3632265856, 3640646528, 3649043584, 3657430144, 3665821568, + 3674207872, 3682597504, 3690984832, 3699367808, 3707764352, + 3716152448, 3724541056, 3732925568, 3741318016, 3749706368, + 3758091136, 3766481536, 3774872704, 3783260032, 3791650432, + 3800036224, 3808427648, 3816815488, 3825204608, 3833592704, + 3841981568, 3850370432, 3858755968, 3867147904, 3875536256, + 3883920512, 3892313728, 3900702592, 3909087872, 3917478784, + 3925868416, 3934256512, 3942645376, 3951032192, 3959422336, + 3967809152, 3976200064, 3984588416, 3992974976, 4001363584, + 4009751168, 4018141312, 4026530432, 4034911616, 4043308928, + 4051695488, 4060084352, 4068472448, 4076862848, 4085249408, + 4093640576, 4102028416, 4110413696, 4118805632, 4127194496, + 4135583104, 4143971968, 4152360832, 4160746112, 4169135744, + 4177525888, 4185912704, 4194303616, 4202691968, 4211076736, + 4219463552, 4227855488, 4236246656, 4244633728, 4253022848, + 4261412224, 4269799808, 4278184832, 4286578048, 4294962304, + 4303349632, 4311743104, 4320130432, 4328521088, 4336909184, + 4345295488, 4353687424, 4362073472, 4370458496, 4378852736, + 4387238528, 4395630208, 4404019072, 4412407424, 4420790656, + 4429182848, 4437571456, 4445962112, 4454344064, 4462738048, + 4471119232, 4479516544, 4487904128, 4496289664, 4504682368, + 4513068416, 4521459584, 4529846144, 4538232704, 4546619776, + 4555010176, 4563402112, 4571790208, 4580174464, 4588567936, + 4596957056, 4605344896, 4613734016, 4622119808, 4630511488, + 4638898816, 4647287936, 4655675264, 4664065664, 4672451968, + 4680842624, 4689231488, 4697620352, 4706007424, 4714397056, + 4722786176, 4731173248, 4739562368, 4747951744, 4756340608, + 4764727936, 4773114496, 4781504384, 4789894784, 4798283648, + 4806667648, 4815059584, 4823449472, 4831835776, 4840226176, + 4848612224, 4857003392, 4865391488, 4873780096, 4882169728, + 4890557312, 4898946944, 4907333248, 4915722368, 4924110976, + 4932499328, 4940889728, 4949276032, 4957666432, 4966054784, + 4974438016, 4982831488, 4991221376, 4999607168, 5007998848, + 5016386432, 5024763776, 5033164672, 5041544576, 5049941888, + 5058329728, 5066717056, 5075107456, 5083494272, 5091883904, + 5100273536, 5108662144, 5117048192, 5125436032, 5133827456, + 5142215296, 5150605184, 5158993024, 5167382144, 5175769472, + 5184157568, 5192543872, 5200936064, 5209324928, 5217711232, + 5226102656, 5234490496, 5242877312, 5251263872, 5259654016, + 5268040832, 5276434304, 5284819328, 5293209728, 5301598592, + 5309986688, 5318374784, 5326764416, 5335151488, 5343542144, + 5351929472, 5360319872, 5368706944, 5377096576, 5385484928, + 5393871232, 5402263424, 5410650496, 5419040384, 5427426944, + 5435816576, 5444205952, 5452594816, 5460981376, 5469367936, + 5477760896, 5486148736, 5494536832, 5502925952, 5511315328, + 5519703424, 5528089984, 5536481152, 5544869504, 5553256064, + 5561645696, 5570032768, 5578423936, 5586811264, 5595193216, + 5603585408, 5611972736, 5620366208, 5628750464, 5637143936, + 5645528192, 5653921408, 5662310272, 5670694784, 5679082624, + 5687474048, 5695864448, 5704251008, 5712641408, 5721030272, + 5729416832, 5737806208, 5746194304, 5754583936, 5762969984, + 5771358592, 5779748224, 5788137856, 5796527488, 5804911232, + 5813300608, 5821692544, 5830082176, 5838468992, 5846855552, + 5855247488, 5863636096, 5872024448, 5880411008, 5888799872, + 5897186432, 5905576832, 5913966976, 5922352768, 5930744704, + 5939132288, 5947522432, 5955911296, 5964299392, 5972688256, + 5981074304, 5989465472, 5997851008, 6006241408, 6014627968, + 6023015552, 6031408256, 6039796096, 6048185216, 6056574848, + 6064963456, 6073351808, 6081736064, 6090128768, 6098517632, + 6106906496, 6115289216, 6123680896, 6132070016, 6140459648, + 6148849024, 6157237376, 6165624704, 6174009728, 6182403712, + 6190792064, 6199176064, 6207569792, 6215952256, 6224345216, + 6232732544, 6241124224, 6249510272, 6257899136, 6266287744, + 6274676864, 6283065728, 6291454336, 6299843456, 6308232064, + 6316620928, 6325006208, 6333395584, 6341784704, 6350174848, + 6358562176, 6366951296, 6375337856, 6383729536, 6392119168, + 6400504192, 6408895616, 6417283456, 6425673344, 6434059136, + 6442444672, 6450837376, 6459223424, 6467613056, 6476004224, + 6484393088, 6492781952, 6501170048, 6509555072, 6517947008, + 6526336384, 6534725504, 6543112832, 6551500672, 6559888768, + 6568278656, 6576662912, 6585055616, 6593443456, 6601834112, + 6610219648, 6618610304, 6626999168, 6635385472, 6643777408, + 6652164224, 6660552832, 6668941952, 6677330048, 6685719424, + 6694107776, 6702493568, 6710882176, 6719274112, 6727662976, + 6736052096, 6744437632, 6752825984, 6761213824, 6769604224, + 6777993856, 6786383488, 6794770816, 6803158144, 6811549312, + 6819937664, 6828326528, 6836706176, 6845101696, 6853491328, + 6861880448, 6870269312, 6878655104, 6887046272, 6895433344, + 6903822208, 6912212864, 6920596864, 6928988288, 6937377152, + 6945764992, 6954149248, 6962544256, 6970928768, 6979317376, + 6987709312, 6996093824, 7004487296, 7012875392, 7021258624, + 7029652352, 7038038912, 7046427776, 7054818944, 7063207808, + 7071595136, 7079980928, 7088372608, 7096759424, 7105149824, + 7113536896, 7121928064, 7130315392, 7138699648, 7147092352, + 7155479168, 7163865728, 7172249984, 7180648064, 7189036672, + 7197424768, 7205810816, 7214196608, 7222589824, 7230975104, + 7239367552, 7247755904, 7256145536, 7264533376, 7272921472, + 7281308032, 7289694848, 7298088832, 7306471808, 7314864512, + 7323253888, 7331643008, 7340029568, 7348419712, 7356808832, + 7365196672, 7373585792, 7381973888, 7390362752, 7398750592, + 7407138944, 7415528576, 7423915648, 7432302208, 7440690304, + 7449080192, 7457472128, 7465860992, 7474249088, 7482635648, + 7491023744, 7499412608, 7507803008, 7516192384, 7524579968, + 7532967296, 7541358464, 7549745792, 7558134656, 7566524032, + 7574912896, 7583300992, 7591690112, 7600075136, 7608466816, + 7616854912, 7625244544, 7633629824, 7642020992, 7650410368, + 7658794112, 7667187328, 7675574912, 7683961984, 7692349568, + 7700739712, 7709130368, 7717519232, 7725905536, 7734295424, + 7742683264, 7751069056, 7759457408, 7767849088, 7776238208, + 7784626816, 7793014912, 7801405312, 7809792128, 7818179968, + 7826571136, 7834957184, 7843347328, 7851732352, 7860124544, + 7868512384, 7876902016, 7885287808, 7893679744, 7902067072, + 7910455936, 7918844288, 7927230848, 7935622784, 7944009344, + 7952400256, 7960786048, 7969176704, 7977565312, 7985953408, + 7994339968, 8002730368, 8011119488, 8019508096, 8027896192, + 8036285056, 8044674688, 8053062272, 8061448832, 8069838464, + 8078227328, 8086616704, 8095006592, 8103393664, 8111783552, + 8120171392, 8128560256, 8136949376, 8145336704, 8153726848, + 8162114944, 8170503296, 8178891904, 8187280768, 8195669632, + 8204058496, 8212444544, 8220834176, 8229222272, 8237612672, + 8246000768, 8254389376, 8262775168, 8271167104, 8279553664, + 8287944064, 8296333184, 8304715136, 8313108352, 8321497984, + 8329885568, 8338274432, 8346663296, 8355052928, 8363441536, + 8371828352, 8380217984, 8388606592, 8396996224, 8405384576, + 8413772672, 8422161536, 8430549376, 8438939008, 8447326592, + 8455715456, 8464104832, 8472492928, 8480882048, 8489270656, + 8497659776, 8506045312, 8514434944, 8522823808, 8531208832, + 8539602304, 8547990656, 8556378752, 8564768384, 8573154176, + 8581542784, 8589933952, 8598322816, 8606705024, 8615099264, + 8623487872, 8631876992, 8640264064, 8648653952, 8657040256, + 8665430656, 8673820544, 8682209152, 8690592128, 8698977152, + 8707374464, 8715763328, 8724151424, 8732540032, 8740928384, + 8749315712, 8757704576, 8766089344, 8774480768, 8782871936, + 8791260032, 8799645824, 8808034432, 8816426368, 8824812928, + 8833199488, 8841591424, 8849976448, 8858366336, 8866757248, + 8875147136, 8883532928, 8891923328, 8900306816, 8908700288, + 8917088384, 8925478784, 8933867392, 8942250368, 8950644608, + 8959032704, 8967420544, 8975809664, 8984197504, 8992584064, + 9000976256, 9009362048, 9017752448, 9026141312, 9034530688, + 9042917504, 9051307904, 9059694208, 9068084864, 9076471424, + 9084861824, 9093250688, 9101638528, 9110027648, 9118416512, + 9126803584, 9135188096, 9143581312, 9151969664, 9160356224, + 9168747136, 9177134464, 9185525632, 9193910144, 9202302848, + 9210690688, 9219079552, 9227465344, 9235854464, 9244244864, + 9252633472, 9261021824, 9269411456, 9277799296, 9286188928, + 9294574208, 9302965888, 9311351936, 9319740032, 9328131968, + 9336516736, 9344907392, 9353296768, 9361685888, 9370074752, + 9378463616, 9386849408, 9395239808, 9403629184, 9412016512, + 9420405376, 9428795008, 9437181568, 9445570688, 9453960832, + 9462346624, 9470738048, 9479121536, 9487515008, 9495903616, + 9504289664, 9512678528, 9521067904, 9529456256, 9537843584, + 9546233728, 9554621312, 9563011456, 9571398784, 9579788672, + 9588178304, 9596567168, 9604954496, 9613343104, 9621732992, + 9630121856, 9638508416, 9646898816, 9655283584, 9663675776, + 9672061312, 9680449664, 9688840064, 9697230464, 9705617536, + 9714003584, 9722393984, 9730772608, 9739172224, 9747561088, + 9755945344, 9764338816, 9772726144, 9781116544, 9789503872, + 9797892992, 9806282624, 9814670464, 9823056512, 9831439232, + 9839833984, 9848224384, 9856613504, 9865000576, 9873391232, + 9881772416, 9890162816, 9898556288, 9906940544, 9915333248, + 9923721088, 9932108672, 9940496512, 9948888448, 9957276544, + 9965666176, 9974048384, 9982441088, 9990830464, 9999219584, + 10007602816, 10015996544, 10024385152, 10032774016, 10041163648, + 10049548928, 10057940096, 10066329472, 10074717824, 10083105152, + 10091495296, 10099878784, 10108272256, 10116660608, 10125049216, + 10133437312, 10141825664, 10150213504, 10158601088, 10166991232, + 10175378816, 10183766144, 10192157312, 10200545408, 10208935552, + 10217322112, 10225712768, 10234099328, 10242489472, 10250876032, + 10259264896, 10267656064, 10276042624, 10284429184, 10292820352, + 10301209472, 10309598848, 10317987712, 10326375296, 10334763392, + 10343153536, 10351541632, 10359930752, 10368318592, 10376707456, + 10385096576, 10393484672, 10401867136, 10410262144, 10418647424, + 10427039104, 10435425664, 10443810176, 10452203648, 10460589952, + 10468982144, 10477369472, 10485759104, 10494147712, 10502533504, + 10510923392, 10519313536, 10527702656, 10536091264, 10544478592, + 10552867712, 10561255808, 10569642368, 10578032768, 10586423168, + 10594805632, 10603200128, 10611588992, 10619976064, 10628361344, + 10636754048, 10645143424, 10653531776, 10661920384, 10670307968, + 10678696832, 10687086464, 10695475072, 10703863168, 10712246144, + 10720639616, 10729026688, 10737414784, 10745806208, 10754190976, + 10762581376, 10770971264, 10779356288, 10787747456, 10796135552, + 10804525184, 10812915584, 10821301888, 10829692288, 10838078336, + 10846469248, 10854858368, 10863247232, 10871631488, 10880023424, + 10888412032, 10896799616, 10905188992, 10913574016, 10921964672, + 10930352768, 10938742912, 10947132544, 10955518592, 10963909504, + 10972298368, 10980687488, 10989074816, 10997462912, 11005851776, + 11014241152, 11022627712, 11031017344, 11039403904, 11047793024, + 11056184704, 11064570752, 11072960896, 11081343872, 11089737856, + 11098128256, 11106514816, 11114904448, 11123293568, 11131680128, + 11140065152, 11148458368, 11156845696, 11165236864, 11173624192, + 11182013824, 11190402688, 11198790784, 11207179136, 11215568768, + 11223957376, 11232345728, 11240734592, 11249122688, 11257511296, + 11265899648, 11274285952, 11282675584, 11291065472, 11299452544, + 11307842432, 11316231296, 11324616832, 11333009024, 11341395584, + 11349782656, 11358172288, 11366560384, 11374950016, 11383339648, + 11391721856, 11400117376, 11408504192, 11416893568, 11425283456, + 11433671552, 11442061184, 11450444672, 11458837888, 11467226752, + 11475611776, 11484003968, 11492392064, 11500780672, 11509169024, + 11517550976, 11525944448, 11534335616, 11542724224, 11551111808, + 11559500672, 11567890304, 11576277376, 11584667008, 11593056128, + 11601443456, 11609830016, 11618221952, 11626607488, 11634995072, + 11643387776, 11651775104, 11660161664, 11668552576, 11676940928, + 11685330304, 11693718656, 11702106496, 11710496128, 11718882688, + 11727273088, 11735660416, 11744050048, 11752437376, 11760824704, + 11769216128, 11777604736, 11785991296, 11794381952, 11802770048, + 11811157888, 11819548544, 11827932544, 11836324736, 11844713344, + 11853100928, 11861486464, 11869879936, 11878268032, 11886656896, + 11895044992, 11903433088, 11911822976, 11920210816, 11928600448, + 11936987264, 11945375872, 11953761152, 11962151296, 11970543488, + 11978928512, 11987320448, 11995708288, 12004095104, 12012486272, + 12020875136, 12029255552, 12037652096, 12046039168, 12054429568, + 12062813824, 12071206528, 12079594624, 12087983744, 12096371072, + 12104759936, 12113147264, 12121534592, 12129924992, 12138314624, + 12146703232, 12155091584, 12163481216, 12171864704, 12180255872, + 12188643968, 12197034112, 12205424512, 12213811328, 12222199424, + 12230590336, 12238977664, 12247365248, 12255755392, 12264143488, + 12272531584, 12280920448, 12289309568, 12297694592, 12306086528, + 12314475392, 12322865024, 12331253632, 12339640448, 12348029312, + 12356418944, 12364805248, 12373196672, 12381580928, 12389969024, + 12398357632, 12406750592, 12415138432, 12423527552, 12431916416, + 12440304512, 12448692352, 12457081216, 12465467776, 12473859968, + 12482245504, 12490636672, 12499025536, 12507411584, 12515801728, + 12524190592, 12532577152, 12540966272, 12549354368, 12557743232, + 12566129536, 12574523264, 12582911872, 12591299456, 12599688064, + 12608074624, 12616463488, 12624845696, 12633239936, 12641631616, + 12650019968, 12658407296, 12666795136, 12675183232, 12683574656, + 12691960192, 12700350592, 12708740224, 12717128576, 12725515904, + 12733906816, 12742295168, 12750680192, 12759071872, 12767460736, + 12775848832, 12784236928, 12792626816, 12801014656, 12809404288, + 12817789312, 12826181504, 12834568832, 12842954624, 12851345792, + 12859732352, 12868122496, 12876512128, 12884901248, 12893289088, + 12901672832, 12910067584, 12918455168, 12926842496, 12935232896, + 12943620736, 12952009856, 12960396928, 12968786816, 12977176192, + 12985563776, 12993951104, 13002341504, 13010730368, 13019115392, + 13027506304, 13035895168, 13044272512, 13052673152, 13061062528, + 13069446272, 13077838976, 13086227072, 13094613632, 13103000192, + 13111393664, 13119782528, 13128157568, 13136559232, 13144945024, + 13153329536, 13161724288, 13170111872, 13178502784, 13186884736, + 13195279744, 13203667072, 13212057472, 13220445824, 13228832128, + 13237221248, 13245610624, 13254000512, 13262388352, 13270777472, + 13279166336, 13287553408, 13295943296, 13304331904, 13312719488, + 13321108096, 13329494656, 13337885824, 13346274944, 13354663808, + 13363051136, 13371439232, 13379825024, 13388210816, 13396605056, + 13404995456, 13413380224, 13421771392, 13430159744, 13438546048, + 13446937216, 13455326848, 13463708288, 13472103808, 13480492672, + 13488875648, 13497269888, 13505657728, 13514045312, 13522435712, + 13530824576, 13539210112, 13547599232, 13555989376, 13564379008, + 13572766336, 13581154432, 13589544832, 13597932928, 13606320512, + 13614710656, 13623097472, 13631477632, 13639874944, 13648264064, + 13656652928, 13665041792, 13673430656, 13681818496, 13690207616, + 13698595712, 13706982272, 13715373184, 13723762048, 13732150144, + 13740536704, 13748926592, 13757316224, 13765700992, 13774090112, + 13782477952, 13790869376, 13799259008, 13807647872, 13816036736, + 13824425344, 13832814208, 13841202304, 13849591424, 13857978752, + 13866368896, 13874754688, 13883145344, 13891533184, 13899919232, + 13908311168, 13916692096, 13925085056, 13933473152, 13941866368, + 13950253696, 13958643584, 13967032192, 13975417216, 13983807616, + 13992197504, 14000582272, 14008973696, 14017363072, 14025752192, + 14034137984, 14042528384, 14050918016, 14059301504, 14067691648, + 14076083584, 14084470144, 14092852352, 14101249664, 14109635968, + 14118024832, 14126407552, 14134804352, 14143188608, 14151577984, + 14159968384, 14168357248, 14176741504, 14185127296, 14193521024, + 14201911424, 14210301824, 14218685056, 14227067264, 14235467392, + 14243855488, 14252243072, 14260630144, 14269021568, 14277409408, + 14285799296, 14294187904, 14302571392, 14310961792, 14319353728, + 14327738752, 14336130944, 14344518784, 14352906368, 14361296512, + 14369685376, 14378071424, 14386462592, 14394848128, 14403230848, + 14411627392, 14420013952, 14428402304, 14436793472, 14445181568, + 14453569664, 14461959808, 14470347904, 14478737024, 14487122816, + 14495511424, 14503901824, 14512291712, 14520677504, 14529064832, + 14537456768, 14545845632, 14554234496, 14562618496, 14571011456, + 14579398784, 14587789184, 14596172672, 14604564608, 14612953984, + 14621341312, 14629724288, 14638120832, 14646503296, 14654897536, + 14663284864, 14671675264, 14680061056, 14688447616, 14696835968, + 14705228416, 14713616768, 14722003328, 14730392192, 14738784128, + 14747172736, 14755561088, 14763947648, 14772336512, 14780725376, + 14789110144, 14797499776, 14805892736, 14814276992, 14822670208, + 14831056256, 14839444352, 14847836032, 14856222848, 14864612992, + 14872997504, 14881388672, 14889775744, 14898165376, 14906553472, + 14914944896, 14923329664, 14931721856, 14940109696, 14948497024, + 14956887424, 14965276544, 14973663616, 14982053248, 14990439808, + 14998830976, 15007216768, 15015605888, 15023995264, 15032385152, + 15040768384, 15049154944, 15057549184, 15065939072, 15074328448, + 15082715008, 15091104128, 15099493504, 15107879296, 15116269184, + 15124659584, 15133042304, 15141431936, 15149824384, 15158214272, + 15166602368, 15174991232, 15183378304, 15191760512, 15200154496, + 15208542592, 15216931712, 15225323392, 15233708416, 15242098048, + 15250489216, 15258875264, 15267265408, 15275654528, 15284043136, + 15292431488, 15300819584, 15309208192, 15317596544, 15325986176, + 15334374784, 15342763648, 15351151744, 15359540608, 15367929728, + 15376318336, 15384706432, 15393092992, 15401481856, 15409869952, + 15418258816, 15426649984, 15435037568, 15443425664, 15451815296, + 15460203392, 15468589184, 15476979328, 15485369216, 15493755776, + 15502146944, 15510534272, 15518924416, 15527311232, 15535699072, + 15544089472, 15552478336, 15560866688, 15569254528, 15577642624, + 15586031488, 15594419072, 15602809472, 15611199104, 15619586432, + 15627975296, 15636364928, 15644753792, 15653141888, 15661529216, + 15669918848, 15678305152, 15686696576, 15695083136, 15703474048, + 15711861632, 15720251264, 15728636288, 15737027456, 15745417088, + 15753804928, 15762194048, 15770582656, 15778971008, 15787358336, + 15795747712, 15804132224, 15812523392, 15820909696, 15829300096, + 15837691264, 15846071936, 15854466944, 15862855808, 15871244672, + 15879634816, 15888020608, 15896409728, 15904799104, 15913185152, + 15921577088, 15929966464, 15938354816, 15946743424, 15955129472, + 15963519872, 15971907968, 15980296064, 15988684928, 15997073024, + 16005460864, 16013851264, 16022241152, 16030629248, 16039012736, + 16047406976, 16055794816, 16064181376, 16072571264, 16080957824, + 16089346688, 16097737856, 16106125184, 16114514816, 16122904192, + 16131292544, 16139678848, 16148066944, 16156453504, 16164839552, + 16173236096, 16181623424, 16190012032, 16198401152, 16206790528, + 16215177344, 16223567744, 16231956352, 16240344704, 16248731008, + 16257117824, 16265504384, 16273898624, 16282281856, 16290668672, + 16299064192, 16307449216, 16315842176, 16324230016, 16332613504, + 16341006464, 16349394304, 16357783168, 16366172288, 16374561664, + 16382951296, 16391337856, 16399726208, 16408116352, 16416505472, + 16424892032, 16433282176, 16441668224, 16450058624, 16458448768, + 16466836864, 16475224448, 16483613056, 16492001408, 16500391808, + 16508779648, 16517166976, 16525555328, 16533944192, 16542330752, + 16550719616, 16559110528, 16567497088, 16575888512, 16584274816, + 16592665472, 16601051008, 16609442944, 16617832064, 16626218624, + 16634607488, 16642996096, 16651385728, 16659773824, 16668163712, + 16676552576, 16684938112, 16693328768, 16701718144, 16710095488, + 16718492288, 16726883968, 16735272832, 16743661184, 16752049792, + 16760436608, 16768827008, 16777214336, 16785599104, 16793992832, + 16802381696, 16810768768, 16819151744, 16827542656, 16835934848, + 16844323712, 16852711552, 16861101952, 16869489536, 16877876864, + 16886265728, 16894653056, 16903044736, 16911431296, 16919821696, + 16928207488, 16936592768, 16944987776, 16953375616, 16961763968, + 16970152832, 16978540928, 16986929536, 16995319168, 17003704448, + 17012096896, 17020481152, 17028870784, 17037262208, 17045649536, + 17054039936, 17062426496, 17070814336, 17079205504, 17087592064, + 17095978112, 17104369024, 17112759424, 17121147776, 17129536384, + 17137926016, 17146314368, 17154700928, 17163089792, 17171480192, + 17179864192, 17188256896, 17196644992, 17205033856, 17213423488, + 17221811072, 17230198912, 17238588032, 17246976896, 17255360384, + 17263754624, 17272143232, 17280530048, 17288918912, 17297309312, + 17305696384, 17314085504, 17322475136, 17330863744, 17339252096, + 17347640192, 17356026496, 17364413824, 17372796544, 17381190016, + 17389583488, 17397972608, 17406360704, 17414748544, 17423135872, + 17431527296, 17439915904, 17448303232, 17456691584, 17465081728, + 17473468288, 17481857408, 17490247552, 17498635904, 17507022464, + 17515409024, 17523801728, 17532189824, 17540577664, 17548966016, + 17557353344, 17565741184, 17574131584, 17582519168, 17590907008, + 17599296128, 17607687808, 17616076672, 17624455808, 17632852352, + 17641238656, 17649630848, 17658018944, 17666403968, 17674794112, + 17683178368, 17691573376, 17699962496, 17708350592, 17716739968, + 17725126528, 17733517184, 17741898112, 17750293888, 17758673024, + 17767070336, 17775458432, 17783848832, 17792236928, 17800625536, + 17809012352, 17817402752, 17825785984, 17834178944, 17842563968, + 17850955648, 17859344512, 17867732864, 17876119424, 17884511872, + 17892900224, 17901287296, 17909677696, 17918058112, 17926451072, + 17934843776, 17943230848, 17951609216, 17960008576, 17968397696, + 17976784256, 17985175424, 17993564032, 18001952128, 18010339712, + 18018728576, 18027116672, 18035503232, 18043894144, 18052283264, + 18060672128, 18069056384, 18077449856, 18085837184, 18094225792, + 18102613376, 18111004544, 18119388544, 18127781248, 18136170368, + 18144558976, 18152947328, 18161336192, 18169724288, 18178108544, + 18186498944, 18194886784, 18203275648, 18211666048, 18220048768, + 18228444544, 18236833408, 18245220736 + }; - [TestCase(0U, false)] - [TestCase(1U, false)] - [TestCase(2U, true)] - [TestCase(3U, true)] - [TestCase(4U, false)] - [TestCase(5U, true)] - [TestCase(6U, false)] - [TestCase(7U, true)] - [TestCase(8U, false)] - [TestCase(9U, false)] - [TestCase(10U, false)] - [TestCase(11U, true)] - [TestCase(25U, false)] - [TestCase(27U, false)] - [TestCase(49U, false)] - public void Is_prime_works(uint number, bool isPrime) - { - Assert.That(Ethash.IsPrime(number), Is.EqualTo(isPrime)); - } + [TestCase(0U, false)] + [TestCase(1U, false)] + [TestCase(2U, true)] + [TestCase(3U, true)] + [TestCase(4U, false)] + [TestCase(5U, true)] + [TestCase(6U, false)] + [TestCase(7U, true)] + [TestCase(8U, false)] + [TestCase(9U, false)] + [TestCase(10U, false)] + [TestCase(11U, true)] + [TestCase(25U, false)] + [TestCase(27U, false)] + [TestCase(49U, false)] + public void Is_prime_works(uint number, bool isPrime) + { + Assert.That(Ethash.IsPrime(number), Is.EqualTo(isPrime)); + } - [TestCase("f9021af90215a0cc395ced01d7af387640ac1258ab8819b84ca3e59ff476d933441c3800c63928a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794738db714c08b8a32a29e0e68af00215079aa9c5ca03665d3f9edac25c8a8cdad22945e0fb2e6812f679bea3445639b3890f310ced9a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b4637b26e7830a2ac9832fefd8808456687ffc98d783010203844765746887676f312e352e31856c696e7578a0a64edb0df18caa7d36fcb8ca740fee12d4d82b39883ddb3d729414122ba7410688524d07ed4c40ab09c0c0")] - [TestCase("f9021af90215a0c49ccf0465b0222c815aed70ec9a8317ffe2cfe3539e9340c6bbeb06699a80dea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942a65aca4d5fc5b5c859090a6c34d164135398226a00a550ad67f02eeb6030abf46f9c88435a05b058374ea1ee4c177ef28c4d2f475a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b53a07965b830a2aca832fefd880845668800198d783010302844765746887676f312e352e31856c696e7578a035f6b345260d8c3807bb0e805f23866c5ba9431a9e9a5e240101f541990f47f5886796ab8d23f3c3c2c0c0", Explicit = true)] - [TestCase("f9021af90215a076e41437e45099f2a0872a8df8623a644ead1136afe751358c56781513ecb74ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a09b0dcb614329b921c4ef22eb4f8a913539806da3cbe43c1eafa37cfa3943a845a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b610aed75d830a2acb832fefd880845668800598d783010203844765746887676f312e342e32856c696e7578a056ac10c8b2378f46b610db89631968bc5f409f32934f287b95d5cfbe12cefd05886ba4adf9b970445ec0c0", Explicit = true)] - [TestCase("f902fdf90217a09daf27b854a6e1272c2f3070f7729ba5f4891a9dc324c360a0ad32d1d62419f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794790b8a3ce86e707ed0ed32bf89b3269692a23cc1a02b7e61e61837adb79b36eee4e1589b2c2140852bb105dc034d5cfa052c6ef5b8a0b36ebb69537e04d3bcd94a20bebcb12a8ef4715eb26fc1d19382392cc98db9b1a0c86bea989ed46040c5d1cbc39da108fb249bb9bf0804a5889e897f7e0c710864b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b539ecc193830a2acc832fefd882a410845668801a98d783010302844765746887676f312e352e31856c696e7578a0d82d30ce9d68e733738eee0c6f37c95968622878334f4f010e95acae000bb40188b34e28af786cc323f8e0f86f82d65e850ba43b740083015f9094ff45159c63fb01f45cd86767a020406f06faa8528820d3ff69fe230800801ba0d0ea8a650bf50b61b421e8275a79219988889c3e86460b323fb3d4d60bd80d3ca05a653410e7fd97786b3b503936127ece61ed3dcfabdbcbe8d7f06066f4a41687f86d822a3b850ba43b740082520894c47aaa860008be6f65b58c6c6e02a84e666efe318742087a56e84c00801ca0bc2b89b75b68e7ad8eb1db4de4aa550db79df3bd6430f2258fe55805ca7d7fe7a07d8b53c48f24788f21e3a26cfbd007cdab71a8ef7f28f6f6fae6ed4dcd4a0df1c0")] - [TestCase("f9021af90215a07cda9a6543dfcafccba0aa0a1a78156ecc7f4b679b8401aec57472294db63a06a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a0ac89cd6a0d58b13786cef698cfeda1f21edbfbd00b67db034cf2f62497b95359a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b61093ff3b830a2acd832fefd880845668802598d783010203844765746887676f312e342e32856c696e7578a0b969e4528849b36fc9c019e83e53cee58e5ef6c3fb3b00105570e602b2a39f1f88aabdc28bdf9e4799c0c0", Explicit = true)] - [TestCase("f9021af90215a06b42cf11dbb8a448a118939d1a68773f3deca05f8063d26113dac5f9f8ce6713a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a037b5b65861017992bd33375bb71e0752d57eb94972a9496177f056aa340a2843a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b6e75611ca830a2ace832fefd880845668803198d783010203844765746887676f312e342e32856c696e7578a08eddfce4ba14ac38363b0534d12ed7ad4c224897dd443730256f04c6f835449f88108919adc0f2952bc0c0", Explicit = true)] - [TestCase("f9036ef90217a0cb927dc709468a107fac77151c6dff1ab73eabcccc57d82d238a7b5554f6db51a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794580992b51e3925e23280efb93d3047c82f17e038a03a68272caba0b4a825667d3d223bb8c18f6f793bd8151822b27798716c0b23cba01e360dfc633f5d2edad4e75cfa36555ae480ce346dcce8f253bb0d298e043dcaa0644b51189a7f9d4287e78fb923ced0b8b30edee234d6756fd06b45abc7ec12bdb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b7be32fc9c830a2acf832fefd882f618845668803a98d783010400844765746887676f312e352e31856c696e7578a09a1a1cb1182fa1c8baeb7f2abd3f109d85b136f5968c76c3c26977dad5dba1ec88de7908cc14f57037f90150f86e82b609850ba43b740083015f909454cec426307c1acaa63b25aa48fade5df9e5d418872fe2475ad71000801ba0884206762dfebbdc69d5fb92ca1c33999a419f9c9ec116e02594f9535a30c9a0a05daf584f1b480ff599e4ed62278bac9c9d4c4f16af1d65504c13dbb713aa3539f86f82b60a850ba43b740083015f9094f442c4ab4d8cf106bcda6b1f7994485f3f4291a9880df897c536bccc00801ba0a7c7855917b5f8319651d241f3ca2ac5d728a76c83c43cb9e60adc9af1988051a009f117ce8cdfccc762d7a221abc19eb8773176c6f56b75c8ce2a1b907e0a3babf86d81d6850ba43b740082562294fbb1b73c4f0bda4f67dca266ce6ef42f520fbb988820d04471d11f6800801ba065586cc9545ea639580de624574644c34ea9bd0d2e7bfd8bab8f5ed3de572d86a0431d8fc8fcc803413f9f0ded6eaf267cb072bfed75fff97286623dd78e0e3d40c0")] - public void Test_real_block_from_ethereumJ(string blockRlp) - { - Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + [TestCase("f9021af90215a0cc395ced01d7af387640ac1258ab8819b84ca3e59ff476d933441c3800c63928a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794738db714c08b8a32a29e0e68af00215079aa9c5ca03665d3f9edac25c8a8cdad22945e0fb2e6812f679bea3445639b3890f310ced9a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b4637b26e7830a2ac9832fefd8808456687ffc98d783010203844765746887676f312e352e31856c696e7578a0a64edb0df18caa7d36fcb8ca740fee12d4d82b39883ddb3d729414122ba7410688524d07ed4c40ab09c0c0")] + [TestCase("f9021af90215a0c49ccf0465b0222c815aed70ec9a8317ffe2cfe3539e9340c6bbeb06699a80dea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942a65aca4d5fc5b5c859090a6c34d164135398226a00a550ad67f02eeb6030abf46f9c88435a05b058374ea1ee4c177ef28c4d2f475a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b53a07965b830a2aca832fefd880845668800198d783010302844765746887676f312e352e31856c696e7578a035f6b345260d8c3807bb0e805f23866c5ba9431a9e9a5e240101f541990f47f5886796ab8d23f3c3c2c0c0", Explicit = true)] + [TestCase("f9021af90215a076e41437e45099f2a0872a8df8623a644ead1136afe751358c56781513ecb74ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a09b0dcb614329b921c4ef22eb4f8a913539806da3cbe43c1eafa37cfa3943a845a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b610aed75d830a2acb832fefd880845668800598d783010203844765746887676f312e342e32856c696e7578a056ac10c8b2378f46b610db89631968bc5f409f32934f287b95d5cfbe12cefd05886ba4adf9b970445ec0c0", Explicit = true)] + [TestCase("f902fdf90217a09daf27b854a6e1272c2f3070f7729ba5f4891a9dc324c360a0ad32d1d62419f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794790b8a3ce86e707ed0ed32bf89b3269692a23cc1a02b7e61e61837adb79b36eee4e1589b2c2140852bb105dc034d5cfa052c6ef5b8a0b36ebb69537e04d3bcd94a20bebcb12a8ef4715eb26fc1d19382392cc98db9b1a0c86bea989ed46040c5d1cbc39da108fb249bb9bf0804a5889e897f7e0c710864b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b539ecc193830a2acc832fefd882a410845668801a98d783010302844765746887676f312e352e31856c696e7578a0d82d30ce9d68e733738eee0c6f37c95968622878334f4f010e95acae000bb40188b34e28af786cc323f8e0f86f82d65e850ba43b740083015f9094ff45159c63fb01f45cd86767a020406f06faa8528820d3ff69fe230800801ba0d0ea8a650bf50b61b421e8275a79219988889c3e86460b323fb3d4d60bd80d3ca05a653410e7fd97786b3b503936127ece61ed3dcfabdbcbe8d7f06066f4a41687f86d822a3b850ba43b740082520894c47aaa860008be6f65b58c6c6e02a84e666efe318742087a56e84c00801ca0bc2b89b75b68e7ad8eb1db4de4aa550db79df3bd6430f2258fe55805ca7d7fe7a07d8b53c48f24788f21e3a26cfbd007cdab71a8ef7f28f6f6fae6ed4dcd4a0df1c0")] + [TestCase("f9021af90215a07cda9a6543dfcafccba0aa0a1a78156ecc7f4b679b8401aec57472294db63a06a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a0ac89cd6a0d58b13786cef698cfeda1f21edbfbd00b67db034cf2f62497b95359a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b61093ff3b830a2acd832fefd880845668802598d783010203844765746887676f312e342e32856c696e7578a0b969e4528849b36fc9c019e83e53cee58e5ef6c3fb3b00105570e602b2a39f1f88aabdc28bdf9e4799c0c0", Explicit = true)] + [TestCase("f9021af90215a06b42cf11dbb8a448a118939d1a68773f3deca05f8063d26113dac5f9f8ce6713a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a037b5b65861017992bd33375bb71e0752d57eb94972a9496177f056aa340a2843a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b6e75611ca830a2ace832fefd880845668803198d783010203844765746887676f312e342e32856c696e7578a08eddfce4ba14ac38363b0534d12ed7ad4c224897dd443730256f04c6f835449f88108919adc0f2952bc0c0", Explicit = true)] + [TestCase("f9036ef90217a0cb927dc709468a107fac77151c6dff1ab73eabcccc57d82d238a7b5554f6db51a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794580992b51e3925e23280efb93d3047c82f17e038a03a68272caba0b4a825667d3d223bb8c18f6f793bd8151822b27798716c0b23cba01e360dfc633f5d2edad4e75cfa36555ae480ce346dcce8f253bb0d298e043dcaa0644b51189a7f9d4287e78fb923ced0b8b30edee234d6756fd06b45abc7ec12bdb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b7be32fc9c830a2acf832fefd882f618845668803a98d783010400844765746887676f312e352e31856c696e7578a09a1a1cb1182fa1c8baeb7f2abd3f109d85b136f5968c76c3c26977dad5dba1ec88de7908cc14f57037f90150f86e82b609850ba43b740083015f909454cec426307c1acaa63b25aa48fade5df9e5d418872fe2475ad71000801ba0884206762dfebbdc69d5fb92ca1c33999a419f9c9ec116e02594f9535a30c9a0a05daf584f1b480ff599e4ed62278bac9c9d4c4f16af1d65504c13dbb713aa3539f86f82b60a850ba43b740083015f9094f442c4ab4d8cf106bcda6b1f7994485f3f4291a9880df897c536bccc00801ba0a7c7855917b5f8319651d241f3ca2ac5d728a76c83c43cb9e60adc9af1988051a009f117ce8cdfccc762d7a221abc19eb8773176c6f56b75c8ce2a1b907e0a3babf86d81d6850ba43b740082562294fbb1b73c4f0bda4f67dca266ce6ef42f520fbb988820d04471d11f6800801ba065586cc9545ea639580de624574644c34ea9bd0d2e7bfd8bab8f5ed3de572d86a0431d8fc8fcc803413f9f0ded6eaf267cb072bfed75fff97286623dd78e0e3d40c0")] + public void Test_real_block_from_ethereumJ(string blockRlp) + { + Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - Ethash ethash = new(LimboLogs.Instance); - EthashSealValidator sealValidator = new(LimboLogs.Instance, new EthashDifficultyCalculator(MainnetSpecProvider.Instance), new CryptoRandom(), ethash, Timestamper.Default); - bool valid = sealValidator.ValidateSeal(b.Header, true); - Assert.True(valid); - } + Ethash ethash = new(LimboLogs.Instance); + EthashSealValidator sealValidator = new(LimboLogs.Instance, new EthashDifficultyCalculator(MainnetSpecProvider.Instance), new CryptoRandom(), ethash, Timestamper.Default); + bool valid = sealValidator.ValidateSeal(b.Header, true); + Assert.That(valid, Is.True); + } - [TestCase("f9036ef90217a0cb927dc709468a107fac77151c6dff1ab73eabcccc57d82d238a7b5554f6db51a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794580992b51e3925e23280efb93d3047c82f17e038a03a68272caba0b4a825667d3d223bb8c18f6f793bd8151822b27798716c0b23cba01e360dfc633f5d2edad4e75cfa36555ae480ce346dcce8f253bb0d298e043dcaa0644b51189a7f9d4287e78fb923ced0b8b30edee234d6756fd06b45abc7ec12bdb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b7be32fc9c830a2acf832fefd882f618845668803a98d783010400844765746887676f312e352e31856c696e7578a09a1a1cb1182fa1c8baeb7f2abd3f109d85b136f5968c76c3c26977dad5dba1ec88de7908cc14f57037f90150f86e82b609850ba43b740083015f909454cec426307c1acaa63b25aa48fade5df9e5d418872fe2475ad71000801ba0884206762dfebbdc69d5fb92ca1c33999a419f9c9ec116e02594f9535a30c9a0a05daf584f1b480ff599e4ed62278bac9c9d4c4f16af1d65504c13dbb713aa3539f86f82b60a850ba43b740083015f9094f442c4ab4d8cf106bcda6b1f7994485f3f4291a9880df897c536bccc00801ba0a7c7855917b5f8319651d241f3ca2ac5d728a76c83c43cb9e60adc9af1988051a009f117ce8cdfccc762d7a221abc19eb8773176c6f56b75c8ce2a1b907e0a3babf86d81d6850ba43b740082562294fbb1b73c4f0bda4f67dca266ce6ef42f520fbb988820d04471d11f6800801ba065586cc9545ea639580de624574644c34ea9bd0d2e7bfd8bab8f5ed3de572d86a0431d8fc8fcc803413f9f0ded6eaf267cb072bfed75fff97286623dd78e0e3d40c0")] - public void Can_use_cache(string blockRlp) - { - Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + [TestCase("f9036ef90217a0cb927dc709468a107fac77151c6dff1ab73eabcccc57d82d238a7b5554f6db51a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794580992b51e3925e23280efb93d3047c82f17e038a03a68272caba0b4a825667d3d223bb8c18f6f793bd8151822b27798716c0b23cba01e360dfc633f5d2edad4e75cfa36555ae480ce346dcce8f253bb0d298e043dcaa0644b51189a7f9d4287e78fb923ced0b8b30edee234d6756fd06b45abc7ec12bdb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b7be32fc9c830a2acf832fefd882f618845668803a98d783010400844765746887676f312e352e31856c696e7578a09a1a1cb1182fa1c8baeb7f2abd3f109d85b136f5968c76c3c26977dad5dba1ec88de7908cc14f57037f90150f86e82b609850ba43b740083015f909454cec426307c1acaa63b25aa48fade5df9e5d418872fe2475ad71000801ba0884206762dfebbdc69d5fb92ca1c33999a419f9c9ec116e02594f9535a30c9a0a05daf584f1b480ff599e4ed62278bac9c9d4c4f16af1d65504c13dbb713aa3539f86f82b60a850ba43b740083015f9094f442c4ab4d8cf106bcda6b1f7994485f3f4291a9880df897c536bccc00801ba0a7c7855917b5f8319651d241f3ca2ac5d728a76c83c43cb9e60adc9af1988051a009f117ce8cdfccc762d7a221abc19eb8773176c6f56b75c8ce2a1b907e0a3babf86d81d6850ba43b740082562294fbb1b73c4f0bda4f67dca266ce6ef42f520fbb988820d04471d11f6800801ba065586cc9545ea639580de624574644c34ea9bd0d2e7bfd8bab8f5ed3de572d86a0431d8fc8fcc803413f9f0ded6eaf267cb072bfed75fff97286623dd78e0e3d40c0")] + public void Can_use_cache(string blockRlp) + { + Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - Ethash ethash = new(LimboLogs.Instance); - EthashSealValidator sealValidator = new(LimboLogs.Instance, new EthashDifficultyCalculator(MainnetSpecProvider.Instance), new CryptoRandom(), ethash, Timestamper.Default); - sealValidator.ValidateSeal(b.Header, true); - b.Header.MixHash = Keccak.Zero; - bool valid = sealValidator.ValidateSeal(b.Header, true); - Assert.True(valid); - } + Ethash ethash = new(LimboLogs.Instance); + EthashSealValidator sealValidator = new(LimboLogs.Instance, new EthashDifficultyCalculator(MainnetSpecProvider.Instance), new CryptoRandom(), ethash, Timestamper.Default); + sealValidator.ValidateSeal(b.Header, true); + b.Header.MixHash = Keccak.Zero; + bool valid = sealValidator.ValidateSeal(b.Header, true); + Assert.That(valid, Is.True); + } - [TestCase("f9021af90215a0cc395ced01d7af387640ac1258ab8819b84ca3e59ff476d933441c3800c63928a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794738db714c08b8a32a29e0e68af00215079aa9c5ca03665d3f9edac25c8a8cdad22945e0fb2e6812f679bea3445639b3890f310ced9a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b4637b26e7830a2ac9832fefd8808456687ffc98d783010203844765746887676f312e352e31856c696e7578a0a64edb0df18caa7d36fcb8ca740fee12d4d82b39883ddb3d729414122ba7410688524d07ed4c40ab09c0c0")] - public void Can_skip_when_not_forced(string blockRlp) - { - Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - b.Header.MixHash = Keccak.Zero; + [TestCase("f9021af90215a0cc395ced01d7af387640ac1258ab8819b84ca3e59ff476d933441c3800c63928a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794738db714c08b8a32a29e0e68af00215079aa9c5ca03665d3f9edac25c8a8cdad22945e0fb2e6812f679bea3445639b3890f310ced9a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b4637b26e7830a2ac9832fefd8808456687ffc98d783010203844765746887676f312e352e31856c696e7578a0a64edb0df18caa7d36fcb8ca740fee12d4d82b39883ddb3d729414122ba7410688524d07ed4c40ab09c0c0")] + public void Can_skip_when_not_forced(string blockRlp) + { + Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + b.Header.MixHash = Keccak.Zero; - Ethash ethash = new(LimboLogs.Instance); - EthashSealValidator sealValidator = new(LimboLogs.Instance, new EthashDifficultyCalculator(MainnetSpecProvider.Instance), new CryptoRandom(), ethash, Timestamper.Default); - bool valid = sealValidator.ValidateSeal(b.Header, false); - Assert.True(valid); - } + Ethash ethash = new(LimboLogs.Instance); + EthashSealValidator sealValidator = new(LimboLogs.Instance, new EthashDifficultyCalculator(MainnetSpecProvider.Instance), new CryptoRandom(), ethash, Timestamper.Default); + bool valid = sealValidator.ValidateSeal(b.Header, false); + Assert.That(valid, Is.True); + } - [TestCase("f9021af90215a0cc395ced01d7af387640ac1258ab8819b84ca3e59ff476d933441c3800c63928a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794738db714c08b8a32a29e0e68af00215079aa9c5ca03665d3f9edac25c8a8cdad22945e0fb2e6812f679bea3445639b3890f310ced9a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b4637b26e7830a2ac9832fefd8808456687ffc98d783010203844765746887676f312e352e31856c696e7578a0a64edb0df18caa7d36fcb8ca740fee12d4d82b39883ddb3d729414122ba7410688524d07ed4c40ab09c0c0")] - public void Rejects_blocks_into_the_future(string blockRlp) - { - Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - b.Header.Timestamp = Timestamper.Default.UnixTime.Seconds + 100; - Ethash ethash = new(LimboLogs.Instance); - EthashSealValidator sealValidator = new(LimboLogs.Instance, new ConstantDifficulty(b.Header.Difficulty), new CryptoRandom(), ethash, Timestamper.Default); - bool valid = sealValidator.ValidateParams(b.Header, b.Header); - valid.Should().BeFalse(); - } + [TestCase("f9021af90215a0cc395ced01d7af387640ac1258ab8819b84ca3e59ff476d933441c3800c63928a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794738db714c08b8a32a29e0e68af00215079aa9c5ca03665d3f9edac25c8a8cdad22945e0fb2e6812f679bea3445639b3890f310ced9a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008606b4637b26e7830a2ac9832fefd8808456687ffc98d783010203844765746887676f312e352e31856c696e7578a0a64edb0df18caa7d36fcb8ca740fee12d4d82b39883ddb3d729414122ba7410688524d07ed4c40ab09c0c0")] + public void Rejects_blocks_into_the_future(string blockRlp) + { + Block b = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); + b.Header.Timestamp = Timestamper.Default.UnixTime.Seconds + 100; + Ethash ethash = new(LimboLogs.Instance); + EthashSealValidator sealValidator = new(LimboLogs.Instance, new ConstantDifficulty(b.Header.Difficulty), new CryptoRandom(), ethash, Timestamper.Default); + bool valid = sealValidator.ValidateParams(b.Header, b.Header); + valid.Should().BeFalse(); + } - [Test] - public void Test_data_size() + [Test] + public void Test_data_size() + { + for (int i = 0; i < _dataSizes.Length; i++) { - for (int i = 0; i < _dataSizes.Length; i++) - { - ulong size = Ethash.GetDataSize((uint)i); - Assert.That(_dataSizes[i], Is.EqualTo(size).Within(i), $"failed at epoch: {i}"); - } + ulong size = Ethash.GetDataSize((uint)i); + Assert.That(_dataSizes[i], Is.EqualTo(size).Within(i), $"failed at epoch: {i}"); } + } - [Test] - public void Test_cache_size() + [Test] + public void Test_cache_size() + { + for (int i = 0; i < _cacheSizes.Length; i++) { - for (int i = 0; i < _cacheSizes.Length; i++) - { - ulong size = Ethash.GetCacheSize((uint)i); - Assert.That(_cacheSizes[i], Is.EqualTo(size).Within(i)); - } + ulong size = Ethash.GetCacheSize((uint)i); + Assert.That(_cacheSizes[i], Is.EqualTo(size).Within(i)); } } } diff --git a/src/Nethermind/Nethermind.Mining.Test/HintBasedCacheTests.cs b/src/Nethermind/Nethermind.Mining.Test/HintBasedCacheTests.cs index a48d9c6b7d6..c1e02a2f1b9 100644 --- a/src/Nethermind/Nethermind.Mining.Test/HintBasedCacheTests.cs +++ b/src/Nethermind/Nethermind.Mining.Test/HintBasedCacheTests.cs @@ -7,176 +7,174 @@ using Nethermind.Logging; using NUnit.Framework; -namespace Nethermind.Mining.Test +namespace Nethermind.Mining.Test; + +[Parallelizable(ParallelScope.Self)] +public class HintBasedCacheTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class HintBasedCacheTests + private class NullDataSet : IEthashDataSet { - private class NullDataSet : IEthashDataSet + public void Dispose() { - public void Dispose() - { - } + } - public uint Size => 0; + public uint Size => 0; - public uint[] CalcDataSetItem(uint i) - { - return new uint[0]; - } + public uint[] CalcDataSetItem(uint i) + { + return []; } + } - [Test] - public void Without_hint_return_null() + [Test] + public void Without_hint_return_null() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + for (uint i = 0; i < 1000; i++) { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - for (uint i = 0; i < 1000; i++) - { - Assert.Null(hintBasedCache.Get(i)); - } + Assert.That(hintBasedCache.Get(i), Is.Null); } + } - private readonly Guid _guidA = Guid.NewGuid(); - private readonly Guid _guidB = Guid.NewGuid(); - private readonly Guid _guidC = Guid.NewGuid(); - - [Test] - public async Task With_hint_returns_value() - { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - hintBasedCache.Hint(_guidA, 0, 200000); - await WaitFor(() => hintBasedCache.CachedEpochsCount == 7); + private readonly Guid _guidA = Guid.NewGuid(); + private readonly Guid _guidB = Guid.NewGuid(); + private readonly Guid _guidC = Guid.NewGuid(); - for (uint i = 0; i < 7; i++) - { - Assert.NotNull(hintBasedCache.Get(i)); - } - } + [Test] + public async Task With_hint_returns_value() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + hintBasedCache.Hint(_guidA, 0, 200000); + await WaitFor(() => hintBasedCache.CachedEpochsCount == 7); - [Test] - public void Sync_hint_and_get() + for (uint i = 0; i < 7; i++) { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - hintBasedCache.Hint(_guidA, 200000, 200000); - Assert.NotNull(hintBasedCache.Get((uint)(200000 / Ethash.EpochLength))); + Assert.That(hintBasedCache.Get(i), Is.Not.Null); } + } + + [Test] + public void Sync_hint_and_get() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + hintBasedCache.Hint(_guidA, 200000, 200000); + Assert.That(hintBasedCache.Get((uint)(200000 / Ethash.EpochLength)), Is.Not.Null); + } - [Test] - public async Task Many_threads() + [Test] + public async Task Many_threads() + { + int range = 10000000; + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + void KeepHinting(Guid guid, int start) { - int range = 10000000; - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - void KeepHinting(Guid guid, int start) + for (int i = start; i <= range; i++) { - for (int i = start; i <= range; i++) - { - hintBasedCache.Hint(guid, i, i + 120000); - } - }; + hintBasedCache.Hint(guid, i, i + 120000); + } + }; - Task a = new(() => KeepHinting(_guidA, 100000)); - Task b = new(() => KeepHinting(_guidB, 0)); - Task c = new(() => KeepHinting(_guidC, 500000)); + Task a = new(() => KeepHinting(_guidA, 100000)); + Task b = new(() => KeepHinting(_guidB, 0)); + Task c = new(() => KeepHinting(_guidC, 500000)); - a.Start(); - b.Start(); - c.Start(); + a.Start(); + b.Start(); + c.Start(); - await Task.WhenAll(a, b, c); + await Task.WhenAll(a, b, c); - Assert.That(hintBasedCache.CachedEpochsCount, Is.EqualTo(5)); - for (uint i = (uint)(range / Ethash.EpochLength); i < (uint)((range + 120000) / Ethash.EpochLength); i++) - { - Assert.NotNull(hintBasedCache.Get(i)); - } - } - - [Test] - public async Task Different_users_reuse_cached_epochs() + Assert.That(hintBasedCache.CachedEpochsCount, Is.EqualTo(5)); + for (uint i = (uint)(range / Ethash.EpochLength); i < (uint)((range + 120000) / Ethash.EpochLength); i++) { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - hintBasedCache.Hint(_guidA, 0, 200000); - hintBasedCache.Hint(_guidB, 0, 200000); - await WaitFor(() => hintBasedCache.CachedEpochsCount == 7); - for (uint i = 0; i < 7; i++) - { - Assert.NotNull(hintBasedCache.Get(i)); - } + Assert.That(hintBasedCache.Get(i), Is.Not.Null); } + } - [Test] - public async Task Different_users_can_use_cache() + [Test] + public async Task Different_users_reuse_cached_epochs() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + hintBasedCache.Hint(_guidA, 0, 200000); + hintBasedCache.Hint(_guidB, 0, 200000); + await WaitFor(() => hintBasedCache.CachedEpochsCount == 7); + for (uint i = 0; i < 7; i++) { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - hintBasedCache.Hint(_guidA, 0, 29999); - hintBasedCache.Hint(_guidB, 30000, 59999); - await WaitFor(() => hintBasedCache.CachedEpochsCount == 2); - for (uint i = 0; i < 2; i++) - { - Assert.NotNull(hintBasedCache.Get(i)); - } + Assert.That(hintBasedCache.Get(i), Is.Not.Null); } + } - [Test] - public async Task Different_users_can_use_disconnected_epochs() + [Test] + public async Task Different_users_can_use_cache() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + hintBasedCache.Hint(_guidA, 0, 29999); + hintBasedCache.Hint(_guidB, 30000, 59999); + await WaitFor(() => hintBasedCache.CachedEpochsCount == 2); + for (uint i = 0; i < 2; i++) { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - hintBasedCache.Hint(_guidA, 0, 29999); - hintBasedCache.Hint(_guidB, 120000, 149999); - await WaitFor(() => hintBasedCache.CachedEpochsCount == 2); - Assert.NotNull(hintBasedCache.Get(0)); - Assert.Null(hintBasedCache.Get(1)); - Assert.Null(hintBasedCache.Get(2)); - Assert.Null(hintBasedCache.Get(3)); - Assert.NotNull(hintBasedCache.Get(4)); + Assert.That(hintBasedCache.Get(i), Is.Not.Null); } + } - [Test] - public async Task Moving_range_evicts_cached_epochs() - { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - hintBasedCache.Hint(_guidA, 0, 209999); - hintBasedCache.Hint(_guidA, 30000, 239999); - await WaitFor(() => hintBasedCache.CachedEpochsCount == 7); + [Test] + public async Task Different_users_can_use_disconnected_epochs() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + hintBasedCache.Hint(_guidA, 0, 29999); + hintBasedCache.Hint(_guidB, 120000, 149999); + await WaitFor(() => hintBasedCache.CachedEpochsCount == 2); + Assert.That(hintBasedCache.Get(0), Is.Not.Null); + Assert.That(hintBasedCache.Get(1), Is.Null); + Assert.That(hintBasedCache.Get(2), Is.Null); + Assert.That(hintBasedCache.Get(3), Is.Null); + Assert.That(hintBasedCache.Get(4), Is.Not.Null); + } - Assert.Null(hintBasedCache.Get(0)); - for (uint i = 1; i < 8; i++) - { - Assert.NotNull(hintBasedCache.Get(i), i.ToString()); - } - } + [Test] + public async Task Moving_range_evicts_cached_epochs() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + hintBasedCache.Hint(_guidA, 0, 209999); + hintBasedCache.Hint(_guidA, 30000, 239999); + await WaitFor(() => hintBasedCache.CachedEpochsCount == 7); - [Test] - public async Task Can_hint_far() + Assert.That(hintBasedCache.Get(0), Is.Null); + for (uint i = 1; i < 8; i++) { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - hintBasedCache.Hint(_guidA, 1000000000, 1000000000); - await WaitFor(() => hintBasedCache.CachedEpochsCount == 1); - - Assert.NotNull(hintBasedCache.Get(1000000000 / 30000)); + Assert.That(hintBasedCache.Get(i), Is.Not.Null, i.ToString()); } + } - [Test] - public void Throws_on_wide_hint() - { - HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); - Assert.Throws(() => hintBasedCache.Hint(_guidA, 0, 1000000000)); - } + [Test] + public async Task Can_hint_far() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + hintBasedCache.Hint(_guidA, 1000000000, 1000000000); + await WaitFor(() => hintBasedCache.CachedEpochsCount == 1); + + Assert.That(hintBasedCache.Get(1000000000 / 30000), Is.Not.Null); + } + + [Test] + public void Throws_on_wide_hint() + { + HintBasedCache hintBasedCache = new(e => new NullDataSet(), LimboLogs.Instance); + Assert.Throws(() => hintBasedCache.Hint(_guidA, 0, 1000000000)); + } - private async Task WaitFor(Func isConditionMet, string description = "condition to be met") + private async Task WaitFor(Func isConditionMet, string description = "condition to be met") + { + const int waitInterval = 10; + for (int i = 0; i < 10; i++) { - const int waitInterval = 10; - for (int i = 0; i < 10; i++) + if (isConditionMet()) { - if (isConditionMet()) - { - return; - } - - TestContext.WriteLine($"({i}) Waiting {waitInterval} for {description}"); - await Task.Delay(waitInterval); + return; } + + TestContext.Out.WriteLine($"({i}) Waiting {waitInterval} for {description}"); + await Task.Delay(waitInterval); } } } diff --git a/src/Nethermind/Nethermind.Mining.Test/MiningConfigTest.cs b/src/Nethermind/Nethermind.Mining.Test/MiningConfigTest.cs index daa19ee6b57..a2a70e87740 100644 --- a/src/Nethermind/Nethermind.Mining.Test/MiningConfigTest.cs +++ b/src/Nethermind/Nethermind.Mining.Test/MiningConfigTest.cs @@ -8,7 +8,6 @@ namespace Nethermind.Mining.Test; -[TestFixture] public class MiningConfigTest { [TestCase] @@ -37,10 +36,9 @@ public void TestTooLongExtraData() IBlocksConfig config = new BlocksConfig(); string defaultData = config.ExtraData; byte[] defaultDataBytes = Encoding.UTF8.GetBytes(defaultData); - byte[] dataBytes = Encoding.UTF8.GetBytes(data); - Assert.Greater(dataBytes.Length, 32); + Assert.That(dataBytes.Length, Is.GreaterThan(32)); Assert.Throws(() => config.ExtraData = data); //throw on update Assert.That(defaultData, Is.EqualTo(config.ExtraData)); // Keep previous one Assert.That(defaultDataBytes, Is.EqualTo(config.GetExtraDataBytes())); diff --git a/src/Nethermind/Nethermind.Monitoring.Test/MetricsTests.cs b/src/Nethermind/Nethermind.Monitoring.Test/MetricsTests.cs index 05326ff65fb..2baef78b6d2 100644 --- a/src/Nethermind/Nethermind.Monitoring.Test/MetricsTests.cs +++ b/src/Nethermind/Nethermind.Monitoring.Test/MetricsTests.cs @@ -19,7 +19,6 @@ namespace Nethermind.Monitoring.Test; -[TestFixture] public class MetricsTests { public static class TestMetrics @@ -79,8 +78,8 @@ public void Test_update_correct_gauge() var keyOldDictionary0 = $"{nameof(TestMetrics.OldDictionaryMetrics)}.metrics0"; var keyOldDictionary1 = $"{nameof(TestMetrics.OldDictionaryMetrics)}.metrics1"; - Assert.Contains(keyDefault, gauges.Keys); - Assert.Contains(keySpecial, gauges.Keys); + Assert.That(gauges.Keys, Has.Member(keyDefault)); + Assert.That(gauges.Keys, Has.Member(keySpecial)); Assert.That(gauges[keyDefault].Name, Is.EqualTo("nethermind_one_two_three")); Assert.That(gauges[keySpecial].Name, Is.EqualTo("one_two_three")); diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs index 406843dd1cc..ef9e96510bc 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs @@ -15,188 +15,186 @@ using Nethermind.Stats.Model; using NUnit.Framework; -namespace Nethermind.Network.Discovery.Test +namespace Nethermind.Network.Discovery.Test; + +[Parallelizable(ParallelScope.Self)] +public class DiscoveryMessageSerializerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class DiscoveryMessageSerializerTests + private readonly PrivateKey _privateKey = + new("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee"); + + //private readonly PrivateKey _farPrivateKey = new PrivateKey("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); + private readonly IPEndPoint _farAddress; + private readonly IPEndPoint _nearAddress; + private readonly IMessageSerializationService _messageSerializationService; + private readonly ITimestamper _timestamper; + public DiscoveryMessageSerializerTests() { - private readonly PrivateKey _privateKey = - new("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee"); - - //private readonly PrivateKey _farPrivateKey = new PrivateKey("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); - private readonly IPEndPoint _farAddress; - private readonly IPEndPoint _nearAddress; - private readonly IMessageSerializationService _messageSerializationService; - private readonly ITimestamper _timestamper; - public DiscoveryMessageSerializerTests() - { - INetworkConfig networkConfig = new NetworkConfig(); - networkConfig.ExternalIp = "99.10.10.66"; - networkConfig.LocalIp = "10.0.0.5"; - _farAddress = new IPEndPoint(IPAddress.Parse("192.168.1.2"), 1); - _nearAddress = new IPEndPoint(IPAddress.Parse(networkConfig.LocalIp), networkConfig.DiscoveryPort); - _messageSerializationService = Build.A.SerializationService().WithDiscovery(_privateKey).TestObject; - _timestamper = Timestamper.Default; - } + INetworkConfig networkConfig = new NetworkConfig(); + networkConfig.ExternalIp = "99.10.10.66"; + networkConfig.LocalIp = "10.0.0.5"; + _farAddress = new IPEndPoint(IPAddress.Parse("192.168.1.2"), 1); + _nearAddress = new IPEndPoint(IPAddress.Parse(networkConfig.LocalIp), networkConfig.DiscoveryPort); + _messageSerializationService = Build.A.SerializationService().WithDiscovery(_privateKey).TestObject; + _timestamper = Timestamper.Default; + } - [Test] - public void PingMessageTest() - { - PingMsg message = - new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, _farAddress, _nearAddress, - new byte[32]) - { FarAddress = _farAddress }; - - IByteBuffer data = _messageSerializationService.ZeroSerialize(message); - PingMsg deserializedMessage = _messageSerializationService.Deserialize(data); - data.SafeRelease(); - - Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); - Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); - Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); - - Assert.That(deserializedMessage.SourceAddress, Is.EqualTo(message.FarAddress)); - Assert.That(deserializedMessage.DestinationAddress, Is.EqualTo(message.DestinationAddress)); - Assert.That(deserializedMessage.SourceAddress, Is.EqualTo(message.SourceAddress)); - Assert.That(deserializedMessage.Version, Is.EqualTo(message.Version)); - - byte[] expectedPingMdc = - Bytes.FromHexString("0xf8c61953f3b94a91aefe611e61dd74fe26aa5c969d9f29b7e063e6169171a772"); - Assert.IsNotNull(expectedPingMdc); - } + [Test] + public void PingMessageTest() + { + PingMsg message = + new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, _farAddress, _nearAddress, + new byte[32]) + { FarAddress = _farAddress }; + + IByteBuffer data = _messageSerializationService.ZeroSerialize(message); + PingMsg deserializedMessage = _messageSerializationService.Deserialize(data); + data.SafeRelease(); + + Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); + Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); + Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); + + Assert.That(deserializedMessage.SourceAddress, Is.EqualTo(message.FarAddress)); + Assert.That(deserializedMessage.DestinationAddress, Is.EqualTo(message.DestinationAddress)); + Assert.That(deserializedMessage.SourceAddress, Is.EqualTo(message.SourceAddress)); + Assert.That(deserializedMessage.Version, Is.EqualTo(message.Version)); + + byte[] expectedPingMdc = + Bytes.FromHexString("0xf8c61953f3b94a91aefe611e61dd74fe26aa5c969d9f29b7e063e6169171a772"); + Assert.That(expectedPingMdc, Is.Not.Null); + } - [Test] - public void PongMessageTest() - { - PongMsg message = - new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, new byte[] { 1, 2, 3 }) - { - FarAddress = _farAddress - }; + [Test] + public void PongMessageTest() + { + PongMsg message = + new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, new byte[] { 1, 2, 3 }) + { + FarAddress = _farAddress + }; - IByteBuffer data = _messageSerializationService.ZeroSerialize(message); - PongMsg deserializedMessage = _messageSerializationService.Deserialize(data); - data.SafeRelease(); + IByteBuffer data = _messageSerializationService.ZeroSerialize(message); + PongMsg deserializedMessage = _messageSerializationService.Deserialize(data); + data.SafeRelease(); - Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); - Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); - Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); + Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); + Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); + Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); - Assert.That(deserializedMessage.PingMdc, Is.EqualTo(message.PingMdc)); - } + Assert.That(deserializedMessage.PingMdc, Is.EqualTo(message.PingMdc)); + } - [Test] - public void Ping_with_enr_there_and_back() - { - PingMsg pingMsg = new(TestItem.PublicKeyA, long.MaxValue, TestItem.IPEndPointA, TestItem.IPEndPointB, new byte[32]); - pingMsg.EnrSequence = 3; - IByteBuffer serialized = _messageSerializationService.ZeroSerialize(pingMsg); - pingMsg = _messageSerializationService.Deserialize(serialized); - serialized.SafeRelease(); - Assert.That(pingMsg.EnrSequence, Is.EqualTo(3)); - } + [Test] + public void Ping_with_enr_there_and_back() + { + PingMsg pingMsg = new(TestItem.PublicKeyA, long.MaxValue, TestItem.IPEndPointA, TestItem.IPEndPointB, new byte[32]); + pingMsg.EnrSequence = 3; + IByteBuffer serialized = _messageSerializationService.ZeroSerialize(pingMsg); + pingMsg = _messageSerializationService.Deserialize(serialized); + serialized.SafeRelease(); + Assert.That(pingMsg.EnrSequence, Is.EqualTo(3)); + } - [Test] - public void Enr_request_there_and_back() - { - EnrRequestMsg msg = new(TestItem.PublicKeyA, long.MaxValue); - IByteBuffer serialized = _messageSerializationService.ZeroSerialize(msg); - EnrRequestMsg deserialized = _messageSerializationService.Deserialize(serialized); - serialized.SafeRelease(); - Assert.That(deserialized.ExpirationTime, Is.EqualTo(msg.ExpirationTime)); - Assert.That(_privateKey.PublicKey, Is.EqualTo(deserialized.FarPublicKey)); - } + [Test] + public void Enr_request_there_and_back() + { + EnrRequestMsg msg = new(TestItem.PublicKeyA, long.MaxValue); + IByteBuffer serialized = _messageSerializationService.ZeroSerialize(msg); + EnrRequestMsg deserialized = _messageSerializationService.Deserialize(serialized); + serialized.SafeRelease(); + Assert.That(deserialized.ExpirationTime, Is.EqualTo(msg.ExpirationTime)); + Assert.That(_privateKey.PublicKey, Is.EqualTo(deserialized.FarPublicKey)); + } - [Test] - public void Enr_response_there_and_back() - { - NodeRecord nodeRecord = new(); - nodeRecord.SetEntry(new Secp256K1Entry(_privateKey.CompressedPublicKey)); - nodeRecord.EnrSequence = 5; - NodeRecordSigner signer = new(new Ecdsa(), _privateKey); - signer.Sign(nodeRecord); - EnrResponseMsg msg = new(TestItem.PublicKeyA, nodeRecord, TestItem.KeccakA); - - IByteBuffer serialized = _messageSerializationService.ZeroSerialize(msg); - EnrResponseMsg deserialized = _messageSerializationService.Deserialize(serialized); - serialized.SafeRelease(); - Assert.That(deserialized.NodeRecord.EnrSequence, Is.EqualTo(msg.NodeRecord.EnrSequence)); - Assert.That(deserialized.RequestKeccak, Is.EqualTo(msg.RequestKeccak)); - Assert.That(deserialized.NodeRecord.Signature, Is.EqualTo(msg.NodeRecord.Signature)); - } + [Test] + public void Enr_response_there_and_back() + { + NodeRecord nodeRecord = new(); + nodeRecord.SetEntry(new Secp256K1Entry(_privateKey.CompressedPublicKey)); + nodeRecord.EnrSequence = 5; + NodeRecordSigner signer = new(new Ecdsa(), _privateKey); + signer.Sign(nodeRecord); + EnrResponseMsg msg = new(TestItem.PublicKeyA, nodeRecord, TestItem.KeccakA); + + IByteBuffer serialized = _messageSerializationService.ZeroSerialize(msg); + EnrResponseMsg deserialized = _messageSerializationService.Deserialize(serialized); + serialized.SafeRelease(); + Assert.That(deserialized.NodeRecord.EnrSequence, Is.EqualTo(msg.NodeRecord.EnrSequence)); + Assert.That(deserialized.RequestKeccak, Is.EqualTo(msg.RequestKeccak)); + Assert.That(deserialized.NodeRecord.Signature, Is.EqualTo(msg.NodeRecord.Signature)); + } - [Test] - public void Ping_with_node_id_address() - { - string message = - "24917ba09abd910901145714c396ade5679735cf9f7796f7576439a13e6e5fc4466988ce6936ac208c4e513d1d0caa0e93160bd5ebdb10ec09df80c95e8d6c0c32d0f154d5bed121c028596f02cf974d50454e3b0ff2d0973deeb742e14e087a0004f9058df90585f8578e3138352e3136392e3233312e343982c35082c350b84036ae45a29ae5d99c0cdb78794fa439f180b13f595a2acd82bf7c0541c0238ea33f5fec5c16bfd7b851449ae0c1e8cbf1502342425fdb65face5eac705d6416a2f8568d3138352e37382e36362e31323282765f82765fb84034dedd0befcd6beb1acc3b7138246b08bd6056ec608b84983d5ce202e1af83c8cf8121063df26d7135536c1636aaa782b63e9f889f4c97172c3a4e5b09a4d721f8558c3138352e31372e34332e343382c35082c350b84035fb64bf23d73efa210bd9299e39d1b33bc189389a98c2d9998394df8d3b6f2e94cad1c36e8a00e3050d60394a8bd0febdfcd22b8127edc71ee7fd28bd2a8f8df8578e3136372e39392e3133382e32313482520b82520bb8403d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5f8578e31332e3132352e3131302e323336820bd9820bd9b8402b40b3299cc4680a191c67564ab877face479b8d0c06e17946c68832dd2f17d814fda0258b941f0bd54358d2fc7b1bb5018197114ee0054e3dce576ce6567174f8568d36392e3136342e3231352e313482765f82765fb8402d11cfe93f8caf5aa9c4a90128ddc61350f585d5b0a14c137c18b12f21c4c5d0d28e440601ace627498e8d19903f0676b18ea210c80b528b14afb57edcbcee12f8578e3138352e3136392e3233302e363082c35082c350b840209dc79ec6937114afcefe9ca604a2b62a5313181cfa517298c386030cc421b23feb84b82ab024e983b902c410f936bacc55d88aee3d819b0e7bfcf7d285d28cf8548b31332e3232392e312e3339827597827597b84023c049cfc57345656e1fc9924a121859723a6cc3adea62e6ddd5c15f4b04b8ed044a29cd188d7c26d798da93aa828b911d65e37914935c34f92c9d6f671b3e7bf8588f3232302e3131372e3135342e313431820400820400b8401eecac5177f517a00373f5918f373fb3aa347c87dba678b58a09c0fe73bf578c2447e8f1d6e8f92c3248514d55157398e4909d36d42840f2c70f98120fd2da92f8558c3132322e31312e34372e393582c4a782c4a7b84011e4bc809f78687ac4cceff4ac574cda15010ef20d657d296fc0daf696dd8e80178c3aa64a02db51eecd7c6e05513d49dbbc0824df0fbb53fbbef07e81335926f8588f3138352e3135332e3139382e32303382c35082c350b84014ce698fb9ebd75a7ee6ab123b87f10e041e8bad7b290e5caddd7b75e3f477661923d7ad303a9a97042eb9b1657dc0848411d7b58287d8655881971ab25fd965f8588f3230372e3135342e3231382e313139825209825209b8400ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416f8558c3133372e37342e3134342e3482765f82765fb8401083237e8c12e17153970639079096ad87bf0f534c84c131e7da339d70282e81919e1dbe02415453464849c72e9deb6c784997de2c4aa175282f84ffcd4b79f3f8568d35312e3134302e3132372e393582765f82765fb8400efa939a67ba0d177143c26cad8bc86a29cf7456af8132ddcfb956ab470173981fcf1d08fdbaa14ec4aa9e240880115406f533911f833545809704f5fff6b89ef8568d3230372e3134382e32372e3834827661827661b84003944d60046265f36aa333373e36604570029dc0dc9518d4226ba2037ae33cc2c5dd6940ee22c3ce85ad8a3c5791f81b73530dbe77aacd22d9e25593c4a354c8f8568d36342e33342e3233312e31343082765f82765fb8401feb66dd6b901ba73614a5bb7946426e1d9f0bf3df8368c3d80b47c6983b0f82d0fc360d422e79d67e81faaa0b37ec39c84f962179805dc85357fdb27e282c47845b867da0"; - NeighborsMsg deserializedMessage = - _messageSerializationService.Deserialize(Bytes.FromHexString(message)); - Assert.IsNotNull(deserializedMessage); - } + [Test] + public void Ping_with_node_id_address() + { + string message = + "24917ba09abd910901145714c396ade5679735cf9f7796f7576439a13e6e5fc4466988ce6936ac208c4e513d1d0caa0e93160bd5ebdb10ec09df80c95e8d6c0c32d0f154d5bed121c028596f02cf974d50454e3b0ff2d0973deeb742e14e087a0004f9058df90585f8578e3138352e3136392e3233312e343982c35082c350b84036ae45a29ae5d99c0cdb78794fa439f180b13f595a2acd82bf7c0541c0238ea33f5fec5c16bfd7b851449ae0c1e8cbf1502342425fdb65face5eac705d6416a2f8568d3138352e37382e36362e31323282765f82765fb84034dedd0befcd6beb1acc3b7138246b08bd6056ec608b84983d5ce202e1af83c8cf8121063df26d7135536c1636aaa782b63e9f889f4c97172c3a4e5b09a4d721f8558c3138352e31372e34332e343382c35082c350b84035fb64bf23d73efa210bd9299e39d1b33bc189389a98c2d9998394df8d3b6f2e94cad1c36e8a00e3050d60394a8bd0febdfcd22b8127edc71ee7fd28bd2a8f8df8578e3136372e39392e3133382e32313482520b82520bb8403d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5f8578e31332e3132352e3131302e323336820bd9820bd9b8402b40b3299cc4680a191c67564ab877face479b8d0c06e17946c68832dd2f17d814fda0258b941f0bd54358d2fc7b1bb5018197114ee0054e3dce576ce6567174f8568d36392e3136342e3231352e313482765f82765fb8402d11cfe93f8caf5aa9c4a90128ddc61350f585d5b0a14c137c18b12f21c4c5d0d28e440601ace627498e8d19903f0676b18ea210c80b528b14afb57edcbcee12f8578e3138352e3136392e3233302e363082c35082c350b840209dc79ec6937114afcefe9ca604a2b62a5313181cfa517298c386030cc421b23feb84b82ab024e983b902c410f936bacc55d88aee3d819b0e7bfcf7d285d28cf8548b31332e3232392e312e3339827597827597b84023c049cfc57345656e1fc9924a121859723a6cc3adea62e6ddd5c15f4b04b8ed044a29cd188d7c26d798da93aa828b911d65e37914935c34f92c9d6f671b3e7bf8588f3232302e3131372e3135342e313431820400820400b8401eecac5177f517a00373f5918f373fb3aa347c87dba678b58a09c0fe73bf578c2447e8f1d6e8f92c3248514d55157398e4909d36d42840f2c70f98120fd2da92f8558c3132322e31312e34372e393582c4a782c4a7b84011e4bc809f78687ac4cceff4ac574cda15010ef20d657d296fc0daf696dd8e80178c3aa64a02db51eecd7c6e05513d49dbbc0824df0fbb53fbbef07e81335926f8588f3138352e3135332e3139382e32303382c35082c350b84014ce698fb9ebd75a7ee6ab123b87f10e041e8bad7b290e5caddd7b75e3f477661923d7ad303a9a97042eb9b1657dc0848411d7b58287d8655881971ab25fd965f8588f3230372e3135342e3231382e313139825209825209b8400ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416f8558c3133372e37342e3134342e3482765f82765fb8401083237e8c12e17153970639079096ad87bf0f534c84c131e7da339d70282e81919e1dbe02415453464849c72e9deb6c784997de2c4aa175282f84ffcd4b79f3f8568d35312e3134302e3132372e393582765f82765fb8400efa939a67ba0d177143c26cad8bc86a29cf7456af8132ddcfb956ab470173981fcf1d08fdbaa14ec4aa9e240880115406f533911f833545809704f5fff6b89ef8568d3230372e3134382e32372e3834827661827661b84003944d60046265f36aa333373e36604570029dc0dc9518d4226ba2037ae33cc2c5dd6940ee22c3ce85ad8a3c5791f81b73530dbe77aacd22d9e25593c4a354c8f8568d36342e33342e3233312e31343082765f82765fb8401feb66dd6b901ba73614a5bb7946426e1d9f0bf3df8368c3d80b47c6983b0f82d0fc360d422e79d67e81faaa0b37ec39c84f962179805dc85357fdb27e282c47845b867da0"; + NeighborsMsg deserializedMessage = + _messageSerializationService.Deserialize(Bytes.FromHexString(message)); + Assert.That(deserializedMessage, Is.Not.Null); + } - [Test] - [Ignore("Is it some v5 message?")] - public void Can_deserialize_the_strange_message() - { - string message = - "46261b14e3783640a24a652205a6fb7afdb94855c07bb9559777d98e54e51562442219fd8673b1a6aef0f4eaa3b1ed39695839775ed634e9b58d56bde116cd1c63e88d9e953bf05b24e9871de8ea630d98f812bdf176b712b7f9ba2c4db242170102f6c3808080cb845adc681b827668827668a070dfc96ee3da9864524f1f0214a35d46b56093f020ee588a05fafe1323335ce7845cc60fd7"; - PongMsg deserializedMessage = - _messageSerializationService.Deserialize(Bytes.FromHexString(message)); - Assert.IsNotNull(deserializedMessage); - } + [Test] + [Ignore("Is it some v5 message?")] + public void Can_deserialize_the_strange_message() + { + string message = + "46261b14e3783640a24a652205a6fb7afdb94855c07bb9559777d98e54e51562442219fd8673b1a6aef0f4eaa3b1ed39695839775ed634e9b58d56bde116cd1c63e88d9e953bf05b24e9871de8ea630d98f812bdf176b712b7f9ba2c4db242170102f6c3808080cb845adc681b827668827668a070dfc96ee3da9864524f1f0214a35d46b56093f020ee588a05fafe1323335ce7845cc60fd7"; + PongMsg deserializedMessage = + _messageSerializationService.Deserialize(Bytes.FromHexString(message)); + Assert.That(deserializedMessage, Is.Not.Null); + } - [Test] - public void FindNodeMessageTest() - { - FindNodeMsg message = - new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, new byte[] { 1, 2, 3 }) - { - FarAddress = _farAddress - }; + [Test] + public void FindNodeMessageTest() + { + FindNodeMsg message = + new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, new byte[] { 1, 2, 3 }) + { + FarAddress = _farAddress + }; - IByteBuffer data = _messageSerializationService.ZeroSerialize(message); - FindNodeMsg deserializedMessage = _messageSerializationService.Deserialize(data); - data.SafeRelease(); + IByteBuffer data = _messageSerializationService.ZeroSerialize(message); + FindNodeMsg deserializedMessage = _messageSerializationService.Deserialize(data); + data.SafeRelease(); - Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); - Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); - Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); + Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); + Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); + Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); - Assert.That(deserializedMessage.SearchedNodeId, Is.EqualTo(message.SearchedNodeId)); - } + Assert.That(deserializedMessage.SearchedNodeId, Is.EqualTo(message.SearchedNodeId)); + } - [Test] - public void NeighborsMessageTest() - { - NeighborsMsg message = - new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, - new[] - { - new Node(TestItem.PublicKeyA, "192.168.1.2", 1), - new Node(TestItem.PublicKeyB, "192.168.1.3", 2), - new Node(TestItem.PublicKeyC, "192.168.1.4", 3) - }) + [Test] + public void NeighborsMessageTest() + { + NeighborsMsg message = + new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, + new[] { - FarAddress = _farAddress - }; + new Node(TestItem.PublicKeyA, "192.168.1.2", 1), + new Node(TestItem.PublicKeyB, "192.168.1.3", 2), + new Node(TestItem.PublicKeyC, "192.168.1.4", 3) + }) + { + FarAddress = _farAddress + }; - IByteBuffer data = _messageSerializationService.ZeroSerialize(message); - NeighborsMsg deserializedMessage = _messageSerializationService.Deserialize(data); - data.SafeRelease(); + IByteBuffer data = _messageSerializationService.ZeroSerialize(message); + NeighborsMsg deserializedMessage = _messageSerializationService.Deserialize(data); + data.SafeRelease(); - Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); - Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); - Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); + Assert.That(deserializedMessage.MsgType, Is.EqualTo(message.MsgType)); + Assert.That(deserializedMessage.FarPublicKey, Is.EqualTo(message.FarPublicKey)); + Assert.That(deserializedMessage.ExpirationTime, Is.EqualTo(message.ExpirationTime)); - for (int i = 0; i < message.Nodes.Length; i++) - { - Assert.That(deserializedMessage.Nodes[i].Host, Is.EqualTo(message.Nodes[i].Host)); - Assert.That(deserializedMessage.Nodes[i].Port, Is.EqualTo(message.Nodes[i].Port)); - Assert.That(deserializedMessage.Nodes[i].IdHash, Is.EqualTo(message.Nodes[i].IdHash)); - Assert.That(deserializedMessage.Nodes[i], Is.EqualTo(message.Nodes[i])); - } + for (int i = 0; i < message.Nodes.Length; i++) + { + Assert.That(deserializedMessage.Nodes[i].Host, Is.EqualTo(message.Nodes[i].Host)); + Assert.That(deserializedMessage.Nodes[i].Port, Is.EqualTo(message.Nodes[i].Port)); + Assert.That(deserializedMessage.Nodes[i].IdHash, Is.EqualTo(message.Nodes[i].IdHash)); + Assert.That(deserializedMessage.Nodes[i], Is.EqualTo(message.Nodes[i])); } } } diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/IPResolverTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/IPResolverTests.cs index bbd80a692ce..4d5b3dd72ca 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/IPResolverTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/IPResolverTests.cs @@ -7,52 +7,50 @@ using Nethermind.Network.Config; using NUnit.Framework; -namespace Nethermind.Network.Discovery.Test +namespace Nethermind.Network.Discovery.Test; + +[Parallelizable(ParallelScope.All)] +public class IPResolverTests { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class IPResolverTests + [Test] + public async Task Can_resolve_external_ip() { - [Test] - public async Task Can_resolve_external_ip() - { - IPResolver ipResolver = new(new NetworkConfig(), LimboLogs.Instance); - await ipResolver.Initialize(); - IPAddress address = ipResolver.ExternalIp; - Assert.IsNotNull(address); - } + IPResolver ipResolver = new(new NetworkConfig(), LimboLogs.Instance); + await ipResolver.Initialize(); + IPAddress address = ipResolver.ExternalIp; + Assert.That(address, Is.Not.Null); + } - [TestCase("99.99.99.99")] - [TestCase("10.50.50.50")] - public async Task Can_resolve_external_ip_with_override(string ipOverride) - { - INetworkConfig networkConfig = new NetworkConfig(); - networkConfig.ExternalIp = ipOverride; - IPResolver ipResolver = new(networkConfig, LimboLogs.Instance); - await ipResolver.Initialize(); - IPAddress address = ipResolver.ExternalIp; - Assert.That(address, Is.EqualTo(IPAddress.Parse(ipOverride))); - } + [TestCase("99.99.99.99")] + [TestCase("10.50.50.50")] + public async Task Can_resolve_external_ip_with_override(string ipOverride) + { + INetworkConfig networkConfig = new NetworkConfig(); + networkConfig.ExternalIp = ipOverride; + IPResolver ipResolver = new(networkConfig, LimboLogs.Instance); + await ipResolver.Initialize(); + IPAddress address = ipResolver.ExternalIp; + Assert.That(address, Is.EqualTo(IPAddress.Parse(ipOverride))); + } - [Test] - public async Task Can_resolve_internal_ip() - { - IPResolver ipResolver = new(new NetworkConfig(), LimboLogs.Instance); - await ipResolver.Initialize(); - IPAddress address = ipResolver.LocalIp; - Assert.IsNotNull(address); - } + [Test] + public async Task Can_resolve_internal_ip() + { + IPResolver ipResolver = new(new NetworkConfig(), LimboLogs.Instance); + await ipResolver.Initialize(); + IPAddress address = ipResolver.LocalIp; + Assert.That(address, Is.Not.Null); + } - [Test] - public async Task Can_resolve_local_ip_with_override() - { - string ipOverride = "99.99.99.99"; - INetworkConfig networkConfig = new NetworkConfig(); - networkConfig.LocalIp = ipOverride; - IPResolver ipResolver = new(networkConfig, LimboLogs.Instance); - await ipResolver.Initialize(); - IPAddress address = ipResolver.LocalIp; - Assert.That(address, Is.EqualTo(IPAddress.Parse(ipOverride))); - } + [Test] + public async Task Can_resolve_local_ip_with_override() + { + string ipOverride = "99.99.99.99"; + INetworkConfig networkConfig = new NetworkConfig(); + networkConfig.LocalIp = ipOverride; + IPResolver ipResolver = new(networkConfig, LimboLogs.Instance); + await ipResolver.Initialize(); + IPAddress address = ipResolver.LocalIp; + Assert.That(address, Is.EqualTo(IPAddress.Parse(ipOverride))); } } diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/NodeLifecycleManagerTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/NodeLifecycleManagerTests.cs index 4a32fca9168..dd922bf0905 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/NodeLifecycleManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/NodeLifecycleManagerTests.cs @@ -25,377 +25,375 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Network.Discovery.Test +namespace Nethermind.Network.Discovery.Test; + +[Parallelizable(ParallelScope.Self)] +public class NodeLifecycleManagerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class NodeLifecycleManagerTests + private Signature[] _signatureMocks = Array.Empty(); + private PublicKey[] _nodeIds = Array.Empty(); + private INodeStats _nodeStatsMock = null!; + + private readonly INetworkConfig _networkConfig = new NetworkConfig(); + private IDiscoveryManager _discoveryManager = null!; + private IDiscoveryManager _discoveryManagerMock = null!; + private IDiscoveryConfig _discoveryConfigMock = null!; + private INodeTable _nodeTable = null!; + private IEvictionManager _evictionManagerMock = null!; + private ILogger _loggerMock = default; + private readonly int _port = 1; + private readonly string _host = "192.168.1.27"; + + [SetUp] + public void Setup() { - private Signature[] _signatureMocks = Array.Empty(); - private PublicKey[] _nodeIds = Array.Empty(); - private INodeStats _nodeStatsMock = null!; - - private readonly INetworkConfig _networkConfig = new NetworkConfig(); - private IDiscoveryManager _discoveryManager = null!; - private IDiscoveryManager _discoveryManagerMock = null!; - private IDiscoveryConfig _discoveryConfigMock = null!; - private INodeTable _nodeTable = null!; - private IEvictionManager _evictionManagerMock = null!; - private ILogger _loggerMock = default; - private readonly int _port = 1; - private readonly string _host = "192.168.1.27"; - - [SetUp] - public void Setup() - { - _discoveryManagerMock = Substitute.For(); - _discoveryConfigMock = Substitute.For(); + _discoveryManagerMock = Substitute.For(); + _discoveryConfigMock = Substitute.For(); - NetworkNodeDecoder.Init(); - SetupNodeIds(); + NetworkNodeDecoder.Init(); + SetupNodeIds(); - LimboLogs? logManager = LimboLogs.Instance; - _loggerMock = new(Substitute.For()); - //setting config to store 3 nodes in a bucket and for table to have one bucket//setting config to store 3 nodes in a bucket and for table to have one bucket + LimboLogs? logManager = LimboLogs.Instance; + _loggerMock = new(Substitute.For()); + //setting config to store 3 nodes in a bucket and for table to have one bucket//setting config to store 3 nodes in a bucket and for table to have one bucket - IConfigProvider configurationProvider = new ConfigProvider(); - _networkConfig.ExternalIp = "99.10.10.66"; - _networkConfig.LocalIp = "10.0.0.5"; + IConfigProvider configurationProvider = new ConfigProvider(); + _networkConfig.ExternalIp = "99.10.10.66"; + _networkConfig.LocalIp = "10.0.0.5"; - IDiscoveryConfig discoveryConfig = configurationProvider.GetConfig(); - discoveryConfig.PongTimeout = 50; - discoveryConfig.BucketSize = 3; - discoveryConfig.BucketsCount = 1; + IDiscoveryConfig discoveryConfig = configurationProvider.GetConfig(); + discoveryConfig.PongTimeout = 50; + discoveryConfig.BucketSize = 3; + discoveryConfig.BucketsCount = 1; - NodeDistanceCalculator calculator = new(discoveryConfig); + NodeDistanceCalculator calculator = new(discoveryConfig); - _nodeTable = new NodeTable(calculator, discoveryConfig, _networkConfig, logManager); - _nodeTable.Initialize(TestItem.PublicKeyA); - _nodeStatsMock = Substitute.For(); + _nodeTable = new NodeTable(calculator, discoveryConfig, _networkConfig, logManager); + _nodeTable.Initialize(TestItem.PublicKeyA); + _nodeStatsMock = Substitute.For(); - EvictionManager evictionManager = new(_nodeTable, logManager); - _evictionManagerMock = Substitute.For(); - ITimerFactory timerFactory = Substitute.For(); - NodeLifecycleManagerFactory lifecycleFactory = new(_nodeTable, evictionManager, - new NodeStatsManager(timerFactory, logManager), new NodeRecord(), discoveryConfig, Timestamper.Default, logManager); + EvictionManager evictionManager = new(_nodeTable, logManager); + _evictionManagerMock = Substitute.For(); + ITimerFactory timerFactory = Substitute.For(); + NodeLifecycleManagerFactory lifecycleFactory = new(_nodeTable, evictionManager, + new NodeStatsManager(timerFactory, logManager), new NodeRecord(), discoveryConfig, Timestamper.Default, logManager); - IMsgSender udpClient = Substitute.For(); + IMsgSender udpClient = Substitute.For(); - SimpleFilePublicKeyDb discoveryDb = new("Test", "test", logManager); - _discoveryManager = new DiscoveryManager(lifecycleFactory, _nodeTable, new NetworkStorage(discoveryDb, logManager), discoveryConfig, logManager); - _discoveryManager.MsgSender = udpClient; + SimpleFilePublicKeyDb discoveryDb = new("Test", "test", logManager); + _discoveryManager = new DiscoveryManager(lifecycleFactory, _nodeTable, new NetworkStorage(discoveryDb, logManager), discoveryConfig, logManager); + _discoveryManager.MsgSender = udpClient; - _discoveryManagerMock = Substitute.For(); - } + _discoveryManagerMock = Substitute.For(); + } - [Test] - public async Task sending_ping_receiving_proper_pong_sets_bounded() + [Test] + public async Task sending_ping_receiving_proper_pong_sets_bounded() + { + Node node = new(TestItem.PublicKeyB, _host, _port); + NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock + , _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); + + byte[] mdc = new byte[32]; + PingMsg? sentPing = null; + await _discoveryManagerMock.SendMessageAsync(Arg.Do(msg => { - Node node = new(TestItem.PublicKeyB, _host, _port); - NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock - , _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); + msg.Mdc = mdc; + sentPing = msg; + })); - byte[] mdc = new byte[32]; - PingMsg? sentPing = null; - await _discoveryManagerMock.SendMessageAsync(Arg.Do(msg => - { - msg.Mdc = mdc; - sentPing = msg; - })); + await nodeManager.SendPingAsync(); + nodeManager.ProcessPongMsg(new PongMsg(node.Address, GetExpirationTime(), sentPing!.Mdc!)); + + Assert.That(nodeManager.IsBonded, Is.True); + } - await nodeManager.SendPingAsync(); - nodeManager.ProcessPongMsg(new PongMsg(node.Address, GetExpirationTime(), sentPing!.Mdc!)); + [Test] + public async Task handling_findnode_msg_will_limit_result_to_12() + { + IDiscoveryConfig discoveryConfig = new DiscoveryConfig(); + discoveryConfig.PongTimeout = 50; + discoveryConfig.BucketSize = 32; + discoveryConfig.BucketsCount = 1; + + _nodeTable = new NodeTable(new NodeDistanceCalculator(discoveryConfig), discoveryConfig, _networkConfig, LimboLogs.Instance); + _nodeTable.Initialize(TestItem.PublicKeyA); + + Node node = new(TestItem.PublicKeyB, _host, _port); + NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock, _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); - Assert.IsTrue(nodeManager.IsBonded); + await BondWithSelf(nodeManager, node); + + for (int i = 0; i < 32; i++) + { + _nodeTable.AddNode( + new Node( + new PublicKey(Random.Shared.NextBytes(64)), + "127.0.0.1", + i + )); } - [Test] - public async Task handling_findnode_msg_will_limit_result_to_12() + NeighborsMsg? sentMsg = null; + _discoveryManagerMock.SendMessage(Arg.Do(msg => { - IDiscoveryConfig discoveryConfig = new DiscoveryConfig(); - discoveryConfig.PongTimeout = 50; - discoveryConfig.BucketSize = 32; - discoveryConfig.BucketsCount = 1; + sentMsg = msg; + })); - _nodeTable = new NodeTable(new NodeDistanceCalculator(discoveryConfig), discoveryConfig, _networkConfig, LimboLogs.Instance); - _nodeTable.Initialize(TestItem.PublicKeyA); + nodeManager.ProcessFindNodeMsg(new FindNodeMsg(TestItem.PublicKeyA, 1, new byte[] { 0 })); - Node node = new(TestItem.PublicKeyB, _host, _port); - NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock, _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); + Assert.That(sentMsg, Is.Not.Null); + _nodeTable.Buckets[0].BondedItemsCount.Should().Be(32); + sentMsg!.Nodes.Length.Should().Be(12); + } - await BondWithSelf(nodeManager, node); + [Test] + public async Task processNeighboursMessage_willCombineTwoSubsequentMessage() + { + IDiscoveryConfig discoveryConfig = new DiscoveryConfig(); + discoveryConfig.PongTimeout = 50; + discoveryConfig.BucketSize = 32; + discoveryConfig.BucketsCount = 1; + + _nodeTable = new NodeTable(new NodeDistanceCalculator(discoveryConfig), discoveryConfig, _networkConfig, LimboLogs.Instance); + _nodeTable.Initialize(TestItem.PublicKeyA); + + Node node = new(TestItem.PublicKeyB, _host, _port); + NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock, _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); + + await BondWithSelf(nodeManager, node); + + _discoveryManagerMock + .Received(0) + .GetNodeLifecycleManager(Arg.Any(), Arg.Any()); + + await nodeManager.SendFindNode(Array.Empty()); + + Node[] firstNodes = TestItem.PublicKeys + .Take(12) + .Select(pubkey => new Node(pubkey, "127.0.0.2", 0)) + .ToArray(); + NeighborsMsg firstNodeMsg = new NeighborsMsg(TestItem.PublicKeyA, 1, firstNodes); + Node[] secondNodes = TestItem.PublicKeys + .Skip(12) + .Take(4) + .Select(pubkey => new Node(pubkey, "127.0.0.2", 0)) + .ToArray(); + NeighborsMsg secondNodeMsg = new NeighborsMsg(TestItem.PublicKeyA, 1, secondNodes); + + nodeManager.ProcessNeighborsMsg(firstNodeMsg); + nodeManager.ProcessNeighborsMsg(secondNodeMsg); + + _discoveryManagerMock + .Received(16) + .GetNodeLifecycleManager(Arg.Any(), Arg.Any()); + } - for (int i = 0; i < 32; i++) - { - _nodeTable.AddNode( - new Node( - new PublicKey(Random.Shared.NextBytes(64)), - "127.0.0.1", - i - )); - } + [Test] + public async Task sending_ping_receiving_incorrect_pong_does_not_bond() + { + Node node = new(TestItem.PublicKeyB, _host, _port); + NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock + , _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); - NeighborsMsg? sentMsg = null; - _discoveryManagerMock.SendMessage(Arg.Do(msg => - { - sentMsg = msg; - })); + await nodeManager.SendPingAsync(); + nodeManager.ProcessPongMsg(new PongMsg(TestItem.PublicKeyB, GetExpirationTime(), new byte[] { 1, 1, 1 })); - nodeManager.ProcessFindNodeMsg(new FindNodeMsg(TestItem.PublicKeyA, 1, new byte[] { 0 })); + Assert.That(nodeManager.IsBonded, Is.False); + } - Assert.IsNotNull(sentMsg); - _nodeTable.Buckets[0].BondedItemsCount.Should().Be(32); - sentMsg!.Nodes.Length.Should().Be(12); - } + [Test] + public void Wrong_pong_will_get_ignored() + { + Node node = new(TestItem.PublicKeyB, _host, _port); + INodeLifecycleManager? manager = _discoveryManager.GetNodeLifecycleManager(node); + Assert.That(manager?.State, Is.EqualTo(NodeLifecycleState.New)); - [Test] - public async Task processNeighboursMessage_willCombineTwoSubsequentMessage() - { - IDiscoveryConfig discoveryConfig = new DiscoveryConfig(); - discoveryConfig.PongTimeout = 50; - discoveryConfig.BucketSize = 32; - discoveryConfig.BucketsCount = 1; - - _nodeTable = new NodeTable(new NodeDistanceCalculator(discoveryConfig), discoveryConfig, _networkConfig, LimboLogs.Instance); - _nodeTable.Initialize(TestItem.PublicKeyA); - - Node node = new(TestItem.PublicKeyB, _host, _port); - NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock, _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); - - await BondWithSelf(nodeManager, node); - - _discoveryManagerMock - .Received(0) - .GetNodeLifecycleManager(Arg.Any(), Arg.Any()); - - await nodeManager.SendFindNode(Array.Empty()); - - Node[] firstNodes = TestItem.PublicKeys - .Take(12) - .Select(pubkey => new Node(pubkey, "127.0.0.2", 0)) - .ToArray(); - NeighborsMsg firstNodeMsg = new NeighborsMsg(TestItem.PublicKeyA, 1, firstNodes); - Node[] secondNodes = TestItem.PublicKeys - .Skip(12) - .Take(4) - .Select(pubkey => new Node(pubkey, "127.0.0.2", 0)) - .ToArray(); - NeighborsMsg secondNodeMsg = new NeighborsMsg(TestItem.PublicKeyA, 1, secondNodes); - - nodeManager.ProcessNeighborsMsg(firstNodeMsg); - nodeManager.ProcessNeighborsMsg(secondNodeMsg); - - _discoveryManagerMock - .Received(16) - .GetNodeLifecycleManager(Arg.Any(), Arg.Any()); - } + PongMsg msgI = new(_nodeIds[0], GetExpirationTime(), new byte[32]); + msgI.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); + _discoveryManager.OnIncomingMsg(msgI); - [Test] - public async Task sending_ping_receiving_incorrect_pong_does_not_bond() - { - Node node = new(TestItem.PublicKeyB, _host, _port); - NodeLifecycleManager nodeManager = new(node, _discoveryManagerMock - , _nodeTable, _evictionManagerMock, _nodeStatsMock, new NodeRecord(), _discoveryConfigMock, Timestamper.Default, _loggerMock); + Assert.That(manager?.State, Is.EqualTo(NodeLifecycleState.New)); + } + + [Test] + [Retry(3)] + public async Task UnreachableStateTest() + { + Node node = new(TestItem.PublicKeyB, _host, _port); + INodeLifecycleManager? manager = _discoveryManager.GetNodeLifecycleManager(node); + Assert.That(manager?.State, Is.EqualTo(NodeLifecycleState.New)); - await nodeManager.SendPingAsync(); - nodeManager.ProcessPongMsg(new PongMsg(TestItem.PublicKeyB, GetExpirationTime(), new byte[] { 1, 1, 1 })); + await Task.Delay(500); - Assert.IsFalse(nodeManager.IsBonded); - } + Assert.That(() => manager?.State, Is.EqualTo(NodeLifecycleState.Unreachable).After(500, 50)); + //Assert.AreEqual(NodeLifecycleState.Unreachable, manager.State); + } - [Test] - public void Wrong_pong_will_get_ignored() + [Test, Retry(3), Ignore("Eviction changes were introduced and we would need to expose some internals to test bonding")] + public void EvictCandidateStateWonEvictionTest() + { + //adding 3 active nodes + List managers = new(); + for (int i = 0; i < 3; i++) { - Node node = new(TestItem.PublicKeyB, _host, _port); + string host = "192.168.1." + i; + Node node = new(_nodeIds[i], host, _port); INodeLifecycleManager? manager = _discoveryManager.GetNodeLifecycleManager(node); - Assert.That(manager?.State, Is.EqualTo(NodeLifecycleState.New)); + if (manager is null) + { + throw new Exception("Manager is null"); + } - PongMsg msgI = new(_nodeIds[0], GetExpirationTime(), new byte[32]); + managers.Add(manager); + Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.New)); + + PongMsg msgI = new(_nodeIds[i], GetExpirationTime(), new byte[32]); msgI.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); _discoveryManager.OnIncomingMsg(msgI); - - Assert.That(manager?.State, Is.EqualTo(NodeLifecycleState.New)); + Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.New)); } - [Test] - [Retry(3)] - public async Task UnreachableStateTest() - { - Node node = new(TestItem.PublicKeyB, _host, _port); - INodeLifecycleManager? manager = _discoveryManager.GetNodeLifecycleManager(node); - Assert.That(manager?.State, Is.EqualTo(NodeLifecycleState.New)); + //table should contain 3 active nodes + IEnumerable closestNodes = _nodeTable.GetClosestNodes().ToArray(); + Assert.That(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 0, Is.True); + Assert.That(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 0, Is.True); + Assert.That(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 0, Is.True); - await Task.Delay(500); + //adding 4th node - table can store only 3, eviction process should start + Node candidateNode = new(_nodeIds[3], _host, _port); + INodeLifecycleManager? candidateManager = _discoveryManager.GetNodeLifecycleManager(candidateNode); - Assert.That(() => manager?.State, Is.EqualTo(NodeLifecycleState.Unreachable).After(500, 50)); - //Assert.AreEqual(NodeLifecycleState.Unreachable, manager.State); - } + Assert.That(candidateManager?.State, Is.EqualTo(NodeLifecycleState.New)); - [Test, Retry(3), Ignore("Eviction changes were introduced and we would need to expose some internals to test bonding")] - public void EvictCandidateStateWonEvictionTest() - { - //adding 3 active nodes - List managers = new(); - for (int i = 0; i < 3; i++) - { - string host = "192.168.1." + i; - Node node = new(_nodeIds[i], host, _port); - INodeLifecycleManager? manager = _discoveryManager.GetNodeLifecycleManager(node); - if (manager is null) - { - throw new Exception("Manager is null"); - } - - managers.Add(manager); - Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.New)); - - PongMsg msgI = new(_nodeIds[i], GetExpirationTime(), new byte[32]); - msgI.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); - _discoveryManager.OnIncomingMsg(msgI); - Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.New)); - } + PongMsg pongMsg = new(_nodeIds[3], GetExpirationTime(), new byte[32]); + pongMsg.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); + _discoveryManager.OnIncomingMsg(pongMsg); - //table should contain 3 active nodes - IEnumerable closestNodes = _nodeTable.GetClosestNodes().ToArray(); - Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 0); - Assert.IsTrue(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 0); - Assert.IsTrue(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 0); + Assert.That(candidateManager?.State, Is.EqualTo(NodeLifecycleState.New)); + INodeLifecycleManager evictionCandidate = managers.First(x => x.State == NodeLifecycleState.EvictCandidate); - //adding 4th node - table can store only 3, eviction process should start - Node candidateNode = new(_nodeIds[3], _host, _port); - INodeLifecycleManager? candidateManager = _discoveryManager.GetNodeLifecycleManager(candidateNode); + //receiving pong for eviction candidate - should survive + PongMsg msg = new(evictionCandidate.ManagedNode.Id, GetExpirationTime(), new byte[32]); + msg.FarAddress = new IPEndPoint(IPAddress.Parse(evictionCandidate.ManagedNode.Host), _port); + _discoveryManager.OnIncomingMsg(msg); - Assert.That(candidateManager?.State, Is.EqualTo(NodeLifecycleState.New)); + //await Task.Delay(100); - PongMsg pongMsg = new(_nodeIds[3], GetExpirationTime(), new byte[32]); - pongMsg.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); - _discoveryManager.OnIncomingMsg(pongMsg); + //3th node should survive, 4th node should be active but not in the table + Assert.That(() => candidateManager?.State, Is.EqualTo(NodeLifecycleState.ActiveExcluded).After(100, 50)); + Assert.That(() => evictionCandidate.State, Is.EqualTo(NodeLifecycleState.Active).After(100, 50)); - Assert.That(candidateManager?.State, Is.EqualTo(NodeLifecycleState.New)); - INodeLifecycleManager evictionCandidate = managers.First(x => x.State == NodeLifecycleState.EvictCandidate); + //Assert.AreEqual(NodeLifecycleState.ActiveExcluded, candidateManager.State); + //Assert.AreEqual(NodeLifecycleState.Active, evictionCandidate.State); + closestNodes = _nodeTable.GetClosestNodes(); + Assert.That(() => closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1, Is.True.After(100, 50)); + Assert.That(() => closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1, Is.True.After(100, 50)); + Assert.That(() => closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1, Is.True.After(100, 50)); + Assert.That(() => closestNodes.Count(x => x.Host == candidateNode.Host) == 0, Is.True.After(100, 50)); - //receiving pong for eviction candidate - should survive - PongMsg msg = new(evictionCandidate.ManagedNode.Id, GetExpirationTime(), new byte[32]); - msg.FarAddress = new IPEndPoint(IPAddress.Parse(evictionCandidate.ManagedNode.Host), _port); - _discoveryManager.OnIncomingMsg(msg); + //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1); + //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1); + //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1); + //Assert.IsTrue(closestNodes.Count(x => x.Host == candidateNode.Host) == 0); + } - //await Task.Delay(100); + private static long GetExpirationTime() => Timestamper.Default.UnixTime.SecondsLong + 20; - //3th node should survive, 4th node should be active but not in the table - Assert.That(() => candidateManager?.State, Is.EqualTo(NodeLifecycleState.ActiveExcluded).After(100, 50)); - Assert.That(() => evictionCandidate.State, Is.EqualTo(NodeLifecycleState.Active).After(100, 50)); + [Test] + [Ignore("This test keeps failing and should be only manually enabled / understood when we review the discovery code")] + public void EvictCandidateStateLostEvictionTest() + { + //adding 3 active nodes + List managers = new(); + for (int i = 0; i < 3; i++) + { + string host = "192.168.1." + i; + Node node = new(_nodeIds[i], host, _port); + INodeLifecycleManager? manager = _discoveryManager.GetNodeLifecycleManager(node); + if (manager is null) + { + throw new Exception("Manager is null"); + } - //Assert.AreEqual(NodeLifecycleState.ActiveExcluded, candidateManager.State); - //Assert.AreEqual(NodeLifecycleState.Active, evictionCandidate.State); - closestNodes = _nodeTable.GetClosestNodes(); - Assert.That(() => closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1, Is.True.After(100, 50)); - Assert.That(() => closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1, Is.True.After(100, 50)); - Assert.That(() => closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1, Is.True.After(100, 50)); - Assert.That(() => closestNodes.Count(x => x.Host == candidateNode.Host) == 0, Is.True.After(100, 50)); + managers.Add(manager); + Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.New)); - //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1); - //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1); - //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1); - //Assert.IsTrue(closestNodes.Count(x => x.Host == candidateNode.Host) == 0); - } + PongMsg msg = new(_nodeIds[i], GetExpirationTime(), new byte[32]); + msg.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); + _discoveryManager.OnIncomingMsg(msg); - private static long GetExpirationTime() => Timestamper.Default.UnixTime.SecondsLong + 20; + Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.Active)); + } - [Test] - [Ignore("This test keeps failing and should be only manually enabled / understood when we review the discovery code")] - public void EvictCandidateStateLostEvictionTest() + //table should contain 3 active nodes + IEnumerable closestNodes = _nodeTable.GetClosestNodes().ToArray(); + for (int i = 0; i < 3; i++) { - //adding 3 active nodes - List managers = new(); - for (int i = 0; i < 3; i++) - { - string host = "192.168.1." + i; - Node node = new(_nodeIds[i], host, _port); - INodeLifecycleManager? manager = _discoveryManager.GetNodeLifecycleManager(node); - if (manager is null) - { - throw new Exception("Manager is null"); - } - - managers.Add(manager); - Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.New)); - - PongMsg msg = new(_nodeIds[i], GetExpirationTime(), new byte[32]); - msg.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); - _discoveryManager.OnIncomingMsg(msg); - - Assert.That(manager.State, Is.EqualTo(NodeLifecycleState.Active)); - } + Assert.That(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1, Is.True); + } - //table should contain 3 active nodes - IEnumerable closestNodes = _nodeTable.GetClosestNodes().ToArray(); - for (int i = 0; i < 3; i++) - { - Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1); - } + //adding 4th node - table can store only 3, eviction process should start + Node candidateNode = new(_nodeIds[3], _host, _port); - //adding 4th node - table can store only 3, eviction process should start - Node candidateNode = new(_nodeIds[3], _host, _port); + INodeLifecycleManager? candidateManager = _discoveryManager.GetNodeLifecycleManager(candidateNode); + Assert.That(candidateManager?.State, Is.EqualTo(NodeLifecycleState.New)); - INodeLifecycleManager? candidateManager = _discoveryManager.GetNodeLifecycleManager(candidateNode); - Assert.That(candidateManager?.State, Is.EqualTo(NodeLifecycleState.New)); + PongMsg pongMsg = new(_nodeIds[3], GetExpirationTime(), new byte[32]); + pongMsg.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); + _discoveryManager.OnIncomingMsg(pongMsg); - PongMsg pongMsg = new(_nodeIds[3], GetExpirationTime(), new byte[32]); - pongMsg.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); - _discoveryManager.OnIncomingMsg(pongMsg); + //await Task.Delay(10); + Assert.That(() => candidateManager?.State, Is.EqualTo(NodeLifecycleState.Active).After(10, 5)); + //Assert.AreEqual(NodeLifecycleState.Active, candidateManager.State); - //await Task.Delay(10); - Assert.That(() => candidateManager?.State, Is.EqualTo(NodeLifecycleState.Active).After(10, 5)); - //Assert.AreEqual(NodeLifecycleState.Active, candidateManager.State); + INodeLifecycleManager evictionCandidate = managers.First(x => x.State == NodeLifecycleState.EvictCandidate); + //await Task.Delay(300); - INodeLifecycleManager evictionCandidate = managers.First(x => x.State == NodeLifecycleState.EvictCandidate); - //await Task.Delay(300); + //3th node should be evicted, 4th node should be added to the table + //Assert.AreEqual(NodeLifecycleState.Active, candidateManager.State); + Assert.That(() => candidateManager?.State, Is.EqualTo(NodeLifecycleState.Active).After(300, 50)); + //Assert.AreEqual(NodeLifecycleState.Unreachable, evictionCandidate.State); + Assert.That(() => evictionCandidate.State, Is.EqualTo(NodeLifecycleState.Unreachable).After(300, 50)); - //3th node should be evicted, 4th node should be added to the table - //Assert.AreEqual(NodeLifecycleState.Active, candidateManager.State); - Assert.That(() => candidateManager?.State, Is.EqualTo(NodeLifecycleState.Active).After(300, 50)); - //Assert.AreEqual(NodeLifecycleState.Unreachable, evictionCandidate.State); - Assert.That(() => evictionCandidate.State, Is.EqualTo(NodeLifecycleState.Unreachable).After(300, 50)); + closestNodes = _nodeTable.GetClosestNodes(); + Assert.That(() => managers.Where(x => x.State == NodeLifecycleState.Active).All(x => closestNodes.Any(y => y.Host == x.ManagedNode.Host)), Is.True.After(300, 50)); + Assert.That(() => closestNodes.Count(x => x.Host == evictionCandidate.ManagedNode.Host) == 0, Is.True.After(300, 50)); + Assert.That(() => closestNodes.Count(x => x.Host == candidateNode.Host) == 1, Is.True.After(300, 50)); - closestNodes = _nodeTable.GetClosestNodes(); - Assert.That(() => managers.Where(x => x.State == NodeLifecycleState.Active).All(x => closestNodes.Any(y => y.Host == x.ManagedNode.Host)), Is.True.After(300, 50)); - Assert.That(() => closestNodes.Count(x => x.Host == evictionCandidate.ManagedNode.Host) == 0, Is.True.After(300, 50)); - Assert.That(() => closestNodes.Count(x => x.Host == candidateNode.Host) == 1, Is.True.After(300, 50)); + //Assert.IsTrue(managers.Where(x => x.State == NodeLifecycleState.Active).All(x => closestNodes.Any(y => y.Host == x.ManagedNode.Host))); + //Assert.IsTrue(closestNodes.Count(x => x.Host == evictionCandidate.ManagedNode.Host) == 0); + //Assert.IsTrue(closestNodes.Count(x => x.Host == candidateNode.Host) == 1); + } - //Assert.IsTrue(managers.Where(x => x.State == NodeLifecycleState.Active).All(x => closestNodes.Any(y => y.Host == x.ManagedNode.Host))); - //Assert.IsTrue(closestNodes.Count(x => x.Host == evictionCandidate.ManagedNode.Host) == 0); - //Assert.IsTrue(closestNodes.Count(x => x.Host == candidateNode.Host) == 1); - } + private void SetupNodeIds() + { + _signatureMocks = new Signature[4]; + _nodeIds = new PublicKey[4]; - private void SetupNodeIds() + for (int i = 0; i < 4; i++) { - _signatureMocks = new Signature[4]; - _nodeIds = new PublicKey[4]; + byte[] signatureBytes = new byte[65]; + signatureBytes[64] = (byte)i; + _signatureMocks[i] = new Signature(signatureBytes); - for (int i = 0; i < 4; i++) - { - byte[] signatureBytes = new byte[65]; - signatureBytes[64] = (byte)i; - _signatureMocks[i] = new Signature(signatureBytes); - - byte[] nodeIdBytes = new byte[64]; - nodeIdBytes[63] = (byte)i; - _nodeIds[i] = new PublicKey(nodeIdBytes); - } + byte[] nodeIdBytes = new byte[64]; + nodeIdBytes[63] = (byte)i; + _nodeIds[i] = new PublicKey(nodeIdBytes); } + } - private async Task BondWithSelf(NodeLifecycleManager nodeManager, Node node) + private async Task BondWithSelf(NodeLifecycleManager nodeManager, Node node) + { + byte[] mdc = new byte[32]; + PingMsg? sentPing = null; + await _discoveryManagerMock.SendMessageAsync(Arg.Do(msg => { - byte[] mdc = new byte[32]; - PingMsg? sentPing = null; - await _discoveryManagerMock.SendMessageAsync(Arg.Do(msg => - { - msg.Mdc = mdc; - sentPing = msg; - })); - await nodeManager.SendPingAsync(); - nodeManager.ProcessPongMsg(new PongMsg(node.Address, GetExpirationTime(), sentPing!.Mdc!)); - } - + msg.Mdc = mdc; + sentPing = msg; + })); + await nodeManager.SendPingAsync(); + nodeManager.ProcessPongMsg(new PongMsg(node.Address, GetExpirationTime(), sentPing!.Mdc!)); } + } diff --git a/src/Nethermind/Nethermind.Network.Enr.Test/NodeRecordSignerTests.cs b/src/Nethermind/Nethermind.Network.Enr.Test/NodeRecordSignerTests.cs index 5f595d82afa..b3e84ea9375 100644 --- a/src/Nethermind/Nethermind.Network.Enr.Test/NodeRecordSignerTests.cs +++ b/src/Nethermind/Nethermind.Network.Enr.Test/NodeRecordSignerTests.cs @@ -94,7 +94,7 @@ public void Can_verify_signature() nodeRecord.EnrSequence = 1; // override signer.Sign(nodeRecord); - Assert.IsTrue(signer.Verify(nodeRecord)); + Assert.That(signer.Verify(nodeRecord), Is.True); } [TestCase] @@ -125,7 +125,7 @@ public void Can_deserialize_and_verify_real_world_cases(string testCase) string hex = nodeRecord.GetHex(); Console.WriteLine(testCase); Console.WriteLine(hex); - Assert.IsTrue(signer.Verify(nodeRecord)); + Assert.That(signer.Verify(nodeRecord), Is.True); } diff --git a/src/Nethermind/Nethermind.Network.Test/NetworkStorageTests.cs b/src/Nethermind/Nethermind.Network.Test/NetworkStorageTests.cs index 01042fc47b4..1961030c024 100644 --- a/src/Nethermind/Nethermind.Network.Test/NetworkStorageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/NetworkStorageTests.cs @@ -14,151 +14,149 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Network.Test +namespace Nethermind.Network.Test; + +[Parallelizable(ParallelScope.Self)] +public class NetworkStorageTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class NetworkStorageTests + [SetUp] + public void SetUp() + { + NetworkNodeDecoder.Init(); + ILogManager logManager = LimboLogs.Instance; + ConfigProvider configSource = new(); + _tempDir = TempPath.GetTempDirectory(); + + var db = new SimpleFilePublicKeyDb("Test", _tempDir.Path, logManager); + _storage = new NetworkStorage(db, logManager); + } + + [TearDown] + public void TearDown() { - [SetUp] - public void SetUp() + _tempDir.Dispose(); + } + + private TempPath _tempDir; + private INetworkStorage _storage; + + private INodeLifecycleManager CreateLifecycleManager(Node node) + { + INodeLifecycleManager manager = Substitute.For(); + manager.ManagedNode.Returns(node); + manager.NodeStats.Returns(new NodeStatsLight(node) + { + CurrentPersistedNodeReputation = node.Port + }); + + return manager; + } + + [Test] + public void Can_store_discovery_nodes() + { + var persistedNodes = _storage.GetPersistedNodes(); + Assert.That(persistedNodes.Length, Is.EqualTo(0)); + + var nodes = new[] { - NetworkNodeDecoder.Init(); - ILogManager logManager = LimboLogs.Instance; - ConfigProvider configSource = new(); - _tempDir = TempPath.GetTempDirectory(); + new Node(TestItem.PublicKeyA, "192.1.1.1", 3441), + new Node(TestItem.PublicKeyB, "192.1.1.2", 3442), + new Node(TestItem.PublicKeyC, "192.1.1.3", 3443), + new Node(TestItem.PublicKeyD, "192.1.1.4", 3444), + new Node(TestItem.PublicKeyE, "192.1.1.5", 3445) + }; - var db = new SimpleFilePublicKeyDb("Test", _tempDir.Path, logManager); - _storage = new NetworkStorage(db, logManager); + var managers = nodes.Select(CreateLifecycleManager).ToArray(); + DateTime utcNow = DateTime.UtcNow; + var networkNodes = managers.Select(x => new NetworkNode(x.ManagedNode.Id, x.ManagedNode.Host, x.ManagedNode.Port, x.NodeStats.NewPersistedNodeReputation(utcNow))).ToArray(); + + + _storage.StartBatch(); + _storage.UpdateNodes(networkNodes); + _storage.Commit(); + + persistedNodes = _storage.GetPersistedNodes(); + foreach (INodeLifecycleManager manager in managers) + { + NetworkNode persistedNode = persistedNodes.FirstOrDefault(x => x.NodeId.Equals(manager.ManagedNode.Id)); + Assert.That(persistedNode, Is.Not.Null); + Assert.That(persistedNode.Port, Is.EqualTo(manager.ManagedNode.Port)); + Assert.That(persistedNode.Host, Is.EqualTo(manager.ManagedNode.Host)); + Assert.That(persistedNode.Reputation, Is.EqualTo(manager.NodeStats.CurrentNodeReputation())); } - [TearDown] - public void TearDown() + _storage.StartBatch(); + _storage.RemoveNode(networkNodes.First().NodeId); + _storage.Commit(); + + persistedNodes = _storage.GetPersistedNodes(); + foreach (INodeLifecycleManager manager in managers.Take(1)) { - _tempDir.Dispose(); + NetworkNode persistedNode = persistedNodes.FirstOrDefault(x => x.NodeId.Equals(manager.ManagedNode.Id)); + Assert.That(persistedNode, Is.Null); } - private TempPath _tempDir; - private INetworkStorage _storage; + utcNow = DateTime.UtcNow; + foreach (INodeLifecycleManager manager in managers.Skip(1)) + { + NetworkNode persistedNode = persistedNodes.FirstOrDefault(x => x.NodeId.Equals(manager.ManagedNode.Id)); + Assert.That(persistedNode, Is.Not.Null); + Assert.That(persistedNode.Port, Is.EqualTo(manager.ManagedNode.Port)); + Assert.That(persistedNode.Host, Is.EqualTo(manager.ManagedNode.Host)); + Assert.That(persistedNode.Reputation, Is.EqualTo(manager.NodeStats.CurrentNodeReputation(utcNow))); + } + } - private INodeLifecycleManager CreateLifecycleManager(Node node) + [Test] + public void Can_store_peers() + { + var persistedPeers = _storage.GetPersistedNodes(); + Assert.That(persistedPeers.Length, Is.EqualTo(0)); + + var nodes = new[] { - INodeLifecycleManager manager = Substitute.For(); - manager.ManagedNode.Returns(node); - manager.NodeStats.Returns(new NodeStatsLight(node) - { - CurrentPersistedNodeReputation = node.Port - }); - - return manager; + new Node(TestItem.PublicKeyA, "192.1.1.1", 3441), + new Node(TestItem.PublicKeyB, "192.1.1.2", 3442), + new Node(TestItem.PublicKeyC, "192.1.1.3", 3443), + new Node(TestItem.PublicKeyD, "192.1.1.4", 3444), + new Node(TestItem.PublicKeyE, "192.1.1.5", 3445) + }; + + var peers = nodes.Select(x => new NetworkNode(x.Id, x.Host, x.Port, 0L)).ToArray(); + + _storage.StartBatch(); + _storage.UpdateNodes(peers); + _storage.Commit(); + + persistedPeers = _storage.GetPersistedNodes(); + foreach (NetworkNode peer in peers) + { + NetworkNode persistedNode = persistedPeers.FirstOrDefault(x => x.NodeId.Equals(peer.NodeId)); + Assert.That(persistedNode, Is.Not.Null); + Assert.That(persistedNode.Port, Is.EqualTo(peer.Port)); + Assert.That(persistedNode.Host, Is.EqualTo(peer.Host)); + Assert.That(persistedNode.Reputation, Is.EqualTo(peer.Reputation)); } - [Test] - public void Can_store_discovery_nodes() + _storage.StartBatch(); + _storage.RemoveNode(peers.First().NodeId); + _storage.Commit(); + + persistedPeers = _storage.GetPersistedNodes(); + foreach (NetworkNode peer in peers.Take(1)) { - var persistedNodes = _storage.GetPersistedNodes(); - Assert.That(persistedNodes.Length, Is.EqualTo(0)); - - var nodes = new[] - { - new Node(TestItem.PublicKeyA, "192.1.1.1", 3441), - new Node(TestItem.PublicKeyB, "192.1.1.2", 3442), - new Node(TestItem.PublicKeyC, "192.1.1.3", 3443), - new Node(TestItem.PublicKeyD, "192.1.1.4", 3444), - new Node(TestItem.PublicKeyE, "192.1.1.5", 3445) - }; - - var managers = nodes.Select(CreateLifecycleManager).ToArray(); - DateTime utcNow = DateTime.UtcNow; - var networkNodes = managers.Select(x => new NetworkNode(x.ManagedNode.Id, x.ManagedNode.Host, x.ManagedNode.Port, x.NodeStats.NewPersistedNodeReputation(utcNow))).ToArray(); - - - _storage.StartBatch(); - _storage.UpdateNodes(networkNodes); - _storage.Commit(); - - persistedNodes = _storage.GetPersistedNodes(); - foreach (INodeLifecycleManager manager in managers) - { - NetworkNode persistedNode = persistedNodes.FirstOrDefault(x => x.NodeId.Equals(manager.ManagedNode.Id)); - Assert.IsNotNull(persistedNode); - Assert.That(persistedNode.Port, Is.EqualTo(manager.ManagedNode.Port)); - Assert.That(persistedNode.Host, Is.EqualTo(manager.ManagedNode.Host)); - Assert.That(persistedNode.Reputation, Is.EqualTo(manager.NodeStats.CurrentNodeReputation())); - } - - _storage.StartBatch(); - _storage.RemoveNode(networkNodes.First().NodeId); - _storage.Commit(); - - persistedNodes = _storage.GetPersistedNodes(); - foreach (INodeLifecycleManager manager in managers.Take(1)) - { - NetworkNode persistedNode = persistedNodes.FirstOrDefault(x => x.NodeId.Equals(manager.ManagedNode.Id)); - Assert.IsNull(persistedNode); - } - - utcNow = DateTime.UtcNow; - foreach (INodeLifecycleManager manager in managers.Skip(1)) - { - NetworkNode persistedNode = persistedNodes.FirstOrDefault(x => x.NodeId.Equals(manager.ManagedNode.Id)); - Assert.IsNotNull(persistedNode); - Assert.That(persistedNode.Port, Is.EqualTo(manager.ManagedNode.Port)); - Assert.That(persistedNode.Host, Is.EqualTo(manager.ManagedNode.Host)); - Assert.That(persistedNode.Reputation, Is.EqualTo(manager.NodeStats.CurrentNodeReputation(utcNow))); - } + NetworkNode persistedNode = persistedPeers.FirstOrDefault(x => x.NodeId.Equals(peer.NodeId)); + Assert.That(persistedNode, Is.Null); } - [Test] - public void Can_store_peers() + foreach (NetworkNode peer in peers.Skip(1)) { - var persistedPeers = _storage.GetPersistedNodes(); - Assert.That(persistedPeers.Length, Is.EqualTo(0)); - - var nodes = new[] - { - new Node(TestItem.PublicKeyA, "192.1.1.1", 3441), - new Node(TestItem.PublicKeyB, "192.1.1.2", 3442), - new Node(TestItem.PublicKeyC, "192.1.1.3", 3443), - new Node(TestItem.PublicKeyD, "192.1.1.4", 3444), - new Node(TestItem.PublicKeyE, "192.1.1.5", 3445) - }; - - var peers = nodes.Select(x => new NetworkNode(x.Id, x.Host, x.Port, 0L)).ToArray(); - - _storage.StartBatch(); - _storage.UpdateNodes(peers); - _storage.Commit(); - - persistedPeers = _storage.GetPersistedNodes(); - foreach (NetworkNode peer in peers) - { - NetworkNode persistedNode = persistedPeers.FirstOrDefault(x => x.NodeId.Equals(peer.NodeId)); - Assert.IsNotNull(persistedNode); - Assert.That(persistedNode.Port, Is.EqualTo(peer.Port)); - Assert.That(persistedNode.Host, Is.EqualTo(peer.Host)); - Assert.That(persistedNode.Reputation, Is.EqualTo(peer.Reputation)); - } - - _storage.StartBatch(); - _storage.RemoveNode(peers.First().NodeId); - _storage.Commit(); - - persistedPeers = _storage.GetPersistedNodes(); - foreach (NetworkNode peer in peers.Take(1)) - { - NetworkNode persistedNode = persistedPeers.FirstOrDefault(x => x.NodeId.Equals(peer.NodeId)); - Assert.IsNull(persistedNode); - } - - foreach (NetworkNode peer in peers.Skip(1)) - { - NetworkNode persistedNode = persistedPeers.FirstOrDefault(x => x.NodeId.Equals(peer.NodeId)); - Assert.IsNotNull(persistedNode); - Assert.That(persistedNode.Port, Is.EqualTo(peer.Port)); - Assert.That(persistedNode.Host, Is.EqualTo(peer.Host)); - Assert.That(persistedNode.Reputation, Is.EqualTo(peer.Reputation)); - } + NetworkNode persistedNode = persistedPeers.FirstOrDefault(x => x.NodeId.Equals(peer.NodeId)); + Assert.That(persistedNode, Is.Not.Null); + Assert.That(persistedNode.Port, Is.EqualTo(peer.Port)); + Assert.That(persistedNode.Host, Is.EqualTo(peer.Host)); + Assert.That(persistedNode.Reputation, Is.EqualTo(peer.Reputation)); } } } diff --git a/src/Nethermind/Nethermind.Network.Test/NodeStatsTests.cs b/src/Nethermind/Nethermind.Network.Test/NodeStatsTests.cs index 86d3e048eda..d81e8e4acdc 100644 --- a/src/Nethermind/Nethermind.Network.Test/NodeStatsTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/NodeStatsTests.cs @@ -9,117 +9,115 @@ using Nethermind.Stats.Model; using NUnit.Framework; -namespace Nethermind.Network.Test +namespace Nethermind.Network.Test; + +[Parallelizable(ParallelScope.Self)] +public class NodeStatsTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class NodeStatsTests - { - private INodeStats _nodeStats; - private Node _node; + private INodeStats _nodeStats; + private Node _node; - [SetUp] - public void Initialize() - { - _node = new Node(TestItem.PublicKeyA, "192.1.1.1", 3333); - } + [SetUp] + public void Initialize() + { + _node = new Node(TestItem.PublicKeyA, "192.1.1.1", 3333); + } - [TestCase(TransferSpeedType.Bodies)] - [TestCase(TransferSpeedType.Headers)] - [TestCase(TransferSpeedType.Receipts)] - [TestCase(TransferSpeedType.Latency)] - [TestCase(TransferSpeedType.NodeData)] - public void TransferSpeedCaptureTest(TransferSpeedType speedType) - { - _nodeStats = new NodeStatsLight(_node, 0.5m); - - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 30); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 51); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 140); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 110); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 133); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 51); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 140); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 110); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 133); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 51); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 140); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 110); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 133); - - var av = _nodeStats.GetAverageTransferSpeed(speedType); - Assert.That(av, Is.EqualTo(122)); - - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 0); - _nodeStats.AddTransferSpeedCaptureEvent(speedType, 0); - - av = _nodeStats.GetAverageTransferSpeed(speedType); - Assert.That(av, Is.EqualTo(30)); - } + [TestCase(TransferSpeedType.Bodies)] + [TestCase(TransferSpeedType.Headers)] + [TestCase(TransferSpeedType.Receipts)] + [TestCase(TransferSpeedType.Latency)] + [TestCase(TransferSpeedType.NodeData)] + public void TransferSpeedCaptureTest(TransferSpeedType speedType) + { + _nodeStats = new NodeStatsLight(_node, 0.5m); + + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 30); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 51); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 140); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 110); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 133); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 51); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 140); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 110); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 133); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 51); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 140); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 110); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 133); + + var av = _nodeStats.GetAverageTransferSpeed(speedType); + Assert.That(av, Is.EqualTo(122)); + + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 0); + _nodeStats.AddTransferSpeedCaptureEvent(speedType, 0); + + av = _nodeStats.GetAverageTransferSpeed(speedType); + Assert.That(av, Is.EqualTo(30)); + } - [Test] - public async Task DisconnectDelayTest() - { - _nodeStats = new NodeStatsLight(_node); - - var isConnDelayed = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); - Assert.IsFalse(isConnDelayed.Result, "before disconnect"); - - _nodeStats.AddNodeStatsDisconnectEvent(DisconnectType.Remote, DisconnectReason.Other); - isConnDelayed = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); - Assert.IsTrue(isConnDelayed.Result, "just after disconnect"); - Assert.That(isConnDelayed.DelayReason, Is.EqualTo(NodeStatsEventType.Disconnect)); - await Task.Delay(125); - isConnDelayed = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); - Assert.IsFalse(isConnDelayed.Result, "125ms after disconnect"); - } + [Test] + public async Task DisconnectDelayTest() + { + _nodeStats = new NodeStatsLight(_node); + + var isConnDelayed = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); + Assert.That(isConnDelayed.Result, Is.False, "before disconnect"); + + _nodeStats.AddNodeStatsDisconnectEvent(DisconnectType.Remote, DisconnectReason.Other); + isConnDelayed = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); + Assert.That(isConnDelayed.Result, Is.True, "just after disconnect"); + Assert.That(isConnDelayed.DelayReason, Is.EqualTo(NodeStatsEventType.Disconnect)); + await Task.Delay(125); + isConnDelayed = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); + Assert.That(isConnDelayed.Result, Is.False, "125ms after disconnect"); + } - [TestCase(NodeStatsEventType.Connecting, true)] - [TestCase(NodeStatsEventType.None, false)] - [TestCase(NodeStatsEventType.ConnectionFailedTargetUnreachable, true)] - [TestCase(NodeStatsEventType.ConnectionFailed, true)] - public void DisconnectDelayDueToNodeStatsEvent(NodeStatsEventType eventType, bool connectionDelayed) - { - _nodeStats = new NodeStatsLight(_node); + [TestCase(NodeStatsEventType.Connecting, true)] + [TestCase(NodeStatsEventType.None, false)] + [TestCase(NodeStatsEventType.ConnectionFailedTargetUnreachable, true)] + [TestCase(NodeStatsEventType.ConnectionFailed, true)] + public void DisconnectDelayDueToNodeStatsEvent(NodeStatsEventType eventType, bool connectionDelayed) + { + _nodeStats = new NodeStatsLight(_node); - (bool isConnDelayed, NodeStatsEventType? _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); - Assert.IsFalse(isConnDelayed, "before disconnect"); + (bool isConnDelayed, NodeStatsEventType? _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); + Assert.That(isConnDelayed, Is.False, "before disconnect"); - _nodeStats.AddNodeStatsEvent(eventType); - (isConnDelayed, _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); - isConnDelayed.Should().Be(connectionDelayed); - } + _nodeStats.AddNodeStatsEvent(eventType); + (isConnDelayed, _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); + isConnDelayed.Should().Be(connectionDelayed); + } - [TestCase(DisconnectType.Local, DisconnectReason.UselessPeer, true)] - [TestCase(DisconnectType.Remote, DisconnectReason.ClientQuitting, true)] - public async Task DisconnectDelayDueToDisconnect(DisconnectType disconnectType, DisconnectReason reason, bool connectionDelayed) - { - _nodeStats = new NodeStatsLight(_node); + [TestCase(DisconnectType.Local, DisconnectReason.UselessPeer, true)] + [TestCase(DisconnectType.Remote, DisconnectReason.ClientQuitting, true)] + public async Task DisconnectDelayDueToDisconnect(DisconnectType disconnectType, DisconnectReason reason, bool connectionDelayed) + { + _nodeStats = new NodeStatsLight(_node); - (bool isConnDelayed, NodeStatsEventType? _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); - Assert.IsFalse(isConnDelayed, "before disconnect"); + (bool isConnDelayed, NodeStatsEventType? _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); + Assert.That(isConnDelayed, Is.False, "before disconnect"); - _nodeStats.AddNodeStatsDisconnectEvent(disconnectType, reason); - await Task.Delay(125); // Standard disconnect delay without specific handling - (isConnDelayed, _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); - isConnDelayed.Should().Be(connectionDelayed); - } + _nodeStats.AddNodeStatsDisconnectEvent(disconnectType, reason); + await Task.Delay(125); // Standard disconnect delay without specific handling + (isConnDelayed, _) = _nodeStats.IsConnectionDelayed(DateTime.UtcNow); + isConnDelayed.Should().Be(connectionDelayed); + } - [TestCase(null, DisconnectReason.Other, 0)] - [TestCase(DisconnectType.Local, DisconnectReason.UselessPeer, -10000)] - [TestCase(DisconnectType.Local, DisconnectReason.PeerRefreshFailed, -500)] - [TestCase(DisconnectType.Local, DisconnectReason.BreachOfProtocol, -10000)] - [TestCase(DisconnectType.Remote, DisconnectReason.ClientQuitting, -1000)] - [TestCase(DisconnectType.Remote, DisconnectReason.BreachOfProtocol, -10000)] - public void DisconnectReputation(DisconnectType? disconnectType, DisconnectReason reason, long reputation) + [TestCase(null, DisconnectReason.Other, 0)] + [TestCase(DisconnectType.Local, DisconnectReason.UselessPeer, -10000)] + [TestCase(DisconnectType.Local, DisconnectReason.PeerRefreshFailed, -500)] + [TestCase(DisconnectType.Local, DisconnectReason.BreachOfProtocol, -10000)] + [TestCase(DisconnectType.Remote, DisconnectReason.ClientQuitting, -1000)] + [TestCase(DisconnectType.Remote, DisconnectReason.BreachOfProtocol, -10000)] + public void DisconnectReputation(DisconnectType? disconnectType, DisconnectReason reason, long reputation) + { + _nodeStats = new NodeStatsLight(_node); + if (disconnectType is not null) { - _nodeStats = new NodeStatsLight(_node); - if (disconnectType is not null) - { - _nodeStats.AddNodeStatsDisconnectEvent(disconnectType.Value, reason); - } - - _nodeStats.CurrentNodeReputation().Should().Be(reputation); + _nodeStats.AddNodeStatsDisconnectEvent(disconnectType.Value, reason); } + + _nodeStats.CurrentNodeReputation().Should().Be(reputation); } } diff --git a/src/Nethermind/Nethermind.Network.Test/NodesLoaderTests.cs b/src/Nethermind/Nethermind.Network.Test/NodesLoaderTests.cs index fc3ac709530..cb68afb421d 100644 --- a/src/Nethermind/Nethermind.Network.Test/NodesLoaderTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/NodesLoaderTests.cs @@ -14,90 +14,88 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Network.Test +namespace Nethermind.Network.Test; + +[Parallelizable(ParallelScope.Self)] +public class NodesLoaderTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class NodesLoaderTests - { - private NetworkConfig _networkConfig; - private DiscoveryConfig _discoveryConfig; - private INodeStatsManager _statsManager; - private INetworkStorage _peerStorage; - private NodesLoader _loader; + private NetworkConfig _networkConfig; + private DiscoveryConfig _discoveryConfig; + private INodeStatsManager _statsManager; + private INetworkStorage _peerStorage; + private NodesLoader _loader; - [SetUp] - public void SetUp() - { - _networkConfig = new NetworkConfig(); - _discoveryConfig = new DiscoveryConfig(); - _statsManager = Substitute.For(); - _peerStorage = Substitute.For(); - IRlpxHost rlpxHost = Substitute.For(); - _loader = new NodesLoader(_networkConfig, _statsManager, _peerStorage, rlpxHost, LimboLogs.Instance); - } + [SetUp] + public void SetUp() + { + _networkConfig = new NetworkConfig(); + _discoveryConfig = new DiscoveryConfig(); + _statsManager = Substitute.For(); + _peerStorage = Substitute.For(); + IRlpxHost rlpxHost = Substitute.For(); + _loader = new NodesLoader(_networkConfig, _statsManager, _peerStorage, rlpxHost, LimboLogs.Instance); + } - [Test] - public void When_no_peers_then_no_peers_nada_zero() - { - List peers = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); - Assert.That(peers.Count, Is.EqualTo(0)); - } + [Test] + public void When_no_peers_then_no_peers_nada_zero() + { + List peers = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); + Assert.That(peers.Count, Is.EqualTo(0)); + } - private const string enodesString = enode1String + "," + enode2String; - private const string enode1String = "enode://22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222@51.141.78.53:30303"; - private const string enode2String = "enode://1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111b@52.141.78.53:30303"; + private const string enodesString = enode1String + "," + enode2String; + private const string enode1String = "enode://22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222@51.141.78.53:30303"; + private const string enode2String = "enode://1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111b@52.141.78.53:30303"; - [Test] - public void Can_load_static_nodes() + [Test] + public void Can_load_static_nodes() + { + _networkConfig.StaticPeers = enodesString; + List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); + Assert.That(nodes.Count, Is.EqualTo(2)); + foreach (Node node in nodes) { - _networkConfig.StaticPeers = enodesString; - List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); - Assert.That(nodes.Count, Is.EqualTo(2)); - foreach (Node node in nodes) - { - Assert.True(node.IsStatic); - } + Assert.That(node.IsStatic, Is.True); } + } - [Test] - public void Can_load_bootnodes() + [Test] + public void Can_load_bootnodes() + { + _discoveryConfig.Bootnodes = enodesString; + _networkConfig.Bootnodes = _discoveryConfig.Bootnodes; + List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); + Assert.That(nodes.Count, Is.EqualTo(2)); + foreach (Node node in nodes) { - _discoveryConfig.Bootnodes = enodesString; - _networkConfig.Bootnodes = _discoveryConfig.Bootnodes; - List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); - Assert.That(nodes.Count, Is.EqualTo(2)); - foreach (Node node in nodes) - { - Assert.True(node.IsBootnode); - } + Assert.That(node.IsBootnode, Is.True); } + } - [Test] - public void Can_load_persisted() + [Test] + public void Can_load_persisted() + { + _peerStorage.GetPersistedNodes().Returns(new[] { new NetworkNode(enode1String), new NetworkNode(enode2String) }); + List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); + Assert.That(nodes.Count, Is.EqualTo(2)); + foreach (Node node in nodes) { - _peerStorage.GetPersistedNodes().Returns(new[] { new NetworkNode(enode1String), new NetworkNode(enode2String) }); - List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); - Assert.That(nodes.Count, Is.EqualTo(2)); - foreach (Node node in nodes) - { - Assert.False(node.IsBootnode); - Assert.False(node.IsStatic); - } + Assert.That(node.IsBootnode, Is.False); + Assert.That(node.IsStatic, Is.False); } + } - [Test] - public void Can_load_only_static_nodes() + [Test] + public void Can_load_only_static_nodes() + { + _networkConfig.StaticPeers = enode1String; + _networkConfig.Bootnodes = enode2String; + _networkConfig.OnlyStaticPeers = true; + List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); + Assert.That(nodes.Count, Is.EqualTo(1)); + foreach (Node node in nodes) { - _networkConfig.StaticPeers = enode1String; - _networkConfig.Bootnodes = enode2String; - _networkConfig.OnlyStaticPeers = true; - List nodes = _loader.DiscoverNodes(default).ToBlockingEnumerable().ToList(); - Assert.That(nodes.Count, Is.EqualTo(1)); - foreach (Node node in nodes) - { - Assert.True(node.IsStatic); - } + Assert.That(node.IsStatic, Is.True); } } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs index 9f9803fa5db..99033eace38 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System.Collections.Generic; using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; @@ -10,80 +9,78 @@ using Nethermind.Stats.Model; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P +namespace Nethermind.Network.Test.P2P; + +[Parallelizable(ParallelScope.Self)] +public class HelloMessageSerializerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class HelloMessageSerializerTests + [Test] + public void Can_do_roundtrip() { - [Test] - public void Can_do_roundtrip() - { - using HelloMessage helloMessage = new(); - helloMessage.P2PVersion = 1; - helloMessage.Capabilities = new ArrayPoolList(1) { new(Protocol.Eth, 1) }; - helloMessage.ClientId = "Nethermind/alpha"; - helloMessage.ListenPort = 8002; - helloMessage.NodeId = NetTestVectors.StaticKeyA.PublicKey; + using HelloMessage helloMessage = new(); + helloMessage.P2PVersion = 1; + helloMessage.Capabilities = new ArrayPoolList(1) { new(Protocol.Eth, 1) }; + helloMessage.ClientId = "Nethermind/alpha"; + helloMessage.ListenPort = 8002; + helloMessage.NodeId = NetTestVectors.StaticKeyA.PublicKey; - HelloMessageSerializer serializer = new(); - byte[] serialized = serializer.Serialize(helloMessage); - byte[] expectedBytes = Bytes.FromHexString("f85e01904e65746865726d696e642f616c706861c6c58365746801821f42b840fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877"); + HelloMessageSerializer serializer = new(); + byte[] serialized = serializer.Serialize(helloMessage); + byte[] expectedBytes = Bytes.FromHexString("f85e01904e65746865726d696e642f616c706861c6c58365746801821f42b840fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877"); - Assert.True(Bytes.AreEqual(serialized, expectedBytes), "bytes"); + Assert.That(Bytes.AreEqual(serialized, expectedBytes), Is.True, "bytes"); - using HelloMessage deserialized = serializer.Deserialize(serialized); + using HelloMessage deserialized = serializer.Deserialize(serialized); - Assert.That(deserialized.P2PVersion, Is.EqualTo(helloMessage.P2PVersion)); - Assert.That(deserialized.ClientId, Is.EqualTo(helloMessage.ClientId)); - Assert.That(deserialized.NodeId, Is.EqualTo(helloMessage.NodeId)); - Assert.That(deserialized.ListenPort, Is.EqualTo(helloMessage.ListenPort)); - Assert.That(deserialized.Capabilities.Count, Is.EqualTo(helloMessage.Capabilities.Count)); - Assert.That(deserialized.Capabilities[0].ProtocolCode, Is.EqualTo(helloMessage.Capabilities[0].ProtocolCode)); - Assert.That(deserialized.Capabilities[0].Version, Is.EqualTo(helloMessage.Capabilities[0].Version)); - } + Assert.That(deserialized.P2PVersion, Is.EqualTo(helloMessage.P2PVersion)); + Assert.That(deserialized.ClientId, Is.EqualTo(helloMessage.ClientId)); + Assert.That(deserialized.NodeId, Is.EqualTo(helloMessage.NodeId)); + Assert.That(deserialized.ListenPort, Is.EqualTo(helloMessage.ListenPort)); + Assert.That(deserialized.Capabilities.Count, Is.EqualTo(helloMessage.Capabilities.Count)); + Assert.That(deserialized.Capabilities[0].ProtocolCode, Is.EqualTo(helloMessage.Capabilities[0].ProtocolCode)); + Assert.That(deserialized.Capabilities[0].Version, Is.EqualTo(helloMessage.Capabilities[0].Version)); + } - [Test] - public void Can_deserialize_sample_from_ethereumJ() - { - byte[] helloMessageRaw = Bytes.FromHexString("f87902a5457468657265756d282b2b292f76302e372e392f52656c656173652f4c696e75782f672b2bccc58365746827c583736868018203e0b8401fbf1e41f08078918c9f7b6734594ee56d7f538614f602c71194db0a1af5a77f9b86eb14669fe7a8a46a2dd1b7d070b94e463f4ecd5b337c8b4d31bbf8dd5646"); - HelloMessageSerializer serializer = new(); - using HelloMessage helloMessage = serializer.Deserialize(helloMessageRaw); - Assert.That(helloMessage.ClientId, Is.EqualTo("Ethereum(++)/v0.7.9/Release/Linux/g++"), $"{nameof(HelloMessage.ClientId)}"); - Assert.That(helloMessage.ListenPort, Is.EqualTo(992), $"{nameof(HelloMessage.ListenPort)}"); - Assert.That(helloMessage.P2PVersion, Is.EqualTo(2), $"{nameof(HelloMessage.P2PVersion)}"); - Assert.That(helloMessage.Capabilities.Count, Is.EqualTo(2), $"{nameof(helloMessage.Capabilities.Count)}"); - Assert.That( - helloMessage.NodeId, Is.EqualTo(new PublicKey("1fbf1e41f08078918c9f7b6734594ee56d7f538614f602c71194db0a1af5a77f9b86eb14669fe7a8a46a2dd1b7d070b94e463f4ecd5b337c8b4d31bbf8dd5646")), $"{nameof(HelloMessage.NodeId)}"); - } + [Test] + public void Can_deserialize_sample_from_ethereumJ() + { + byte[] helloMessageRaw = Bytes.FromHexString("f87902a5457468657265756d282b2b292f76302e372e392f52656c656173652f4c696e75782f672b2bccc58365746827c583736868018203e0b8401fbf1e41f08078918c9f7b6734594ee56d7f538614f602c71194db0a1af5a77f9b86eb14669fe7a8a46a2dd1b7d070b94e463f4ecd5b337c8b4d31bbf8dd5646"); + HelloMessageSerializer serializer = new(); + using HelloMessage helloMessage = serializer.Deserialize(helloMessageRaw); + Assert.That(helloMessage.ClientId, Is.EqualTo("Ethereum(++)/v0.7.9/Release/Linux/g++"), $"{nameof(HelloMessage.ClientId)}"); + Assert.That(helloMessage.ListenPort, Is.EqualTo(992), $"{nameof(HelloMessage.ListenPort)}"); + Assert.That(helloMessage.P2PVersion, Is.EqualTo(2), $"{nameof(HelloMessage.P2PVersion)}"); + Assert.That(helloMessage.Capabilities.Count, Is.EqualTo(2), $"{nameof(helloMessage.Capabilities.Count)}"); + Assert.That( + helloMessage.NodeId, Is.EqualTo(new PublicKey("1fbf1e41f08078918c9f7b6734594ee56d7f538614f602c71194db0a1af5a77f9b86eb14669fe7a8a46a2dd1b7d070b94e463f4ecd5b337c8b4d31bbf8dd5646")), $"{nameof(HelloMessage.NodeId)}"); + } - [Test] - public void Can_deserialize_sample_from_eip8_ethereumJ() - { - byte[] helloMessageRaw = Bytes.FromHexString("f87137916b6e6574682f76302e39312f706c616e39cdc5836574683dc6846d6f726b1682270fb840" + - "fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569" + - "bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877c883666f6f836261720304"); - HelloMessageSerializer serializer = new(); - using HelloMessage helloMessage = serializer.Deserialize(helloMessageRaw); - Assert.That(helloMessage.ClientId, Is.EqualTo("kneth/v0.91/plan9"), $"{nameof(HelloMessage.ClientId)}"); - Assert.That(helloMessage.ListenPort, Is.EqualTo(9999), $"{nameof(HelloMessage.ListenPort)}"); - Assert.That(helloMessage.P2PVersion, Is.EqualTo(55), $"{nameof(HelloMessage.P2PVersion)}"); - Assert.That(helloMessage.Capabilities.Count, Is.EqualTo(2), $"{nameof(helloMessage.Capabilities.Count)}"); - Assert.That( - helloMessage.NodeId, Is.EqualTo(new PublicKey("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877")), $"{nameof(HelloMessage.NodeId)}"); - } + [Test] + public void Can_deserialize_sample_from_eip8_ethereumJ() + { + byte[] helloMessageRaw = Bytes.FromHexString("f87137916b6e6574682f76302e39312f706c616e39cdc5836574683dc6846d6f726b1682270fb840" + + "fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569" + + "bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877c883666f6f836261720304"); + HelloMessageSerializer serializer = new(); + using HelloMessage helloMessage = serializer.Deserialize(helloMessageRaw); + Assert.That(helloMessage.ClientId, Is.EqualTo("kneth/v0.91/plan9"), $"{nameof(HelloMessage.ClientId)}"); + Assert.That(helloMessage.ListenPort, Is.EqualTo(9999), $"{nameof(HelloMessage.ListenPort)}"); + Assert.That(helloMessage.P2PVersion, Is.EqualTo(55), $"{nameof(HelloMessage.P2PVersion)}"); + Assert.That(helloMessage.Capabilities.Count, Is.EqualTo(2), $"{nameof(helloMessage.Capabilities.Count)}"); + Assert.That( + helloMessage.NodeId, Is.EqualTo(new PublicKey("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877")), $"{nameof(HelloMessage.NodeId)}"); + } - [Test] - public void Can_deserialize_ethereumJ_eip8_sample() - { - byte[] bytes = Bytes.FromHexString( - "f87137916b6e6574682f76302e39312f706c616e39cdc5836574683dc6846d6f726b1682270fb840" + - "fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569" + - "bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877c883666f6f836261720304"); + [Test] + public void Can_deserialize_ethereumJ_eip8_sample() + { + byte[] bytes = Bytes.FromHexString( + "f87137916b6e6574682f76302e39312f706c616e39cdc5836574683dc6846d6f726b1682270fb840" + + "fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569" + + "bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877c883666f6f836261720304"); - HelloMessageSerializer serializer = new(); - using HelloMessage helloMessage = serializer.Deserialize(bytes); - Assert.That(helloMessage.P2PVersion, Is.EqualTo(55)); - } + HelloMessageSerializer serializer = new(); + using HelloMessage helloMessage = serializer.Deserialize(bytes); + Assert.That(helloMessage.P2PVersion, Is.EqualTo(55)); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs index b42677ed229..44e4ec9709e 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs @@ -4,21 +4,19 @@ using Nethermind.Network.P2P.Messages; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P +namespace Nethermind.Network.Test.P2P; + +[Parallelizable(ParallelScope.Self)] +public class PingMessageSerializerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class PingMessageSerializerTests + [Test] + public void Can_do_roundtrip() { - [Test] - public void Can_do_roundtrip() - { - PingMessage msg = PingMessage.Instance; - PingMessageSerializer serializer = new(); - byte[] serialized = serializer.Serialize(msg); - Assert.That(serialized[0], Is.EqualTo(0xc0)); - using PingMessage deserialized = serializer.Deserialize(serialized); - Assert.NotNull(deserialized); - } + PingMessage msg = PingMessage.Instance; + PingMessageSerializer serializer = new(); + byte[] serialized = serializer.Serialize(msg); + Assert.That(serialized[0], Is.EqualTo(0xc0)); + using PingMessage deserialized = serializer.Deserialize(serialized); + Assert.That(deserialized, Is.Not.Null); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs index 61bd7028c07..642d096437b 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs @@ -4,21 +4,19 @@ using Nethermind.Network.P2P.Messages; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P +namespace Nethermind.Network.Test.P2P; + +[Parallelizable(ParallelScope.Self)] +public class PongMessageSerializerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class PongMessageSerializerTests + [Test] + public void Can_do_roundtrip() { - [Test] - public void Can_do_roundtrip() - { - PongMessage msg = PongMessage.Instance; - PongMessageSerializer serializer = new(); - byte[] serialized = serializer.Serialize(msg); - Assert.That(serialized[0], Is.EqualTo(0xc0)); - using PongMessage deserialized = serializer.Deserialize(serialized); - Assert.NotNull(deserialized); - } + PongMessage msg = PongMessage.Instance; + PongMessageSerializer serializer = new(); + byte[] serialized = serializer.Serialize(msg); + Assert.That(serialized[0], Is.EqualTo(0xc0)); + using PongMessage deserialized = serializer.Deserialize(serialized); + Assert.That(deserialized, Is.Not.Null); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/SessionTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/SessionTests.cs index 3a9a3401b14..95108ed1533 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/SessionTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/SessionTests.cs @@ -14,612 +14,609 @@ using Nethermind.Network.P2P.ProtocolHandlers; using Nethermind.Network.Rlpx; using Nethermind.Stats.Model; -using NonBlocking; using NSubstitute; using NSubstitute.ReceivedExtensions; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P +namespace Nethermind.Network.Test.P2P; + +[Parallelizable(ParallelScope.Self)] +public class SessionTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class SessionTests + private IChannel _channel; + private IChannelHandlerContext _channelHandlerContext; + private IPacketSender _packetSender; + private IChannelPipeline _pipeline; + + [SetUp] + public void SetUp() { - private IChannel _channel; - private IChannelHandlerContext _channelHandlerContext; - private IPacketSender _packetSender; - private IChannelPipeline _pipeline; + _channel = Substitute.For(); + _channelHandlerContext = Substitute.For(); + _pipeline = Substitute.For(); + _channelHandlerContext.Channel.Returns(_channel); + _channel.Pipeline.Returns(_pipeline); + _pipeline.Get().Returns(new ZeroPacketSplitter(LimboLogs.Instance)); + _packetSender = Substitute.For(); + } - [SetUp] - public void SetUp() - { - _channel = Substitute.For(); - _channelHandlerContext = Substitute.For(); - _pipeline = Substitute.For(); - _channelHandlerContext.Channel.Returns(_channel); - _channel.Pipeline.Returns(_pipeline); - _pipeline.Get().Returns(new ZeroPacketSplitter(LimboLogs.Instance)); - _packetSender = Substitute.For(); - } - - [Test] - public void Constructor_sets_the_values() - { - Session session = new(30312, new Node(TestItem.PublicKeyB, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.That(session.RemoteNodeId, Is.EqualTo(TestItem.PublicKeyB)); - Assert.That(session.LocalPort, Is.EqualTo(30312)); - Assert.That(session.Direction, Is.EqualTo(ConnectionDirection.Out)); - Assert.That(session.SessionId, Is.Not.EqualTo(default(Guid))); - } - - [Test] - public void Can_set_remaining_properties() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.PingSender = Substitute.For(); - Assert.NotNull(session.PingSender); - session.ObsoleteRemoteNodeId = TestItem.PublicKeyC; - Assert.NotNull(session.ObsoleteRemoteNodeId); - } - - [Test] - public void Node_can_be_retrieved_only_after_remote_known() - { - Session session = new(30312, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.Throws(() => - { - var node = session.Node; - }); + [Test] + public void Constructor_sets_the_values() + { + Session session = new(30312, new Node(TestItem.PublicKeyB, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.That(session.RemoteNodeId, Is.EqualTo(TestItem.PublicKeyB)); + Assert.That(session.LocalPort, Is.EqualTo(30312)); + Assert.That(session.Direction, Is.EqualTo(ConnectionDirection.Out)); + Assert.That(session.SessionId, Is.Not.EqualTo(default(Guid))); + } - session.Handshake(TestItem.PublicKeyA); - session.RemoteHost = "127.0.0.1"; - session.RemotePort = 30000; - Assert.NotNull(session.Node); - } + [Test] + public void Can_set_remaining_properties() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.PingSender = Substitute.For(); + Assert.That(session.PingSender, Is.Not.Null); + session.ObsoleteRemoteNodeId = TestItem.PublicKeyC; + Assert.That(session.ObsoleteRemoteNodeId, Is.Not.Null); + } - [Test] - public void Throws_when_init_called_before_the_handshake() + [Test] + public void Node_can_be_retrieved_only_after_remote_known() + { + Session session = new(30312, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.Throws(() => { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.Throws(() => session.Init(5, _channelHandlerContext, _packetSender)); - } + var node = session.Node; + }); - [Test] - public void Raises_event_on_init() - { - bool wasCalled = false; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Initialized += (s, e) => wasCalled = true; - - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - Assert.That(session.P2PVersion, Is.EqualTo(5)); - Assert.True(wasCalled); - } - - [Test] - public void Sets_p2p_version_on_init() - { - Session session = new(30312, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyB); - session.Init(4, _channelHandlerContext, _packetSender); - Assert.That(session.P2PVersion, Is.EqualTo(4)); - Assert.That(session.RemoteNodeId, Is.EqualTo(TestItem.PublicKeyB)); - } - - [Test] - public void Raises_event_on_handshake() - { - bool wasCalled = false; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.HandshakeComplete += (s, e) => wasCalled = true; + session.Handshake(TestItem.PublicKeyA); + session.RemoteHost = "127.0.0.1"; + session.RemotePort = 30000; + Assert.That(session.Node, Is.Not.Null); + } + + [Test] + public void Throws_when_init_called_before_the_handshake() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.Throws(() => session.Init(5, _channelHandlerContext, _packetSender)); + } - session.Handshake(TestItem.PublicKeyA); - Assert.True(wasCalled); - } + [Test] + public void Raises_event_on_init() + { + bool wasCalled = false; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Initialized += (s, e) => wasCalled = true; + + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + Assert.That(session.P2PVersion, Is.EqualTo(5)); + Assert.That(wasCalled, Is.True); + } - [Test] - public void Cannot_handshake_twice() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - Assert.Throws(() => session.Handshake(TestItem.PublicKeyA)); - } + [Test] + public void Sets_p2p_version_on_init() + { + Session session = new(30312, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyB); + session.Init(4, _channelHandlerContext, _packetSender); + Assert.That(session.P2PVersion, Is.EqualTo(4)); + Assert.That(session.RemoteNodeId, Is.EqualTo(TestItem.PublicKeyB)); + } - [Test] - public void Cannot_handshake_after_init() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - Assert.Throws(() => session.Handshake(TestItem.PublicKeyA)); - } - - [Test] - public void Cannot_enable_snappy_before_init() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.Throws(() => session.EnableSnappy()); - session.Handshake(TestItem.PublicKeyA); - Assert.Throws(() => session.EnableSnappy()); - session.Init(5, _channelHandlerContext, _packetSender); - } - - [Test] - public void Can_enable_snappy() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - ZeroNettyP2PHandler handler = new(session, LimboLogs.Instance); - _pipeline.Get().Returns(handler); - Assert.False(handler.SnappyEnabled); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.EnableSnappy(); - Assert.True(handler.SnappyEnabled); - _pipeline.Received().Get(); - _pipeline.Received().AddBefore(Arg.Any(), Arg.Any(), Arg.Any()); - } - - [Test] - public void Enabling_snappy_on_disconnected_will_not_cause_trouble() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, "test"); - session.EnableSnappy(); - } - - [Test] - public async Task Adding_protocols_when_disconnecting_will_not_cause_trouble() - { - bool shouldStop = false; - int i = 0; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Action addProtocol = () => + [Test] + public void Raises_event_on_handshake() + { + bool wasCalled = false; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.HandshakeComplete += (s, e) => wasCalled = true; + + session.Handshake(TestItem.PublicKeyA); + Assert.That(wasCalled, Is.True); + } + + [Test] + public void Cannot_handshake_twice() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + Assert.Throws(() => session.Handshake(TestItem.PublicKeyA)); + } + + [Test] + public void Cannot_handshake_after_init() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + Assert.Throws(() => session.Handshake(TestItem.PublicKeyA)); + } + + [Test] + public void Cannot_enable_snappy_before_init() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.Throws(() => session.EnableSnappy()); + session.Handshake(TestItem.PublicKeyA); + Assert.Throws(() => session.EnableSnappy()); + session.Init(5, _channelHandlerContext, _packetSender); + } + + [Test] + public void Can_enable_snappy() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + ZeroNettyP2PHandler handler = new(session, LimboLogs.Instance); + _pipeline.Get().Returns(handler); + Assert.That(handler.SnappyEnabled, Is.False); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.EnableSnappy(); + Assert.That(handler.SnappyEnabled, Is.True); + _pipeline.Received().Get(); + _pipeline.Received().AddBefore(Arg.Any(), Arg.Any(), Arg.Any()); + } + + [Test] + public void Enabling_snappy_on_disconnected_will_not_cause_trouble() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, "test"); + session.EnableSnappy(); + } + + [Test] + public async Task Adding_protocols_when_disconnecting_will_not_cause_trouble() + { + bool shouldStop = false; + int i = 0; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Action addProtocol = () => + { + IProtocolHandler required = Substitute.For(); + required.ProtocolCode.Returns("p2p"); + required.MessageIdSpaceSize.Returns(16); + session.AddProtocolHandler(required); + while (!shouldStop) { - IProtocolHandler required = Substitute.For(); - required.ProtocolCode.Returns("p2p"); - required.MessageIdSpaceSize.Returns(16); - session.AddProtocolHandler(required); - while (!shouldStop) - { - IProtocolHandler protocolHandler = Substitute.For(); - protocolHandler.ProtocolCode.Returns("aa" + i++); - protocolHandler.MessageIdSpaceSize.Returns(10); - session.AddProtocolHandler(protocolHandler); - } - }; - - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - Task task = new(addProtocol); - task.Start(); - - await Task.Delay(20); - session.InitiateDisconnect(DisconnectReason.Other, "test"); - await Task.Delay(10); - shouldStop = true; - } - - [Test] - public void Cannot_init_before_the_handshake() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.Throws(() => session.Init(5, _channelHandlerContext, _packetSender)); - } + IProtocolHandler protocolHandler = Substitute.For(); + protocolHandler.ProtocolCode.Returns("aa" + i++); + protocolHandler.MessageIdSpaceSize.Returns(10); + session.AddProtocolHandler(protocolHandler); + } + }; + + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + Task task = new(addProtocol); + task.Start(); + + await Task.Delay(20); + session.InitiateDisconnect(DisconnectReason.Other, "test"); + await Task.Delay(10); + shouldStop = true; + } - [Test] - public void Is_closing_is_false_when_not_closing() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.False(session.IsClosing); - session.Handshake(TestItem.PublicKeyA); - Assert.False(session.IsClosing); - session.Init(5, _channelHandlerContext, _packetSender); - Assert.False(session.IsClosing); - } - - [Test] - public void Best_state_reached_is_correct() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.That(session.BestStateReached, Is.EqualTo(SessionState.New)); - session.Handshake(TestItem.PublicKeyA); - Assert.That(session.BestStateReached, Is.EqualTo(SessionState.HandshakeComplete)); - session.Init(5, _channelHandlerContext, _packetSender); - Assert.That(session.BestStateReached, Is.EqualTo(SessionState.Initialized)); - } - - [Test] - public void Cannot_dispose_unless_disconnected() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - Assert.Throws(() => session.Dispose()); - session.Init(5, _channelHandlerContext, _packetSender); - Assert.Throws(() => session.Dispose()); - - IProtocolHandler p2p = BuildHandler("p2p", 10); - IProtocolHandler aaa = BuildHandler("aaa", 10); - IProtocolHandler bbb = BuildHandler("bbb", 5); - IProtocolHandler ccc = BuildHandler("ccc", 1); - session.AddProtocolHandler(p2p); - session.AddProtocolHandler(aaa); - session.AddProtocolHandler(bbb); - session.AddProtocolHandler(ccc); - - session.InitiateDisconnect(DisconnectReason.Other, "test"); - session.Dispose(); - - aaa.Received().DisconnectProtocol(DisconnectReason.Other, "test"); - bbb.Received().DisconnectProtocol(DisconnectReason.Other, "test"); - ccc.Received().DisconnectProtocol(DisconnectReason.Other, "test"); - - aaa.Received().Dispose(); - bbb.Received().Dispose(); - ccc.Received().Dispose(); - } - - [Test] - public void Raises_event_on_disconnecting() - { - bool wasCalled = false; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Disconnecting += (s, e) => wasCalled = true; - - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.InitiateDisconnect(DisconnectReason.Other); - Assert.True(wasCalled); - } - - [Test] - public void Raises_event_on_disconnected() - { - bool wasCalled = false; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Disconnected += (s, e) => wasCalled = true; - - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); - Assert.True(wasCalled); - } - - [Test] - public void Disconnects_after_initiating_disconnect() - { - bool wasCalled = false; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Disconnecting += (s, e) => wasCalled = true; - - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.InitiateDisconnect(DisconnectReason.Other); - Assert.True(wasCalled); - Assert.True(session.IsClosing); - } - - [Test] - public void Do_not_disconnects_after_initiating_disconnect_on_static_node() - { - bool wasCalled = false; - Node node = new Node(TestItem.PublicKeyA, "127.0.0.1", 8545); - node.IsStatic = true; - Session session = new(30312, node, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Disconnecting += (s, e) => wasCalled = true; - - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.InitiateDisconnect(DisconnectReason.TooManyPeers); - Assert.False(wasCalled); - Assert.False(session.IsClosing); - } - - [Test] - public void Error_on_channel_when_disconnecting_channels_does_not_prevent_the_event() - { - bool wasCalled = false; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - _channel.DisconnectAsync().Returns(Task.FromException(new Exception())); - session.Disconnected += (s, e) => wasCalled = true; - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); - Assert.True(wasCalled); - } - - [Test] - public void Error_on_context_when_disconnecting_channels_does_not_prevent_the_event() - { - bool wasCalled = false; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - _channelHandlerContext.DisconnectAsync().Returns(Task.FromException(new Exception())); - session.Disconnected += (s, e) => wasCalled = true; - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); - Assert.True(wasCalled); - } - - [Test] - public void Can_disconnect_many_times() - { - int wasCalledTimes = 0; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Disconnecting += (s, e) => wasCalledTimes++; - - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - session.InitiateDisconnect(DisconnectReason.Other); - session.InitiateDisconnect(DisconnectReason.Other); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, "test"); - Assert.That(wasCalledTimes, Is.EqualTo(1)); - } - - [Test] - public void Can_disconnect_before_init() - { - int wasCalledTimes = 0; - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Disconnecting += (s, e) => wasCalledTimes++; - session.Handshake(TestItem.PublicKeyA); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, "test"); - session.Init(5, _channelHandlerContext, _packetSender); - Assert.That(wasCalledTimes, Is.EqualTo(1)); - } - - [Test] - public void On_incoming_sessions_can_fill_remote_id_on_handshake() - { - Session session = new(30312, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyB); - Assert.That(session.RemoteNodeId, Is.EqualTo(TestItem.PublicKeyB)); - } + [Test] + public void Cannot_init_before_the_handshake() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.Throws(() => session.Init(5, _channelHandlerContext, _packetSender)); + } - [Test] - public void Checks_init_arguments() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - Assert.Throws(() => session.Init(5, null, _packetSender), "context"); - Assert.Throws(() => session.Init(5, _channelHandlerContext, null), "packageSender"); - } - - [Test] - public void Can_add_and_disconnect_many_handlers() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - IProtocolHandler aaa = BuildHandler("aaa", 10); - IProtocolHandler bbb = BuildHandler("bbb", 5); - IProtocolHandler ccc = BuildHandler("ccc", 1); - session.AddProtocolHandler(p2p); - session.AddProtocolHandler(aaa); - session.AddProtocolHandler(bbb); - session.AddProtocolHandler(ccc); - session.InitiateDisconnect(DisconnectReason.Other, "test"); - aaa.Received().DisconnectProtocol(DisconnectReason.Other, "test"); - bbb.Received().DisconnectProtocol(DisconnectReason.Other, "test"); - ccc.Received().DisconnectProtocol(DisconnectReason.Other, "test"); - } - - [Test] - public void Cannot_add_handlers_before_p2p() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler aaa = BuildHandler("aaa", 10); - Assert.Throws(() => session.AddProtocolHandler(aaa)); - } - - [Test] - public void Cannot_add_handler_twice() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - IProtocolHandler p2pAgain = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); - Assert.Throws(() => session.AddProtocolHandler(p2pAgain)); - } - - private IProtocolHandler BuildHandler(string code, int spaceSize) - { - IProtocolHandler handler = Substitute.For(); - handler.ProtocolCode.Returns(code); - handler.MessageIdSpaceSize.Returns(spaceSize); - return handler; - } - - [Test] - [NonParallelizable] - public void Can_deliver_messages() - { - Metrics.P2PBytesSent = 0; - - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - IProtocolHandler aaa = BuildHandler("aaa", 10); - IProtocolHandler bbb = BuildHandler("bbb", 5); - IProtocolHandler ccc = BuildHandler("ccc", 1); - session.AddProtocolHandler(p2p); - session.AddProtocolHandler(aaa); - session.AddProtocolHandler(bbb); - session.AddProtocolHandler(ccc); - - _packetSender.Enqueue(PingMessage.Instance).Returns(10); - session.DeliverMessage(PingMessage.Instance); - _packetSender.Received().Enqueue(PingMessage.Instance); - - Metrics.P2PBytesSent.Should().Be(10); - } - - [Test] - public void Cannot_deliver_before_initialized() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.Throws(() => session.DeliverMessage(PingMessage.Instance)); - session.Handshake(TestItem.PublicKeyA); - Assert.Throws(() => session.DeliverMessage(PingMessage.Instance)); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); - } - - [Test] - public void Cannot_receive_before_initialized() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - Assert.Throws(() => session.ReceiveMessage(new Packet("p2p", 1, Array.Empty()))); - session.Handshake(TestItem.PublicKeyA); - Assert.Throws(() => session.ReceiveMessage(new Packet("p2p", 1, Array.Empty()))); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); - } - - [Test] - public void Stops_delivering_messages_after_disconnect() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); + [Test] + public void Is_closing_is_false_when_not_closing() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.That(session.IsClosing, Is.False); + session.Handshake(TestItem.PublicKeyA); + Assert.That(session.IsClosing, Is.False); + session.Init(5, _channelHandlerContext, _packetSender); + Assert.That(session.IsClosing, Is.False); + } - session.InitiateDisconnect(DisconnectReason.Other); + [Test] + public void Best_state_reached_is_correct() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.That(session.BestStateReached, Is.EqualTo(SessionState.New)); + session.Handshake(TestItem.PublicKeyA); + Assert.That(session.BestStateReached, Is.EqualTo(SessionState.HandshakeComplete)); + session.Init(5, _channelHandlerContext, _packetSender); + Assert.That(session.BestStateReached, Is.EqualTo(SessionState.Initialized)); + } - session.DeliverMessage(PingMessage.Instance); - _packetSender.DidNotReceive().Enqueue(Arg.Any()); - } + [Test] + public void Cannot_dispose_unless_disconnected() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + Assert.Throws(() => session.Dispose()); + session.Init(5, _channelHandlerContext, _packetSender); + Assert.Throws(() => session.Dispose()); + + IProtocolHandler p2p = BuildHandler("p2p", 10); + IProtocolHandler aaa = BuildHandler("aaa", 10); + IProtocolHandler bbb = BuildHandler("bbb", 5); + IProtocolHandler ccc = BuildHandler("ccc", 1); + session.AddProtocolHandler(p2p); + session.AddProtocolHandler(aaa); + session.AddProtocolHandler(bbb); + session.AddProtocolHandler(ccc); + + session.InitiateDisconnect(DisconnectReason.Other, "test"); + session.Dispose(); + + aaa.Received().DisconnectProtocol(DisconnectReason.Other, "test"); + bbb.Received().DisconnectProtocol(DisconnectReason.Other, "test"); + ccc.Received().DisconnectProtocol(DisconnectReason.Other, "test"); + + aaa.Received().Dispose(); + bbb.Received().Dispose(); + ccc.Received().Dispose(); + } - [Test] - public void Stops_receiving_messages_after_disconnect() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); + [Test] + public void Raises_event_on_disconnecting() + { + bool wasCalled = false; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Disconnecting += (s, e) => wasCalled = true; + + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.InitiateDisconnect(DisconnectReason.Other); + Assert.That(wasCalled, Is.True); + } - session.InitiateDisconnect(DisconnectReason.Other); + [Test] + public void Raises_event_on_disconnected() + { + bool wasCalled = false; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Disconnected += (s, e) => wasCalled = true; + + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); + Assert.That(wasCalled, Is.True); + } - session.ReceiveMessage(new Packet("p2p", 3, Array.Empty())); - p2p.DidNotReceive().HandleMessage(Arg.Is(p => p.Protocol == "p2p" && p.PacketType == 3)); - } + [Test] + public void Disconnects_after_initiating_disconnect() + { + bool wasCalled = false; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Disconnecting += (s, e) => wasCalled = true; + + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.InitiateDisconnect(DisconnectReason.Other); + Assert.That(wasCalled, Is.True); + Assert.That(session.IsClosing, Is.True); + } - [Test] - public void Delay_disconnect_until_after_initialize() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.InitiateDisconnect(DisconnectReason.TooManyPeers); + [Test] + public void Do_not_disconnects_after_initiating_disconnect_on_static_node() + { + bool wasCalled = false; + Node node = new Node(TestItem.PublicKeyA, "127.0.0.1", 8545); + node.IsStatic = true; + Session session = new(30312, node, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Disconnecting += (s, e) => wasCalled = true; + + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.InitiateDisconnect(DisconnectReason.TooManyPeers); + Assert.That(wasCalled, Is.False); + Assert.That(session.IsClosing, Is.False); + } - IProtocolHandler p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); + [Test] + public void Error_on_channel_when_disconnecting_channels_does_not_prevent_the_event() + { + bool wasCalled = false; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + _channel.DisconnectAsync().Returns(Task.FromException(new Exception())); + session.Disconnected += (s, e) => wasCalled = true; + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); + Assert.That(wasCalled, Is.True); + } - session.Init(5, _channelHandlerContext, _packetSender); + [Test] + public void Error_on_context_when_disconnecting_channels_does_not_prevent_the_event() + { + bool wasCalled = false; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + _channelHandlerContext.DisconnectAsync().Returns(Task.FromException(new Exception())); + session.Disconnected += (s, e) => wasCalled = true; + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); + Assert.That(wasCalled, Is.True); + } - p2p.Received().DisconnectProtocol(Arg.Any(), Arg.Any()); - } + [Test] + public void Can_disconnect_many_times() + { + int wasCalledTimes = 0; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Disconnecting += (s, e) => wasCalledTimes++; + + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + session.InitiateDisconnect(DisconnectReason.Other); + session.InitiateDisconnect(DisconnectReason.Other); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, "test"); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, "test"); + Assert.That(wasCalledTimes, Is.EqualTo(1)); + } - [Test] - public void Protocol_handler_can_send_message_on_disconnect() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.InitiateDisconnect(DisconnectReason.TooManyPeers); - - IProtocolHandler p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); - - p2p.When(it => it.DisconnectProtocol(Arg.Any(), Arg.Any())) - .Do((_) => - { - session.DeliverMessage(PingMessage.Instance); - }); - - session.Init(5, _channelHandlerContext, _packetSender); - session.InitiateDisconnect(DisconnectReason.Other); - - _packetSender - .Received() - .Enqueue(PingMessage.Instance); - } - - [Test, Retry(3)] - [Parallelizable(ParallelScope.None)] // It touches global metrics - public void Can_receive_messages() - { - Metrics.P2PBytesReceived = 0; + [Test] + public void Can_disconnect_before_init() + { + int wasCalledTimes = 0; + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Disconnecting += (s, e) => wasCalledTimes++; + session.Handshake(TestItem.PublicKeyA); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, "test"); + session.Init(5, _channelHandlerContext, _packetSender); + Assert.That(wasCalledTimes, Is.EqualTo(1)); + } + + [Test] + public void On_incoming_sessions_can_fill_remote_id_on_handshake() + { + Session session = new(30312, _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyB); + Assert.That(session.RemoteNodeId, Is.EqualTo(TestItem.PublicKeyB)); + } - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - IProtocolHandler aaa = BuildHandler("aaa", 10); - IProtocolHandler bbb = BuildHandler("bbb", 5); - IProtocolHandler ccc = BuildHandler("ccc", 1); - session.AddProtocolHandler(p2p); - session.AddProtocolHandler(aaa); - session.AddProtocolHandler(bbb); - session.AddProtocolHandler(ccc); + [Test] + public void Checks_init_arguments() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + Assert.Throws(() => session.Init(5, null, _packetSender), "context"); + Assert.Throws(() => session.Init(5, _channelHandlerContext, null), "packageSender"); + } - byte[] data = new byte[10]; - session.ReceiveMessage(new Packet("---", 3, data)); - p2p.Received().HandleMessage(Arg.Is(p => p.Protocol == "p2p" && p.PacketType == 3)); + [Test] + public void Can_add_and_disconnect_many_handlers() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + IProtocolHandler aaa = BuildHandler("aaa", 10); + IProtocolHandler bbb = BuildHandler("bbb", 5); + IProtocolHandler ccc = BuildHandler("ccc", 1); + session.AddProtocolHandler(p2p); + session.AddProtocolHandler(aaa); + session.AddProtocolHandler(bbb); + session.AddProtocolHandler(ccc); + session.InitiateDisconnect(DisconnectReason.Other, "test"); + aaa.Received().DisconnectProtocol(DisconnectReason.Other, "test"); + bbb.Received().DisconnectProtocol(DisconnectReason.Other, "test"); + ccc.Received().DisconnectProtocol(DisconnectReason.Other, "test"); + } - session.ReceiveMessage(new Packet("---", 11, data)); - aaa.Received().HandleMessage(Arg.Is(p => p.Protocol == "aaa" && p.PacketType == 1)); + [Test] + public void Cannot_add_handlers_before_p2p() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler aaa = BuildHandler("aaa", 10); + Assert.Throws(() => session.AddProtocolHandler(aaa)); + } - session.ReceiveMessage(new Packet("---", 21, data)); - bbb.Received().HandleMessage(Arg.Is(p => p.Protocol == "bbb" && p.PacketType == 1)); + [Test] + public void Cannot_add_handler_twice() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + IProtocolHandler p2pAgain = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + Assert.Throws(() => session.AddProtocolHandler(p2pAgain)); + } - session.ReceiveMessage(new Packet("---", 25, data)); - ccc.Received().HandleMessage(Arg.Is(p => p.Protocol == "ccc" && p.PacketType == 0)); + private IProtocolHandler BuildHandler(string code, int spaceSize) + { + IProtocolHandler handler = Substitute.For(); + handler.ProtocolCode.Returns(code); + handler.MessageIdSpaceSize.Returns(spaceSize); + return handler; + } - session.ReceiveMessage(new Packet("---", 100, data)); + [Test] + [NonParallelizable] + public void Can_deliver_messages() + { + Metrics.P2PBytesSent = 0; + + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + IProtocolHandler aaa = BuildHandler("aaa", 10); + IProtocolHandler bbb = BuildHandler("bbb", 5); + IProtocolHandler ccc = BuildHandler("ccc", 1); + session.AddProtocolHandler(p2p); + session.AddProtocolHandler(aaa); + session.AddProtocolHandler(bbb); + session.AddProtocolHandler(ccc); + + _packetSender.Enqueue(PingMessage.Instance).Returns(10); + session.DeliverMessage(PingMessage.Instance); + _packetSender.Received().Enqueue(PingMessage.Instance); + + Metrics.P2PBytesSent.Should().Be(10); + } - Metrics.P2PBytesReceived.Should().Be(data.Length * 5); - } + [Test] + public void Cannot_deliver_before_initialized() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.Throws(() => session.DeliverMessage(PingMessage.Instance)); + session.Handshake(TestItem.PublicKeyA); + Assert.Throws(() => session.DeliverMessage(PingMessage.Instance)); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + } - [Test] - public void Updates_local_and_remote_metrics_on_disconnects() - { - Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, new MetricsDisconnectsAnalyzer(), LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - IProtocolHandler p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); - - long beforeLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - long beforeRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, string.Empty); - long afterLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - long afterRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - Assert.That(afterLocal, Is.EqualTo(beforeLocal + 1)); - Assert.That(afterRemote, Is.EqualTo(beforeRemote)); - - session = new Session(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, new MetricsDisconnectsAnalyzer(), LimboLogs.Instance); - session.Handshake(TestItem.PublicKeyA); - session.Init(5, _channelHandlerContext, _packetSender); - p2p = BuildHandler("p2p", 10); - session.AddProtocolHandler(p2p); - - beforeLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - beforeRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, string.Empty); - afterLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - afterRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); - Assert.That(afterLocal, Is.EqualTo(beforeLocal)); - Assert.That(afterRemote, Is.EqualTo(beforeRemote + 1)); - } + [Test] + public void Cannot_receive_before_initialized() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + Assert.Throws(() => session.ReceiveMessage(new Packet("p2p", 1, Array.Empty()))); + session.Handshake(TestItem.PublicKeyA); + Assert.Throws(() => session.ReceiveMessage(new Packet("p2p", 1, Array.Empty()))); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + } + + [Test] + public void Stops_delivering_messages_after_disconnect() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + + session.InitiateDisconnect(DisconnectReason.Other); + + session.DeliverMessage(PingMessage.Instance); + _packetSender.DidNotReceive().Enqueue(Arg.Any()); + } + + [Test] + public void Stops_receiving_messages_after_disconnect() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + + session.InitiateDisconnect(DisconnectReason.Other); + + session.ReceiveMessage(new Packet("p2p", 3, Array.Empty())); + p2p.DidNotReceive().HandleMessage(Arg.Is(p => p.Protocol == "p2p" && p.PacketType == 3)); + } + + [Test] + public void Delay_disconnect_until_after_initialize() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.InitiateDisconnect(DisconnectReason.TooManyPeers); + + IProtocolHandler p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + + session.Init(5, _channelHandlerContext, _packetSender); + + p2p.Received().DisconnectProtocol(Arg.Any(), Arg.Any()); + } + + [Test] + public void Protocol_handler_can_send_message_on_disconnect() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.InitiateDisconnect(DisconnectReason.TooManyPeers); + + IProtocolHandler p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + + p2p.When(it => it.DisconnectProtocol(Arg.Any(), Arg.Any())) + .Do((_) => + { + session.DeliverMessage(PingMessage.Instance); + }); + + session.Init(5, _channelHandlerContext, _packetSender); + session.InitiateDisconnect(DisconnectReason.Other); + + _packetSender + .Received() + .Enqueue(PingMessage.Instance); + } + + [Test, Retry(3)] + [Parallelizable(ParallelScope.None)] // It touches global metrics + public void Can_receive_messages() + { + Metrics.P2PBytesReceived = 0; + + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + IProtocolHandler aaa = BuildHandler("aaa", 10); + IProtocolHandler bbb = BuildHandler("bbb", 5); + IProtocolHandler ccc = BuildHandler("ccc", 1); + session.AddProtocolHandler(p2p); + session.AddProtocolHandler(aaa); + session.AddProtocolHandler(bbb); + session.AddProtocolHandler(ccc); + + byte[] data = new byte[10]; + session.ReceiveMessage(new Packet("---", 3, data)); + p2p.Received().HandleMessage(Arg.Is(p => p.Protocol == "p2p" && p.PacketType == 3)); + + session.ReceiveMessage(new Packet("---", 11, data)); + aaa.Received().HandleMessage(Arg.Is(p => p.Protocol == "aaa" && p.PacketType == 1)); + + session.ReceiveMessage(new Packet("---", 21, data)); + bbb.Received().HandleMessage(Arg.Is(p => p.Protocol == "bbb" && p.PacketType == 1)); + + session.ReceiveMessage(new Packet("---", 25, data)); + ccc.Received().HandleMessage(Arg.Is(p => p.Protocol == "ccc" && p.PacketType == 0)); + + session.ReceiveMessage(new Packet("---", 100, data)); + + Metrics.P2PBytesReceived.Should().Be(data.Length * 5); + } + + [Test] + public void Updates_local_and_remote_metrics_on_disconnects() + { + Session session = new(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, new MetricsDisconnectsAnalyzer(), LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + IProtocolHandler p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + + long beforeLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + long beforeRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Local, string.Empty); + long afterLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + long afterRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + Assert.That(afterLocal, Is.EqualTo(beforeLocal + 1)); + Assert.That(afterRemote, Is.EqualTo(beforeRemote)); + + session = new Session(30312, new Node(TestItem.PublicKeyA, "127.0.0.1", 8545), _channel, new MetricsDisconnectsAnalyzer(), LimboLogs.Instance); + session.Handshake(TestItem.PublicKeyA); + session.Init(5, _channelHandlerContext, _packetSender); + p2p = BuildHandler("p2p", 10); + session.AddProtocolHandler(p2p); + + beforeLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + beforeRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + session.MarkDisconnected(DisconnectReason.Other, DisconnectType.Remote, string.Empty); + afterLocal = Network.Metrics.LocalDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + afterRemote = Network.Metrics.RemoteDisconnectsTotal.GetValueOrDefault(DisconnectReason.Other); + Assert.That(afterLocal, Is.EqualTo(beforeLocal)); + Assert.That(afterRemote, Is.EqualTo(beforeRemote + 1)); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockHeadersMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockHeadersMessageSerializerTests.cs index 2594f9d5f57..c5e17a767f4 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockHeadersMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockHeadersMessageSerializerTests.cs @@ -9,63 +9,62 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V62 +namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V62; + +[Parallelizable(ParallelScope.All)] +public class BlockHeadersMessageSerializerTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class BlockHeadersMessageSerializerTests + [Test] + public void Roundtrip() { - [Test] - public void Roundtrip() - { - using BlockHeadersMessage message = new(); - message.BlockHeaders = new ArrayPoolList(1) { Build.A.BlockHeader.TestObject }; + using BlockHeadersMessage message = new(); + message.BlockHeaders = new ArrayPoolList(1) { Build.A.BlockHeader.TestObject }; - BlockHeadersMessageSerializer serializer = new(); - byte[] bytes = serializer.Serialize(message); - byte[] expectedBytes = Bytes.FromHexString("f901fcf901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8"); + BlockHeadersMessageSerializer serializer = new(); + byte[] bytes = serializer.Serialize(message); + byte[] expectedBytes = Bytes.FromHexString("f901fcf901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8"); - Assert.That(expectedBytes.ToHexString(), Is.EqualTo(bytes.ToHexString()), "bytes"); + Assert.That(expectedBytes.ToHexString(), Is.EqualTo(bytes.ToHexString()), "bytes"); - using BlockHeadersMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.BlockHeaders.Count, Is.EqualTo(message.BlockHeaders.Count), "length"); - Assert.That(deserialized.BlockHeaders[0].Hash, Is.EqualTo(message.BlockHeaders[0].Hash), "hash"); + using BlockHeadersMessage deserialized = serializer.Deserialize(bytes); + Assert.That(deserialized.BlockHeaders.Count, Is.EqualTo(message.BlockHeaders.Count), "length"); + Assert.That(deserialized.BlockHeaders[0].Hash, Is.EqualTo(message.BlockHeaders[0].Hash), "hash"); - SerializerTester.TestZero(serializer, message); - } + SerializerTester.TestZero(serializer, message); + } - [Test] - public void Roundtrip_nulls() - { - using BlockHeadersMessage message = new(); - message.BlockHeaders = new ArrayPoolList(2) { Build.A.BlockHeader.TestObject, null }; + [Test] + public void Roundtrip_nulls() + { + using BlockHeadersMessage message = new(); + message.BlockHeaders = new ArrayPoolList(2) { Build.A.BlockHeader.TestObject, null }; - BlockHeadersMessageSerializer serializer = new(); - byte[] bytes = serializer.Serialize(message); + BlockHeadersMessageSerializer serializer = new(); + byte[] bytes = serializer.Serialize(message); - using BlockHeadersMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.BlockHeaders.Count, Is.EqualTo(message.BlockHeaders.Count), "length"); - Assert.That(deserialized.BlockHeaders[0].Hash, Is.EqualTo(message.BlockHeaders[0].Hash), "hash"); - Assert.Null(message.BlockHeaders[1]); + using BlockHeadersMessage deserialized = serializer.Deserialize(bytes); + Assert.That(deserialized.BlockHeaders.Count, Is.EqualTo(message.BlockHeaders.Count), "length"); + Assert.That(deserialized.BlockHeaders[0].Hash, Is.EqualTo(message.BlockHeaders[0].Hash), "hash"); + Assert.That(message.BlockHeaders[1], Is.Null); - SerializerTester.TestZero(serializer, message); - } + SerializerTester.TestZero(serializer, message); + } - [Test] - public void Can_decode_249_bloom() - { - Rlp rlp = new(Bytes.FromHexString("f910d6f90215a08b8c20b1111b5878303659d6d031410dae6b47585fe234e20b938dbaf6a9923aa0866fb183df639e433c5384d72dd1c35b35211369ae422bf579ff7afe2fb34c4e9428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a04ba55dee2c3db4c86330c11d41d344361c31969c40837d4a522b43ebd0c19b82a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850491f9d09282011f821388808455ba455d99476574682f76312e302e302f6c696e75782f676f312e342e32a00b7569d0f36a9f4fde37f77eca6a28a63e1492a92424b72e22de6f3410053c3f886647bd7a7a538ae8f90215a0295e34c3e8e8c2a6c47c57fbbca73b4e5e850d520c1edb3beb14c0fa4c947f26a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a0834a40551ab921955a21ae89a496fb66a421cff1e2b37540c0b77866a99593eea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008504928c0fcc820120821388808455ba455e99476574682f76312e302e302f6c696e75782f676f312e342e32a0db320302cb2151d8e4f5cdcfe151a9bd5d24aa42bf7dcb13bb6d478fd1a21a0888c4492cd95dac48a7f9021ca062e0387d05aff1fe68908a4b1fe16ec77404c0ea47eae69fff7de169bea22fc3a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347945088d623ba0fcf0131e0897a91734a4d83596aa0a00599a594fee6857c194abfc7527f5d2fa640a402db82df333651160fb0312c6da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008504931e614d820121821388808455ba455fa0476574682f76312e302e302d66633739643332642f6c696e75782f676f312e34a0cf66152a3b185b7279266af8f58a456d4c306d3beb9de4e6322e54fa86b575988861e28007c09d5da5f90215a0db2ca8e376e9cf43b22247f8667d2f442a372cbf69eb0c9e2092c26cb181d9cea0bcfd748f0c3f3df45082eb8e9df9a374b9ee5c7452cde33cf3e9e66e777e5c739428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a0baef66ae9f81dd8c760311b4c8fc40f778c79adfb222b7db2296755c62fe160ba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850493b0c519820122821388808455ba456299476574682f76312e302e302f6c696e75782f676f312e342e32a0e2d67432faa69b6e8becc228a2263f0d6170304bc7cabb424b0c9a025bfcd8e788dd0fdf364b69c838f9021aa07abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bb7b8287f3f0a933474a79eae42cbca977791171a03fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850494433b31820123821388808455ba45649e476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32a0943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea08829d6547c196e00e0f9021aa0c5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bb7b8287f3f0a933474a79eae42cbca977791171a0a81ba06268f6c38a31f013533919865c9ef9bf99000be82448b3636854796d78a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850494d5c398820124821388808455ba45689e476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32a0e3316e17ecdaf6bd28a80d5d8d7d0d949db4a8a270e47b1f81d2483f714145af88d3c2b61d983eadaaf9021aa0feeb6c4b368a1b1e2352a1294d8639c30ae0a80649774b27affafb630c374d4ea08f3b8f2291c71ab534edfa0f12152030a37d39395c645d0a38a7e125f6715a5f94bb7b8287f3f0a933474a79eae42cbca977791171a0698bf7bd1e9944e79e2e336cd7ad10b6ebc6d3e59b1e60bed04ad0620409854ba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850495685e50820125821388808455ba45699e476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32a0248937d2c7e78b06f22f094df2b31924a585206b1e5272a5282704359bc173af88a9be835214328debf90215a075a4bcc34789e630cf090c35e963509ec722536691abffb92e0f39681ec6a485a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a0e38d24a17a68dc6ce7d9de9e5dfc717940520440fd5715a6956f8e551655eb42a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850495fb0b5b820126821388808455ba456a99476574682f76312e302e302f6c696e75782f676f312e342e32a09fa5dbef8aacbd9d07a070621f42ccc84e66b188e091583013a7eeba7a67b7fd882729cad648f253bd")); - // f9 01 02 81 7f 0 0 0 ... 0 - // 249 -> 258 -> 129 127 0 0 0 ... 0 (strange?) - BlockHeadersMessageSerializer serializer = new(); - using BlockHeadersMessage message = serializer.Deserialize(rlp.Bytes); - Assert.That(message.BlockHeaders.Count, Is.EqualTo(8)); - } + [Test] + public void Can_decode_249_bloom() + { + Rlp rlp = new(Bytes.FromHexString("f910d6f90215a08b8c20b1111b5878303659d6d031410dae6b47585fe234e20b938dbaf6a9923aa0866fb183df639e433c5384d72dd1c35b35211369ae422bf579ff7afe2fb34c4e9428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a04ba55dee2c3db4c86330c11d41d344361c31969c40837d4a522b43ebd0c19b82a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850491f9d09282011f821388808455ba455d99476574682f76312e302e302f6c696e75782f676f312e342e32a00b7569d0f36a9f4fde37f77eca6a28a63e1492a92424b72e22de6f3410053c3f886647bd7a7a538ae8f90215a0295e34c3e8e8c2a6c47c57fbbca73b4e5e850d520c1edb3beb14c0fa4c947f26a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a0834a40551ab921955a21ae89a496fb66a421cff1e2b37540c0b77866a99593eea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008504928c0fcc820120821388808455ba455e99476574682f76312e302e302f6c696e75782f676f312e342e32a0db320302cb2151d8e4f5cdcfe151a9bd5d24aa42bf7dcb13bb6d478fd1a21a0888c4492cd95dac48a7f9021ca062e0387d05aff1fe68908a4b1fe16ec77404c0ea47eae69fff7de169bea22fc3a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347945088d623ba0fcf0131e0897a91734a4d83596aa0a00599a594fee6857c194abfc7527f5d2fa640a402db82df333651160fb0312c6da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008504931e614d820121821388808455ba455fa0476574682f76312e302e302d66633739643332642f6c696e75782f676f312e34a0cf66152a3b185b7279266af8f58a456d4c306d3beb9de4e6322e54fa86b575988861e28007c09d5da5f90215a0db2ca8e376e9cf43b22247f8667d2f442a372cbf69eb0c9e2092c26cb181d9cea0bcfd748f0c3f3df45082eb8e9df9a374b9ee5c7452cde33cf3e9e66e777e5c739428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a0baef66ae9f81dd8c760311b4c8fc40f778c79adfb222b7db2296755c62fe160ba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850493b0c519820122821388808455ba456299476574682f76312e302e302f6c696e75782f676f312e342e32a0e2d67432faa69b6e8becc228a2263f0d6170304bc7cabb424b0c9a025bfcd8e788dd0fdf364b69c838f9021aa07abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bb7b8287f3f0a933474a79eae42cbca977791171a03fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850494433b31820123821388808455ba45649e476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32a0943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea08829d6547c196e00e0f9021aa0c5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bb7b8287f3f0a933474a79eae42cbca977791171a0a81ba06268f6c38a31f013533919865c9ef9bf99000be82448b3636854796d78a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850494d5c398820124821388808455ba45689e476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32a0e3316e17ecdaf6bd28a80d5d8d7d0d949db4a8a270e47b1f81d2483f714145af88d3c2b61d983eadaaf9021aa0feeb6c4b368a1b1e2352a1294d8639c30ae0a80649774b27affafb630c374d4ea08f3b8f2291c71ab534edfa0f12152030a37d39395c645d0a38a7e125f6715a5f94bb7b8287f3f0a933474a79eae42cbca977791171a0698bf7bd1e9944e79e2e336cd7ad10b6ebc6d3e59b1e60bed04ad0620409854ba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850495685e50820125821388808455ba45699e476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32a0248937d2c7e78b06f22f094df2b31924a585206b1e5272a5282704359bc173af88a9be835214328debf90215a075a4bcc34789e630cf090c35e963509ec722536691abffb92e0f39681ec6a485a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479428921e4e2c9d84f4c0f0c0ceb991f45751a0fe93a0e38d24a17a68dc6ce7d9de9e5dfc717940520440fd5715a6956f8e551655eb42a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90102817f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850495fb0b5b820126821388808455ba456a99476574682f76312e302e302f6c696e75782f676f312e342e32a09fa5dbef8aacbd9d07a070621f42ccc84e66b188e091583013a7eeba7a67b7fd882729cad648f253bd")); + // f9 01 02 81 7f 0 0 0 ... 0 + // 249 -> 258 -> 129 127 0 0 0 ... 0 (strange?) + BlockHeadersMessageSerializer serializer = new(); + using BlockHeadersMessage message = serializer.Deserialize(rlp.Bytes); + Assert.That(message.BlockHeaders.Count, Is.EqualTo(8)); + } - [Test] - public void To_string() - { - using BlockHeadersMessage newBlockMessage = new(); - _ = newBlockMessage.ToString(); - } + [Test] + public void To_string() + { + using BlockHeadersMessage newBlockMessage = new(); + _ = newBlockMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockBodiesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockBodiesMessageSerializerTests.cs index c292b37c091..dee2db5b6fd 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockBodiesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockBodiesMessageSerializerTests.cs @@ -6,36 +6,35 @@ using Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V62 +namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V62; + +[Parallelizable(ParallelScope.All)] +public class GetBlockBodiesMessageSerializerTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class GetBlockBodiesMessageSerializerTests + [Test] + public void Roundtrip() { - [Test] - public void Roundtrip() - { - GetBlockBodiesMessageSerializer serializer = new(); - using GetBlockBodiesMessage message = new(Keccak.OfAnEmptySequenceRlp, Keccak.Zero, Keccak.EmptyTreeHash); - byte[] bytes = serializer.Serialize(message); - byte[] expectedBytes = Bytes.FromHexString("f863a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - - Assert.True(Bytes.AreEqual(bytes, expectedBytes), "bytes"); + GetBlockBodiesMessageSerializer serializer = new(); + using GetBlockBodiesMessage message = new(Keccak.OfAnEmptySequenceRlp, Keccak.Zero, Keccak.EmptyTreeHash); + byte[] bytes = serializer.Serialize(message); + byte[] expectedBytes = Bytes.FromHexString("f863a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - using GetBlockBodiesMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.BlockHashes.Count, Is.EqualTo(message.BlockHashes.Count), $"count"); - for (int i = 0; i < message.BlockHashes.Count; i++) - { - Assert.That(deserialized.BlockHashes[i], Is.EqualTo(message.BlockHashes[i]), $"hash {i}"); - } - - SerializerTester.TestZero(serializer, message); - } + Assert.That(Bytes.AreEqual(bytes, expectedBytes), Is.True, "bytes"); - [Test] - public void To_string() + using GetBlockBodiesMessage deserialized = serializer.Deserialize(bytes); + Assert.That(deserialized.BlockHashes.Count, Is.EqualTo(message.BlockHashes.Count), $"count"); + for (int i = 0; i < message.BlockHashes.Count; i++) { - using GetBlockBodiesMessage newBlockMessage = new(); - _ = newBlockMessage.ToString(); + Assert.That(deserialized.BlockHashes[i], Is.EqualTo(message.BlockHashes[i]), $"hash {i}"); } + + SerializerTester.TestZero(serializer, message); + } + + [Test] + public void To_string() + { + using GetBlockBodiesMessage newBlockMessage = new(); + _ = newBlockMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockHeadersMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockHeadersMessageSerializerTests.cs index 42279051591..f93f4b96cb1 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockHeadersMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/GetBlockHeadersMessageSerializerTests.cs @@ -6,86 +6,85 @@ using Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V62 +namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V62; + +[Parallelizable(ParallelScope.All)] +public class GetBlockHeadersMessageSerializerTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class GetBlockHeadersMessageSerializerTests + [Test] + public void Roundtrip_hash() + { + using GetBlockHeadersMessage message = new(); + message.MaxHeaders = 1; + message.Skip = 2; + message.Reverse = 1; + message.StartBlockHash = Keccak.OfAnEmptyString; + GetBlockHeadersMessageSerializer serializer = new(); + byte[] bytes = serializer.Serialize(message); + byte[] expectedBytes = Bytes.FromHexString("e4a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470010201"); + + Assert.That(Bytes.AreEqual(bytes, expectedBytes), Is.True, "bytes"); + + using GetBlockHeadersMessage deserialized = serializer.Deserialize(bytes); + Assert.That(deserialized.StartBlockHash, Is.EqualTo(message.StartBlockHash), $"{nameof(message.StartBlockHash)}"); + Assert.That(deserialized.MaxHeaders, Is.EqualTo(message.MaxHeaders), $"{nameof(message.MaxHeaders)}"); + Assert.That(deserialized.Reverse, Is.EqualTo(message.Reverse), $"{nameof(message.Reverse)}"); + Assert.That(deserialized.Skip, Is.EqualTo(message.Skip), $"{nameof(message.Skip)}"); + + SerializerTester.TestZero(serializer, message); + } + + [Test] + public void Roundtrip_number() + { + using GetBlockHeadersMessage message = new(); + message.MaxHeaders = 1; + message.Skip = 2; + message.Reverse = 1; + message.StartBlockNumber = 100; + GetBlockHeadersMessageSerializer serializer = new(); + byte[] bytes = serializer.Serialize(message); + byte[] expectedBytes = Bytes.FromHexString("c464010201"); + + Assert.That(Bytes.AreEqual(bytes, expectedBytes), Is.True, "bytes"); + + using GetBlockHeadersMessage deserialized = serializer.Deserialize(bytes); + Assert.That(deserialized.StartBlockNumber, Is.EqualTo(message.StartBlockNumber), $"{nameof(message.StartBlockNumber)}"); + Assert.That(deserialized.MaxHeaders, Is.EqualTo(message.MaxHeaders), $"{nameof(message.MaxHeaders)}"); + Assert.That(deserialized.Reverse, Is.EqualTo(message.Reverse), $"{nameof(message.Reverse)}"); + Assert.That(deserialized.Skip, Is.EqualTo(message.Skip), $"{nameof(message.Skip)}"); + + SerializerTester.TestZero(serializer, message); + } + + [Test] + public void Roundtrip_zero() + { + using GetBlockHeadersMessage message = new(); + message.MaxHeaders = 1; + message.Skip = 2; + message.Reverse = 0; + message.StartBlockNumber = 100; + GetBlockHeadersMessageSerializer serializer = new(); + + byte[] bytes = serializer.Serialize(message); + byte[] expectedBytes = Bytes.FromHexString("c464010280"); + + Assert.That(bytes, Is.EqualTo(expectedBytes), "bytes"); + + using GetBlockHeadersMessage deserialized = serializer.Deserialize(bytes); + Assert.That(deserialized.StartBlockNumber, Is.EqualTo(message.StartBlockNumber), $"{nameof(message.StartBlockNumber)}"); + Assert.That(deserialized.MaxHeaders, Is.EqualTo(message.MaxHeaders), $"{nameof(message.MaxHeaders)}"); + Assert.That(deserialized.Reverse, Is.EqualTo(message.Reverse), $"{nameof(message.Reverse)}"); + Assert.That(deserialized.Skip, Is.EqualTo(message.Skip), $"{nameof(message.Skip)}"); + + SerializerTester.TestZero(serializer, message); + } + + [Test] + public void To_string() { - [Test] - public void Roundtrip_hash() - { - using GetBlockHeadersMessage message = new(); - message.MaxHeaders = 1; - message.Skip = 2; - message.Reverse = 1; - message.StartBlockHash = Keccak.OfAnEmptyString; - GetBlockHeadersMessageSerializer serializer = new(); - byte[] bytes = serializer.Serialize(message); - byte[] expectedBytes = Bytes.FromHexString("e4a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470010201"); - - Assert.True(Bytes.AreEqual(bytes, expectedBytes), "bytes"); - - using GetBlockHeadersMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.StartBlockHash, Is.EqualTo(message.StartBlockHash), $"{nameof(message.StartBlockHash)}"); - Assert.That(deserialized.MaxHeaders, Is.EqualTo(message.MaxHeaders), $"{nameof(message.MaxHeaders)}"); - Assert.That(deserialized.Reverse, Is.EqualTo(message.Reverse), $"{nameof(message.Reverse)}"); - Assert.That(deserialized.Skip, Is.EqualTo(message.Skip), $"{nameof(message.Skip)}"); - - SerializerTester.TestZero(serializer, message); - } - - [Test] - public void Roundtrip_number() - { - using GetBlockHeadersMessage message = new(); - message.MaxHeaders = 1; - message.Skip = 2; - message.Reverse = 1; - message.StartBlockNumber = 100; - GetBlockHeadersMessageSerializer serializer = new(); - byte[] bytes = serializer.Serialize(message); - byte[] expectedBytes = Bytes.FromHexString("c464010201"); - - Assert.True(Bytes.AreEqual(bytes, expectedBytes), "bytes"); - - using GetBlockHeadersMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.StartBlockNumber, Is.EqualTo(message.StartBlockNumber), $"{nameof(message.StartBlockNumber)}"); - Assert.That(deserialized.MaxHeaders, Is.EqualTo(message.MaxHeaders), $"{nameof(message.MaxHeaders)}"); - Assert.That(deserialized.Reverse, Is.EqualTo(message.Reverse), $"{nameof(message.Reverse)}"); - Assert.That(deserialized.Skip, Is.EqualTo(message.Skip), $"{nameof(message.Skip)}"); - - SerializerTester.TestZero(serializer, message); - } - - [Test] - public void Roundtrip_zero() - { - using GetBlockHeadersMessage message = new(); - message.MaxHeaders = 1; - message.Skip = 2; - message.Reverse = 0; - message.StartBlockNumber = 100; - GetBlockHeadersMessageSerializer serializer = new(); - - byte[] bytes = serializer.Serialize(message); - byte[] expectedBytes = Bytes.FromHexString("c464010280"); - - Assert.That(bytes, Is.EqualTo(expectedBytes), "bytes"); - - using GetBlockHeadersMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.StartBlockNumber, Is.EqualTo(message.StartBlockNumber), $"{nameof(message.StartBlockNumber)}"); - Assert.That(deserialized.MaxHeaders, Is.EqualTo(message.MaxHeaders), $"{nameof(message.MaxHeaders)}"); - Assert.That(deserialized.Reverse, Is.EqualTo(message.Reverse), $"{nameof(message.Reverse)}"); - Assert.That(deserialized.Skip, Is.EqualTo(message.Skip), $"{nameof(message.Skip)}"); - - SerializerTester.TestZero(serializer, message); - } - - [Test] - public void To_string() - { - using GetBlockHeadersMessage newBlockMessage = new(); - _ = newBlockMessage.ToString(); - } + using GetBlockHeadersMessage newBlockMessage = new(); + _ = newBlockMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs index 71628a407e2..489697345f1 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Linq; using DotNetty.Buffers; using FluentAssertions; using Nethermind.Blockchain.Receipts; @@ -14,150 +13,149 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V63 +namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V63; + +[Parallelizable(ParallelScope.All)] +public class ReceiptsMessageSerializerTests { - [Parallelizable(ParallelScope.All)] - public class ReceiptsMessageSerializerTests + private static void Test(TxReceipt[][]? txReceipts) { - private static void Test(TxReceipt[][]? txReceipts) - { - using ReceiptsMessage message = new(txReceipts?.ToPooledList()); - ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); - var serialized = serializer.Serialize(message); - using ReceiptsMessage deserialized = serializer.Deserialize(serialized); + using ReceiptsMessage message = new(txReceipts?.ToPooledList()); + ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); + var serialized = serializer.Serialize(message); + using ReceiptsMessage deserialized = serializer.Deserialize(serialized); - if (txReceipts is null) - { - Assert.That(deserialized.TxReceipts.Count, Is.EqualTo(0)); - } - else + if (txReceipts is null) + { + Assert.That(deserialized.TxReceipts.Count, Is.EqualTo(0)); + } + else + { + Assert.That(deserialized.TxReceipts.Count, Is.EqualTo(txReceipts.Length), "length"); + for (int i = 0; i < txReceipts.Length; i++) { - Assert.That(deserialized.TxReceipts.Count, Is.EqualTo(txReceipts.Length), "length"); - for (int i = 0; i < txReceipts.Length; i++) + if (txReceipts[i] is null) { - if (txReceipts[i] is null) - { - Assert.IsNull(deserialized.TxReceipts[i], $"receipts[{i}]"); - } - else + Assert.That(deserialized.TxReceipts[i], Is.Null, $"receipts[{i}]"); + } + else + { + for (int j = 0; j < txReceipts[i].Length; j++) { - for (int j = 0; j < txReceipts[i].Length; j++) + if (txReceipts[i][j] is null) { - if (txReceipts[i][j] is null) - { - Assert.IsNull(deserialized.TxReceipts[i][j], $"receipts[{i}][{j}]"); - } - else + Assert.That(deserialized.TxReceipts[i][j], Is.Null, $"receipts[{i}][{j}]"); + } + else + { + Assert.That(deserialized.TxReceipts[i][j].TxType, Is.EqualTo(txReceipts[i][j].TxType), $"receipts[{i}][{j}].TxType"); + Assert.That(deserialized.TxReceipts[i][j].Bloom, Is.EqualTo(txReceipts[i][j].Bloom), $"receipts[{i}][{j}].Bloom"); + Assert.That(deserialized.TxReceipts[i][j].Error, Is.Null, $"receipts[{i}][{j}].Error"); + Assert.That(deserialized.TxReceipts[i][j].Index, Is.EqualTo(0), $"receipts[{i}][{j}].Index"); + Assert.That(deserialized.TxReceipts[i][j].Logs.Length, Is.EqualTo(txReceipts[i][j].Logs.Length), $"receipts[{i}][{j}].Logs.Length"); + Assert.That(deserialized.TxReceipts[i][j].Recipient, Is.Null, $"receipts[{i}][{j}].Recipient"); + Assert.That(deserialized.TxReceipts[i][j].Sender, Is.Null, $"receipts[{i}][{j}].Sender"); + Assert.That(deserialized.TxReceipts[i][j].BlockHash, Is.Null, $"receipts[{i}][{j}].BlockHash"); + Assert.That(deserialized.TxReceipts[i][j].BlockNumber, Is.EqualTo(0L), $"receipts[{i}][{j}].BlockNumber"); + Assert.That(deserialized.TxReceipts[i][j].ContractAddress, Is.Null, $"receipts[{i}][{j}].ContractAddress"); + Assert.That(deserialized.TxReceipts[i][j].GasUsed, Is.EqualTo(0L), $"receipts[{i}][{j}].GasUsed"); + Assert.That(deserialized.TxReceipts[i][j].GasUsedTotal, Is.EqualTo(txReceipts[i][j].GasUsedTotal), $"receipts[{i}][{j}].GasUsedTotal"); + if (!txReceipts[i][j].SkipStateAndStatusInRlp) { - Assert.That(deserialized.TxReceipts[i][j].TxType, Is.EqualTo(txReceipts[i][j].TxType), $"receipts[{i}][{j}].TxType"); - Assert.That(deserialized.TxReceipts[i][j].Bloom, Is.EqualTo(txReceipts[i][j].Bloom), $"receipts[{i}][{j}].Bloom"); - Assert.Null(deserialized.TxReceipts[i][j].Error, $"receipts[{i}][{j}].Error"); - Assert.That(deserialized.TxReceipts[i][j].Index, Is.EqualTo(0), $"receipts[{i}][{j}].Index"); - Assert.That(deserialized.TxReceipts[i][j].Logs.Length, Is.EqualTo(txReceipts[i][j].Logs.Length), $"receipts[{i}][{j}].Logs.Length"); - Assert.Null(deserialized.TxReceipts[i][j].Recipient, $"receipts[{i}][{j}].Recipient"); - Assert.Null(deserialized.TxReceipts[i][j].Sender, $"receipts[{i}][{j}].Sender"); - Assert.Null(deserialized.TxReceipts[i][j].BlockHash, $"receipts[{i}][{j}].BlockHash"); - Assert.That(deserialized.TxReceipts[i][j].BlockNumber, Is.EqualTo(0L), $"receipts[{i}][{j}].BlockNumber"); - Assert.Null(deserialized.TxReceipts[i][j].ContractAddress, $"receipts[{i}][{j}].ContractAddress"); - Assert.That(deserialized.TxReceipts[i][j].GasUsed, Is.EqualTo(0L), $"receipts[{i}][{j}].GasUsed"); - Assert.That(deserialized.TxReceipts[i][j].GasUsedTotal, Is.EqualTo(txReceipts[i][j].GasUsedTotal), $"receipts[{i}][{j}].GasUsedTotal"); - if (!txReceipts[i][j].SkipStateAndStatusInRlp) - { - Assert.That(deserialized.TxReceipts[i][j].StatusCode, Is.EqualTo(txReceipts[i][j].BlockNumber < MainnetSpecProvider.ByzantiumBlockNumber ? 0 : txReceipts[i][j].StatusCode), $"receipts[{i}][{j}].StatusCode"); - Assert.That(deserialized.TxReceipts[i][j].PostTransactionState, Is.EqualTo(txReceipts[i][j].BlockNumber < MainnetSpecProvider.ByzantiumBlockNumber ? txReceipts[i][j].PostTransactionState : null), $"receipts[{i}][{j}].PostTransactionState"); - } + Assert.That(deserialized.TxReceipts[i][j].StatusCode, Is.EqualTo(txReceipts[i][j].BlockNumber < MainnetSpecProvider.ByzantiumBlockNumber ? 0 : txReceipts[i][j].StatusCode), $"receipts[{i}][{j}].StatusCode"); + Assert.That(deserialized.TxReceipts[i][j].PostTransactionState, Is.EqualTo(txReceipts[i][j].BlockNumber < MainnetSpecProvider.ByzantiumBlockNumber ? txReceipts[i][j].PostTransactionState : null), $"receipts[{i}][{j}].PostTransactionState"); } } } } } } + } - [Test] - public void Roundtrip() - { - TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject], [Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; - Test(data); - } + [Test] + public void Roundtrip() + { + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject], [Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; + Test(data); + } - [Test] - public void Roundtrip_with_IgnoreOutputs() + [Test] + public void Roundtrip_with_IgnoreOutputs() + { + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject], [Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; + foreach (TxReceipt[] receipts in data) { - TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject], [Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; - foreach (TxReceipt[] receipts in data) - { - receipts.SetSkipStateAndStatusInRlp(true); - } - Test(data); + receipts.SetSkipStateAndStatusInRlp(true); } + Test(data); + } - [Test] - public void Roundtrip_with_eip658() - { - TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject], [Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(MainnetSpecProvider.ConstantinopleFixBlockNumber).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; - Test(data); - } + [Test] + public void Roundtrip_with_eip658() + { + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject], [Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(MainnetSpecProvider.ConstantinopleFixBlockNumber).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; + Test(data); + } - [Test] - public void Roundtrip_with_null_top_level() - { - Test(null); - } + [Test] + public void Roundtrip_with_null_top_level() + { + Test(null); + } - [Test] - public void Roundtrip_with_nulls() - { - TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject], null, new[] { null, Build.A.Receipt.WithAllFieldsFilled.TestObject }]; - Test(data); - } + [Test] + public void Roundtrip_with_nulls() + { + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject], null, new[] { null, Build.A.Receipt.WithAllFieldsFilled.TestObject }]; + Test(data); + } - [Test] - public void Deserialize_empty() - { - ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); - using ReceiptsMessage receiptsMessage = serializer.Deserialize(Array.Empty()); - receiptsMessage.TxReceipts.Should().HaveCount(0); - } + [Test] + public void Deserialize_empty() + { + ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); + using ReceiptsMessage receiptsMessage = serializer.Deserialize(Array.Empty()); + receiptsMessage.TxReceipts.Should().HaveCount(0); + } - [Test] - public void Deserialize_non_empty_but_bytebuffer_starts_with_empty() - { - TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject], [Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; - using ReceiptsMessage message = new(data.ToPooledList()); - ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); + [Test] + public void Deserialize_non_empty_but_bytebuffer_starts_with_empty() + { + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject], [Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; + using ReceiptsMessage message = new(data.ToPooledList()); + ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); - IByteBuffer buffer = Unpooled.Buffer(serializer.GetLength(message, out int _) + 1); - buffer.WriteByte(Rlp.OfEmptySequence[0]); - buffer.ReadByte(); + IByteBuffer buffer = Unpooled.Buffer(serializer.GetLength(message, out int _) + 1); + buffer.WriteByte(Rlp.OfEmptySequence[0]); + buffer.ReadByte(); - serializer.Serialize(buffer, message); - using ReceiptsMessage deserialized = serializer.Deserialize(buffer); + serializer.Serialize(buffer, message); + using ReceiptsMessage deserialized = serializer.Deserialize(buffer); - deserialized.TxReceipts.Count.Should().Be(data.Length); - } + deserialized.TxReceipts.Count.Should().Be(data.Length); + } - [Test] - public void Roundtrip_mainnet_sample() - { - byte[] bytes = Bytes.FromHexString("f9012ef9012bf90128a08ccc6709a5df7acef07f97c5681356b6c37cfac15b554aff68e986f57116df2e825208b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0"); - ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); - using ReceiptsMessage message = serializer.Deserialize(bytes); - byte[] serialized = serializer.Serialize(message); - Assert.That(serialized, Is.EqualTo(bytes)); - } + [Test] + public void Roundtrip_mainnet_sample() + { + byte[] bytes = Bytes.FromHexString("f9012ef9012bf90128a08ccc6709a5df7acef07f97c5681356b6c37cfac15b554aff68e986f57116df2e825208b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0"); + ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); + using ReceiptsMessage message = serializer.Deserialize(bytes); + byte[] serialized = serializer.Serialize(message); + Assert.That(serialized, Is.EqualTo(bytes)); + } - [Test] - public void Roundtrip_one_receipt_with_accessList() - { - TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject]]; - Test(data); - } + [Test] + public void Roundtrip_one_receipt_with_accessList() + { + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject]]; + Test(data); + } - [Test] - public void Roundtrip_with_both_txTypes_of_receipt() - { - TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).WithTxType(TxType.AccessList).TestObject], [Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; - Test(data); - } + [Test] + public void Roundtrip_with_both_txTypes_of_receipt() + { + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).WithTxType(TxType.AccessList).TestObject], [Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject]]; + Test(data); } } diff --git a/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs b/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs index fd99eaf4d3a..3f10c542571 100644 --- a/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System.Collections.Generic; using System.Numerics; using System.Threading; using DotNetty.Buffers; @@ -35,453 +34,451 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Network.Test +namespace Nethermind.Network.Test; + +[Parallelizable(ParallelScope.Self)] +public class ProtocolsManagerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class ProtocolsManagerTests + [SetUp] + public void SetUp() + { + } + + public static Context When => new(); + + public class Context { - [SetUp] - public void SetUp() + private readonly int _localPort = 30312; + private readonly int _remotePort = 30000; + private readonly string _remoteHost = "35.0.0.1"; + private ISession _currentSession; + private readonly IDiscoveryApp _discoveryApp; + private readonly IRlpxHost _rlpxHost; + private readonly ProtocolsManager _manager; + private readonly INodeStatsManager _nodeStatsManager; + private readonly INetworkStorage _peerStorage; + private readonly IProtocolValidator _protocolValidator; + private readonly IMessageSerializationService _serializer; + private readonly ISyncServer _syncServer; + private readonly ISyncPeerPool _syncPeerPool; + private readonly ITxPool _txPool; + private readonly IPooledTxsRequestor _pooledTxsRequestor; + private readonly IChannelHandlerContext _channelHandlerContext; + private readonly IChannel _channel; + private readonly IChannelPipeline _pipeline; + private readonly IPacketSender _packetSender; + private readonly IBlockTree _blockTree; + private readonly IGossipPolicy _gossipPolicy; + + public Context() + { + _channel = Substitute.For(); + _channelHandlerContext = Substitute.For(); + _pipeline = Substitute.For(); + _channelHandlerContext.Channel.Returns(_channel); + _channel.Pipeline.Returns(_pipeline); + _pipeline.Get().Returns(new ZeroPacketSplitter(LimboLogs.Instance)); + _packetSender = Substitute.For(); + _syncServer = Substitute.For(); + _syncServer = Substitute.For(); + _syncServer.Genesis.Returns(Build.A.Block.Genesis.TestObject.Header); + _syncServer.Head.Returns(Build.A.BlockHeader.TestObject); + _txPool = Substitute.For(); + _pooledTxsRequestor = Substitute.For(); + _discoveryApp = Substitute.For(); + _serializer = new MessageSerializationService(); + _rlpxHost = Substitute.For(); + _rlpxHost.LocalPort.Returns(_localPort); + _rlpxHost.LocalNodeId.Returns(TestItem.PublicKeyA); + ITimerFactory timerFactory = Substitute.For(); + _nodeStatsManager = new NodeStatsManager(timerFactory, LimboLogs.Instance); + _blockTree = Substitute.For(); + _blockTree.NetworkId.Returns((ulong)TestBlockchainIds.NetworkId); + _blockTree.ChainId.Returns((ulong)TestBlockchainIds.ChainId); + _blockTree.Genesis.Returns(Build.A.Block.Genesis.TestObject.Header); + ForkInfo forkInfo = new ForkInfo(MainnetSpecProvider.Instance, _syncServer.Genesis.Hash!); + _protocolValidator = new ProtocolValidator(_nodeStatsManager, _blockTree, forkInfo, LimboLogs.Instance); + _peerStorage = Substitute.For(); + _syncPeerPool = Substitute.For(); + _gossipPolicy = Substitute.For(); + _manager = new ProtocolsManager( + _syncPeerPool, + _syncServer, + RunImmediatelyScheduler.Instance, + _txPool, + _pooledTxsRequestor, + _discoveryApp, + _serializer, + _rlpxHost, + _nodeStatsManager, + _protocolValidator, + _peerStorage, + forkInfo, + _gossipPolicy, + new NetworkConfig(), + Substitute.For(), + LimboLogs.Instance); + + _serializer.Register(new HelloMessageSerializer()); + _serializer.Register(new StatusMessageSerializer()); + _serializer.Register(new DisconnectMessageSerializer()); + } + + public Context CreateIncomingSession() + { + IChannel channel = Substitute.For(); + _currentSession = new Session(_localPort, channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + _pipeline.Get().Returns(new ZeroNettyP2PHandler(_currentSession, LimboLogs.Instance)); + _rlpxHost.SessionCreated += Raise.EventWith(new object(), new SessionEventArgs(_currentSession)); + return this; + } + + public Context CreateOutgoingSession() + { + IChannel channel = Substitute.For(); + _currentSession = new Session(_localPort, new Node(TestItem.PublicKeyB, _remoteHost, _remotePort), channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); + _pipeline.Get().Returns(new ZeroNettyP2PHandler(_currentSession, LimboLogs.Instance)); + _rlpxHost.SessionCreated += Raise.EventWith(new object(), new SessionEventArgs(_currentSession)); + return this; + } + + public Context Handshake() + { + _currentSession.Handshake(TestItem.PublicKeyB); + return this; + } + + public Context Init() + { + _currentSession.Init(5, _channelHandlerContext, _packetSender); + return this; + } + + public Context ActivateChannel() { + _currentSession.RemoteHost = _remoteHost; + _currentSession.RemotePort = _remotePort; + return this; } - public static Context When => new(); + public Context VerifyPingSenderSet() + { + Assert.That(_currentSession.PingSender, Is.Not.Null); + return this; + } + + public Context VerifyDisconnected() + { + Assert.That(_currentSession.State, Is.EqualTo(SessionState.Disconnected)); + return this; + } - public class Context + public Context ReceiveDisconnect() { - private readonly int _localPort = 30312; - private readonly int _remotePort = 30000; - private readonly string _remoteHost = "35.0.0.1"; - private ISession _currentSession; - private readonly IDiscoveryApp _discoveryApp; - private readonly IRlpxHost _rlpxHost; - private readonly ProtocolsManager _manager; - private readonly INodeStatsManager _nodeStatsManager; - private readonly INetworkStorage _peerStorage; - private readonly IProtocolValidator _protocolValidator; - private readonly IMessageSerializationService _serializer; - private readonly ISyncServer _syncServer; - private readonly ISyncPeerPool _syncPeerPool; - private readonly ITxPool _txPool; - private readonly IPooledTxsRequestor _pooledTxsRequestor; - private readonly IChannelHandlerContext _channelHandlerContext; - private readonly IChannel _channel; - private readonly IChannelPipeline _pipeline; - private readonly IPacketSender _packetSender; - private readonly IBlockTree _blockTree; - private readonly IGossipPolicy _gossipPolicy; - - public Context() - { - _channel = Substitute.For(); - _channelHandlerContext = Substitute.For(); - _pipeline = Substitute.For(); - _channelHandlerContext.Channel.Returns(_channel); - _channel.Pipeline.Returns(_pipeline); - _pipeline.Get().Returns(new ZeroPacketSplitter(LimboLogs.Instance)); - _packetSender = Substitute.For(); - _syncServer = Substitute.For(); - _syncServer = Substitute.For(); - _syncServer.Genesis.Returns(Build.A.Block.Genesis.TestObject.Header); - _syncServer.Head.Returns(Build.A.BlockHeader.TestObject); - _txPool = Substitute.For(); - _pooledTxsRequestor = Substitute.For(); - _discoveryApp = Substitute.For(); - _serializer = new MessageSerializationService(); - _rlpxHost = Substitute.For(); - _rlpxHost.LocalPort.Returns(_localPort); - _rlpxHost.LocalNodeId.Returns(TestItem.PublicKeyA); - ITimerFactory timerFactory = Substitute.For(); - _nodeStatsManager = new NodeStatsManager(timerFactory, LimboLogs.Instance); - _blockTree = Substitute.For(); - _blockTree.NetworkId.Returns((ulong)TestBlockchainIds.NetworkId); - _blockTree.ChainId.Returns((ulong)TestBlockchainIds.ChainId); - _blockTree.Genesis.Returns(Build.A.Block.Genesis.TestObject.Header); - ForkInfo forkInfo = new ForkInfo(MainnetSpecProvider.Instance, _syncServer.Genesis.Hash!); - _protocolValidator = new ProtocolValidator(_nodeStatsManager, _blockTree, forkInfo, LimboLogs.Instance); - _peerStorage = Substitute.For(); - _syncPeerPool = Substitute.For(); - _gossipPolicy = Substitute.For(); - _manager = new ProtocolsManager( - _syncPeerPool, - _syncServer, - RunImmediatelyScheduler.Instance, - _txPool, - _pooledTxsRequestor, - _discoveryApp, - _serializer, - _rlpxHost, - _nodeStatsManager, - _protocolValidator, - _peerStorage, - forkInfo, - _gossipPolicy, - new NetworkConfig(), - Substitute.For(), - LimboLogs.Instance); - - _serializer.Register(new HelloMessageSerializer()); - _serializer.Register(new StatusMessageSerializer()); - _serializer.Register(new DisconnectMessageSerializer()); - } - - public Context CreateIncomingSession() - { - IChannel channel = Substitute.For(); - _currentSession = new Session(_localPort, channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - _pipeline.Get().Returns(new ZeroNettyP2PHandler(_currentSession, LimboLogs.Instance)); - _rlpxHost.SessionCreated += Raise.EventWith(new object(), new SessionEventArgs(_currentSession)); - return this; - } - - public Context CreateOutgoingSession() - { - IChannel channel = Substitute.For(); - _currentSession = new Session(_localPort, new Node(TestItem.PublicKeyB, _remoteHost, _remotePort), channel, NullDisconnectsAnalyzer.Instance, LimboLogs.Instance); - _pipeline.Get().Returns(new ZeroNettyP2PHandler(_currentSession, LimboLogs.Instance)); - _rlpxHost.SessionCreated += Raise.EventWith(new object(), new SessionEventArgs(_currentSession)); - return this; - } - - public Context Handshake() - { - _currentSession.Handshake(TestItem.PublicKeyB); - return this; - } - - public Context Init() - { - _currentSession.Init(5, _channelHandlerContext, _packetSender); - return this; - } - - public Context ActivateChannel() - { - _currentSession.RemoteHost = _remoteHost; - _currentSession.RemotePort = _remotePort; - return this; - } - - public Context VerifyPingSenderSet() - { - Assert.NotNull(_currentSession.PingSender); - return this; - } - - public Context VerifyDisconnected() - { - Assert.That(_currentSession.State, Is.EqualTo(SessionState.Disconnected)); - return this; - } - - public Context ReceiveDisconnect() - { - using DisconnectMessage message = new(EthDisconnectReason.Other); - IByteBuffer disconnectPacket = _serializer.ZeroSerialize(message); - - // to account for AdaptivePacketType byte - disconnectPacket.ReadByte(); - _currentSession.ReceiveMessage(new ZeroPacket(disconnectPacket) { PacketType = P2PMessageCode.Disconnect }); - return this; - } - - public Context Wait(int i) - { - Thread.Sleep(i); - return this; - } - - public Context VerifyInitialized() - { - Assert.That(_currentSession.State, Is.EqualTo(SessionState.Initialized)); - return this; - } - - public Context VerifyCompatibilityValidationType(CompatibilityValidationType expectedType) - { - Assert.That(_nodeStatsManager.GetOrAdd(_currentSession.Node).FailedCompatibilityValidation, Is.EqualTo(expectedType)); - return this; - } - - public Context Disconnect() - { - _currentSession.MarkDisconnected(DisconnectReason.TooManyPeers, DisconnectType.Local, "test"); - return this; - } - - public Context ReceiveStatus() - { - using StatusMessage msg = new(); - msg.TotalDifficulty = 1; - msg.NetworkId = TestBlockchainIds.NetworkId; - msg.GenesisHash = _blockTree.Genesis.Hash; - msg.BestHash = _blockTree.Genesis.Hash; - msg.ProtocolVersion = 66; - msg.ForkId = new ForkId(0, 0); - - return ReceiveStatus(msg); - } - - private Context ReceiveStatus(StatusMessage msg) - { - IByteBuffer statusPacket = _serializer.ZeroSerialize(msg); - statusPacket.ReadByte(); - - _currentSession.ReceiveMessage(new ZeroPacket(statusPacket) { PacketType = Eth62MessageCode.Status + 16 }); - return this; - } - - public Context VerifyEthInitialized() - { - INodeStats stats = _nodeStatsManager.GetOrAdd(_currentSession.Node); - Assert.That(stats.EthNodeDetails.NetworkId, Is.EqualTo(TestBlockchainIds.NetworkId)); - Assert.That(stats.EthNodeDetails.GenesisHash, Is.EqualTo(_blockTree.Genesis.Hash)); - Assert.That(stats.EthNodeDetails.ProtocolVersion, Is.EqualTo(66)); - Assert.That(stats.EthNodeDetails.TotalDifficulty, Is.EqualTo(BigInteger.One)); - return this; - } - - public Context VerifySyncPeersRemoved() - { - _txPool.Received().RemovePeer(Arg.Any()); - _syncPeerPool.Received().RemovePeer(Arg.Any()); - return this; - } - - private Context ReceiveHello(HelloMessage msg) - { - IByteBuffer helloPacket = _serializer.ZeroSerialize(msg); - // to account for AdaptivePacketType byte - helloPacket.ReadByte(); - - _currentSession.ReceiveMessage(new ZeroPacket(helloPacket) { PacketType = P2PMessageCode.Hello }); - return this; - } - - - public Context ReceiveHello(byte p2pVersion = 5) - { - using HelloMessage msg = new(); - msg.Capabilities = new ArrayPoolList(1) { new("eth", 66) }; - msg.NodeId = TestItem.PublicKeyB; - msg.ClientId = "other client v1"; - msg.P2PVersion = p2pVersion; - msg.ListenPort = 30314; - - return ReceiveHello(msg); - } - - public Context ReceiveHelloNoEth() - { - using HelloMessage msg = new(); - msg.Capabilities = ArrayPoolList.Empty(); - msg.NodeId = TestItem.PublicKeyB; - msg.ClientId = "other client v1"; - msg.P2PVersion = 5; - msg.ListenPort = 30314; - return ReceiveHello(msg); - } - - public Context ReceiveHelloEth(int protocolVersion) - { - using HelloMessage msg = new(); - msg.Capabilities = new ArrayPoolList(1) { new("eth", protocolVersion) }; - msg.NodeId = TestItem.PublicKeyB; - msg.ClientId = "other client v1"; - msg.P2PVersion = 5; - msg.ListenPort = 30314; - return ReceiveHello(msg); - } - - - public Context ReceiveHelloWrongEth() - { - return ReceiveHelloEth(65); - } - - public Context ReceiveStatusWrongChain(ulong networkId) - { - using StatusMessage msg = new(); - msg.TotalDifficulty = 1; - msg.NetworkId = networkId; - msg.GenesisHash = TestItem.KeccakA; - msg.BestHash = TestItem.KeccakA; - msg.ProtocolVersion = 66; - - return ReceiveStatus(msg); - } - - public Context ReceiveStatusWrongGenesis() - { - using StatusMessage msg = new(); - msg.TotalDifficulty = 1; - msg.NetworkId = TestBlockchainIds.NetworkId; - msg.GenesisHash = TestItem.KeccakB; - msg.BestHash = TestItem.KeccakB; - msg.ProtocolVersion = 66; - - return ReceiveStatus(msg); - } + using DisconnectMessage message = new(EthDisconnectReason.Other); + IByteBuffer disconnectPacket = _serializer.ZeroSerialize(message); + + // to account for AdaptivePacketType byte + disconnectPacket.ReadByte(); + _currentSession.ReceiveMessage(new ZeroPacket(disconnectPacket) { PacketType = P2PMessageCode.Disconnect }); + return this; } - [Test] - public void Sets_ping_sender_after_receiving_hello() + public Context Wait(int i) { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .ReceiveHello() - .VerifyPingSenderSet(); + Thread.Sleep(i); + return this; } - [Test] - public void Disconnects_on_p2p_before_version_4() + public Context VerifyInitialized() { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .ReceiveHello(3) - .VerifyDisconnected(); + Assert.That(_currentSession.State, Is.EqualTo(SessionState.Initialized)); + return this; } - [Test] - public void Disconnects_on_receiving_disconnect() + public Context VerifyCompatibilityValidationType(CompatibilityValidationType expectedType) { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .ReceiveHello() - .ReceiveDisconnect() - .VerifyDisconnected(); + Assert.That(_nodeStatsManager.GetOrAdd(_currentSession.Node).FailedCompatibilityValidation, Is.EqualTo(expectedType)); + return this; } - [Test] - public void Runs_ok_when_initializing_protocol_on_a_closing_session() + public Context Disconnect() { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .Disconnect() - .ReceiveHello(); + _currentSession.MarkDisconnected(DisconnectReason.TooManyPeers, DisconnectType.Local, "test"); + return this; } - [Test] - public void Can_initialize_a_session() + public Context ReceiveStatus() { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized(); + using StatusMessage msg = new(); + msg.TotalDifficulty = 1; + msg.NetworkId = TestBlockchainIds.NetworkId; + msg.GenesisHash = _blockTree.Genesis.Hash; + msg.BestHash = _blockTree.Genesis.Hash; + msg.ProtocolVersion = 66; + msg.ForkId = new ForkId(0, 0); + + return ReceiveStatus(msg); } - [Test] - public void Can_initialize_eth_protocol() + private Context ReceiveStatus(StatusMessage msg) { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized() - .ReceiveHello() - .ReceiveStatus() - .VerifyEthInitialized(); + IByteBuffer statusPacket = _serializer.ZeroSerialize(msg); + statusPacket.ReadByte(); + + _currentSession.ReceiveMessage(new ZeroPacket(statusPacket) { PacketType = Eth62MessageCode.Status + 16 }); + return this; } - [Test] - public void Removes_sync_peers_on_disconnect() + public Context VerifyEthInitialized() { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized() - .ReceiveHello() - .ReceiveStatus() - .VerifyEthInitialized() - .Disconnect() - .VerifySyncPeersRemoved(); + INodeStats stats = _nodeStatsManager.GetOrAdd(_currentSession.Node); + Assert.That(stats.EthNodeDetails.NetworkId, Is.EqualTo(TestBlockchainIds.NetworkId)); + Assert.That(stats.EthNodeDetails.GenesisHash, Is.EqualTo(_blockTree.Genesis.Hash)); + Assert.That(stats.EthNodeDetails.ProtocolVersion, Is.EqualTo(66)); + Assert.That(stats.EthNodeDetails.TotalDifficulty, Is.EqualTo(BigInteger.One)); + return this; } - [Test] - public void Disconnects_on_missing_eth() + public Context VerifySyncPeersRemoved() { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized() - .ReceiveHelloNoEth() - .VerifyDisconnected(); + _txPool.Received().RemovePeer(Arg.Any()); + _syncPeerPool.Received().RemovePeer(Arg.Any()); + return this; } - [Test] - public void Disconnects_on_wrong_eth() + private Context ReceiveHello(HelloMessage msg) { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized() - .ReceiveHelloWrongEth() - .VerifyDisconnected(); + IByteBuffer helloPacket = _serializer.ZeroSerialize(msg); + // to account for AdaptivePacketType byte + helloPacket.ReadByte(); + + _currentSession.ReceiveMessage(new ZeroPacket(helloPacket) { PacketType = P2PMessageCode.Hello }); + return this; } - [TestCase(TestBlockchainIds.NetworkId + 1)] - [TestCase(TestBlockchainIds.ChainId)] - public void Disconnects_on_wrong_network_id(int networkId) + + public Context ReceiveHello(byte p2pVersion = 5) { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized() - .ReceiveHello() - .ReceiveStatusWrongChain((ulong)networkId) - .VerifyCompatibilityValidationType(CompatibilityValidationType.NetworkId) - .VerifyDisconnected(); + using HelloMessage msg = new(); + msg.Capabilities = new ArrayPoolList(1) { new("eth", 66) }; + msg.NodeId = TestItem.PublicKeyB; + msg.ClientId = "other client v1"; + msg.P2PVersion = p2pVersion; + msg.ListenPort = 30314; + + return ReceiveHello(msg); } - [Test] - public void Disconnects_on_wrong_genesis_hash() + public Context ReceiveHelloNoEth() { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized() - .ReceiveHello() - .ReceiveStatusWrongGenesis() - .VerifyDisconnected(); + using HelloMessage msg = new(); + msg.Capabilities = ArrayPoolList.Empty(); + msg.NodeId = TestItem.PublicKeyB; + msg.ClientId = "other client v1"; + msg.P2PVersion = 5; + msg.ListenPort = 30314; + return ReceiveHello(msg); } - [Test] - public void Initialized_with_eth66_only() + public Context ReceiveHelloEth(int protocolVersion) { - When - .CreateIncomingSession() - .ActivateChannel() - .Handshake() - .Init() - .VerifyInitialized() - .ReceiveHelloEth(66) - .VerifyInitialized(); + using HelloMessage msg = new(); + msg.Capabilities = new ArrayPoolList(1) { new("eth", protocolVersion) }; + msg.NodeId = TestItem.PublicKeyB; + msg.ClientId = "other client v1"; + msg.P2PVersion = 5; + msg.ListenPort = 30314; + return ReceiveHello(msg); } + + + public Context ReceiveHelloWrongEth() + { + return ReceiveHelloEth(65); + } + + public Context ReceiveStatusWrongChain(ulong networkId) + { + using StatusMessage msg = new(); + msg.TotalDifficulty = 1; + msg.NetworkId = networkId; + msg.GenesisHash = TestItem.KeccakA; + msg.BestHash = TestItem.KeccakA; + msg.ProtocolVersion = 66; + + return ReceiveStatus(msg); + } + + public Context ReceiveStatusWrongGenesis() + { + using StatusMessage msg = new(); + msg.TotalDifficulty = 1; + msg.NetworkId = TestBlockchainIds.NetworkId; + msg.GenesisHash = TestItem.KeccakB; + msg.BestHash = TestItem.KeccakB; + msg.ProtocolVersion = 66; + + return ReceiveStatus(msg); + } + } + + [Test] + public void Sets_ping_sender_after_receiving_hello() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .ReceiveHello() + .VerifyPingSenderSet(); + } + + [Test] + public void Disconnects_on_p2p_before_version_4() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .ReceiveHello(3) + .VerifyDisconnected(); + } + + [Test] + public void Disconnects_on_receiving_disconnect() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .ReceiveHello() + .ReceiveDisconnect() + .VerifyDisconnected(); + } + + [Test] + public void Runs_ok_when_initializing_protocol_on_a_closing_session() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .Disconnect() + .ReceiveHello(); + } + + [Test] + public void Can_initialize_a_session() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized(); + } + + [Test] + public void Can_initialize_eth_protocol() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized() + .ReceiveHello() + .ReceiveStatus() + .VerifyEthInitialized(); + } + + [Test] + public void Removes_sync_peers_on_disconnect() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized() + .ReceiveHello() + .ReceiveStatus() + .VerifyEthInitialized() + .Disconnect() + .VerifySyncPeersRemoved(); + } + + [Test] + public void Disconnects_on_missing_eth() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized() + .ReceiveHelloNoEth() + .VerifyDisconnected(); + } + + [Test] + public void Disconnects_on_wrong_eth() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized() + .ReceiveHelloWrongEth() + .VerifyDisconnected(); + } + + [TestCase(TestBlockchainIds.NetworkId + 1)] + [TestCase(TestBlockchainIds.ChainId)] + public void Disconnects_on_wrong_network_id(int networkId) + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized() + .ReceiveHello() + .ReceiveStatusWrongChain((ulong)networkId) + .VerifyCompatibilityValidationType(CompatibilityValidationType.NetworkId) + .VerifyDisconnected(); + } + + [Test] + public void Disconnects_on_wrong_genesis_hash() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized() + .ReceiveHello() + .ReceiveStatusWrongGenesis() + .VerifyDisconnected(); + } + + [Test] + public void Initialized_with_eth66_only() + { + When + .CreateIncomingSession() + .ActivateChannel() + .Handshake() + .Init() + .VerifyInitialized() + .ReceiveHelloEth(66) + .VerifyInitialized(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthEip8MessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthEip8MessageSerializerTests.cs index 2e137b200c2..9435a2bdbc4 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthEip8MessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthEip8MessageSerializerTests.cs @@ -7,69 +7,65 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Crypto; -using Nethermind.Logging; using Nethermind.Network.Rlpx.Handshake; using NUnit.Framework; -using Org.BouncyCastle.Utilities.Encoders; -namespace Nethermind.Network.Test.Rlpx.Handshake +namespace Nethermind.Network.Test.Rlpx.Handshake; + +[Parallelizable(ParallelScope.Self)] +public class AuthEip8MessageSerializerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class AuthEip8MessageSerializerTests - { - private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; + private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; - private readonly Random _random = new(1); + private readonly Random _random = new(1); - private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); + private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); - private readonly AuthEip8MessageSerializer _serializer = new(new Eip8MessagePad(new CryptoRandom())); + private readonly AuthEip8MessageSerializer _serializer = new(new Eip8MessagePad(new CryptoRandom())); - private void TestEncodeDecode(IEthereumEcdsa ecdsa) - { - AuthEip8Message authMessage = new(); - authMessage.Nonce = new byte[AuthMessageSerializer.NonceLength]; // sic! - authMessage.Signature = ecdsa.Sign(_privateKey, Keccak.Compute("anything")); - authMessage.PublicKey = _privateKey.PublicKey; - _random.NextBytes(authMessage.Nonce); - byte[] data = _serializer.Serialize(authMessage); - AuthEip8Message after = _serializer.Deserialize(data); + private void TestEncodeDecode(IEthereumEcdsa ecdsa) + { + AuthEip8Message authMessage = new(); + authMessage.Nonce = new byte[AuthMessageSerializer.NonceLength]; // sic! + authMessage.Signature = ecdsa.Sign(_privateKey, Keccak.Compute("anything")); + authMessage.PublicKey = _privateKey.PublicKey; + _random.NextBytes(authMessage.Nonce); + byte[] data = _serializer.Serialize(authMessage); + AuthEip8Message after = _serializer.Deserialize(data); - Assert.That(after.Signature, Is.EqualTo(authMessage.Signature)); - Assert.That(after.PublicKey, Is.EqualTo(authMessage.PublicKey)); - Assert.True(Bytes.AreEqual(authMessage.Nonce, after.Nonce)); - Assert.That(after.Version, Is.EqualTo(authMessage.Version)); - } + Assert.That(after.Signature, Is.EqualTo(authMessage.Signature)); + Assert.That(after.PublicKey, Is.EqualTo(authMessage.PublicKey)); + Assert.That(Bytes.AreEqual(authMessage.Nonce, after.Nonce), Is.True); + Assert.That(after.Version, Is.EqualTo(authMessage.Version)); + } - [TestCase(BlockchainIds.Mainnet)] - [TestCase(BlockchainIds.Morden)] - [TestCase(BlockchainIds.RootstockMainnet)] - [TestCase(BlockchainIds.DefaultGethPrivateChain)] - [TestCase(BlockchainIds.EthereumClassicMainnet)] - [TestCase(BlockchainIds.EthereumClassicTestnet)] - public void Encode_decode_before_eip155(int chainId) - { - EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); - TestEncodeDecode(ecdsa); - } + [TestCase(BlockchainIds.Mainnet)] + [TestCase(BlockchainIds.Morden)] + [TestCase(BlockchainIds.RootstockMainnet)] + [TestCase(BlockchainIds.DefaultGethPrivateChain)] + [TestCase(BlockchainIds.EthereumClassicMainnet)] + [TestCase(BlockchainIds.EthereumClassicTestnet)] + public void Encode_decode_before_eip155(int chainId) + { + EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); + TestEncodeDecode(ecdsa); + } - [TestCase(BlockchainIds.Mainnet)] - [TestCase(BlockchainIds.Sepolia)] - public void Encode_decode_with_eip155(int chainId) - { - EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); - TestEncodeDecode(ecdsa); - } + [TestCase(BlockchainIds.Mainnet)] + [TestCase(BlockchainIds.Sepolia)] + public void Encode_decode_with_eip155(int chainId) + { + EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); + TestEncodeDecode(ecdsa); + } - [Test] - public void TestBadVersion() - { - string rawMsg = "f8bab841b054620e0d28697f4d4cbc1b25873d45ba17a62d724fea574982b76885ba164423b0160e39943610fe8c795f5d5167e2f3b5d52452d255a6dfb95d8339f0361f00b840a84e79d9c17895ec9720603c950293a5570727240e83774c128ea1654e64880ae2b1384167cab68dc3b2e7d1a741220a98c9842f36c5daa6094e586914516928a016e33b0bacaa8a7b493e2e43ec1bdb45b28f2f9111066228fb3c1063ffd8067d932b383f24302935273b29302a2f2b3d2621212a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - IByteBuffer byteBuffer = Unpooled.Buffer(); - byteBuffer.WriteBytes(Bytes.FromHexString(rawMsg)); + [Test] + public void TestBadVersion() + { + string rawMsg = "f8bab841b054620e0d28697f4d4cbc1b25873d45ba17a62d724fea574982b76885ba164423b0160e39943610fe8c795f5d5167e2f3b5d52452d255a6dfb95d8339f0361f00b840a84e79d9c17895ec9720603c950293a5570727240e83774c128ea1654e64880ae2b1384167cab68dc3b2e7d1a741220a98c9842f36c5daa6094e586914516928a016e33b0bacaa8a7b493e2e43ec1bdb45b28f2f9111066228fb3c1063ffd8067d932b383f24302935273b29302a2f2b3d2621212a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + IByteBuffer byteBuffer = Unpooled.Buffer(); + byteBuffer.WriteBytes(Bytes.FromHexString(rawMsg)); - _serializer.Deserialize(byteBuffer); - } + _serializer.Deserialize(byteBuffer); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthMessageSerializerTests.cs index fac56e55d35..b65fd0c5b78 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthMessageSerializerTests.cs @@ -6,62 +6,59 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Crypto; -using Nethermind.Logging; using Nethermind.Network.Rlpx.Handshake; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx.Handshake +namespace Nethermind.Network.Test.Rlpx.Handshake; + +[Parallelizable(ParallelScope.Self)] +public class AuthMessageSerializerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class AuthMessageSerializerTests - { - private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; + private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; - private readonly Random _random = new(1); + private readonly Random _random = new(1); - private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); + private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); - private readonly AuthMessageSerializer _serializer = new(); + private readonly AuthMessageSerializer _serializer = new(); - private void TestEncodeDecode(IEthereumEcdsa ecdsa) - { - AuthMessage authMessage = new(); - authMessage.EphemeralPublicHash = new Hash256(new byte[AuthMessageSerializer.EphemeralHashLength]); - authMessage.Nonce = new byte[AuthMessageSerializer.NonceLength]; - authMessage.Signature = ecdsa.Sign(_privateKey, Keccak.Compute("anything")); - _random.NextBytes(authMessage.EphemeralPublicHash.Bytes); - authMessage.PublicKey = _privateKey.PublicKey; - _random.NextBytes(authMessage.Nonce); - authMessage.IsTokenUsed = true; - byte[] bytes = _serializer.Serialize(authMessage); - AuthMessage after = _serializer.Deserialize(bytes); + private void TestEncodeDecode(IEthereumEcdsa ecdsa) + { + AuthMessage authMessage = new(); + authMessage.EphemeralPublicHash = new Hash256(new byte[AuthMessageSerializer.EphemeralHashLength]); + authMessage.Nonce = new byte[AuthMessageSerializer.NonceLength]; + authMessage.Signature = ecdsa.Sign(_privateKey, Keccak.Compute("anything")); + _random.NextBytes(authMessage.EphemeralPublicHash.Bytes); + authMessage.PublicKey = _privateKey.PublicKey; + _random.NextBytes(authMessage.Nonce); + authMessage.IsTokenUsed = true; + byte[] bytes = _serializer.Serialize(authMessage); + AuthMessage after = _serializer.Deserialize(bytes); - Assert.That(after.Signature, Is.EqualTo(authMessage.Signature)); - Assert.That(after.EphemeralPublicHash, Is.EqualTo(authMessage.EphemeralPublicHash)); - Assert.That(after.PublicKey, Is.EqualTo(authMessage.PublicKey)); - Assert.True(Bytes.AreEqual(authMessage.Nonce, after.Nonce)); - Assert.That(after.IsTokenUsed, Is.EqualTo(authMessage.IsTokenUsed)); - } + Assert.That(after.Signature, Is.EqualTo(authMessage.Signature)); + Assert.That(after.EphemeralPublicHash, Is.EqualTo(authMessage.EphemeralPublicHash)); + Assert.That(after.PublicKey, Is.EqualTo(authMessage.PublicKey)); + Assert.That(Bytes.AreEqual(authMessage.Nonce, after.Nonce), Is.True); + Assert.That(after.IsTokenUsed, Is.EqualTo(authMessage.IsTokenUsed)); + } - [TestCase(BlockchainIds.Mainnet)] - [TestCase(BlockchainIds.Morden)] - [TestCase(BlockchainIds.RootstockMainnet)] - [TestCase(BlockchainIds.DefaultGethPrivateChain)] - [TestCase(BlockchainIds.EthereumClassicMainnet)] - [TestCase(BlockchainIds.EthereumClassicTestnet)] - public void Encode_decode_before_eip155(int chainId) - { - EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); - TestEncodeDecode(ecdsa); - } + [TestCase(BlockchainIds.Mainnet)] + [TestCase(BlockchainIds.Morden)] + [TestCase(BlockchainIds.RootstockMainnet)] + [TestCase(BlockchainIds.DefaultGethPrivateChain)] + [TestCase(BlockchainIds.EthereumClassicMainnet)] + [TestCase(BlockchainIds.EthereumClassicTestnet)] + public void Encode_decode_before_eip155(int chainId) + { + EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); + TestEncodeDecode(ecdsa); + } - [TestCase(BlockchainIds.Mainnet)] - [TestCase(BlockchainIds.Sepolia)] - public void Encode_decode_with_eip155(int chainId) - { - EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); - TestEncodeDecode(ecdsa); - } + [TestCase(BlockchainIds.Mainnet)] + [TestCase(BlockchainIds.Sepolia)] + public void Encode_decode_with_eip155(int chainId) + { + EthereumEcdsa ecdsa = new(BlockchainIds.Olympic); + TestEncodeDecode(ecdsa); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseEip8MessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseEip8MessageSerializerTests.cs index 646a1600843..eb980cf71c2 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseEip8MessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseEip8MessageSerializerTests.cs @@ -7,38 +7,36 @@ using Nethermind.Network.Rlpx.Handshake; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx.Handshake -{ - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class AuthResponseEip8MessageSerializerTests - { - private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; +namespace Nethermind.Network.Test.Rlpx.Handshake; - private readonly Random _random = new(1); +[Parallelizable(ParallelScope.Self)] +public class AuthResponseEip8MessageSerializerTests +{ + private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; - private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); + private readonly Random _random = new(1); - private readonly AckEip8MessageSerializer _serializer = new(new Eip8MessagePad(new CryptoRandom())); + private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); - private void TestEncodeDecode() - { - AckEip8Message before = new(); - before.EphemeralPublicKey = _privateKey.PublicKey; - before.Nonce = new byte[AckEip8MessageSerializer.NonceLength]; - _random.NextBytes(before.Nonce); - byte[] data = _serializer.Serialize(before); - AckEip8Message after = _serializer.Deserialize(data); + private readonly AckEip8MessageSerializer _serializer = new(new Eip8MessagePad(new CryptoRandom())); - Assert.That(after.EphemeralPublicKey, Is.EqualTo(before.EphemeralPublicKey)); - Assert.True(Bytes.AreEqual(before.Nonce, after.Nonce)); - Assert.That(after.Version, Is.EqualTo(0x04)); - } + private void TestEncodeDecode() + { + AckEip8Message before = new(); + before.EphemeralPublicKey = _privateKey.PublicKey; + before.Nonce = new byte[AckEip8MessageSerializer.NonceLength]; + _random.NextBytes(before.Nonce); + byte[] data = _serializer.Serialize(before); + AckEip8Message after = _serializer.Deserialize(data); + + Assert.That(after.EphemeralPublicKey, Is.EqualTo(before.EphemeralPublicKey)); + Assert.That(Bytes.AreEqual(before.Nonce, after.Nonce), Is.True); + Assert.That(after.Version, Is.EqualTo(0x04)); + } - [Test] - public void Test() - { - TestEncodeDecode(); - } + [Test] + public void Test() + { + TestEncodeDecode(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseMessageSerializerTests.cs index 40306e607c8..c87d3e3fa89 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/AuthResponseMessageSerializerTests.cs @@ -7,39 +7,37 @@ using Nethermind.Network.Rlpx.Handshake; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx.Handshake +namespace Nethermind.Network.Test.Rlpx.Handshake; + +[Parallelizable(ParallelScope.Self)] +public class AuthResponseMessageSerializerTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class AuthResponseMessageSerializerTests + private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; + + private readonly Random _random = new(1); + + private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); + + private readonly AckMessageSerializer _serializer = new(); + + private void TestEncodeDecode() + { + AckMessage before = new(); + before.EphemeralPublicKey = _privateKey.PublicKey; + before.Nonce = new byte[AckMessageSerializer.NonceLength]; + _random.NextBytes(before.Nonce); + before.IsTokenUsed = true; + byte[] data = _serializer.Serialize(before); + AckMessage after = _serializer.Deserialize(data); + + Assert.That(after.EphemeralPublicKey, Is.EqualTo(before.EphemeralPublicKey)); + Assert.That(Bytes.AreEqual(before.Nonce, after.Nonce), Is.True); + Assert.That(after.IsTokenUsed, Is.EqualTo(before.IsTokenUsed)); + } + + [Test] + public void Test() { - private const string TestPrivateKeyHex = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; - - private readonly Random _random = new(1); - - private readonly PrivateKey _privateKey = new(TestPrivateKeyHex); - - private readonly AckMessageSerializer _serializer = new(); - - private void TestEncodeDecode() - { - AckMessage before = new(); - before.EphemeralPublicKey = _privateKey.PublicKey; - before.Nonce = new byte[AckMessageSerializer.NonceLength]; - _random.NextBytes(before.Nonce); - before.IsTokenUsed = true; - byte[] data = _serializer.Serialize(before); - AckMessage after = _serializer.Deserialize(data); - - Assert.That(after.EphemeralPublicKey, Is.EqualTo(before.EphemeralPublicKey)); - Assert.True(Bytes.AreEqual(before.Nonce, after.Nonce)); - Assert.That(after.IsTokenUsed, Is.EqualTo(before.IsTokenUsed)); - } - - [Test] - public void Test() - { - TestEncodeDecode(); - } + TestEncodeDecode(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs index 7aee5a58582..ba13e4db511 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs @@ -13,216 +13,213 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx.Handshake +namespace Nethermind.Network.Test.Rlpx.Handshake; + +[Parallelizable(ParallelScope.Self)] +public class EciesCipherTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class EciesCipherTests + private IMessageSerializationService _messageSerializationService; + private TestRandom _cryptoRandom; + private IEciesCipher _eciesCipher; + + [SetUp] + public void Setup() + { + _cryptoRandom = new TestRandom(); + _eciesCipher = new EciesCipher(_cryptoRandom); + _messageSerializationService = Build.A.SerializationService().WithEncryptionHandshake().TestObject; + } + + [TearDown] + public void TearDown() => _cryptoRandom?.Dispose(); + + [Test] + public void Can_decrypt_auth_eip8_message_with_additional_elements() + { + byte[] allBytes = Bytes.FromHexString("01b8044c6c312173685d1edd268aa95e1d495474c6959bcdd10067ba4c9013df9e40ff45f5bfd6f7" + + "2471f93a91b493f8e00abc4b80f682973de715d77ba3a005a242eb859f9a211d93a347fa64b597bf" + + "280a6b88e26299cf263b01b8dfdb712278464fd1c25840b995e84d367d743f66c0e54a586725b7bb" + + "f12acca27170ae3283c1073adda4b6d79f27656993aefccf16e0d0409fe07db2dc398a1b7e8ee93b" + + "cd181485fd332f381d6a050fba4c7641a5112ac1b0b61168d20f01b479e19adf7fdbfa0905f63352" + + "bfc7e23cf3357657455119d879c78d3cf8c8c06375f3f7d4861aa02a122467e069acaf513025ff19" + + "6641f6d2810ce493f51bee9c966b15c5043505350392b57645385a18c78f14669cc4d960446c1757" + + "1b7c5d725021babbcd786957f3d17089c084907bda22c2b2675b4378b114c601d858802a55345a15" + + "116bc61da4193996187ed70d16730e9ae6b3bb8787ebcaea1871d850997ddc08b4f4ea668fbf3740" + + "7ac044b55be0908ecb94d4ed172ece66fd31bfdadf2b97a8bc690163ee11f5b575a4b44e36e2bfb2" + + "f0fce91676fd64c7773bac6a003f481fddd0bae0a1f31aa27504e2a533af4cef3b623f4791b2cca6" + + "d490"); + + Span sizeBytes = allBytes.AsSpan(0, 2); + int size = sizeBytes.ReadEthInt32(); + + (_, byte[] deciphered) = _eciesCipher.Decrypt(NetTestVectors.StaticKeyB, allBytes.Slice(2, size), sizeBytes.ToArray()); + + AuthEip8Message authMessage = _messageSerializationService.Deserialize(deciphered); + Assert.That(NetTestVectors.StaticKeyA.PublicKey, Is.EqualTo(authMessage.PublicKey)); + Assert.That(NetTestVectors.NonceA, Is.EqualTo(authMessage.Nonce)); + Assert.That(authMessage.Version, Is.EqualTo(4)); + Assert.That(authMessage.Signature, Is.Not.Null); + } + + [Test] + public void Can_decrypt_auth_message() + { + byte[] allBytes = Bytes.FromHexString("048ca79ad18e4b0659fab4853fe5bc58eb83992980f4c9cc147d2aa31532efd29a3d3dc6a3d89eaf" + + "913150cfc777ce0ce4af2758bf4810235f6e6ceccfee1acc6b22c005e9e3a49d6448610a58e98744" + + "ba3ac0399e82692d67c1f58849050b3024e21a52c9d3b01d871ff5f210817912773e610443a9ef14" + + "2e91cdba0bd77b5fdf0769b05671fc35f83d83e4d3b0b000c6b2a1b1bba89e0fc51bf4e460df3105" + + "c444f14be226458940d6061c296350937ffd5e3acaceeaaefd3c6f74be8e23e0f45163cc7ebd7622" + + "0f0128410fd05250273156d548a414444ae2f7dea4dfca2d43c057adb701a715bf59f6fb66b2d1d2" + + "0f2c703f851cbf5ac47396d9ca65b6260bd141ac4d53e2de585a73d1750780db4c9ee4cd4d225173" + + "a4592ee77e2bd94d0be3691f3b406f9bba9b591fc63facc016bfa8"); + + (_, byte[] deciphered) = _eciesCipher.Decrypt(NetTestVectors.StaticKeyB, allBytes); + + AuthMessage authMessage = _messageSerializationService.Deserialize(deciphered); + Assert.That(NetTestVectors.StaticKeyA.PublicKey, Is.EqualTo(authMessage.PublicKey)); + Assert.That(Keccak.Compute(NetTestVectors.EphemeralKeyA.PublicKey.Bytes), Is.EqualTo(authMessage.EphemeralPublicHash)); + Assert.That(NetTestVectors.NonceA, Is.EqualTo(authMessage.Nonce)); + Assert.That(authMessage.IsTokenUsed, Is.EqualTo(false)); + Assert.That(authMessage.Signature, Is.Not.Null); + + IByteBuffer data = _messageSerializationService.ZeroSerialize(authMessage); + Assert.That(data.ReadAllBytesAsArray(), Is.EqualTo(deciphered), "serialization"); + data.SafeRelease(); + } + + [Test] + public void Can_decrypt_auth_eip8_message() + { + byte[] allBytes = Bytes.FromHexString("01b304ab7578555167be8154d5cc456f567d5ba302662433674222360f08d5f1534499d3678b513b" + + "0fca474f3a514b18e75683032eb63fccb16c156dc6eb2c0b1593f0d84ac74f6e475f1b8d56116b84" + + "9634a8c458705bf83a626ea0384d4d7341aae591fae42ce6bd5c850bfe0b999a694a49bbbaf3ef6c" + + "da61110601d3b4c02ab6c30437257a6e0117792631a4b47c1d52fc0f8f89caadeb7d02770bf999cc" + + "147d2df3b62e1ffb2c9d8c125a3984865356266bca11ce7d3a688663a51d82defaa8aad69da39ab6" + + "d5470e81ec5f2a7a47fb865ff7cca21516f9299a07b1bc63ba56c7a1a892112841ca44b6e0034dee" + + "70c9adabc15d76a54f443593fafdc3b27af8059703f88928e199cb122362a4b35f62386da7caad09" + + "c001edaeb5f8a06d2b26fb6cb93c52a9fca51853b68193916982358fe1e5369e249875bb8d0d0ec3" + + "6f917bc5e1eafd5896d46bd61ff23f1a863a8a8dcd54c7b109b771c8e61ec9c8908c733c0263440e" + + "2aa067241aaa433f0bb053c7b31a838504b148f570c0ad62837129e547678c5190341e4f1693956c" + + "3bf7678318e2d5b5340c9e488eefea198576344afbdf66db5f51204a6961a63ce072c8926c"); + + Span sizeBytes = allBytes.AsSpan(0, 2); + int size = sizeBytes.ReadEthInt32(); + + ICryptoRandom cryptoRandom = new CryptoRandom(); + EciesCipher cipher = new(cryptoRandom); + (_, byte[] deciphered) = cipher.Decrypt(NetTestVectors.StaticKeyB, allBytes.Slice(2, size), sizeBytes.ToArray()); + + AuthEip8Message authMessage = _messageSerializationService.Deserialize(deciphered); + Assert.That(NetTestVectors.StaticKeyA.PublicKey, Is.EqualTo(authMessage.PublicKey)); + Assert.That(NetTestVectors.NonceA, Is.EqualTo(authMessage.Nonce)); + Assert.That(authMessage.Version, Is.EqualTo(4)); + Assert.That(authMessage.Signature, Is.Not.Null); + + IByteBuffer data = _messageSerializationService.ZeroSerialize(authMessage); + + Assert.That(data.Slice(0, 169).ReadAllBytesAsArray(), Is.EqualTo(deciphered.Slice(0, 169)), "serialization"); + data.SafeRelease(); + } + + [Test] + public void Can_decrypt_ack() { - private IMessageSerializationService _messageSerializationService; - private TestRandom _cryptoRandom; - private IEciesCipher _eciesCipher; - - [SetUp] - public void Setup() - { - _cryptoRandom = new TestRandom(); - _eciesCipher = new EciesCipher(_cryptoRandom); - _messageSerializationService = Build.A.SerializationService().WithEncryptionHandshake().TestObject; - } - - [TearDown] - public void TearDown() => _cryptoRandom?.Dispose(); - - [Test] - public void Can_decrypt_auth_eip8_message_with_additional_elements() - { - byte[] allBytes = Bytes.FromHexString("01b8044c6c312173685d1edd268aa95e1d495474c6959bcdd10067ba4c9013df9e40ff45f5bfd6f7" + - "2471f93a91b493f8e00abc4b80f682973de715d77ba3a005a242eb859f9a211d93a347fa64b597bf" + - "280a6b88e26299cf263b01b8dfdb712278464fd1c25840b995e84d367d743f66c0e54a586725b7bb" + - "f12acca27170ae3283c1073adda4b6d79f27656993aefccf16e0d0409fe07db2dc398a1b7e8ee93b" + - "cd181485fd332f381d6a050fba4c7641a5112ac1b0b61168d20f01b479e19adf7fdbfa0905f63352" + - "bfc7e23cf3357657455119d879c78d3cf8c8c06375f3f7d4861aa02a122467e069acaf513025ff19" + - "6641f6d2810ce493f51bee9c966b15c5043505350392b57645385a18c78f14669cc4d960446c1757" + - "1b7c5d725021babbcd786957f3d17089c084907bda22c2b2675b4378b114c601d858802a55345a15" + - "116bc61da4193996187ed70d16730e9ae6b3bb8787ebcaea1871d850997ddc08b4f4ea668fbf3740" + - "7ac044b55be0908ecb94d4ed172ece66fd31bfdadf2b97a8bc690163ee11f5b575a4b44e36e2bfb2" + - "f0fce91676fd64c7773bac6a003f481fddd0bae0a1f31aa27504e2a533af4cef3b623f4791b2cca6" + - "d490"); - - Span sizeBytes = allBytes.AsSpan(0, 2); - int size = sizeBytes.ReadEthInt32(); - - (_, byte[] deciphered) = _eciesCipher.Decrypt(NetTestVectors.StaticKeyB, allBytes.Slice(2, size), sizeBytes.ToArray()); - - AuthEip8Message authMessage = _messageSerializationService.Deserialize(deciphered); - Assert.That(NetTestVectors.StaticKeyA.PublicKey, Is.EqualTo(authMessage.PublicKey)); - Assert.That(NetTestVectors.NonceA, Is.EqualTo(authMessage.Nonce)); - Assert.That(authMessage.Version, Is.EqualTo(4)); - - Assert.NotNull(authMessage.Signature); - } - - [Test] - public void Can_decrypt_auth_message() - { - byte[] allBytes = Bytes.FromHexString("048ca79ad18e4b0659fab4853fe5bc58eb83992980f4c9cc147d2aa31532efd29a3d3dc6a3d89eaf" + - "913150cfc777ce0ce4af2758bf4810235f6e6ceccfee1acc6b22c005e9e3a49d6448610a58e98744" + - "ba3ac0399e82692d67c1f58849050b3024e21a52c9d3b01d871ff5f210817912773e610443a9ef14" + - "2e91cdba0bd77b5fdf0769b05671fc35f83d83e4d3b0b000c6b2a1b1bba89e0fc51bf4e460df3105" + - "c444f14be226458940d6061c296350937ffd5e3acaceeaaefd3c6f74be8e23e0f45163cc7ebd7622" + - "0f0128410fd05250273156d548a414444ae2f7dea4dfca2d43c057adb701a715bf59f6fb66b2d1d2" + - "0f2c703f851cbf5ac47396d9ca65b6260bd141ac4d53e2de585a73d1750780db4c9ee4cd4d225173" + - "a4592ee77e2bd94d0be3691f3b406f9bba9b591fc63facc016bfa8"); - - (_, byte[] deciphered) = _eciesCipher.Decrypt(NetTestVectors.StaticKeyB, allBytes); - - AuthMessage authMessage = _messageSerializationService.Deserialize(deciphered); - Assert.That(NetTestVectors.StaticKeyA.PublicKey, Is.EqualTo(authMessage.PublicKey)); - Assert.That(Keccak.Compute(NetTestVectors.EphemeralKeyA.PublicKey.Bytes), Is.EqualTo(authMessage.EphemeralPublicHash)); - Assert.That(NetTestVectors.NonceA, Is.EqualTo(authMessage.Nonce)); - Assert.That(authMessage.IsTokenUsed, Is.EqualTo(false)); - Assert.NotNull(authMessage.Signature); - - IByteBuffer data = _messageSerializationService.ZeroSerialize(authMessage); - Assert.That(data.ReadAllBytesAsArray(), Is.EqualTo(deciphered), "serialization"); - data.SafeRelease(); - } - - [Test] - public void Can_decrypt_auth_eip8_message() - { - byte[] allBytes = Bytes.FromHexString("01b304ab7578555167be8154d5cc456f567d5ba302662433674222360f08d5f1534499d3678b513b" + - "0fca474f3a514b18e75683032eb63fccb16c156dc6eb2c0b1593f0d84ac74f6e475f1b8d56116b84" + - "9634a8c458705bf83a626ea0384d4d7341aae591fae42ce6bd5c850bfe0b999a694a49bbbaf3ef6c" + - "da61110601d3b4c02ab6c30437257a6e0117792631a4b47c1d52fc0f8f89caadeb7d02770bf999cc" + - "147d2df3b62e1ffb2c9d8c125a3984865356266bca11ce7d3a688663a51d82defaa8aad69da39ab6" + - "d5470e81ec5f2a7a47fb865ff7cca21516f9299a07b1bc63ba56c7a1a892112841ca44b6e0034dee" + - "70c9adabc15d76a54f443593fafdc3b27af8059703f88928e199cb122362a4b35f62386da7caad09" + - "c001edaeb5f8a06d2b26fb6cb93c52a9fca51853b68193916982358fe1e5369e249875bb8d0d0ec3" + - "6f917bc5e1eafd5896d46bd61ff23f1a863a8a8dcd54c7b109b771c8e61ec9c8908c733c0263440e" + - "2aa067241aaa433f0bb053c7b31a838504b148f570c0ad62837129e547678c5190341e4f1693956c" + - "3bf7678318e2d5b5340c9e488eefea198576344afbdf66db5f51204a6961a63ce072c8926c"); - - Span sizeBytes = allBytes.AsSpan(0, 2); - int size = sizeBytes.ReadEthInt32(); - - ICryptoRandom cryptoRandom = new CryptoRandom(); - EciesCipher cipher = new(cryptoRandom); - (_, byte[] deciphered) = cipher.Decrypt(NetTestVectors.StaticKeyB, allBytes.Slice(2, size), sizeBytes.ToArray()); - - AuthEip8Message authMessage = _messageSerializationService.Deserialize(deciphered); - Assert.That(NetTestVectors.StaticKeyA.PublicKey, Is.EqualTo(authMessage.PublicKey)); - Assert.That(NetTestVectors.NonceA, Is.EqualTo(authMessage.Nonce)); - Assert.That(authMessage.Version, Is.EqualTo(4)); - Assert.NotNull(authMessage.Signature); - - IByteBuffer data = _messageSerializationService.ZeroSerialize(authMessage); - - Assert.That(data.Slice(0, 169).ReadAllBytesAsArray(), Is.EqualTo(deciphered.Slice(0, 169)), "serialization"); - data.SafeRelease(); - } - - [Test] - public void Can_decrypt_ack() - { - byte[] allBytes = Bytes.FromHexString("049f8abcfa9c0dc65b982e98af921bc0ba6e4243169348a236abe9df5f93aa69d99cadddaa387662" + - "b0ff2c08e9006d5a11a278b1b3331e5aaabf0a32f01281b6f4ede0e09a2d5f585b26513cb794d963" + - "5a57563921c04a9090b4f14ee42be1a5461049af4ea7a7f49bf4c97a352d39c8d02ee4acc416388c" + - "1c66cec761d2bc1c72da6ba143477f049c9d2dde846c252c111b904f630ac98e51609b3b1f58168d" + - "dca6505b7196532e5f85b259a20c45e1979491683fee108e9660edbf38f3add489ae73e3dda2c71b" + - "d1497113d5c755e942d1"); - - (_, byte[] deciphered) = _eciesCipher.Decrypt(NetTestVectors.StaticKeyA, allBytes); - - AckMessage ackMessage = _messageSerializationService.Deserialize(deciphered); - Assert.That(NetTestVectors.EphemeralKeyB.PublicKey, Is.EqualTo(ackMessage.EphemeralPublicKey)); - Assert.That(NetTestVectors.NonceB, Is.EqualTo(ackMessage.Nonce)); - Assert.That(ackMessage.IsTokenUsed, Is.EqualTo(false)); - - IByteBuffer data = _messageSerializationService.ZeroSerialize(ackMessage); - Assert.That(data.ReadAllBytesAsArray(), Is.EqualTo(deciphered), "serialization"); - data.SafeRelease(); - } - - [Test] - public void Can_decrypt_ack_eip8_message() - { - byte[] allBytes = Bytes.FromHexString("01ea0451958701280a56482929d3b0757da8f7fbe5286784beead59d95089c217c9b917788989470" + - "b0e330cc6e4fb383c0340ed85fab836ec9fb8a49672712aeabbdfd1e837c1ff4cace34311cd7f4de" + - "05d59279e3524ab26ef753a0095637ac88f2b499b9914b5f64e143eae548a1066e14cd2f4bd7f814" + - "c4652f11b254f8a2d0191e2f5546fae6055694aed14d906df79ad3b407d94692694e259191cde171" + - "ad542fc588fa2b7333313d82a9f887332f1dfc36cea03f831cb9a23fea05b33deb999e85489e645f" + - "6aab1872475d488d7bd6c7c120caf28dbfc5d6833888155ed69d34dbdc39c1f299be1057810f34fb" + - "e754d021bfca14dc989753d61c413d261934e1a9c67ee060a25eefb54e81a4d14baff922180c395d" + - "3f998d70f46f6b58306f969627ae364497e73fc27f6d17ae45a413d322cb8814276be6ddd13b885b" + - "201b943213656cde498fa0e9ddc8e0b8f8a53824fbd82254f3e2c17e8eaea009c38b4aa0a3f306e8" + - "797db43c25d68e86f262e564086f59a2fc60511c42abfb3057c247a8a8fe4fb3ccbadde17514b7ac" + - "8000cdb6a912778426260c47f38919a91f25f4b5ffb455d6aaaf150f7e5529c100ce62d6d92826a7" + - "1778d809bdf60232ae21ce8a437eca8223f45ac37f6487452ce626f549b3b5fdee26afd2072e4bc7" + - "5833c2464c805246155289f4"); - - Span sizeBytes = allBytes.AsSpan(0, 2); - int size = sizeBytes.ReadEthInt32(); - - ICryptoRandom cryptoRandom = new CryptoRandom(); - EciesCipher cipher = new(cryptoRandom); - (_, byte[] deciphered) = cipher.Decrypt(NetTestVectors.StaticKeyA, allBytes.Slice(2, size), sizeBytes.ToArray()); - - AckEip8Message ackMessage = _messageSerializationService.Deserialize(deciphered); - Assert.That(NetTestVectors.EphemeralKeyB.PublicKey, Is.EqualTo(ackMessage.EphemeralPublicKey)); - Assert.That(NetTestVectors.NonceB, Is.EqualTo(ackMessage.Nonce)); - Assert.That(ackMessage.Version, Is.EqualTo(4)); - - IByteBuffer data = _messageSerializationService.ZeroSerialize(ackMessage); - - // TODO: check 102 - Assert.That(data.ReadAllBytesAsArray().Slice(0, 102), Is.EqualTo(deciphered.Slice(0, 102)), "serialization"); - data.SafeRelease(); - } - - [Test] - public void Can_decrypt_ack_eip8_message_with_additional_elements() - { - byte[] allBytes = Bytes.FromHexString("01f004076e58aae772bb101ab1a8e64e01ee96e64857ce82b1113817c6cdd52c09d26f7b90981cd7" + - "ae835aeac72e1573b8a0225dd56d157a010846d888dac7464baf53f2ad4e3d584531fa203658fab0" + - "3a06c9fd5e35737e417bc28c1cbf5e5dfc666de7090f69c3b29754725f84f75382891c561040ea1d" + - "dc0d8f381ed1b9d0d4ad2a0ec021421d847820d6fa0ba66eaf58175f1b235e851c7e2124069fbc20" + - "2888ddb3ac4d56bcbd1b9b7eab59e78f2e2d400905050f4a92dec1c4bdf797b3fc9b2f8e84a482f3" + - "d800386186712dae00d5c386ec9387a5e9c9a1aca5a573ca91082c7d68421f388e79127a5177d4f8" + - "590237364fd348c9611fa39f78dcdceee3f390f07991b7b47e1daa3ebcb6ccc9607811cb17ce51f1" + - "c8c2c5098dbdd28fca547b3f58c01a424ac05f869f49c6a34672ea2cbbc558428aa1fe48bbfd6115" + - "8b1b735a65d99f21e70dbc020bfdface9f724a0d1fb5895db971cc81aa7608baa0920abb0a565c9c" + - "436e2fd13323428296c86385f2384e408a31e104670df0791d93e743a3a5194ee6b076fb6323ca59" + - "3011b7348c16cf58f66b9633906ba54a2ee803187344b394f75dd2e663a57b956cb830dd7a908d4f" + - "39a2336a61ef9fda549180d4ccde21514d117b6c6fd07a9102b5efe710a32af4eeacae2cb3b1dec0" + - "35b9593b48b9d3ca4c13d245d5f04169b0b1"); - - Span sizeBytes = allBytes.AsSpan(0, 2); - int size = sizeBytes.ReadEthInt32(); - - ICryptoRandom cryptoRandom = new CryptoRandom(); - EciesCipher cipher = new(cryptoRandom); - (_, byte[] deciphered) = cipher.Decrypt(NetTestVectors.StaticKeyA, allBytes.Slice(2, size), sizeBytes.ToArray()); - - AckEip8Message ackMessage = _messageSerializationService.Deserialize(deciphered); - Assert.That(NetTestVectors.EphemeralKeyB.PublicKey, Is.EqualTo(ackMessage.EphemeralPublicKey)); - Assert.That(NetTestVectors.NonceB, Is.EqualTo(ackMessage.Nonce)); - Assert.That(ackMessage.Version, Is.EqualTo(4)); - } - - [Test] - public void Can_do_roundtrip() - { - PrivateKey privateKey = NetTestVectors.StaticKeyA; - - byte[] plainText = { 1, 2, 3, 4, 5 }; - _cryptoRandom.EnqueueRandomBytes(Bytes.FromHexString("0x0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a")); - _cryptoRandom.EnqueueRandomBytes(NetTestVectors.EphemeralKeyA.KeyBytes); - byte[] cipherText = _eciesCipher.Encrypt(privateKey.PublicKey, plainText, null); // public(65) | IV(16) | cipher(...) - - (_, byte[] deciphered) = _eciesCipher.Decrypt(privateKey, cipherText); - Assert.That(deciphered, Is.EqualTo(plainText)); - } + byte[] allBytes = Bytes.FromHexString("049f8abcfa9c0dc65b982e98af921bc0ba6e4243169348a236abe9df5f93aa69d99cadddaa387662" + + "b0ff2c08e9006d5a11a278b1b3331e5aaabf0a32f01281b6f4ede0e09a2d5f585b26513cb794d963" + + "5a57563921c04a9090b4f14ee42be1a5461049af4ea7a7f49bf4c97a352d39c8d02ee4acc416388c" + + "1c66cec761d2bc1c72da6ba143477f049c9d2dde846c252c111b904f630ac98e51609b3b1f58168d" + + "dca6505b7196532e5f85b259a20c45e1979491683fee108e9660edbf38f3add489ae73e3dda2c71b" + + "d1497113d5c755e942d1"); + + (_, byte[] deciphered) = _eciesCipher.Decrypt(NetTestVectors.StaticKeyA, allBytes); + + AckMessage ackMessage = _messageSerializationService.Deserialize(deciphered); + Assert.That(NetTestVectors.EphemeralKeyB.PublicKey, Is.EqualTo(ackMessage.EphemeralPublicKey)); + Assert.That(NetTestVectors.NonceB, Is.EqualTo(ackMessage.Nonce)); + Assert.That(ackMessage.IsTokenUsed, Is.EqualTo(false)); + + IByteBuffer data = _messageSerializationService.ZeroSerialize(ackMessage); + Assert.That(data.ReadAllBytesAsArray(), Is.EqualTo(deciphered), "serialization"); + data.SafeRelease(); + } + + [Test] + public void Can_decrypt_ack_eip8_message() + { + byte[] allBytes = Bytes.FromHexString("01ea0451958701280a56482929d3b0757da8f7fbe5286784beead59d95089c217c9b917788989470" + + "b0e330cc6e4fb383c0340ed85fab836ec9fb8a49672712aeabbdfd1e837c1ff4cace34311cd7f4de" + + "05d59279e3524ab26ef753a0095637ac88f2b499b9914b5f64e143eae548a1066e14cd2f4bd7f814" + + "c4652f11b254f8a2d0191e2f5546fae6055694aed14d906df79ad3b407d94692694e259191cde171" + + "ad542fc588fa2b7333313d82a9f887332f1dfc36cea03f831cb9a23fea05b33deb999e85489e645f" + + "6aab1872475d488d7bd6c7c120caf28dbfc5d6833888155ed69d34dbdc39c1f299be1057810f34fb" + + "e754d021bfca14dc989753d61c413d261934e1a9c67ee060a25eefb54e81a4d14baff922180c395d" + + "3f998d70f46f6b58306f969627ae364497e73fc27f6d17ae45a413d322cb8814276be6ddd13b885b" + + "201b943213656cde498fa0e9ddc8e0b8f8a53824fbd82254f3e2c17e8eaea009c38b4aa0a3f306e8" + + "797db43c25d68e86f262e564086f59a2fc60511c42abfb3057c247a8a8fe4fb3ccbadde17514b7ac" + + "8000cdb6a912778426260c47f38919a91f25f4b5ffb455d6aaaf150f7e5529c100ce62d6d92826a7" + + "1778d809bdf60232ae21ce8a437eca8223f45ac37f6487452ce626f549b3b5fdee26afd2072e4bc7" + + "5833c2464c805246155289f4"); + + Span sizeBytes = allBytes.AsSpan(0, 2); + int size = sizeBytes.ReadEthInt32(); + + ICryptoRandom cryptoRandom = new CryptoRandom(); + EciesCipher cipher = new(cryptoRandom); + (_, byte[] deciphered) = cipher.Decrypt(NetTestVectors.StaticKeyA, allBytes.Slice(2, size), sizeBytes.ToArray()); + + AckEip8Message ackMessage = _messageSerializationService.Deserialize(deciphered); + Assert.That(NetTestVectors.EphemeralKeyB.PublicKey, Is.EqualTo(ackMessage.EphemeralPublicKey)); + Assert.That(NetTestVectors.NonceB, Is.EqualTo(ackMessage.Nonce)); + Assert.That(ackMessage.Version, Is.EqualTo(4)); + + IByteBuffer data = _messageSerializationService.ZeroSerialize(ackMessage); + + // TODO: check 102 + Assert.That(data.ReadAllBytesAsArray().Slice(0, 102), Is.EqualTo(deciphered.Slice(0, 102)), "serialization"); + data.SafeRelease(); + } + + [Test] + public void Can_decrypt_ack_eip8_message_with_additional_elements() + { + byte[] allBytes = Bytes.FromHexString("01f004076e58aae772bb101ab1a8e64e01ee96e64857ce82b1113817c6cdd52c09d26f7b90981cd7" + + "ae835aeac72e1573b8a0225dd56d157a010846d888dac7464baf53f2ad4e3d584531fa203658fab0" + + "3a06c9fd5e35737e417bc28c1cbf5e5dfc666de7090f69c3b29754725f84f75382891c561040ea1d" + + "dc0d8f381ed1b9d0d4ad2a0ec021421d847820d6fa0ba66eaf58175f1b235e851c7e2124069fbc20" + + "2888ddb3ac4d56bcbd1b9b7eab59e78f2e2d400905050f4a92dec1c4bdf797b3fc9b2f8e84a482f3" + + "d800386186712dae00d5c386ec9387a5e9c9a1aca5a573ca91082c7d68421f388e79127a5177d4f8" + + "590237364fd348c9611fa39f78dcdceee3f390f07991b7b47e1daa3ebcb6ccc9607811cb17ce51f1" + + "c8c2c5098dbdd28fca547b3f58c01a424ac05f869f49c6a34672ea2cbbc558428aa1fe48bbfd6115" + + "8b1b735a65d99f21e70dbc020bfdface9f724a0d1fb5895db971cc81aa7608baa0920abb0a565c9c" + + "436e2fd13323428296c86385f2384e408a31e104670df0791d93e743a3a5194ee6b076fb6323ca59" + + "3011b7348c16cf58f66b9633906ba54a2ee803187344b394f75dd2e663a57b956cb830dd7a908d4f" + + "39a2336a61ef9fda549180d4ccde21514d117b6c6fd07a9102b5efe710a32af4eeacae2cb3b1dec0" + + "35b9593b48b9d3ca4c13d245d5f04169b0b1"); + + Span sizeBytes = allBytes.AsSpan(0, 2); + int size = sizeBytes.ReadEthInt32(); + + ICryptoRandom cryptoRandom = new CryptoRandom(); + EciesCipher cipher = new(cryptoRandom); + (_, byte[] deciphered) = cipher.Decrypt(NetTestVectors.StaticKeyA, allBytes.Slice(2, size), sizeBytes.ToArray()); + + AckEip8Message ackMessage = _messageSerializationService.Deserialize(deciphered); + Assert.That(NetTestVectors.EphemeralKeyB.PublicKey, Is.EqualTo(ackMessage.EphemeralPublicKey)); + Assert.That(NetTestVectors.NonceB, Is.EqualTo(ackMessage.Nonce)); + Assert.That(ackMessage.Version, Is.EqualTo(4)); + } + + [Test] + public void Can_do_roundtrip() + { + PrivateKey privateKey = NetTestVectors.StaticKeyA; + + byte[] plainText = { 1, 2, 3, 4, 5 }; + _cryptoRandom.EnqueueRandomBytes(Bytes.FromHexString("0x0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a")); + _cryptoRandom.EnqueueRandomBytes(NetTestVectors.EphemeralKeyA.KeyBytes); + byte[] cipherText = _eciesCipher.Encrypt(privateKey.PublicKey, plainText, null); // public(65) | IV(16) | cipher(...) + + (_, byte[] deciphered) = _eciesCipher.Decrypt(privateKey, cipherText); + Assert.That(deciphered, Is.EqualTo(plainText)); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EncryptionHandshakeServiceTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EncryptionHandshakeServiceTests.cs index 566387af20f..ce128755a73 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EncryptionHandshakeServiceTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EncryptionHandshakeServiceTests.cs @@ -10,306 +10,304 @@ using Nethermind.Network.Rlpx.Handshake; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx.Handshake +namespace Nethermind.Network.Test.Rlpx.Handshake; + +[Parallelizable(ParallelScope.Self)] +public class EncryptionHandshakeServiceTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class EncryptionHandshakeServiceTests + [SetUp] + public void SetUp() { - [SetUp] - public void SetUp() - { - _trueCryptoRandom = new CryptoRandom(); + _trueCryptoRandom = new CryptoRandom(); - _testRandom = new TestRandom(); + _testRandom = new TestRandom(); - _messageSerializationService = new MessageSerializationService(); - _messageSerializationService.Register(new AuthMessageSerializer()); - _messageSerializationService.Register(new AuthEip8MessageSerializer(new Eip8MessagePad(_testRandom))); - _messageSerializationService.Register(new AckMessageSerializer()); - _messageSerializationService.Register(new AckEip8MessageSerializer(new Eip8MessagePad(_testRandom))); + _messageSerializationService = new MessageSerializationService(); + _messageSerializationService.Register(new AuthMessageSerializer()); + _messageSerializationService.Register(new AuthEip8MessageSerializer(new Eip8MessagePad(_testRandom))); + _messageSerializationService.Register(new AckMessageSerializer()); + _messageSerializationService.Register(new AckEip8MessageSerializer(new Eip8MessagePad(_testRandom))); - _eciesCipher = new EciesCipher(_trueCryptoRandom); // TODO: provide a separate test random with specific IV and epehemeral key for testing + _eciesCipher = new EciesCipher(_trueCryptoRandom); // TODO: provide a separate test random with specific IV and epehemeral key for testing - _initiatorService = new HandshakeService(_messageSerializationService, _eciesCipher, _testRandom, _ecdsa, NetTestVectors.StaticKeyA, LimboLogs.Instance); - _recipientService = new HandshakeService(_messageSerializationService, _eciesCipher, _testRandom, _ecdsa, NetTestVectors.StaticKeyB, LimboLogs.Instance); + _initiatorService = new HandshakeService(_messageSerializationService, _eciesCipher, _testRandom, _ecdsa, NetTestVectors.StaticKeyA, LimboLogs.Instance); + _recipientService = new HandshakeService(_messageSerializationService, _eciesCipher, _testRandom, _ecdsa, NetTestVectors.StaticKeyB, LimboLogs.Instance); - _initiatorHandshake = new EncryptionHandshake(); - _recipientHandshake = new EncryptionHandshake(); + _initiatorHandshake = new EncryptionHandshake(); + _recipientHandshake = new EncryptionHandshake(); - _auth = null; - _ack = null; - } + _auth = null; + _ack = null; + } - [TearDown] - public void TearDown() - { - _testRandom?.Dispose(); - _trueCryptoRandom?.Dispose(); - } + [TearDown] + public void TearDown() + { + _testRandom?.Dispose(); + _trueCryptoRandom?.Dispose(); + } - private readonly IEthereumEcdsa _ecdsa = new EthereumEcdsa(BlockchainIds.Sepolia); // TODO: separate general crypto signer from Ethereum transaction signing + private readonly IEthereumEcdsa _ecdsa = new EthereumEcdsa(BlockchainIds.Sepolia); // TODO: separate general crypto signer from Ethereum transaction signing - private IMessageSerializationService _messageSerializationService; + private IMessageSerializationService _messageSerializationService; - private TestRandom _testRandom; + private TestRandom _testRandom; - private ICryptoRandom _trueCryptoRandom; + private ICryptoRandom _trueCryptoRandom; - private IEciesCipher _eciesCipher; + private IEciesCipher _eciesCipher; - private IHandshakeService _initiatorService; + private IHandshakeService _initiatorService; - private IHandshakeService _recipientService; + private IHandshakeService _recipientService; - private EncryptionHandshake _initiatorHandshake; - private EncryptionHandshake _recipientHandshake; + private EncryptionHandshake _initiatorHandshake; + private EncryptionHandshake _recipientHandshake; - private Packet _auth; - private Packet _ack; + private Packet _auth; + private Packet _ack; - private void Auth(bool preEip8Format = false) - { - _auth = _initiatorService.Auth(NetTestVectors.StaticKeyB.PublicKey, _initiatorHandshake, preEip8Format); - } + private void Auth(bool preEip8Format = false) + { + _auth = _initiatorService.Auth(NetTestVectors.StaticKeyB.PublicKey, _initiatorHandshake, preEip8Format); + } - private void Ack() - { - _ack = _recipientService.Ack(_recipientHandshake, _auth); - } + private void Ack() + { + _ack = _recipientService.Ack(_recipientHandshake, _auth); + } - private void Agree() - { - _initiatorService.Agree(_initiatorHandshake, _ack); - } + private void Agree() + { + _initiatorService.Agree(_initiatorHandshake, _ack); + } - private void InitializeRandom(bool preEip8Format = false) + private void InitializeRandom(bool preEip8Format = false) + { + // WARN: order reflects the internal implementation of the service (tests may fail after any refactoring) + if (preEip8Format) { - // WARN: order reflects the internal implementation of the service (tests may fail after any refactoring) - if (preEip8Format) - { - _testRandom.EnqueueRandomBytes(NetTestVectors.NonceA, - NetTestVectors.EphemeralKeyA.KeyBytes, - NetTestVectors.NonceB, - NetTestVectors.EphemeralKeyB.KeyBytes); - } - else - { - _testRandom.EnqueueRandomBytes(NetTestVectors.NonceA, - NetTestVectors.EphemeralKeyA.KeyBytes, - _trueCryptoRandom.GenerateRandomBytes(100), - NetTestVectors.NonceB, - NetTestVectors.EphemeralKeyB.KeyBytes, - _trueCryptoRandom.GenerateRandomBytes(100)); - } + _testRandom.EnqueueRandomBytes(NetTestVectors.NonceA, + NetTestVectors.EphemeralKeyA.KeyBytes, + NetTestVectors.NonceB, + NetTestVectors.EphemeralKeyB.KeyBytes); } - - /// - /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-8.md - /// - [Test] - public void Aes_and_mac_secrets_as_in_test_vectors() + else { - InitializeRandom(); - Packet auth = _initiatorService.Auth(NetTestVectors.StaticKeyB.PublicKey, _initiatorHandshake); - // TODO: cannot recover signature from this one... - auth.Data = Bytes.FromHexString( - "01b304ab7578555167be8154d5cc456f567d5ba302662433674222360f08d5f1534499d3678b513b" + - "0fca474f3a514b18e75683032eb63fccb16c156dc6eb2c0b1593f0d84ac74f6e475f1b8d56116b84" + - "9634a8c458705bf83a626ea0384d4d7341aae591fae42ce6bd5c850bfe0b999a694a49bbbaf3ef6c" + - "da61110601d3b4c02ab6c30437257a6e0117792631a4b47c1d52fc0f8f89caadeb7d02770bf999cc" + - "147d2df3b62e1ffb2c9d8c125a3984865356266bca11ce7d3a688663a51d82defaa8aad69da39ab6" + - "d5470e81ec5f2a7a47fb865ff7cca21516f9299a07b1bc63ba56c7a1a892112841ca44b6e0034dee" + - "70c9adabc15d76a54f443593fafdc3b27af8059703f88928e199cb122362a4b35f62386da7caad09" + - "c001edaeb5f8a06d2b26fb6cb93c52a9fca51853b68193916982358fe1e5369e249875bb8d0d0ec3" + - "6f917bc5e1eafd5896d46bd61ff23f1a863a8a8dcd54c7b109b771c8e61ec9c8908c733c0263440e" + - "2aa067241aaa433f0bb053c7b31a838504b148f570c0ad62837129e547678c5190341e4f1693956c" + - "3bf7678318e2d5b5340c9e488eefea198576344afbdf66db5f51204a6961a63ce072c8926c"); - - Packet ack = _recipientService.Ack(_recipientHandshake, auth); - ack.Data = Bytes.FromHexString( - "01ea0451958701280a56482929d3b0757da8f7fbe5286784beead59d95089c217c9b917788989470" + - "b0e330cc6e4fb383c0340ed85fab836ec9fb8a49672712aeabbdfd1e837c1ff4cace34311cd7f4de" + - "05d59279e3524ab26ef753a0095637ac88f2b499b9914b5f64e143eae548a1066e14cd2f4bd7f814" + - "c4652f11b254f8a2d0191e2f5546fae6055694aed14d906df79ad3b407d94692694e259191cde171" + - "ad542fc588fa2b7333313d82a9f887332f1dfc36cea03f831cb9a23fea05b33deb999e85489e645f" + - "6aab1872475d488d7bd6c7c120caf28dbfc5d6833888155ed69d34dbdc39c1f299be1057810f34fb" + - "e754d021bfca14dc989753d61c413d261934e1a9c67ee060a25eefb54e81a4d14baff922180c395d" + - "3f998d70f46f6b58306f969627ae364497e73fc27f6d17ae45a413d322cb8814276be6ddd13b885b" + - "201b943213656cde498fa0e9ddc8e0b8f8a53824fbd82254f3e2c17e8eaea009c38b4aa0a3f306e8" + - "797db43c25d68e86f262e564086f59a2fc60511c42abfb3057c247a8a8fe4fb3ccbadde17514b7ac" + - "8000cdb6a912778426260c47f38919a91f25f4b5ffb455d6aaaf150f7e5529c100ce62d6d92826a7" + - "1778d809bdf60232ae21ce8a437eca8223f45ac37f6487452ce626f549b3b5fdee26afd2072e4bc7" + - "5833c2464c805246155289f4"); - - _initiatorService.Agree(_initiatorHandshake, ack); - - Assert.That(_initiatorHandshake.Secrets.AesSecret, Is.EqualTo(NetTestVectors.AesSecret), "initiator AES"); - Assert.That(_recipientHandshake.Secrets.AesSecret, Is.EqualTo(NetTestVectors.AesSecret), "recipient AES"); - Assert.That(_initiatorHandshake.Secrets.MacSecret, Is.EqualTo(NetTestVectors.MacSecret), "initiator MAC"); - Assert.That(_recipientHandshake.Secrets.MacSecret, Is.EqualTo(NetTestVectors.MacSecret), "recipient MAC"); - - // TODO: below failing, probably different format after serialization / during encryption (only tested decryption / deserialization in EciesCoder) - // ingress uses the auth packet which is encrypted with a random IV and ephemeral key - need to remove that randomness for tests - byte[] fooBytes = Encoding.ASCII.GetBytes("foo"); - _recipientHandshake.Secrets.IngressMac.Update(fooBytes); - - byte[] ingressFooResult = _recipientHandshake.Secrets.IngressMac.Hash; - Assert.That(ingressFooResult, Is.EqualTo(NetTestVectors.BIngressMacFoo), "recipient ingress foo"); + _testRandom.EnqueueRandomBytes(NetTestVectors.NonceA, + NetTestVectors.EphemeralKeyA.KeyBytes, + _trueCryptoRandom.GenerateRandomBytes(100), + NetTestVectors.NonceB, + NetTestVectors.EphemeralKeyB.KeyBytes, + _trueCryptoRandom.GenerateRandomBytes(100)); } + } - [TestCase(true)] - [TestCase(false)] - public void Agrees_on_secrets(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Agree(); + /// + /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-8.md + /// + [Test] + public void Aes_and_mac_secrets_as_in_test_vectors() + { + InitializeRandom(); + Packet auth = _initiatorService.Auth(NetTestVectors.StaticKeyB.PublicKey, _initiatorHandshake); + // TODO: cannot recover signature from this one... + auth.Data = Bytes.FromHexString( + "01b304ab7578555167be8154d5cc456f567d5ba302662433674222360f08d5f1534499d3678b513b" + + "0fca474f3a514b18e75683032eb63fccb16c156dc6eb2c0b1593f0d84ac74f6e475f1b8d56116b84" + + "9634a8c458705bf83a626ea0384d4d7341aae591fae42ce6bd5c850bfe0b999a694a49bbbaf3ef6c" + + "da61110601d3b4c02ab6c30437257a6e0117792631a4b47c1d52fc0f8f89caadeb7d02770bf999cc" + + "147d2df3b62e1ffb2c9d8c125a3984865356266bca11ce7d3a688663a51d82defaa8aad69da39ab6" + + "d5470e81ec5f2a7a47fb865ff7cca21516f9299a07b1bc63ba56c7a1a892112841ca44b6e0034dee" + + "70c9adabc15d76a54f443593fafdc3b27af8059703f88928e199cb122362a4b35f62386da7caad09" + + "c001edaeb5f8a06d2b26fb6cb93c52a9fca51853b68193916982358fe1e5369e249875bb8d0d0ec3" + + "6f917bc5e1eafd5896d46bd61ff23f1a863a8a8dcd54c7b109b771c8e61ec9c8908c733c0263440e" + + "2aa067241aaa433f0bb053c7b31a838504b148f570c0ad62837129e547678c5190341e4f1693956c" + + "3bf7678318e2d5b5340c9e488eefea198576344afbdf66db5f51204a6961a63ce072c8926c"); + + Packet ack = _recipientService.Ack(_recipientHandshake, auth); + ack.Data = Bytes.FromHexString( + "01ea0451958701280a56482929d3b0757da8f7fbe5286784beead59d95089c217c9b917788989470" + + "b0e330cc6e4fb383c0340ed85fab836ec9fb8a49672712aeabbdfd1e837c1ff4cace34311cd7f4de" + + "05d59279e3524ab26ef753a0095637ac88f2b499b9914b5f64e143eae548a1066e14cd2f4bd7f814" + + "c4652f11b254f8a2d0191e2f5546fae6055694aed14d906df79ad3b407d94692694e259191cde171" + + "ad542fc588fa2b7333313d82a9f887332f1dfc36cea03f831cb9a23fea05b33deb999e85489e645f" + + "6aab1872475d488d7bd6c7c120caf28dbfc5d6833888155ed69d34dbdc39c1f299be1057810f34fb" + + "e754d021bfca14dc989753d61c413d261934e1a9c67ee060a25eefb54e81a4d14baff922180c395d" + + "3f998d70f46f6b58306f969627ae364497e73fc27f6d17ae45a413d322cb8814276be6ddd13b885b" + + "201b943213656cde498fa0e9ddc8e0b8f8a53824fbd82254f3e2c17e8eaea009c38b4aa0a3f306e8" + + "797db43c25d68e86f262e564086f59a2fc60511c42abfb3057c247a8a8fe4fb3ccbadde17514b7ac" + + "8000cdb6a912778426260c47f38919a91f25f4b5ffb455d6aaaf150f7e5529c100ce62d6d92826a7" + + "1778d809bdf60232ae21ce8a437eca8223f45ac37f6487452ce626f549b3b5fdee26afd2072e4bc7" + + "5833c2464c805246155289f4"); + + _initiatorService.Agree(_initiatorHandshake, ack); + + Assert.That(_initiatorHandshake.Secrets.AesSecret, Is.EqualTo(NetTestVectors.AesSecret), "initiator AES"); + Assert.That(_recipientHandshake.Secrets.AesSecret, Is.EqualTo(NetTestVectors.AesSecret), "recipient AES"); + Assert.That(_initiatorHandshake.Secrets.MacSecret, Is.EqualTo(NetTestVectors.MacSecret), "initiator MAC"); + Assert.That(_recipientHandshake.Secrets.MacSecret, Is.EqualTo(NetTestVectors.MacSecret), "recipient MAC"); + + // TODO: below failing, probably different format after serialization / during encryption (only tested decryption / deserialization in EciesCoder) + // ingress uses the auth packet which is encrypted with a random IV and ephemeral key - need to remove that randomness for tests + byte[] fooBytes = Encoding.ASCII.GetBytes("foo"); + _recipientHandshake.Secrets.IngressMac.Update(fooBytes); + + byte[] ingressFooResult = _recipientHandshake.Secrets.IngressMac.Hash; + Assert.That(ingressFooResult, Is.EqualTo(NetTestVectors.BIngressMacFoo), "recipient ingress foo"); + } - // Assert.AreEqual(_recipientHandshake.Secrets.Token, _initiatorHandshake.Secrets.Token, "Token"); - Assert.That(_initiatorHandshake.Secrets.AesSecret, Is.EqualTo(_recipientHandshake.Secrets.AesSecret), "AES"); - Assert.That(_initiatorHandshake.Secrets.MacSecret, Is.EqualTo(_recipientHandshake.Secrets.MacSecret), "MAC"); + [TestCase(true)] + [TestCase(false)] + public void Agrees_on_secrets(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Agree(); - byte[] recipientEgress = _recipientHandshake.Secrets.EgressMac.Hash; - byte[] recipientIngress = _recipientHandshake.Secrets.IngressMac.Hash; + // Assert.AreEqual(_recipientHandshake.Secrets.Token, _initiatorHandshake.Secrets.Token, "Token"); + Assert.That(_initiatorHandshake.Secrets.AesSecret, Is.EqualTo(_recipientHandshake.Secrets.AesSecret), "AES"); + Assert.That(_initiatorHandshake.Secrets.MacSecret, Is.EqualTo(_recipientHandshake.Secrets.MacSecret), "MAC"); - byte[] initiatorEgress = _initiatorHandshake.Secrets.EgressMac.Hash; - byte[] initiatorIngress = _initiatorHandshake.Secrets.IngressMac.Hash; + byte[] recipientEgress = _recipientHandshake.Secrets.EgressMac.Hash; + byte[] recipientIngress = _recipientHandshake.Secrets.IngressMac.Hash; - Assert.That(recipientIngress, Is.EqualTo(initiatorEgress), "Egress"); - Assert.That(recipientEgress, Is.EqualTo(initiatorIngress), "Ingress"); - } + byte[] initiatorEgress = _initiatorHandshake.Secrets.EgressMac.Hash; + byte[] initiatorIngress = _initiatorHandshake.Secrets.IngressMac.Hash; - [TestCase(true)] - [TestCase(false)] - public void Initiator_secrets_are_not_null(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Agree(); - - // Assert.NotNull(_recipientHandshake.Secrets.Token, "Token"); - Assert.NotNull(_initiatorHandshake.Secrets.AesSecret, "AES"); - Assert.NotNull(_initiatorHandshake.Secrets.MacSecret, "MAC"); - Assert.NotNull(_initiatorHandshake.Secrets.EgressMac, "Egress"); - Assert.NotNull(_initiatorHandshake.Secrets.IngressMac, "Ingress"); - } + Assert.That(recipientIngress, Is.EqualTo(initiatorEgress), "Egress"); + Assert.That(recipientEgress, Is.EqualTo(initiatorIngress), "Ingress"); + } - [TestCase(true)] - [TestCase(false)] - public void Recipient_secrets_are_not_null(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Agree(); - - // Assert.NotNull(_recipientHandshake.Secrets.Token, "Token"); - Assert.NotNull(_recipientHandshake.Secrets.AesSecret, "AES"); - Assert.NotNull(_recipientHandshake.Secrets.MacSecret, "MAC"); - Assert.NotNull(_recipientHandshake.Secrets.EgressMac, "Egress"); - Assert.NotNull(_recipientHandshake.Secrets.IngressMac, "Ingress"); - } + [TestCase(true)] + [TestCase(false)] + public void Initiator_secrets_are_not_null(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Agree(); + + // Assert.NotNull(_recipientHandshake.Secrets.Token, "Token"); + Assert.That(_initiatorHandshake.Secrets.AesSecret, Is.Not.Null, "AES"); + Assert.That(_initiatorHandshake.Secrets.MacSecret, Is.Not.Null, "MAC"); + Assert.That(_initiatorHandshake.Secrets.EgressMac, Is.Not.Null, "Egress"); + Assert.That(_initiatorHandshake.Secrets.IngressMac, Is.Not.Null, "Ingress"); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_ephemeral_key_on_ack(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Assert.That(_recipientHandshake.EphemeralPrivateKey, Is.EqualTo(NetTestVectors.EphemeralKeyB)); - } + [TestCase(true)] + [TestCase(false)] + public void Recipient_secrets_are_not_null(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Agree(); + + // Assert.NotNull(_recipientHandshake.Secrets.Token, "Token"); + Assert.That(_recipientHandshake.Secrets.AesSecret, Is.Not.Null, "AES"); + Assert.That(_recipientHandshake.Secrets.MacSecret, Is.Not.Null, "MAC"); + Assert.That(_recipientHandshake.Secrets.EgressMac, Is.Not.Null, "Egress"); + Assert.That(_recipientHandshake.Secrets.IngressMac, Is.Not.Null, "Ingress"); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_ephemeral_key_on_auth(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Assert.That(_initiatorHandshake.EphemeralPrivateKey, Is.EqualTo(NetTestVectors.EphemeralKeyA)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_ephemeral_key_on_ack(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Assert.That(_recipientHandshake.EphemeralPrivateKey, Is.EqualTo(NetTestVectors.EphemeralKeyB)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_initiator_nonce_on_ack(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Assert.That(_recipientHandshake.InitiatorNonce, Is.EqualTo(NetTestVectors.NonceA)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_ephemeral_key_on_auth(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Assert.That(_initiatorHandshake.EphemeralPrivateKey, Is.EqualTo(NetTestVectors.EphemeralKeyA)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_initiator_nonce_on_auth(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Assert.That(_initiatorHandshake.InitiatorNonce, Is.EqualTo(NetTestVectors.NonceA)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_initiator_nonce_on_ack(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Assert.That(_recipientHandshake.InitiatorNonce, Is.EqualTo(NetTestVectors.NonceA)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_recipient_nonce_on_ack(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Assert.That(_recipientHandshake.RecipientNonce, Is.EqualTo(NetTestVectors.NonceB)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_initiator_nonce_on_auth(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Assert.That(_initiatorHandshake.InitiatorNonce, Is.EqualTo(NetTestVectors.NonceA)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_recipient_nonce_on_agree(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Agree(); - Assert.That(_initiatorHandshake.RecipientNonce, Is.EqualTo(NetTestVectors.NonceB)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_recipient_nonce_on_ack(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Assert.That(_recipientHandshake.RecipientNonce, Is.EqualTo(NetTestVectors.NonceB)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_remote_ephemeral_key_on_ack(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Assert.That(_recipientHandshake.RemoteEphemeralPublicKey, Is.EqualTo(NetTestVectors.EphemeralKeyA.PublicKey)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_recipient_nonce_on_agree(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Agree(); + Assert.That(_initiatorHandshake.RecipientNonce, Is.EqualTo(NetTestVectors.NonceB)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_remote_ephemeral_key_on_agree(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Agree(); - Assert.That(_initiatorHandshake.RemoteEphemeralPublicKey, Is.EqualTo(NetTestVectors.EphemeralKeyB.PublicKey)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_remote_ephemeral_key_on_ack(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Assert.That(_recipientHandshake.RemoteEphemeralPublicKey, Is.EqualTo(NetTestVectors.EphemeralKeyA.PublicKey)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_remote_public_key_on_ack(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Ack(); - Assert.That(_recipientHandshake.RemoteNodeId, Is.EqualTo(NetTestVectors.StaticKeyA.PublicKey)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_remote_ephemeral_key_on_agree(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Agree(); + Assert.That(_initiatorHandshake.RemoteEphemeralPublicKey, Is.EqualTo(NetTestVectors.EphemeralKeyB.PublicKey)); + } - [TestCase(true)] - [TestCase(false)] - public void Sets_remote_public_key_on_auth(bool preEip8Format) - { - InitializeRandom(preEip8Format); - Auth(preEip8Format); - Assert.That(_initiatorHandshake.RemoteNodeId, Is.EqualTo(NetTestVectors.StaticKeyB.PublicKey)); - } + [TestCase(true)] + [TestCase(false)] + public void Sets_remote_public_key_on_ack(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Ack(); + Assert.That(_recipientHandshake.RemoteNodeId, Is.EqualTo(NetTestVectors.StaticKeyA.PublicKey)); + } + + [TestCase(true)] + [TestCase(false)] + public void Sets_remote_public_key_on_auth(bool preEip8Format) + { + InitializeRandom(preEip8Format); + Auth(preEip8Format); + Assert.That(_initiatorHandshake.RemoteNodeId, Is.EqualTo(NetTestVectors.StaticKeyB.PublicKey)); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs index 0edac2eb045..69bf7d0e9be 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs @@ -11,109 +11,107 @@ using Nethermind.Serialization.Rlp; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx +namespace Nethermind.Network.Test.Rlpx; + +public class SnappyTests { - [TestFixture] - public class SnappyTests - { - private readonly string _uncompressedTestFileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", "block.rlp"); - private readonly string _goCompressedTestFileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", "block.go.snappy"); - private readonly string _pythonCompressedTestFileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", "block.py.snappy"); + private readonly string _uncompressedTestFileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", "block.rlp"); + private readonly string _goCompressedTestFileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", "block.go.snappy"); + private readonly string _pythonCompressedTestFileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", "block.py.snappy"); - public class SnappyDecoderForTest : SnappyDecoder + public class SnappyDecoderForTest : SnappyDecoder + { + public SnappyDecoderForTest() + : base(LimboTraceLogger.Instance) { - public SnappyDecoderForTest() - : base(LimboTraceLogger.Instance) - { - } - - public byte[] TestDecode(byte[] input) - { - List result = new(); - Decode(null, new Packet(input), result); - return ((Packet)result[0]).Data; - } } - public class ZeroSnappyEncoderForTest : ZeroSnappyEncoder + public byte[] TestDecode(byte[] input) { - public ZeroSnappyEncoderForTest() - : base(LimboLogs.Instance) - { - } - - public byte[] TestEncode(byte[] input) - { - var result = UnpooledByteBufferAllocator.Default.Buffer(); - Encode(null, input.ToUnpooledByteBuffer(), result); - return result.ReadAllBytesAsArray(); - } + List result = new(); + Decode(null, new Packet(input), result); + return ((Packet)result[0]).Data; } + } - [Test] - public void Can_decompress_go_compressed_file() + public class ZeroSnappyEncoderForTest : ZeroSnappyEncoder + { + public ZeroSnappyEncoderForTest() + : base(LimboLogs.Instance) { - SnappyDecoderForTest decoder = new(); - byte[] expectedUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); - byte[] compressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _goCompressedTestFileName))); - byte[] uncompressedResult = decoder.TestDecode(compressed); - Assert.That(uncompressedResult, Is.EqualTo(expectedUncompressed)); } - [Test] - public void Can_decompress_python_compressed_file() + public byte[] TestEncode(byte[] input) { - SnappyDecoderForTest decoder = new(); - byte[] expectedUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); - byte[] compressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); - byte[] uncompressedResult = decoder.TestDecode(compressed); - Assert.That(uncompressedResult, Is.EqualTo(expectedUncompressed)); + var result = UnpooledByteBufferAllocator.Default.Buffer(); + Encode(null, input.ToUnpooledByteBuffer(), result); + return result.ReadAllBytesAsArray(); } + } - [Test] - public void Can_load_block_rlp_test_file() - { - byte[] bytes = File.ReadAllBytes(_uncompressedTestFileName); - Assert.Greater(bytes.Length, 2.9 * 1024 * 1024); - } + [Test] + public void Can_decompress_go_compressed_file() + { + SnappyDecoderForTest decoder = new(); + byte[] expectedUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); + byte[] compressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _goCompressedTestFileName))); + byte[] uncompressedResult = decoder.TestDecode(compressed); + Assert.That(uncompressedResult, Is.EqualTo(expectedUncompressed)); + } - [Test] - public void Can_load_go_compressed_test_file() - { - byte[] bytes = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _goCompressedTestFileName))); - Assert.Greater(bytes.Length, 70 * 1024); - } + [Test] + public void Can_decompress_python_compressed_file() + { + SnappyDecoderForTest decoder = new(); + byte[] expectedUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); + byte[] compressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); + byte[] uncompressedResult = decoder.TestDecode(compressed); + Assert.That(uncompressedResult, Is.EqualTo(expectedUncompressed)); + } - [Test] - public void Can_load_python_compressed_test_file() - { - byte[] bytes = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); - Assert.Greater(bytes.Length, 70 * 1024); - } + [Test] + public void Can_load_block_rlp_test_file() + { + byte[] bytes = File.ReadAllBytes(_uncompressedTestFileName); + Assert.That(bytes.Length, Is.GreaterThan(2.9 * 1024 * 1024)); + } - [Test] - [Ignore("Needs further investigation. For now ignoring as it would be requiring too much time.")] - public void Uses_same_compression_as_py_zero_or_go() - { - byte[] bytesPy = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); - byte[] bytesGo = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); - byte[] bytesUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); + [Test] + public void Can_load_go_compressed_test_file() + { + byte[] bytes = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _goCompressedTestFileName))); + Assert.That(bytes.Length, Is.GreaterThan(70 * 1024)); + } - ZeroSnappyEncoderForTest encoder = new(); - byte[] compressed = encoder.TestEncode(Bytes.Concat(1, bytesUncompressed)); - bool oneOfTwoMatches = Bytes.AreEqual(bytesGo, compressed) || Bytes.AreEqual(bytesPy, compressed); - Assert.True(oneOfTwoMatches); - } + [Test] + public void Can_load_python_compressed_test_file() + { + byte[] bytes = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); + Assert.That(bytes.Length, Is.GreaterThan(70 * 1024)); + } - [Test] - public void Roundtrip_zero() - { - SnappyDecoderForTest decoder = new(); - ZeroSnappyEncoderForTest encoder = new(); - byte[] expectedUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); - byte[] compressed = encoder.TestEncode(Bytes.Concat(1, expectedUncompressed)); - byte[] uncompressedResult = decoder.TestDecode(compressed.Skip(1).ToArray()); - Assert.That(uncompressedResult, Is.EqualTo(expectedUncompressed)); - } + [Test] + [Ignore("Needs further investigation. For now ignoring as it would be requiring too much time.")] + public void Uses_same_compression_as_py_zero_or_go() + { + byte[] bytesPy = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); + byte[] bytesGo = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _pythonCompressedTestFileName))); + byte[] bytesUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); + + ZeroSnappyEncoderForTest encoder = new(); + byte[] compressed = encoder.TestEncode(Bytes.Concat(1, bytesUncompressed)); + bool oneOfTwoMatches = Bytes.AreEqual(bytesGo, compressed) || Bytes.AreEqual(bytesPy, compressed); + Assert.That(oneOfTwoMatches, Is.True); + } + + [Test] + public void Roundtrip_zero() + { + SnappyDecoderForTest decoder = new(); + ZeroSnappyEncoderForTest encoder = new(); + byte[] expectedUncompressed = Bytes.FromHexString(File.ReadAllText(Path.Combine(TestContext.CurrentContext.WorkDirectory, "Rlpx", _uncompressedTestFileName))); + byte[] compressed = encoder.TestEncode(Bytes.Concat(1, expectedUncompressed)); + byte[] uncompressedResult = decoder.TestDecode(compressed.Skip(1).ToArray()); + Assert.That(uncompressedResult, Is.EqualTo(expectedUncompressed)); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameDecoderTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameDecoderTests.cs index 30a3dcd5378..8d09d91a895 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameDecoderTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameDecoderTests.cs @@ -10,133 +10,131 @@ using Nethermind.Network.Test.Rlpx.TestWrappers; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx +namespace Nethermind.Network.Test.Rlpx; + +public class ZeroNettyFrameDecoderTests { - [TestFixture] - public class ZeroNettyFrameDecoderTests - { - private const string ShortNewBlockSingleFrame = "96cd2d950a261eae89f0e0cd0432c7d142d19e629f6b6d653a1424b0b7dcd1a6fc75caed4bbbb6d3c888618db2453158b06548d9bdb1b8208b70e0075d675bbe80268afff07570005454467c0c3e85a3468e3225015521fecb9a0c1a2092fd445f14552e33d4ebb4d7b533606989210b4c702662b4d2417f293b2701ee4336624916cddefb4c3777d1a144e1df66162b60bcaed3319becbbe19062f7e3715505dc84fa23a531d7dfd35b9ad95042a85faa643a40365d52d0b57e67cc428676cc364567a6c8cf7fda48bd4c54fd2c8fad1e504f3c2451f538793c022fcdfaef9d8fdafae2c989a7e61dba88879cc9062b774bc3f999b0cdece9aab3d34fafc1513e2de18e6c297d07a5992cc68adb27ce3de39c290884e2f6f0f8b24645c622b2cd9d396498e689a44dc775c22f4baa6b5c1685c19b020110c5788b0e61ebf1794f05df9237d61ca95f49f00fa0217c6a0935f5674c32f8eb7b9c5fe351d429ba0383761d980b53b1187a9a367f80075c020fcc71a75689a4a9e74b8c6137ab267ce6e697008ff5f8c29af53fd4f97018da197f990181f112be738fd0f57bcfc72a78dda731b64aecdd3f83586f1fcfdbdf2c58eff42b38fed19730a1fd0dd21d248d78a396689a508561590543dbe62b44475bec724f2c13678dc877d6cc15099634c10ee4206b339e45c4829c8d81537c3b57fab792929f79a391c29d4f10f6db8318d9f2bffffdafb3038f005ab5e9ce4bf46960f7cf078cebc4287da0330f6a02555851db05eb28dab481313b43dd64eb9a70e8b4460da9955c39e5c24d2d3432189911b6bbdc05c5c6d50fc8e2422a833c3b9ff407ed69cf8fa55248cddddab62951b60c822588ae6b22c67bd9126a5a84cb5723a3079d52972341bcf216"; - private const string ShortNewBlockSingleFrameDecrypted = "000247c180000000000000000000000007f90243f9023ff901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8f840df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080c080000000000000000000"; - private const string BigNewBlockSingleFrame = "96c562950a261eae89f0e0cd0432c7d16fad96fcd58ca3b1c831155745e98a77fc75c2aa4bb389d3c888618db2453158b06548d9bdb1b8208b70e0075d675bbe80268afff07570005454467c0c3e85a3468e3225015521fecb9a0c1a2092fd445f14552e33d4ebb4d7b533606989210b4c702662b4d2417f293b2701ee4336624916cddefb4c3777d1a144e1df66162b60bcaed3319becbbe19062f7e3715505dc84fa23a531d7dfd35b9ad95042a85faa643a40365d52d0b57e67cc428676cc364567a6c8cf7fda48bd4c54fd2c8fad1e504f3c2451f538793c022fcdfaef9d8fdafae2c989a7e61dba88879cc9062b774bc3f999b0cdece9aab3d34fafc1513e2de18e6c297d07a5992cc68adb27ce3de39c290884e2f6f0f8b24645c622b2cd9d396498e689a44dc775c22f4baa6b5c1685c19b020110c5788b0e61ebf1794f05df9237d61ca95f49f00fa0217c6a0935f5674c32f8eb7b9c5fe351d429ba0383761d980b53b1187a9a367f80075c020fcc71a75689a4a9e74b8c6137ab267ce6e697008ff5f8c29af53fd4f97018da197f990181f112be738fd0f57bcfc72a78dda731b64aecdd3f83586f1fcfdbdf2c58eff42b38fed19730a1fd0dd21d248d78a396689a508561590543dbe62b44475bec724f2c13678dc877d6cc15099634c10ee4206b339e45c4829c8d81537c3b57fab792929f79a391c29d4f10f6db8318d9f2bffffdafb3038f005ab5e9ce4bf46960f7cf078cebc4287da0330f6a02555919045a6aab0aee1da53b43dd64eb9a70e8b4460da9955c39e5c24d2d35b3189911e9e45d86159c499bc8e2422a833c3b9ff407ed69cf8fa55248cddddb372951b64cdda5892c392a527bd91230dcb9cf21cbfbc878157866b430e709954d08d53b7e689c01477956bf697eca8dd24a3f51b16c6b15c930500b3c9b9e99620e6cbfbd4c01a35593292b3ab35452c30bd03e44719d96d501b097721f55e5316c0fa3f6eb2cc70965f9798bbd424350a4ce0bb43f9666cb89a710db9ce1f248445d949d8d5b87e4f01ba6f41638dfb200a1788e99f85a896e77fe7a86a17e607d708ca623920705e363e390d0b0025c9b9a5e2ae9e00e34bc1b358e4a787cfa54cfad9384da899bae3887fc745f9e08a21244228c033769c8cadd0215549381282d7f4961c91b2238f8e98310b6953ec92869415c772dfc4581c5bb0aaaf0f65a3e6755d74fdfa49d7eff6154b638e27be6cd9942fefdc615fa93d6b2d66a56aec3c71ba81dd15ec8215048d40b07eeda996a631064b3086520acdaf126b541f4632c63d9822cd6a005d79b1532504211d854e6cad01cf85ff380499909638efc2877b9a2b50f5fc297f620462e314ac10d9bf5b040f27db2df66286318485af830c8af931b300272525aef5c33e7bfaf62622f3575ef9c6e9018209188e1ff3168bf88dd4b1958133eb6a5879fe681868112002df79ee13cdcf5776e04ac6d6b6a461015aee706bc775d335c515703ceda47d59594c883003bb8adcbeed53f188d8e80419bf04dfb13eb23ba7eac216dc71d1af54d6b2c3db2db586b18f544349a00afa8fa64654c8daa5690927c0b0411a06d331023dd2f89670b5779f552c04d333794abf8cac90efc2e0bd8f868a7fc34d8e7ff7cac26e3f01c37f77e8a92383d0a28328767747bada2972f6bcb6eed6e4ec98cb69579a98581c15777408eebffc7ca3167c7b281a8fe4e26d46f337dcbfca91de5785b7556cd2748b4cbc708e90178ca1666a9098fdcd9a10ee65ca37ae9eb5e606e5e2379f116aa345999d82d98f9c0b51a3a132c16d09cb67e4cffb0b36b6e58650062539aa49273e4e64bd05ee720feb0f822707ae29395de5252b7f25e783520273cecf1c1d06a71dfec0abfdec99c34c7ebf708bc800246f17393d218a241191106dfa20891272e7a100e1e8d90d49e18bbbb4f9cea2a0c7de3f6a83f43f76927ec701aab5658fd0f29da7b21855f8c75855b0af8f7a0f6111728c84ac72ecddd365a99840e1b8d5d24e82209bb1017159d4d424e3543b27efbe8dd76e002c308886857667d6ba17f1698f19c144617e225bb9283973934fda3270f4952488ae773f7e79c02009ba604692602d5da3988172f7a5ddbfa5fa5a1471995bc783a96c5f27d0b6d728cbc5ba991a08cd30ee1a9c88530fb1d09662ae5718fed61e0e9668669c75ee4d6eb793b329140c8e39c0e795c2a00ae8688e170883c3af91f0acd34574e9aa5eeb593aed1c623b73f00cc3fcb6807df486731a8e872bd46ad4ab1670fe76134c9eb4de7cf3ded7a7e6bd386d60cfe162b9e5d8f80d1fc9a549afc34f05ee2ca328a367949f375bb2183ecd7f31545cc87b6b19ce3e834d3a98156a71db69484e2213f15b750bb5e9c8e96ebc33abae12c269931dcf380d1f4a861eb4c768b93e751371b9ae211f210d381883976c5c587e9a6e674039a4b486c9fecae2025908cf05c7c88229abefa06a58a558c5fef9908fb546fad3489fb25b4ec62a75b0bc2aa2996bbbf89f6244f9ecbfd2e1e584a38b47c40f169c1612079ac83bfd8995c4154b440e5b02bf803a416ff3444f2e4b7398adcc8df331a210cc4fae101d06f533987fa59293e365361dfd6769b5a71fded46c7a360b5ddc2e8b16f76e5f0b67d696eeb0f9a01543f3aecb9c5b03b55da78e86adc59c8d57479ef9ae4bb86be4734e7587c023eefd7779180c316d4ae6fce63dc11c223c0f02fcf5190f336cab5b4845f050b6ef2eceab22638d7902b58886267c6662fc68102bae8bc7c78c329529251a3fe26a2c047b7910b8c1f874d623b3c2339cbbfe872d63a2ddd230f1cf2d45dc5731fd52641fd99176f3b7ed4fe072cd45b24efc4b0313719c720833e9b6bbb57533a2c1314f2266c1e4ea4fe4f4a8b5cdc46b6ef00e953ef9b3b453a3651ab2c2c96b2b928e239a37c76bfed66d405a88bb0597ca427492f4fc173a944bb6f2515609bd48e1b61b2be163f0f16e845de5f6c309f2c4ac49a9bd198c48b76cd56cc529fbc5fe31e04e5f499589c00957e260dad493a2abdd8487fc6d846bd7d63ed4a80b5b9ce2acebafc60eb9f295e260c51628bc511bbf4fd623690ea63ec2b725921a9927bae4d2ccf5fb07ee995c03e03bcf2d6e89d93db406eaa765f55114edc3b3f3de37f86064f92d045b47d3c53ebf219850b01acb1451f0adc2ca5028aa9ba565481866c55acc76e5c96f0d1b3d933960cc42229ea6d7539a8408c239d4bb324c5fcf7fc2950fd8001d0f02d9f4e25117e80037b3798afcfbcb9b6727b42ca4a50c77cdd3a9e0daaaea571e73a58be0cd5b1260d1d99a9968bb3fed510e567ec8a0bfcc9142ab7b43c03255fa85bf65fc5bf2c7826716597b4dc4df791c7f511f848f08dbb9f7da34f5c998a0f8a02892a243995842f5259175436c03985c5888ac4f4a2e6b9282048c1833226a51dcac1a988fcb099e4fa9a86494d58c010ae9214021f283c6760299b13c89cc8e4b1b98d412debb2c9a79fc7ed444b26a711b93b822cde0328c21530fbf2a075c190bb2eebc8d08ce1eb9cb37e784599db199d97a8c97824cbae8e48e781a82c4bba90f430739ec2d48488895313ccdb77301bdcac2e1465cd0cb3968ac941760795a06e67559d12b7d232854206be25c29fb9cd147dd07ba50536f694461b7d4e357724c9f6f9"; - private const string BigNewBlockSingleFrameDecrypted = "000a08c180000000000000000000000007f90a04f90a00f901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8f90800df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080c0800000000000000000"; + private const string ShortNewBlockSingleFrame = "96cd2d950a261eae89f0e0cd0432c7d142d19e629f6b6d653a1424b0b7dcd1a6fc75caed4bbbb6d3c888618db2453158b06548d9bdb1b8208b70e0075d675bbe80268afff07570005454467c0c3e85a3468e3225015521fecb9a0c1a2092fd445f14552e33d4ebb4d7b533606989210b4c702662b4d2417f293b2701ee4336624916cddefb4c3777d1a144e1df66162b60bcaed3319becbbe19062f7e3715505dc84fa23a531d7dfd35b9ad95042a85faa643a40365d52d0b57e67cc428676cc364567a6c8cf7fda48bd4c54fd2c8fad1e504f3c2451f538793c022fcdfaef9d8fdafae2c989a7e61dba88879cc9062b774bc3f999b0cdece9aab3d34fafc1513e2de18e6c297d07a5992cc68adb27ce3de39c290884e2f6f0f8b24645c622b2cd9d396498e689a44dc775c22f4baa6b5c1685c19b020110c5788b0e61ebf1794f05df9237d61ca95f49f00fa0217c6a0935f5674c32f8eb7b9c5fe351d429ba0383761d980b53b1187a9a367f80075c020fcc71a75689a4a9e74b8c6137ab267ce6e697008ff5f8c29af53fd4f97018da197f990181f112be738fd0f57bcfc72a78dda731b64aecdd3f83586f1fcfdbdf2c58eff42b38fed19730a1fd0dd21d248d78a396689a508561590543dbe62b44475bec724f2c13678dc877d6cc15099634c10ee4206b339e45c4829c8d81537c3b57fab792929f79a391c29d4f10f6db8318d9f2bffffdafb3038f005ab5e9ce4bf46960f7cf078cebc4287da0330f6a02555851db05eb28dab481313b43dd64eb9a70e8b4460da9955c39e5c24d2d3432189911b6bbdc05c5c6d50fc8e2422a833c3b9ff407ed69cf8fa55248cddddab62951b60c822588ae6b22c67bd9126a5a84cb5723a3079d52972341bcf216"; + private const string ShortNewBlockSingleFrameDecrypted = "000247c180000000000000000000000007f90243f9023ff901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8f840df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080c080000000000000000000"; + private const string BigNewBlockSingleFrame = "96c562950a261eae89f0e0cd0432c7d16fad96fcd58ca3b1c831155745e98a77fc75c2aa4bb389d3c888618db2453158b06548d9bdb1b8208b70e0075d675bbe80268afff07570005454467c0c3e85a3468e3225015521fecb9a0c1a2092fd445f14552e33d4ebb4d7b533606989210b4c702662b4d2417f293b2701ee4336624916cddefb4c3777d1a144e1df66162b60bcaed3319becbbe19062f7e3715505dc84fa23a531d7dfd35b9ad95042a85faa643a40365d52d0b57e67cc428676cc364567a6c8cf7fda48bd4c54fd2c8fad1e504f3c2451f538793c022fcdfaef9d8fdafae2c989a7e61dba88879cc9062b774bc3f999b0cdece9aab3d34fafc1513e2de18e6c297d07a5992cc68adb27ce3de39c290884e2f6f0f8b24645c622b2cd9d396498e689a44dc775c22f4baa6b5c1685c19b020110c5788b0e61ebf1794f05df9237d61ca95f49f00fa0217c6a0935f5674c32f8eb7b9c5fe351d429ba0383761d980b53b1187a9a367f80075c020fcc71a75689a4a9e74b8c6137ab267ce6e697008ff5f8c29af53fd4f97018da197f990181f112be738fd0f57bcfc72a78dda731b64aecdd3f83586f1fcfdbdf2c58eff42b38fed19730a1fd0dd21d248d78a396689a508561590543dbe62b44475bec724f2c13678dc877d6cc15099634c10ee4206b339e45c4829c8d81537c3b57fab792929f79a391c29d4f10f6db8318d9f2bffffdafb3038f005ab5e9ce4bf46960f7cf078cebc4287da0330f6a02555919045a6aab0aee1da53b43dd64eb9a70e8b4460da9955c39e5c24d2d35b3189911e9e45d86159c499bc8e2422a833c3b9ff407ed69cf8fa55248cddddb372951b64cdda5892c392a527bd91230dcb9cf21cbfbc878157866b430e709954d08d53b7e689c01477956bf697eca8dd24a3f51b16c6b15c930500b3c9b9e99620e6cbfbd4c01a35593292b3ab35452c30bd03e44719d96d501b097721f55e5316c0fa3f6eb2cc70965f9798bbd424350a4ce0bb43f9666cb89a710db9ce1f248445d949d8d5b87e4f01ba6f41638dfb200a1788e99f85a896e77fe7a86a17e607d708ca623920705e363e390d0b0025c9b9a5e2ae9e00e34bc1b358e4a787cfa54cfad9384da899bae3887fc745f9e08a21244228c033769c8cadd0215549381282d7f4961c91b2238f8e98310b6953ec92869415c772dfc4581c5bb0aaaf0f65a3e6755d74fdfa49d7eff6154b638e27be6cd9942fefdc615fa93d6b2d66a56aec3c71ba81dd15ec8215048d40b07eeda996a631064b3086520acdaf126b541f4632c63d9822cd6a005d79b1532504211d854e6cad01cf85ff380499909638efc2877b9a2b50f5fc297f620462e314ac10d9bf5b040f27db2df66286318485af830c8af931b300272525aef5c33e7bfaf62622f3575ef9c6e9018209188e1ff3168bf88dd4b1958133eb6a5879fe681868112002df79ee13cdcf5776e04ac6d6b6a461015aee706bc775d335c515703ceda47d59594c883003bb8adcbeed53f188d8e80419bf04dfb13eb23ba7eac216dc71d1af54d6b2c3db2db586b18f544349a00afa8fa64654c8daa5690927c0b0411a06d331023dd2f89670b5779f552c04d333794abf8cac90efc2e0bd8f868a7fc34d8e7ff7cac26e3f01c37f77e8a92383d0a28328767747bada2972f6bcb6eed6e4ec98cb69579a98581c15777408eebffc7ca3167c7b281a8fe4e26d46f337dcbfca91de5785b7556cd2748b4cbc708e90178ca1666a9098fdcd9a10ee65ca37ae9eb5e606e5e2379f116aa345999d82d98f9c0b51a3a132c16d09cb67e4cffb0b36b6e58650062539aa49273e4e64bd05ee720feb0f822707ae29395de5252b7f25e783520273cecf1c1d06a71dfec0abfdec99c34c7ebf708bc800246f17393d218a241191106dfa20891272e7a100e1e8d90d49e18bbbb4f9cea2a0c7de3f6a83f43f76927ec701aab5658fd0f29da7b21855f8c75855b0af8f7a0f6111728c84ac72ecddd365a99840e1b8d5d24e82209bb1017159d4d424e3543b27efbe8dd76e002c308886857667d6ba17f1698f19c144617e225bb9283973934fda3270f4952488ae773f7e79c02009ba604692602d5da3988172f7a5ddbfa5fa5a1471995bc783a96c5f27d0b6d728cbc5ba991a08cd30ee1a9c88530fb1d09662ae5718fed61e0e9668669c75ee4d6eb793b329140c8e39c0e795c2a00ae8688e170883c3af91f0acd34574e9aa5eeb593aed1c623b73f00cc3fcb6807df486731a8e872bd46ad4ab1670fe76134c9eb4de7cf3ded7a7e6bd386d60cfe162b9e5d8f80d1fc9a549afc34f05ee2ca328a367949f375bb2183ecd7f31545cc87b6b19ce3e834d3a98156a71db69484e2213f15b750bb5e9c8e96ebc33abae12c269931dcf380d1f4a861eb4c768b93e751371b9ae211f210d381883976c5c587e9a6e674039a4b486c9fecae2025908cf05c7c88229abefa06a58a558c5fef9908fb546fad3489fb25b4ec62a75b0bc2aa2996bbbf89f6244f9ecbfd2e1e584a38b47c40f169c1612079ac83bfd8995c4154b440e5b02bf803a416ff3444f2e4b7398adcc8df331a210cc4fae101d06f533987fa59293e365361dfd6769b5a71fded46c7a360b5ddc2e8b16f76e5f0b67d696eeb0f9a01543f3aecb9c5b03b55da78e86adc59c8d57479ef9ae4bb86be4734e7587c023eefd7779180c316d4ae6fce63dc11c223c0f02fcf5190f336cab5b4845f050b6ef2eceab22638d7902b58886267c6662fc68102bae8bc7c78c329529251a3fe26a2c047b7910b8c1f874d623b3c2339cbbfe872d63a2ddd230f1cf2d45dc5731fd52641fd99176f3b7ed4fe072cd45b24efc4b0313719c720833e9b6bbb57533a2c1314f2266c1e4ea4fe4f4a8b5cdc46b6ef00e953ef9b3b453a3651ab2c2c96b2b928e239a37c76bfed66d405a88bb0597ca427492f4fc173a944bb6f2515609bd48e1b61b2be163f0f16e845de5f6c309f2c4ac49a9bd198c48b76cd56cc529fbc5fe31e04e5f499589c00957e260dad493a2abdd8487fc6d846bd7d63ed4a80b5b9ce2acebafc60eb9f295e260c51628bc511bbf4fd623690ea63ec2b725921a9927bae4d2ccf5fb07ee995c03e03bcf2d6e89d93db406eaa765f55114edc3b3f3de37f86064f92d045b47d3c53ebf219850b01acb1451f0adc2ca5028aa9ba565481866c55acc76e5c96f0d1b3d933960cc42229ea6d7539a8408c239d4bb324c5fcf7fc2950fd8001d0f02d9f4e25117e80037b3798afcfbcb9b6727b42ca4a50c77cdd3a9e0daaaea571e73a58be0cd5b1260d1d99a9968bb3fed510e567ec8a0bfcc9142ab7b43c03255fa85bf65fc5bf2c7826716597b4dc4df791c7f511f848f08dbb9f7da34f5c998a0f8a02892a243995842f5259175436c03985c5888ac4f4a2e6b9282048c1833226a51dcac1a988fcb099e4fa9a86494d58c010ae9214021f283c6760299b13c89cc8e4b1b98d412debb2c9a79fc7ed444b26a711b93b822cde0328c21530fbf2a075c190bb2eebc8d08ce1eb9cb37e784599db199d97a8c97824cbae8e48e781a82c4bba90f430739ec2d48488895313ccdb77301bdcac2e1465cd0cb3968ac941760795a06e67559d12b7d232854206be25c29fb9cd147dd07ba50536f694461b7d4e357724c9f6f9"; + private const string BigNewBlockSingleFrameDecrypted = "000a08c180000000000000000000000007f90a04f90a00f901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8f90800df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080c0800000000000000000"; - private const int LongFrameSize = 48; - private const int ShortFrameSize = 32; + private const int LongFrameSize = 48; + private const int ShortFrameSize = 32; - private byte[] _frame; - private byte[] _shortFrame; - private IFrameCipher _frameCipher; - private FrameMacProcessor _macProcessor; + private byte[] _frame; + private byte[] _shortFrame; + private IFrameCipher _frameCipher; + private FrameMacProcessor _macProcessor; - [SetUp] - public void Setup() - { - var secrets = NetTestVectors.GetSecretsPair(); + [SetUp] + public void Setup() + { + var secrets = NetTestVectors.GetSecretsPair(); - _frameCipher = new FrameCipher(secrets.B.AesSecret); - _macProcessor = new FrameMacProcessor(TestItem.IgnoredPublicKey, secrets.B); + _frameCipher = new FrameCipher(secrets.B.AesSecret); + _macProcessor = new FrameMacProcessor(TestItem.IgnoredPublicKey, secrets.B); - _frame = new byte[16 + 16 + LongFrameSize + 16]; // header | header MAC | packet type | data | padding | frame MAC - _frame[2] = LongFrameSize - 15; // size (total - padding) + _frame = new byte[16 + 16 + LongFrameSize + 16]; // header | header MAC | packet type | data | padding | frame MAC + _frame[2] = LongFrameSize - 15; // size (total - padding) - _shortFrame = new byte[16 + 16 + 1 + ShortFrameSize + 15 + 16]; // header | header MAC | packet type | data | padding | frame MAC - _shortFrame[2] = ShortFrameSize - 15; // size (total - padding) - } + _shortFrame = new byte[16 + 16 + 1 + ShortFrameSize + 15 + 16]; // header | header MAC | packet type | data | padding | frame MAC + _shortFrame[2] = ShortFrameSize - 15; // size (total - padding) + } - [TearDown] - public void TearDown() => _macProcessor?.Dispose(); + [TearDown] + public void TearDown() => _macProcessor?.Dispose(); - [Test] - public void Check_and_decrypt_block() - { - Test(ShortNewBlockSingleFrame, DeliverByteByByte, ShortNewBlockSingleFrameDecrypted); - } + [Test] + public void Check_and_decrypt_block() + { + Test(ShortNewBlockSingleFrame, DeliverByteByByte, ShortNewBlockSingleFrameDecrypted); + } - [Test] - public void Check_and_decrypt_big_frame_delivered_byte_by_byte() - { - Test(BigNewBlockSingleFrame, DeliverByteByByte, BigNewBlockSingleFrameDecrypted); - } + [Test] + public void Check_and_decrypt_big_frame_delivered_byte_by_byte() + { + Test(BigNewBlockSingleFrame, DeliverByteByByte, BigNewBlockSingleFrameDecrypted); + } - [Test] - public void Check_and_decrypt_big_frame_delivered_all_at_once() - { - Test(BigNewBlockSingleFrame, DeliverAllAtOnce, BigNewBlockSingleFrameDecrypted); - } + [Test] + public void Check_and_decrypt_big_frame_delivered_all_at_once() + { + Test(BigNewBlockSingleFrame, DeliverAllAtOnce, BigNewBlockSingleFrameDecrypted); + } - [Test] - public void Check_and_decrypt_big_frame_delivered_all_at_once_and_followed_by_a_corrupted_header() - { - Test(BigNewBlockSingleFrame, DeliverAllAtOnceFollowedByACorruptedHeader, BigNewBlockSingleFrameDecrypted); - } + [Test] + public void Check_and_decrypt_big_frame_delivered_all_at_once_and_followed_by_a_corrupted_header() + { + Test(BigNewBlockSingleFrame, DeliverAllAtOnceFollowedByACorruptedHeader, BigNewBlockSingleFrameDecrypted); + } - [Test] - public void Check_and_decrypt_big_frame_delivered_block_by_block() - { - Test(BigNewBlockSingleFrame, DeliverBlockByBlock, BigNewBlockSingleFrameDecrypted); - } + [Test] + public void Check_and_decrypt_big_frame_delivered_block_by_block() + { + Test(BigNewBlockSingleFrame, DeliverBlockByBlock, BigNewBlockSingleFrameDecrypted); + } - private void Test(string frame, Func deliveryStrategy, string expectedOutput) - { - byte[] frameBytes = Bytes.FromHexString(frame); - IByteBuffer input = ReferenceCountUtil.ReleaseLater(Unpooled.Buffer(256)); - ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper = new(_frameCipher, _macProcessor); - - IByteBuffer result = ReferenceCountUtil.ReleaseLater(deliveryStrategy(frameBytes, input, zeroFrameDecoderTestWrapper)); - Assert.NotNull(result, "did not decode frame"); - - byte[] resultBytes = new byte[result.ReadableBytes]; - result.ReadBytes(resultBytes); - TestContext.WriteLine(resultBytes.ToHexString()); - string expected = expectedOutput; - TestContext.WriteLine(resultBytes.ToHexString()); - Assert.That(resultBytes.ToHexString(), Is.EqualTo(expected)); - Assert.That(input.WriterIndex, Is.EqualTo(input.ReaderIndex), "reader index == writer index"); - } + private void Test(string frame, Func deliveryStrategy, string expectedOutput) + { + byte[] frameBytes = Bytes.FromHexString(frame); + IByteBuffer input = ReferenceCountUtil.ReleaseLater(Unpooled.Buffer(256)); + ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper = new(_frameCipher, _macProcessor); + + IByteBuffer result = ReferenceCountUtil.ReleaseLater(deliveryStrategy(frameBytes, input, zeroFrameDecoderTestWrapper)); + Assert.That(result, Is.Not.Null, "did not decode frame"); + + byte[] resultBytes = new byte[result.ReadableBytes]; + result.ReadBytes(resultBytes); + TestContext.Out.WriteLine(resultBytes.ToHexString()); + string expected = expectedOutput; + TestContext.Out.WriteLine(resultBytes.ToHexString()); + Assert.That(resultBytes.ToHexString(), Is.EqualTo(expected)); + Assert.That(input.WriterIndex, Is.EqualTo(input.ReaderIndex), "reader index == writer index"); + } - private static IByteBuffer DeliverAllAtOnce(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) - { - input.WriteBytes(frame); - return zeroFrameDecoderTestWrapper.Decode(input); - } + private static IByteBuffer DeliverAllAtOnce(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) + { + input.WriteBytes(frame); + return zeroFrameDecoderTestWrapper.Decode(input); + } - private static IByteBuffer DeliverAllAtOnceFollowedByACorruptedHeader(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) - { - byte[] corruptedHeader = new byte[32]; - input.WriteBytes(Bytes.Concat(frame, corruptedHeader)); - return zeroFrameDecoderTestWrapper.Decode(input, false); - } + private static IByteBuffer DeliverAllAtOnceFollowedByACorruptedHeader(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) + { + byte[] corruptedHeader = new byte[32]; + input.WriteBytes(Bytes.Concat(frame, corruptedHeader)); + return zeroFrameDecoderTestWrapper.Decode(input, false); + } - private static IByteBuffer DeliverByteByByte(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) + private static IByteBuffer DeliverByteByByte(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) + { + IByteBuffer result = null; + for (int i = 0; i < frame.Length; i++) { - IByteBuffer result = null; - for (int i = 0; i < frame.Length; i++) + input.WriteByte(frame[i]); + result = zeroFrameDecoderTestWrapper.Decode(input); + if (result is not null) { - input.WriteByte(frame[i]); - result = zeroFrameDecoderTestWrapper.Decode(input); - if (result is not null) - { - break; - } + break; } - - return result; } - private static IByteBuffer DeliverBlockByBlock(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) + return result; + } + + private static IByteBuffer DeliverBlockByBlock(byte[] frame, IByteBuffer input, ZeroFrameDecoderTestWrapper zeroFrameDecoderTestWrapper) + { + IByteBuffer result = null; + for (int i = 0; i < frame.Length; i += 16) { - IByteBuffer result = null; - for (int i = 0; i < frame.Length; i += 16) + input.WriteBytes(frame.Slice(i, 16)); + result = zeroFrameDecoderTestWrapper.Decode(input); + if (result is not null) { - input.WriteBytes(frame.Slice(i, 16)); - result = zeroFrameDecoderTestWrapper.Decode(input); - if (result is not null) - { - break; - } + break; } - - return result; } + + return result; } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameEncoderTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameEncoderTests.cs index 787b112ee0f..a649c6db534 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameEncoderTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameEncoderTests.cs @@ -41,7 +41,7 @@ public void Encrypt_and_mac_block() byte[] resultBytes = new byte[result.ReadableBytes]; result.ReadBytes(resultBytes); - TestContext.WriteLine(resultBytes.ToHexString()); + TestContext.Out.WriteLine(resultBytes.ToHexString()); Assert.That(resultBytes.ToHexString(), Is.EqualTo("96cd2d950a261eae89f0e0cd0432c7d142d19e629f6b6d653a1424b0b7dcd1a6fc75caed4bbbb6d3c888618db2453158b06548d9bdb1b8208b70e0075d675bbe80268afff07570005454467c0c3e85a3468e3225015521fecb9a0c1a2092fd445f14552e33d4ebb4d7b533606989210b4c702662b4d2417f293b2701ee4336624916cddefb4c3777d1a144e1df66162b60bcaed3319becbbe19062f7e3715505dc84fa23a531d7dfd35b9ad95042a85faa643a40365d52d0b57e67cc428676cc364567a6c8cf7fda48bd4c54fd2c8fad1e504f3c2451f538793c022fcdfaef9d8fdafae2c989a7e61dba88879cc9062b774bc3f999b0cdece9aab3d34fafc1513e2de18e6c297d07a5992cc68adb27ce3de39c290884e2f6f0f8b24645c622b2cd9d396498e689a44dc775c22f4baa6b5c1685c19b020110c5788b0e61ebf1794f05df9237d61ca95f49f00fa0217c6a0935f5674c32f8eb7b9c5fe351d429ba0383761d980b53b1187a9a367f80075c020fcc71a75689a4a9e74b8c6137ab267ce6e697008ff5f8c29af53fd4f97018da197f990181f112be738fd0f57bcfc72a78dda731b64aecdd3f83586f1fcfdbdf2c58eff42b38fed19730a1fd0dd21d248d78a396689a508561590543dbe62b44475bec724f2c13678dc877d6cc15099634c10ee4206b339e45c4829c8d81537c3b57fab792929f79a391c29d4f10f6db8318d9f2bffffdafb3038f005ab5e9ce4bf46960f7cf078cebc4287da0330f6a02555851db05eb28dab481313b43dd64eb9a70e8b4460da9955c39e5c24d2d3432189911b6bbdc05c5c6d50fc8e2422a833c3b9ff407ed69cf8fa55248cddddab62951b60c822588ae6b22c67bd9126a5a84cb5723a3079d52972341bcf216")); } @@ -58,7 +58,7 @@ public void Encrypt_and_mac_block_big_frame() byte[] resultBytes = new byte[result.ReadableBytes]; result.ReadBytes(resultBytes); - TestContext.WriteLine(resultBytes.ToHexString()); + TestContext.Out.WriteLine(resultBytes.ToHexString()); Assert.That(resultBytes.ToHexString(), Is.EqualTo("96c562950a261eae89f0e0cd0432c7d16fad96fcd58ca3b1c831155745e98a77fc75c2aa4bb389d3c888618db2453158b06548d9bdb1b8208b70e0075d675bbe80268afff07570005454467c0c3e85a3468e3225015521fecb9a0c1a2092fd445f14552e33d4ebb4d7b533606989210b4c702662b4d2417f293b2701ee4336624916cddefb4c3777d1a144e1df66162b60bcaed3319becbbe19062f7e3715505dc84fa23a531d7dfd35b9ad95042a85faa643a40365d52d0b57e67cc428676cc364567a6c8cf7fda48bd4c54fd2c8fad1e504f3c2451f538793c022fcdfaef9d8fdafae2c989a7e61dba88879cc9062b774bc3f999b0cdece9aab3d34fafc1513e2de18e6c297d07a5992cc68adb27ce3de39c290884e2f6f0f8b24645c622b2cd9d396498e689a44dc775c22f4baa6b5c1685c19b020110c5788b0e61ebf1794f05df9237d61ca95f49f00fa0217c6a0935f5674c32f8eb7b9c5fe351d429ba0383761d980b53b1187a9a367f80075c020fcc71a75689a4a9e74b8c6137ab267ce6e697008ff5f8c29af53fd4f97018da197f990181f112be738fd0f57bcfc72a78dda731b64aecdd3f83586f1fcfdbdf2c58eff42b38fed19730a1fd0dd21d248d78a396689a508561590543dbe62b44475bec724f2c13678dc877d6cc15099634c10ee4206b339e45c4829c8d81537c3b57fab792929f79a391c29d4f10f6db8318d9f2bffffdafb3038f005ab5e9ce4bf46960f7cf078cebc4287da0330f6a02555919045a6aab0aee1da53b43dd64eb9a70e8b4460da9955c39e5c24d2d35b3189911e9e45d86159c499bc8e2422a833c3b9ff407ed69cf8fa55248cddddb372951b64cdda5892c392a527bd91230dcb9cf21cbfbc878157866b430e709954d08d53b7e689c01477956bf697eca8dd24a3f51b16c6b15c930500b3c9b9e99620e6cbfbd4c01a35593292b3ab35452c30bd03e44719d96d501b097721f55e5316c0fa3f6eb2cc70965f9798bbd424350a4ce0bb43f9666cb89a710db9ce1f248445d949d8d5b87e4f01ba6f41638dfb200a1788e99f85a896e77fe7a86a17e607d708ca623920705e363e390d0b0025c9b9a5e2ae9e00e34bc1b358e4a787cfa54cfad9384da899bae3887fc745f9e08a21244228c033769c8cadd0215549381282d7f4961c91b2238f8e98310b6953ec92869415c772dfc4581c5bb0aaaf0f65a3e6755d74fdfa49d7eff6154b638e27be6cd9942fefdc615fa93d6b2d66a56aec3c71ba81dd15ec8215048d40b07eeda996a631064b3086520acdaf126b541f4632c63d9822cd6a005d79b1532504211d854e6cad01cf85ff380499909638efc2877b9a2b50f5fc297f620462e314ac10d9bf5b040f27db2df66286318485af830c8af931b300272525aef5c33e7bfaf62622f3575ef9c6e9018209188e1ff3168bf88dd4b1958133eb6a5879fe681868112002df79ee13cdcf5776e04ac6d6b6a461015aee706bc775d335c515703ceda47d59594c883003bb8adcbeed53f188d8e80419bf04dfb13eb23ba7eac216dc71d1af54d6b2c3db2db586b18f544349a00afa8fa64654c8daa5690927c0b0411a06d331023dd2f89670b5779f552c04d333794abf8cac90efc2e0bd8f868a7fc34d8e7ff7cac26e3f01c37f77e8a92383d0a28328767747bada2972f6bcb6eed6e4ec98cb69579a98581c15777408eebffc7ca3167c7b281a8fe4e26d46f337dcbfca91de5785b7556cd2748b4cbc708e90178ca1666a9098fdcd9a10ee65ca37ae9eb5e606e5e2379f116aa345999d82d98f9c0b51a3a132c16d09cb67e4cffb0b36b6e58650062539aa49273e4e64bd05ee720feb0f822707ae29395de5252b7f25e783520273cecf1c1d06a71dfec0abfdec99c34c7ebf708bc800246f17393d218a241191106dfa20891272e7a100e1e8d90d49e18bbbb4f9cea2a0c7de3f6a83f43f76927ec701aab5658fd0f29da7b21855f8c75855b0af8f7a0f6111728c84ac72ecddd365a99840e1b8d5d24e82209bb1017159d4d424e3543b27efbe8dd76e002c308886857667d6ba17f1698f19c144617e225bb9283973934fda3270f4952488ae773f7e79c02009ba604692602d5da3988172f7a5ddbfa5fa5a1471995bc783a96c5f27d0b6d728cbc5ba991a08cd30ee1a9c88530fb1d09662ae5718fed61e0e9668669c75ee4d6eb793b329140c8e39c0e795c2a00ae8688e170883c3af91f0acd34574e9aa5eeb593aed1c623b73f00cc3fcb6807df486731a8e872bd46ad4ab1670fe76134c9eb4de7cf3ded7a7e6bd386d60cfe162b9e5d8f80d1fc9a549afc34f05ee2ca328a367949f375bb2183ecd7f31545cc87b6b19ce3e834d3a98156a71db69484e2213f15b750bb5e9c8e96ebc33abae12c269931dcf380d1f4a861eb4c768b93e751371b9ae211f210d381883976c5c587e9a6e674039a4b486c9fecae2025908cf05c7c88229abefa06a58a558c5fef9908fb546fad3489fb25b4ec62a75b0bc2aa2996bbbf89f6244f9ecbfd2e1e584a38b47c40f169c1612079ac83bfd8995c4154b440e5b02bf803a416ff3444f2e4b7398adcc8df331a210cc4fae101d06f533987fa59293e365361dfd6769b5a71fded46c7a360b5ddc2e8b16f76e5f0b67d696eeb0f9a01543f3aecb9c5b03b55da78e86adc59c8d57479ef9ae4bb86be4734e7587c023eefd7779180c316d4ae6fce63dc11c223c0f02fcf5190f336cab5b4845f050b6ef2eceab22638d7902b58886267c6662fc68102bae8bc7c78c329529251a3fe26a2c047b7910b8c1f874d623b3c2339cbbfe872d63a2ddd230f1cf2d45dc5731fd52641fd99176f3b7ed4fe072cd45b24efc4b0313719c720833e9b6bbb57533a2c1314f2266c1e4ea4fe4f4a8b5cdc46b6ef00e953ef9b3b453a3651ab2c2c96b2b928e239a37c76bfed66d405a88bb0597ca427492f4fc173a944bb6f2515609bd48e1b61b2be163f0f16e845de5f6c309f2c4ac49a9bd198c48b76cd56cc529fbc5fe31e04e5f499589c00957e260dad493a2abdd8487fc6d846bd7d63ed4a80b5b9ce2acebafc60eb9f295e260c51628bc511bbf4fd623690ea63ec2b725921a9927bae4d2ccf5fb07ee995c03e03bcf2d6e89d93db406eaa765f55114edc3b3f3de37f86064f92d045b47d3c53ebf219850b01acb1451f0adc2ca5028aa9ba565481866c55acc76e5c96f0d1b3d933960cc42229ea6d7539a8408c239d4bb324c5fcf7fc2950fd8001d0f02d9f4e25117e80037b3798afcfbcb9b6727b42ca4a50c77cdd3a9e0daaaea571e73a58be0cd5b1260d1d99a9968bb3fed510e567ec8a0bfcc9142ab7b43c03255fa85bf65fc5bf2c7826716597b4dc4df791c7f511f848f08dbb9f7da34f5c998a0f8a02892a243995842f5259175436c03985c5888ac4f4a2e6b9282048c1833226a51dcac1a988fcb099e4fa9a86494d58c010ae9214021f283c6760299b13c89cc8e4b1b98d412debb2c9a79fc7ed444b26a711b93b822cde0328c21530fbf2a075c190bb2eebc8d08ce1eb9cb37e784599db199d97a8c97824cbae8e48e781a82c4bba90f430739ec2d48488895313ccdb77301bdcac2e1465cd0cb3968ac941760795a06e67559d12b7d232854206be25c29fb9cd147dd07ba50536f694461b7d4e357724c9f6f9")); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs index d4b9301b2c6..0d060f279e4 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs @@ -12,193 +12,191 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Network.Test.Rlpx +namespace Nethermind.Network.Test.Rlpx; + +public class ZeroNettyFrameMergerTests { - [TestFixture] - public class ZeroNettyFrameMergerTests + private class TestFrameHelper : ZeroPacketSplitter + { + private readonly IChannelHandlerContext _context = Substitute.For(); + + public void Encode(IByteBuffer input, IByteBuffer output) + { + base.Encode(_context, input, output); + } + + public TestFrameHelper() : base(LimboLogs.Instance) + { + } + } + + private static IByteBuffer BuildFrames(int count) { - private class TestFrameHelper : ZeroPacketSplitter - { - private readonly IChannelHandlerContext _context = Substitute.For(); - - public void Encode(IByteBuffer input, IByteBuffer output) - { - base.Encode(_context, input, output); - } - - public TestFrameHelper() : base(LimboLogs.Instance) - { - } - } - - private static IByteBuffer BuildFrames(int count) - { - IByteBuffer input = null; - try - { - TestFrameHelper frameBuilder = new(); - int totalLength = (count - 1) * Frame.DefaultMaxFrameSize + 1; - input = PooledByteBufferAllocator.Default.Buffer(1 + totalLength); - input.WriteByte(2); - input.WriteZero(totalLength); - - IByteBuffer output = PooledByteBufferAllocator.Default.Buffer(totalLength + Frame.CalculatePadding(totalLength) + count * 16); - frameBuilder.Encode(input, output); - return output; - } - finally - { - input?.Release(); - } - } - - [Test] - public void Handles_non_chunked_frames() - { - IByteBuffer input = BuildFrames(1); - ZeroPacket output = null; - try - { - ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); - output = zeroFrameMergerTestWrapper.Decode(input); - - Assert.NotNull(output); - } - finally - { - output?.Release(); - input.Release(); - } - } - - [Test] - public void Merges_frames_with_same_context_id() - { - IByteBuffer input = BuildFrames(3); - ZeroPacket output = null; - try - { - ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); - output = zeroFrameMergerTestWrapper.Decode(input); - Assert.NotNull(output); - } - finally - { - output?.Release(); - input.Release(); - } - } - - [Test] - public void Sets_data_on_non_chunked_packets() - { - IByteBuffer input = BuildFrames(1); - ZeroPacket output = null; - try - { - ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); - output = zeroFrameMergerTestWrapper.Decode(input); - Assert.NotNull(output); - Assert.That(output.Content.ReadableBytes, Is.EqualTo(1)); - } - finally - { - output?.Release(); - input.Release(); - } - } - - [Test] - public void Sets_data_on_chunked_packets() - { - IByteBuffer input = BuildFrames(3); - ZeroPacket output = null; - try - { - ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); - output = zeroFrameMergerTestWrapper.Decode(input); - Assert.NotNull(output); - Assert.That(output.Content.ReadableBytes, Is.EqualTo(2049)); - } - finally - { - output?.Release(); - input.Release(); - } - } - - [Test] - public void Sets_packet_type_on_non_chunked_packets() - { - IByteBuffer input = BuildFrames(1); - ZeroPacket output = null; - try - { - ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); - output = zeroFrameMergerTestWrapper.Decode(input); - Assert.NotNull(output); - Assert.That(output.PacketType, Is.EqualTo((byte)2)); - } - finally - { - output?.Release(); - input.Release(); - } - } - - [Test] - public void Can_decode_neth_message() - { - byte[] frame = Bytes.FromHexString("0000adc180000000000000000000000080f8aa05b8554e65746865726d696e642f76312e302e302d726332386465762d63396435353432612f5836342d4d6963726f736f66742057696e646f77732031302e302e3137313334202f436f7265342e362e32373631372e3035ccc5836574683ec5836574683f82765fb840824fa845597b92f99482f0d53993bf2562f8cf38e5ccb85ee4bb333df5cc51d197dc02fd0a533b3dfb6bad3f19aed405d68b72e413f8b206ae4ae31349fc7c1e000000"); - IByteBuffer input = PooledByteBufferAllocator.Default.Buffer(); - ZeroPacket output = null; - try - { - input.WriteBytes(frame); - - ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); - output = zeroFrameMergerTestWrapper.Decode(input); - Assert.NotNull(output); - - Assert.That(output.PacketType, Is.EqualTo(0)); - - byte[] outputBytes = output.Content.ReadAllBytesAsArray(); - HelloMessageSerializer serializer = new(); - using HelloMessage helloMessage = serializer.Deserialize(outputBytes); - - Assert.That(helloMessage.ClientId, Is.EqualTo("Nethermind/v1.0.0-rc28dev-c9d5542a/X64-Microsoft Windows 10.0.17134 /Core4.6.27617.05")); - Assert.That(input.WriterIndex, Is.EqualTo(input.ReaderIndex), "reader index == writer index"); - } - finally - { - output?.Release(); - input.Release(); - } - } - - [Test] - public void Can_merge_big_frame() - { - byte[] frame = Bytes.FromHexString("006a5ec28080000000000000000000002094c10844fa022090f901aaf901a70183016e1bb9010046010000200913008009070400400108005001059601000002112700101109fe010009010588c201000d850004093909db0008090d0901f03cf89df89b947ef66b77759e12caf3ddb3e4aff524e577c59d8df863a08a22ee899102a366ac8ad0495127319cb1ff2403cfae855f83a89cda1266674da00943620100042aa0621b00010190bc8066a062f5669702289f891823d76b2984bcabff54c28e5707e300a4fc91e4d5aab0c7f97aad010d0132ad010df4000009094ee301150135ad0901321a017a01007290013e1d00297952010011bb5a0100329300fead016ead01000476ad019048d41aa0a25049f63fb1d0dd2142dcca659b9a0f024c3800dede31a0cd53e72f02e7bdfff935ad005b525a030d0105f20002ea5a03ba010005706a01003ead011501327c013e01005566050129e1323100fead016ead01825a038853a00879faae3be6fb05e94e1735d5df7f6db727a9b209daa06631d1173244e9aa76f936ad015e25011118252536f4003a3d03360100721d00aa010005781d012e1000119c321500a2010000282e2a00fead016ead010003765a03905c0e9ba0dcba26994b312a8f2b25b83b33ba110687c7c4e674e6a4368b65c2438f958af2f936ad015e010031112525ceb406be0100cd585e010005881901321f033601002e2f02366602fe5a03fe5a033e5a038840a0a3f170e843f15a46306a6cbaee2dcf1ecab0dfca863b47567b742deba4c14d5af9b6ad010041210afead016ead017aa50111013aad016a01002e5307fead01fead0176ad01883ba0e1070d9127562e9da3611cf2ef7bde94952732d9db3ca863f7694094ad10bb4ff9b6ad01252536f4002ebb02420100721d001d012e53013201005abd0105880d0171f63215006a0100369400329503fe0705f20705888aa060bd62384f7917d063d1f201f461b0c8fcd6f17af0d1f58bf7a71008c66b22c5f98aad0104100035112525fe5a036e5a03010132400156010005888e0100324c00366602fe0705fe07053e07059028a0625372ae8243568b9b1781f4fd43305e04d8f4d9474b468a3a1d1bfc5620074df903541a680d860e0a00004dbd36f40072010036c602363b0100003e1e00110162670319010040594005012979520100757956010032ce01fe5a036e5a0382bb0ba808a048efdd24ede4feda0c347125b7cbc68be9199a1f637cfd8b0bbac9395a1a5c9af901a7018302dcb6b96a220111ef45cf465703111f4201003aaa01e201003250015132b2010021cc36630201123a3d02feaa016eaa0182b80b8815a0787c163880dce2bef053d1e04dc43afa95db49731d8fa94c363b62d35eb6b17ef9320405258c4e0100318e052136f4003e90013258013e1d0009012927ee010005880d01119c321500a2010032af00fead016ead0182b80b8879a0e1bb6a52aef623b7ada22f78fae2324fe928909ecb64c64b87a788a76ca66eacf932ad0162010031112525465a0362010052ad0125ed6ac7038a01000588c2010005791501493339ad040400fead0172ad01825a038802a001b28945b68741a379213e0d7a69fc93bd69a02e6a24e4f10c916718052fd96bf9fead019aad0139143201005aea095e0100356efead014ead010000fead01f6ad01987fefa0da3ae50c5a6bfabd5ceb294fc612c977b39ec4389611287dab8d62e7b8e783d5f90354f9c1b40001e25e08523d031e3a085a1d00ee010005012ead0171f6040040ce6e0055464109fe0705f207058868a0143bf2a54eb7df942f1a158c94c447e8297029c56d6ee3bdd069afeaf79b8385f921aaf25e08894e36010029360906fe01004601002eaa017e010079bb218d190109b635aa0101feaa016eaa017e0405887fdca04aeba5b604ce81e33cce146cb704b7f8a5c7e46247bb1dbd2c8d948c75384e7e261d19a6b50bfab106aeab062951320100257caead011901fead01fead0176ad0188d7a0bd4e2ef1fc2c493ba520a7482c032581b77a5a07d7d79bdf1faecfc2afdcf686f966b1062e55019168252532f4002e26004601003a5a0332c702ee010005881d014ad501110111bb010125e9360100329300fe5a036e5a037e620d88d3f6a075fde30f63257583acb65ee0c8de85fb24caebf88309806d444a68c4215bb0f9d5b1046ddb821d191edd0c005036af016e01003aad01fe010015013ead01960100326602000229e131ad25d4fead016ead0182070588c4a0990002233f5712556800923de52a58631405caa5957d705037f6173b407fb445f9c9b1003676aa014992252232f100768d013daa363600fa010005880d01256401012e1500420100299846010031aa0501feaa016eaa0182620d8859a0425a499934be35468ed00b5ee8e93bfa87f83d167128ec843b14619028ca54f0f96604052e010031112510cab1063db5fe010005010588a601000dbf36300229bf35ad418efead016ead0182570388b1a028bbb04cc06d21ab924fc84ab7665edcee919a01da121982dfcda0d491e9bc9bf9fead0132ad01424401fea5013ea501110142690092010039ade16729ad00182e3a00fead01f2ad01889ea0d6c6aff66735d4305d2c7b7c8de01cf5435bcd98bc40d7b7bcafd6131f294b84f962ad014d8e0901110d252519f401015a900109255a1d00e20100710805880d01119c321500a2010011520501fead016ead018207058848a01b5fa50d36909b7ea799cd9f357e5c299ae206a70314fb8af77b2fde60ec1e20f96e6d17811a090131112525b1078a8a018a2300660100056d5601006a1b006a010049411101695afead01a2ad01820705888ba02d557708ecd4ac32393f366f04825222b7d727959fd3708b8898b60db9c5a2b7f9165e08a66d1736f100360100091c35a115090901321701ee01003eaa010020421200150151655a0100329300fe57036e570382b50b88e4a0d866f8636791e5cefb81ab30024d9071729308e0f92438bb8be758dae32444d7f962040532010011f225257157110132f0003601003aad01fe0100150105888a0100493c01010132190e0101fe5703fe57033e57038878a08cf5fe4207bafb417e751de79769a7d52bb746cbd97e36504d299a9232571305f946040501d73e010032ad0109f431881108520100721d00ea01002ea400119c3215004a01001528320100326a02fe5a036e5a0382b1068837a084dba10e557feb4a5ac1282f7fdebb14b09f274e753f94a66b5bef0158f6496af9be04053e57036a010021aa2e5601fe010011015a54003277014601004963110165570040323300feaa016eaa0182ae068873a057e16c68fb03fbcd35bbb00fc70e420ee13a8c7a82a77f68dd08a3e162805b32f9ee0405a90421915e0100051c5a5a01d201006d1cd653004aad0136e001fead01f2ad018860a082e8d94c3ef4ec6d3b42c0ab1c07b2b271bae823d4b743d12ff32487cdccd7bbf972ad0135142d240911ba5a03ca01000e010d72010015994a01004521520100fead01fead0176ad01884da0458ed86f07381cab97215a75a15a0d4090ba398dbf9eca3c5143c60d983551def972ad01150132ad0136f400720100000a361e003274044a01006e84013201003e2900002015a242010011bb5a0100329300fe5a036e5a03820b0a88d2a03ee4721e4734f8b99a836c4017299dde3f4d62fc136e6459e6f55c188453dd54f9caad01ee5a03655a322101d201002ead0122080e825700366602c5b4363500fead016ead0182b406883aa08410ceab8f2aa751fdf61bea4deaf19a40011251f8b002ed52afbfd453a21a28f9caad01001032f50066760422241efe010046010004400039a4753b2ec201a201002ee2010008fead016ead01820b0a8826a0c5548462d123ca85ccf14be10ee46aecec2fafe7e7507906c154d96742785761f9caad01ba5a03828106050149e89e01003d98965f0005013265020d722ead01fe5a03f65a038827a00193e1cc72e50bbfea823ca1ada60e2e8f68dbfd0ab063a02820d32d2f607db9f9fead0136ad0155e61aaf3572770392010036610111013dadaa0100364c00491ffead01fead0139ad8814a0f4dcb6277b576d1344a172e313b32109f98cb92656425e39ec3192b81d255a39f9fead0136ad013e0100eead0129ad1901d59c1efc1c4e010001713694011d01361900fead01fead013ead01880fa0171bda1ac2eb8f25785389da959a5e0ec92e63849dd60e5da4ca6fdce0a83c69f946bf104e0100713245d236f400211f620100721d00ae01002eaa013aad01119c099d66010005bc42010000082e5b03feb406f2b4068815a0aa4aaf65987fa5ae49dff458208a700dd83954597dd30c1a4929a3be170a38b9f9bebf1036aa017201003aaa012e1601f201003d76055469233e010025df35c9560100053fadb2feaa0172aa0182b80b88c0a0c433fc3ad9da0d56c0a5b854cd0b8650aa0f01975ff1e5d2529ce6a6b4617d3ff9fe04053e040536ed073aad01fe0100150121adaa34020d0136320029e131ad0501fe57036e57037eb80b887efca050aca4a9391233f4a7ce91a5ab16d91658ec238bcf09a5815b4dd413d626437dfe7f26467f2632a001110d36c301ee0100090121ad3a01004a13003e0100fead01fead0176ad0188e9a0d95e7995a6ea85d823f2b83b2d67505ee4b2af9d322c54a4cd9f62d0fd35d46df9eeb106c5b172010025ad858e050100081d0cf201003e9a016926360100ad000d075e0100fe5a03a25a0382070588b6a04cd3ddbc49e56b7e4f15363c636dee2216e84a419565d0f1950d151dbcd037caf9d6b106311d258d5e0100321d00291536dc02da01002eaa01358b2e1500a2010009950d01fe04056e0405820f0f8804a0eee9bcdf283d302cc043712f94e2306d72cb27701b78aa8c0330c9165fd90d24f9ceb10632e10072010032ad01fe01001d013a98019a6305362802496e1dcc0001fead0172ad0182b10690d6a0bc64bcf2b630fada7a391183ed60f434f995114d4d40ec7b8a29a6bcc93ea626f9044dc2e538babc101101391729276a01008221003aad019a01007aad01fe0b0a760b0a82ad01a8c3a057197284ca4b71efe51eb5bf8ca9fbecf80c7c54d8cd1919b60475cfd0f3d4e5f902a0018304ff60b93a9d02003025008a19032d01052a8591000831490d1a150139ad8201003e3b0005010563150100802a18140040e1133de1016a04400061702ed60001160d010d1701b0088000800d3af081f90195f89b94112234455c3a32fd11230c42e7bccd4a84e02010f863a0ce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82a0096e2240be03d6804812ff7b63ede4bb6fe19f1e44d0c231a85b67e964463ac4a09baf1e07f520199b833b0d1d3733b68c45304c80acc5bb2ffa6af89478a98bd6a000000d9e6000000079073fc2117dd054fcedacad1e7018c9cbe3ec0bf87a569d00f04342a0335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0a006363f16fc0be1b72c8a8bf3be9af16421c387e75a7d68c3bfec91178fb16637a0017411015a7c005217008842a0b59bb806875ef5718727778ded48d6def0daadc637571c2265f9eaee20aaa024a011570101507633a1e4c27eab9491a1861b76363ca4bfb3ad7ca07e19016e010b5d1400801a0d09457f3641021d263601000127621d00fa010005880d01416905012e1500a201005db9fe50047650047eaa07b00df5a0fb70a4b05a8ee7788082a040b2e00657988e20edecc2e3960cb054702622200ff903aef901080182520c6e282efe0100fe0100fe01009a010004c0f9a15e0803e5d53e0c018972327a02002009143a010041a11a5d19090b625e056201000001bd29420100197500023e9c02a15405016e5e0509955601004df50d63fe5e057a5e057c69e31a4b00b5ecd4de3f5389cf674893db12b4b4307056796505d01b18ea8aaa32704852cb04e65e057c2d2b1bdcbe79740e57e534445eac934d9cc641817e5934f6c7302070a781fb3f8e7c00529300ba5e054cec4078078e6c85d1cad1669fd66d2f7d85d6c95882190108f902b66eae092dbe31cd4925daae09fe01002e01008a4905323705090136af0209dc05274dacfe5b0bf65b0ba8b0a0f3730d9296280a5c601d649c48655fd956748b090587a98878de8afb23c26074f90109018301c067b91ac108fe0100fe0100fe0100ea010000c06e17081d0131da4531feb902feb9025ab90286ce0136b902002412a04345b9110100f8feb452eab452987eaba04a2cac39e1362a42b53b08532043828f781032d09085192e037edc753f940939f9010bf9fe1708fe1708fe1708fe17082a17080404fead74126f55f56a89911501febb02febb0246bb021192ae010036bb0209e300082e4100febb02f2bb028898a04a3336516295e38b93f34e40f6c0effd75068223041200665fb60119781be522f916261400763ec4092e01003118856536f10072010032020a0e4f2416b60ed60100057d09011d0b0501297652010011bb5a0100feaa01a2aa0182d01588a4a0762b632ac622cfe210fd08e265f7f8716804c1e37324ba1be3857afcff61a824f921aa08044a91daaa013a8d013601005a1d007a3e01520100329d0100441d23154d3222009e0100feaa01a2aa0182260e88e4a056ae34678eb7a9e46f003d526a32ed74a14a01d61edfa718722e458aab14a24bf9ced0159e0901526c3c3dc0866e075e0100d298013a1004698b35ad018dfe0105f201058885a035d2e6731c95f8b1fb41d789abbbd11c38c6302fcca9aee16a8fbabf8eaf89d0f9fead01c2ad019a010075305201004aad01357666010036bd0535adf5a3fead01f6ad018872a02be9f83df26fe7b13210571b272b279ca9474fa27270cbc9e832e32aee1b98b8f976cf0d1101313b252536f4007d2a460100721d007a0100056c5a01002e1c000d9c00013215003a562366010032e401fe5a036e5a0382070588d3a05daef9766987a2f89d44d63207cbb06a77959e179cde7d6321b0781006da932ff9fecf0dfecf0dfecf0dfecf0daacf0d4d224d1d090f0050660702110151b11108b60100361a034e01000d97ba010036580095661901feb9026eb90282361a885fa0b6f13fc43a4b7c3ecdcee5fcc0a4e17850f947daae790572378512e766e98508f9ca130601f4c1ee8a01002dad0132010132d30319019a4d001d013ead01297952010051685a0100329300fead016ead0182170b8892a054d7432def2927c2f6f60f8123cc2ac641c6eb9a39603b623bcd9d32ee84f6aff9caad018a5a0311012dad6d9315013e6c01c20100d641005134099729e1fead01a2ad01825a03884ca071b831b611a35b47767bb01ca5efe75f3f28b95589343d485427b19966f2981ff976412409d13a8f1515f405013590050111310d01361d007a01007a04032e01002ead0115372e1500a20100fead01a2ad0182c00788c2a0d723c531d149620a423759d4d32986287d682fe8a3a05d2abaaa6915f0667e6bf90e710ef2c44f660100b2aa015d121d012e4b01150cd295013a6302495515530101fe04056e04058257038847a0467948cb560fe96dcbbeb781be7649feef75cab76e2c2a70b24094a2d092343df9fe04059a0405fe01003a010039ad29733a010052150066ad01152ffead01f2ad018834a0d714d6dbd30ae8a7ee0a8d915f957f3d176239920329c895611a56ca12755d03f96ead01f9f6916825256e04053a0100b65a03055e9201002e2a00119c3215008e01000545fe5a03a25a0382040588b1a02669d25c5355243dfcf1dfe91b02fa5023d66247cb95e8f901384b95601f7d84f96ead011901311105e0c25e0839f57601003606026e010005883201008e3c003624006950fead01a2ad018207058821a051a4cc4313ca9b07278d6311a86f399a947a09ed547b94c9d5593397a03ff55ef986ad0101cf32ad0136f4007201003a5a03014be601003df43ead0129793e010005b60505660100329300fe07056e070582b80b8880a0c06446c490f52dbd04f8443f132d626e5d648a793e5b2fa6556aeddd445c32b8f946ad014e8c0111f22525c25a033601000544ce01003d58d6440036da0029e11d55fe7813fa7813880ea0e133b33c6079779c2476b43afed9ca1c920cd9e8076dcb244cf1a659554f5cadf935ad12d31b5e010076ad012666140501112d56d216fe01000501a6ad012e8d01fead01fead0172ad01887dfba0ef9a1408980c570a0fc20436a126e979bcc98c0ef91e009e9d629abd34812b88227856fed25926d2592e13013a0705fe010015013dad1d0b7e01002e9a00165e3d000132cd01fe07057207057eb406887de8a05d55cb31e40e67de1a280394e3b0514a42a2631049405352543c5b7defdb66dc122a1fae650d36f100728d0100423a7203fe010011010040ddbd75c6aab40119012e7703feaa0172aa01820b0a88a0a0bb054ed3ca12cfe3d62b73a222330ca6b23c7cf7967f81a21695ba30dcef612ff9b504de295d728f0172ca01660100360f024a0100d298011557c9ab0906fead01a2ad0182570388e3a070c372db8f70b641c9437504c5c35dea386be78c27f14bd1d67c893c0e04deecf9caad01824b0112c42005013aad01321a016e0100752e5a01003ead012979520100424b00361100329300fe0b0af20b0a886ea09cbcbcbdb8c5ac10105176786df121f752e97fd31bee3a98794c980725327a34f9761614a9d73a1614fa0b0afe0100215f3ead012e0100664c02361a0029e1014e1501fead016ead01825a0380d0a043b8c8278c311c9229eadc1f683159ad5f872ab04c99257e52c4221c5f13041e57387a295d0901252236f1003a3a030101290401014a1d00fe0100050105880d016d2712ce54c67000feaa01a2aa0182b1068891a03f14b66bb3f663009a3784e700169a1d65d1d645992b45aaf8aa1679ff2e8488f9b50446b50b3d952d11292500501258342e0100399e3a0100c63d019601002ead01a601001dd19531fead01a2ad0182570380bda04d95e0cc8cad3617e5d54c472a99c22952e890c002ab2c5b64db00f06eb647721a4e1dc83ead0105018a3201fead01fead0142ad011d9149621de5fe0b0a760b0a82ad0188aaa0840fadcc0fdae7f3d6baa2cae466c0a92afdce6dbeeee562d41653ce06904a17f9755a860b0a0040795a6e01002a530b3ec74ffe010015010040d24a00fe5a03fe5a03765a038097a09faa69635b0b1e83b7aca1ee3557e957ec50580abf52dee8ba1daf1b701751b2ad011ee81d36f4005dac460100721d008a010049fe4601002ead0171f611159674001e6f0cfe5a03a25a030003320b34420100905c0d80a012adff02e7a44ce1b347bc35c6ca653b12bdd7e6612feff2ad88c90ba47b2f0df9755a46b4061d011e1f3b25253dad35295a01003a390100485a2700c2010005881d015ed5012ac60a5a0100fead01a2ad0182c315885ca06590259c94e0046e9eb0e7af6a9597ce480d6f1921715d2c6145e3c8b4004b48f935ad860705615a219efeb80b7eb80b6a7a01110132ad013270016e01005d66fe6108fe61084a61088884a08d1b14d0d2ed672ab14dfd700b8e2e928182a4b373c8684e8f445348adba7709f966ad012e694521a401012525fead017ead018a01000040268c10aa0100fead01fead0176ad01887fa0a32d6be3f4fa6420dd7bba280c5d338d449e28b85623f18a8dce94f1fca9f8dff93643335e010032ad0136f4007201003a0705a204037e010045351d015e8d0322b27d3a89001901329300fe120f6e120f8207058852a00e7900589a74e1ff344c81e68da59c253e0967654f3c1c9e2ac770ed2b16f97ff9162823a64333a2570300103a2101622f01c201003eaa0196010036630225de0010feaa01a2aa0182b80b886ca0afcf5726efe83ebb8cfb3fb7e4281f1aef1a83a8440d0f61774172467bea239ef921aa08044ad18a4333000125220014321801727f01000236b402fe0100150105880d0171f0321500a20100feaa01a2aa0182080a886fa0e1a28b41d601c004abf1e04125be813f044d2ff868cfff0d040f7e807285553bf966ae062e01003111252562570332f900050172ca012e010005590501190a6a01009225004201004a570336b400fe01056e01058257038859a048342545f1edc16bafd237451562b1f32f96825ab6f1de117d4e8c05baacec5df97ec015090196ad014601004aad01363201da01008aad012e960f0d01097b1194a504fead01fead013dad8846a0951e02ac80de4dd320c07f04336c467a1a4d24e60599a5cf5af9d902d55438bcf9a104fe711c5a711c3116fe01003e01002eaa01514605157dda1eee0e46010029a409011d31fe6612766612820405b05ea060c338436b6b0e8a12a70e6b6224c5b34f93680e0ff0634897f6c589a7af14cdf90285f902820183025e30ddb135000030190b22432100202e2a01010149ae2e010000043aaf023e01001142000226790b46450042120000021137050100010166050101293574451f150e1d0104044001290d1a01e131b3013f0d01f03cf90177f85a94dc0884f78b17913d4ee7bfcd046e13407ffab56bf842a054acb82a9e70d7c289b149758d23167c915428ae854a7aa4abe5bf2f4ef29f36729910f03e616d69f680f89c9464fde89bae3e52b3b853a0ba8f8184d72a398f5bf884a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef325c004c9533d5f75d6ff12529331fcca7fdee660fe15d1b3221004c32e5d066767dbfe5b64b77d2b09113ae7839c2b93221004a01000c2a80f87b56fa008863a04f79409f494e81c38036d80aa8a6507c2cb08d90bfb2fead5519447646b3497ea02e5000ba7d00185af3107a400080268b420e9411319b42010021b80101450a328c07111a5601004516da01006e5a000588c201005d72fee70ffee70f4ae70f8033a030a2884066ffdf701429d1c48105bedd6c2457935151054ae2e78f00d28a3cd2390915f4664405111a3aad016db35a010011358a01003ead0162660226071e5a0100329300fe39096e3909823a0e8840a0faa7c014a3c7fa5129cd6fe9867ae42d59b8684fcdbc77d12dadccc12d0f21e3f9fee60a26e60a32f7000d013aad019601008a35002eb564a601005566050129e132b600fead016ead0182e60ab020a0c680c671e1606686f1a0805a271425daec89dbde8523928a97a3483cf77dd769f9040ef902610183030fb9fd8f8e010081a609f0920100aa37030101015e5e010021cd3e5b03a2010009394a030b0ecc15f03cf90156f8b994f0ce7f5075a1419e6ddb75d8e7118999042dcbffe1a0cff3cf4c6525a5d629f6e2ff46d4ddb2d8d3deca13a243852bb07a5fa538e458b832b3004c43152a3c4678b44e5f6a54d8a1ff1f5ca2b65a230163520100102386f26fc1521a002e010001f76e01000804f8995abb008876a527b8f997064f142eb87b35d9520a142e7fc5254e0ff2bf34c6a4ba15f558b860001d594c3a5fb887a98c72cec9882b9ec5e6b5c0980650781d1f4201000c5d3478fc421500360100000112112808047e146e640200801ac40925a2326b073e0100052215017e18015a010036ba034a01003666009e01003657006921fe1104fe11049911b01ba00a140c8a860676c7d44067a63dbb080ecf2bc6b7e0addd0177deca6d8066d246f901c8f901c50183027b836ead014a0100610009f0920100fe11043a1104e2010072e70104f8bbfe10048d10b25503fe10048910769435190121b8010100420105727803360100da78038201002e91012e0c007601005e780311defe8907f689078808a05d836d5058da55f37ea245c1c6c0a09fdc39ce041badffa0c9fc9f4ae1293d37f92236090e900c15b63e01001119251925ad050a8201004aad01ba8103560100967e003e01005ead011501fe3609ee3609887cf5a0c19b603dc89cd878fcdd96404f17ffff272dba0077acc6ce4bde8fe5d738c80f363d0e3e010015de32ad01151605013213063e01003aad01722c0001019e85013e28006aae0511bb5a0100329300fead016ead0182900c882ea002e3877116a4007ae9949a50b517ed435a6b90eacecc9e545e9368d7a0f8da63f93ec9153a5f010d0111f2252536ad013a31003639033a1d009a0100116e66010005880d01152e2e1500a20100fead01a2ad01821f14884da0629db809f2d40eaae3bf0a45fcd606adb61fcdd63d13d59ea9c0cb93908a5fecf9bec915a504960100d6aa012e0100567f015616007ed40f36630200204556feaa01a2aa017e3a0e887ce2a07d8387d48fdb281b44951677ce7640ff7394f61ca76474ec787d1b47ecfa7872b904fe2823fe28232628238a01005ead0176b00139ad61fda938000801341101fe04056e040582ad0188cfa0c25b3f734b7e0829c3bb48622f95152d0f23122b03832bc5819b2c42754632a0f9225e0896ad0101d77e5a0395951ab945e201001d493a01000588320100217f7e010039ad0101fead01fead013ead0188bca0d75d03b8c48fa05629c3155afb89de47d052e1fd8c514fbeaa4c39b70b4afe9cf9baad0181d87ead0119010008012ffe01004e010046ad018e010039ad0140fead01fead013ead01b0b7a023e4d9cdd2c4bfb6b9ec30c9f1a6cf22e0e66a8f05cdda9db856b992e9580423f9010bf901080182520cb9565512fe0100fe0100fe0100ae010000c0cea63b368f2242ab312e01003abb023282054e010041538e01003e2800498752010066ad040501329300fe15066e150682190b881ca0b04c167e53e8cd45c320877118f78065c0673b729c93e155c60fc8925b134512f9fe6c09fe6c09726c095601003eaa017601001ed81499650101122635feaa01a6aa0182bf0788a4a0016444888c66e2eb81825e76e58a648274e24249811fb491cf705ded7b56783af9561206e50d15dc0040559c2525a612063e5703fe010015010588c2010015d10501698bfe5703a2570382ad018891a009230de771f7b5532bdd858f7c64b3d60ff427f3c9ff2e4cc4ccd2f8ed844f92f9c5120c8082ca97ba4115fe0100fe0100fe01004e010000c0be270c210551bb3aef0526bc211901422300fe01000d01125509c20100febb02febb0276bb02887ea028fd0f7062647554023401b52f7da3227589550ee7b794eeaedef47d8f1e752cf995680e8514010136d2000d01f10431ad69a4860100fead015aad0142202496010036db0009c4fe6804fe68049968886ba0dd81c5809028cf740ded77bfa2da6bd4af297da48702d427ecab5bd418be3800f935ada6d40d36f4007201003aad01321a019e01003a4400050145351d0129795201005168420100093409930d25fe6c09f26c09880aa0afb85fb6f41192eeaed794f2b33dea653a935aa9ef5a2e0ab84a19e7b5c5cb42f93e85145601000dcd00042525b1075601000d2b01010004526901fe010001010588c201003666022ead010d01fead016ead0182c2078853a05b33a9c75d3c7096f1b9dcf202de848fa8333a70293fe1bc5164cf31d6078515f9fe190bfe190b4e190b36550142010031aa11084e010012300a320100365500feaa01feaa013eaa018858a0177a9a7a8b6ce143404deff5b365abb25da593d6152f527ea8ba86f13e36c521f9126c09febb70febb70febb70febb7026bb7000b5fe8c10fe8c10fe8c10fe8c102e8c1061c67a796db14565367670053201003ed906465a03d6010005888e010032810061c601040901fec603fec6033ec6038840a0a19b6a3b51d491f652bbd9f9a137f4f05e5c1b8ca45922f31027fca2fc9b8ff2f9fec603fec603fec603fec60336c60304037016932704995aba410e41ce29fe920100bab502015e5e0100418fa2bc023e01000939563e15fe93272a9327fe8323ca83230002fe93271a9327b24e28180000005d34755a01086e010000f90ec9640803eb66ba6402fe0100fe0100fe01004e010000c07a51751101710245b1d92e41fd7201008221006601005616030d0105883a0100d9085e01003622008930164b0d0d01fe9e0bf29e0b882da0fefe2b5bf764cee7eaf4ad6745ad29bf6a34c6ed1a9680a2386a53af06fad6edf941b97ad807fe0100fe0100fe01009a010004c0f91aae2908033fbcbac80341cc29fc920100fe2c063a2c06e201004ef3021501feae2922ae29b2700596ae2972c9030ef61a263b1b1e7c1352010021b80101250936cb03111b5201003a840432f103ee010005880d0101556a540272a0000000fe388fa6388f7e3b1b88d2f8a08902435cc6d02fde00b003e73a5503bd6248756173cc945c7ae261c899ba5d53125c0c00025a30502107224f2200802922d92e8201003aaa01fe010015012eaa01a6010036630229de000816a83a0901fe2e06f22e06801aa0f515c99369004ca0556244803bb616d8fdfe335b3213723fbda4972d108f0fa68e3409e9252529ad2dc7760100fead01fead0192ad010ddcfe1d3c7a1d3c8279138807a07237347b24be070feabcba512aba0132bd4575b7bf1b6e9fb50fe0019a363e28f942261552780691493dad6e010005270101fead0176ad017ee2053e010049711101755a1901fe5a03ee5a03887bf4a06d50f69a3eaca216ce5e16ca2eb04e1a9f7654582b2601fd251146686f8ed784ad04e2ffa909f232010015133aaa014a8b0335d5b201003e3600157146010051655a0100329300feaa016eaa0182ae0688eea0a3186daecd7d97102ba5d888bf6736262ba42eb5d63bb5036a5147326ebebcc2f95e2a1a360f0111f20516a9049201003aad01000056b5031ef158a601000588c20100fe5703fe570376570388efa0cd2d73f190f671c3c37f15b6a816f4bface6fe5faa31a492a89dbe73219049dcf95ead013668295aad01000801276e010042ad01fe01000d01d6ad010012327e00698e32c300fe5a036e5a037eb106887bdca0811d76ce22ebe9635e5395bb8e766ee634ab347362f6a6cbf4ed04bc7c4745bd56de204264015aad014e0100323c00320d00fe01001d01d6ad016a5a0329b4fead01f2ad0188c9a048270935cd7bb1609908f74534ba8105e38d10c52302f8df52fb96fc29a510cef9425e0852010032ad010e9d2809dd8201003aad019a36005e010039a3190a0901692652010011bb5a0100329300fead016ead0182b40688dca051d8da16af021f95cf5a8723fb1f6ae3ef3355bde40c208c590fdc5a7584dea4f90ebe19aed247eeb106a601003243013eea0636aa013a2b006201006a57030901feaa016eaa0182040588b6a024b7f73b4bd2c99532a83cbbf471510cc116f22692fae2db422cc18567df0675f91abe1904698fba8312fe0100fe0100fe01004e01002cc0f9018af9018701831adee66e0f017aaa0362010026650c221a0d997800081d1f05015d91de71001d5f2ef60f0501858a1d644601000cf87df87b52954088f863a08be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e07e414800003221005499c842718aa0741548582080c96324b0b525418b80f91a111f04a4276e8c01fe0100fe0100fe01009a010000c016b10d0412826e0c01512725d6fe53059653050101454a4e010005887a010001b4362800fe5305fe530576530590a3a08ace4b22dd1fa2278ff708c7c071f402c07e4b20ca3732b20941f90e7a14015ef9010c129f1b0804063d6ead01fe0100fe0100fe01009a0100f2442c8a0100b9413e4005ee010000103a94025e010041be2e0100febc02febc0276bc028890a06dd5d84f1c6bb19bfc78a6f960af08d7d692ba31be73edc7ebc2e498e0472a72f96ac00e1d0111f765b9fe6904a669046201000588960100f57a00001a739b110189c6328607febc09f2bc09908ba0fcb383cb67776bde5c5d2cb816dce9dc9850342df3a1371c969c5276ae6ff91ff90354c516ae567151a129076d3d563f010d1da2010026de087601002e6e005149321500a2010032a50bfead016ead01821c3f883ca06f67675d7548bc2b31953a6b60a6ff9ed89c61a77045a13665183e352dcf0fd9f976130d05cb310e2522fe5703ee57036557000409885132a2010036310071571d01feaa016eaa0182130d8878a0fc34b0d58737241a896eff41d7b8a33957593a1eb94d0162393b0fb532bdc765f9edc00839a69dfec007fec007fec007fec0077ac0072e220432bc023603027201002e44000e481e01055e010089b596010065441d0149882e0100157a11bb5a0100329300febc026ebc0282791180caa024229b680aad51c39bc518838450f115305505910766ecb39295e49d43042d2a89484e5732359711f22525fe6904ee69048569a6fe0535b3050115cf050129e1fe51e5a251e58269048865a01d76b96ac99d901126a67b23448ca0ae76f53eaeda67d3a057be6b94ce44a767f9fe6d09466d092905090100820907520100364901b601004535c201004ead01fe5a03a25a0382ad018852a04a1db3dab98189c322e01b9f0c0d806343c38590f0c5edddda80508f404ee1caf9fead0146ad012e010000032e0d007e01006e6a09366801fead01fead01fead0152ad01883fa0e5efc603e17498f3ebecbbc88cf012bfa5d83b973561319d299bb8029bfe8957f9fec307fec307fec307fec3073ac30722bc674e160615014e16062e51042e01002e0504ee4d046e01002e6400a60100001032f50209c0fe6904fe690499698827a034c18727b0bc4535eb049064032a5d3c31adbe6711f10889e308732e66186648f976290c050132aa01001005135201009d29254d3aaa01321701c20100295b0501055d1d011d1b3e010011bb5a0100329300fe6d09f26d0988b8a027ac3d459cbbedc077581b038c73e10e2d6defaddef1ffbc6cb13bcbbfe0b547f921aa96bc6729220050a6c10a3aaa01fe010015013eaa011101769a0036630229de0088113b0101feaa016eaa0182bd07882ca0bf16c7b1f6fccb42f325c5a100f56ec39f9a581357d8813353d2e2a238a876a6f9f5bda69f2bfe170b9a170b294d11013687012ed680a601004ead01fe5703a2570382ad018814a0ca53be54a3b5ebda00c66c2360bb34f9186664950e805aba1703a3884be171a1f935adc2ae068e0100a65a03369b017e01005e5a037601004ead0100182e7a00fe5a03f25a038001a0617fa8ed0b70370b69bb2bebecd08b8d84777e4fbda3e430912367f6d6f5db2a0eed6a5a030002b5f62525fe5a036a5a037a5e06150105880101b2e4014ead01fe5a03fe5a03755a887aeea0000342135ba2bdacc3ef78c0a5a4547cdb3a12dfa3974e19e9420c58b2219122fe15a6fe15a6fe15a6fe15a63a15a6eeba9d12ba9d7201003a6804512859a255848201002ac7091a4a081d016ac202196c52010011930501fe68046e680482d91288a6a046106ec6c66ba20591349549ad6fe96b47d41362a07cd104d1055307e18bf0d0f90e3836083b14f8fe9215fe9215fe9215fe92157a92152e010031fe45689e740500023634224a010036a3086a7e023e01000588c20100fe7405fe740576740588dba05779bccde43d4b2a3f688b1f471711640c0f0288cf9d99f647a0e20e24f95ad4f922ce081c1bb901000000000000004e010000800d1500400108005001050000090c7a010000027a20007a0100056f4e01000440084e16007e010000103221000020050e324900f03cf89df89b947ef66b77759e12caf3ddb3e4aff524e577c59d8df863a08a22ee899102a366ac8ad0495127319cb1ff2403cfae855f83a89cda1266674da0054f660100042aa0661c00d0000000bc7ac8a07f652e8ce6d19186d5fe009a4bb51932f2e8d655635b27cd9ff0665960a6dd9af90354f901a70183016e5bb9010001365201004ead018e010062ad01363801b6010000203e29029e4d00362800fead01fead013ead0188c3a01c706350c1cacdd76756e6f13844527283795e30b43aaf2fa6c8e23b9a74e285f921aa0c02dcb6b939aa09c50501090b32aa0136f100628d010101721d00ea01002e7003119c3215007201002e3e00fe5703a257030003765703b85c0d2da0c5e13021fce9d08cf1bcc522e02e626ff7a311c6f07bd9f7f242f0f9da22de34f901aaf901a70183016e5b3dad420100311105e7ad048e0100e6ad01117256010005881501327101460100555d150905014987323c00fe0405f2040588b0a01454892f519cc972d036be8a57aa32c4bbdc428d7b3ee1a3cf961ecba588332bf9caad0136f4007201003aad01211a3a13003601009e5b0031ad2971000015084a010076f60105931501fead016ead010004765a039048d294a0af540497bb9405263b221925d64cb4e08b21ea8101fe77d1c567abef37f7a76af9caad01d25a036687013171ae010031ad0101a64000368400093841401501fead016ead01825e08889da06ce11b95a9240a28e0ce1126ee7808c6e99c9f30a6dddbf4f1b760d87e140b09f9fead019ead01321501ee0100050121ad367b018e01003632000420040134329800fead01f2ad01888aa0acec0b370c3c497ca53ce3d84496a0a9badce3e209cbf02e4cab3b6d17a62d73f935ad001ba2b40636f4007201003af404321a010d017aa7041d011d2a21ad00001d1169265201001d364e0100329300fead016ead01820705888aa0f9b6f623227190d39a8ee700ea45b3544d7479be566a92208551b002aeef11baf935ad66b80b00202d1700081a7109d20705fe010036010029adbe010036660229e135ad010ffead016ead018207058877a008788e94be79c7e92a1239cd6c63974c4cf108a6c8e98f6db5ecf5bba7f8f0f6f98aad015dc42525fead0172ad010041016f8201000588ae010065e372ad010101fead01f2ad018864a030fad52d61c42232ae35aa72aeb9ce8967230f3fe84e6ff93a30c8c169d3ce39f942ad01266e0d1d01914c2525fead016ead0155e94e0100057e0501190aae0100fead01fead0176ad01885fa0d716521ec08cfb3a803854d008e419a50cf3ef24a9c13b7803d3a709523504c7f942ad01520100d2ad0104080049d1320100114aae010081a2360100fead01fead01fead014ead01984ca02d7a744c5c627584b49c8164dd50fc56f45e1bc81c8a36574ffd63a568101d98f90354f90192150f65722525fe5a036d5a128d094e010062190019010588c20100fe5a03fe5a03765a039839a086d216db5bd924319899a42c4dfbd1069261e92c169c336985afadc6f7c77c74f901a70183366c12420100710d252205f18a4f01000042570395e215096e010011754a010005881d0146790315016a46000101328a00feb1066eb106820b0a8878a03b3e45b40dfb752f785d0bc59635b7e8f2ff2f7bd20bc6c9c60ee127349ae5acf952040565432e010011f22525fe57036d576601008609020588c201004566150129e12ead010008fead016ead01820b0a8826a0cb22c97bdc768cb08b96992466a6702f674b57cd2c01ef64f36bab02028dad83f9a204050501252536f4001265095e01003e1d00363b00e6010005880d0151493215008a01000138004032ad01fe5a03725a0382c615881ca014ca70b06b045cfef730633360481d5efc3f33826c7d7897e405ee36d8492361f9be0405fe5703825703150132d9012e9e012e0c00a601000011322b00465703feaa0172aa018257038813a095ad1ba1547b34be892411493ac379832cbfd24d3058aea201d33ee3062827eef9b504a6bc1076ad01324801695729740906fe01000901326500a20100368200fead01fead013ead018800a0ee804c6bb19f3cc814b48df36b74fc02196d0524c0b0943939ea7ad05df0d952f935ad42bc102e110181300101051476ad0132010029adfe01004601000588360100726b0029a709061101fead01fead013aad019879fba023a30dceaa6436c3585f0dda7504bb376797c36a41d04ca1693fa69a29725ad2f901aaf9a1070001aa5a0336f4007201002942f5c21509fe01002ead01217501045a0100516836010009990000fe1d19fe1d192e1d198866a07a2a7d99546c75e6036fa1b14668c3154cf52065e9efd9ed666b79c0f69e2b00f9665a032e010011f225255e5a0311251d0135146a0100aafc0115010588010186360a1d01366a0029e1324002fe0b0aee0b0a8879e8a026bb41d66a670351c86715e6f08dd69709b1ee566e78ad3cfe1782363ec81982267b21a6b40636f4003d9009f9354946650dfe010015012e640055242e15008601001a9c0c09b40d01fead016ead01820b0a880ba06c00e39c6360809d19340d40dfb59e7f67703bff510afad4aa0116658a11961df9a1040802dc76a21a195e57034a370b3dc71901b65201360100690cda4300366302094bfeaa01a2aa017e0b0a8879d5a052d3af3c53c3bbf32aa6db1cfe8e91206b155e3976afc1e99187063f9b58c985d9b1425e082e010041bb01dd256866ad0142010035ad05394a0100b2c40419015e4f00760100fead01fead0176ad0188c2a0b4bc1085145bc45f5186bc222172af613ed30ecb2539f48f8e407c732ccdce91f9360f0f21914e0100008009e90040252536f40072010035ad090132c702ee010005881d015eb8002ad5195a0100329300fe04056e04058269128854a0b6f9771ebb4cd420061bfde5169ebae6a98548ee671fdaf99b4995cd96760363f9a9042e7f2642010061570101252236aa013a8d0136b2222e1d00053cfe01000d012e4c00119c321500010192b303feaa01a2aa017eae06880cfaa092e2c158ccb0f71660fe8140e96b5641c2034f5d7566d5da374cec35ce48c3804604052ebe00359731112525ce0405fe01003a01000588b2010001c215cf0501698b2eef00fe570372570382b106b0afa0e99cf3cd0a94f78406fbd428b0e937075f0286dec76bdf47a19f391480f69074f9010cf9010901833a6a3a6e5e08fe0100fe0100fe01009a010000c059bca6170bfebc0282bc023250025201004ebc028636007abc020001febc02f6bc02889ca02c31a1af6c590bfca0ea7123fb61cf1dc9854026befb252cc29157ebc8009326f9fe710e2a710e4a01002e16067601004e7f010501528401622e0019014a38007aad01fe6904fa69048897a02bc85a4a21c49a3af9496119c94d576b8c301f4c38e1dfd15570f6fa6eccd504f9caad0136f400729001461d00a19e01011af00dda01002ead011152321500a2010000082e4b00fe6d096e6d0982c30788e9a0df82cdb164fae0757e256e6ceb38e46af62e71ddfe484483b002990fb8b3661cf9caad01bd077ed30846ad01fe010009012e62014a43034a01000132366602fec307fec3073ec3078884a0873ca76a11997b6034bee72a616b7b90b666ccb51a197598da7e779cdbb43b0df936c70c5e010051be01f33af4001d0146bb0139ad053a9658018a0100054e1d0129790d0136b50311bb5a0100329300fe5a036e5a0382c70c8842a0ddc6238df140b7358a40d6229d29c3c58c16c59ee91f8eac28de7bcecb5266c4f9bec70c7d577e010039aa3201007a3e0186010032aa01320d005a01000589fe5703fe57037657038871a0ad42376c4d3eb3bc49e064ffec728a7f6d1f4bebbddddaba35d0fe53d2621a46f9325703329e022e0100315e251836f40025075e0100661d00468303ae010005880d01119c321500a201006157154efe57036e570382b10688d8a0292b36061c39cfdf6162b740e504887da5c82b8620ff0febe0822f6b5fbeece4f9d6570315df6e010066aa01f60100327d00a2f5013663024597001021aa1501feaa016eaa0182710e885ea0255c3540fc3ac66ffb3cd8e72b9ca47f4ae19afc2acdb756cca5f8793afdd430f99e5b080480002115004001d8ee0405a904ee0100050105889a010059314aad0165571501fead01f2ad01884ba09e71014f557d3afb43a11396ec442feeda31108eb27635ffc4195367fe85b9e7f99ead0109012525f6ad01363201da010005884a0100b510520100157b658c655afead01fead013dad8838a0a2e28bcc3b7a744d68e1a9a1fd243925d8c99366bd78e3b44e589b8c3def4ebcf9fead01c2ad01fe010005012ead013da10010765d00361f0035ad797bfe5a03f25a038833a043546cbb4dacc9d0ae20e67872a8246c1012f6e169c58226604e815f3bba10e6f9325e086201003111252536f40001eb09f8000046d00b011d05011141fe01000d0105880d01155b2e1500a20100feb406a2b406825e0888c9a0b20dbdd515105a6f10af738209ec35ac22b9b770e565218e10d64d71e7e8fa79f9be5e0836aa0172010035aac5ef3617010501a24c000001052f11013e9501552b46010035c9560100feaa01a2aa01825f0db030a046dfd2eeda4e6655271ca4f497cb094a63baf54ce707a1d78ac18df6282997fef902b5f901080182520cb9360f01fe0100fe0100fe0100ce010004c0f941b80801c0676eda1731fd45302ebc0711195adc3d5db8fe0100050151660588c2010036250349ec11520501fe0f06f20f068820a015308fedf6c8a3a53b25114f6160cad1b1257a1e417a49e8acace99938b706b1f9d2bc0709e88a0100bead019e5900aaad013da21d0b555efead01fead0139ad880da0026d40d11a11a4b9807020eeae68209957b45c54a057bdad98fc93cb49c1fb13f9caad0136f4002e010042a80435ad091a321a0176010076b7013ead016a2e0079fc520100329300fe5a036e5a038212068826a0ea116b250d60df6310de440143e19e23badd1539ad34b4501eeb94ee7c69e2fdf9ca6909b1077a0701010135adfe01003a8e0136ad018a890005013666020953fead01a2ad017e1d108878faa09e234c7cf0e594981bbaa326d99f7677794a57c323e93005603acbba5882742ac5b1c2f83515015a8d0112d00d1d1d6958fe010011012eaa0135a82e15003e01003291012e0100321900fe57036e570382130b88b8a0ea66d8502a040d07c8e3bafa6fafa655733509d5c2c73aacd4e13e11a21b0b16f9ca040571575201003695014eca01291f0906de01006e9801660100fe5703fe570376570380e7a0209c5ffdf94e71938224c3b42d311d5035b6edd7ba14b71035e04205449242a6221a09e9252572ad01695211014ead01fe0100010105885e01003683001d0109c41101fe0405fe04053e040588cfa044459be5ac46e8129d72e635111101edd4b03baa02b99886da0c52695e64193af90eb50bae040529aa92850192250076010029513a01004aaa01b50b660100feaa01feaa0176aa0188d4a0858dc8ed58bbed30e1fc84389fc1694d6794533546abf141f1f50fd096f63ad7f9ca5b0836f4007201000002364301f2f9042e3d003ead0152d2010901368200429e102e5600feb10672b10600047ebb4b8814a01dbd12bd7ae3d1f3f73e3270781ddf6b5f6e8afe118074047bcad4ba59fdfcf8f96957a6442f39aa21316e3a0300206e1d0072010062c504090101791101358b2e1500a20100feaa01a2aa01825b0888a7a0b69a0ca30d900f593d00af19af404644291cdf9ea628a76b2064e364fbfe1060f9ba5b0801dca904920100e2ad017a01003e980162680001b0150159660101698b322100fe080a6e080a82b20b88bca0cca696de71f1177382bf161fc4f3682864b5d43505525e40086d6e3ce3aaceeff9baad0101e64ead0136ff09150100025e1900fa01000588c201005ead01154efead01f2ad0188a9a0c826b805066afe169e51dd7e23889154ec1ba86a4ec91d351d56c18912920316f9cab1063dad5aa401150159f200047ad904b60100355fb201005ead011501fead01f2ad018896a0a862a627a6d1bed07b1fac12da181c4d4a918781f1be099aee902810d1f9751cf9c9b1fef13016f1303a900139aafe01003601002eaa017eb106764e02bd040004feaa0172aa0182b1068896a0d8fb08fe5e851eceeef1126f90d0752c35b62a16de8e4cc046d0dd60f6d2c858f96a04053d79311125257d577e010036ad01763701ae010005884a0100766200fe5703fe57037657038883a0d650986c24ac44d9f12a3d0374497e51932b4fa58e75065d58bddeee20e77fcef96aad011d0132ad0136a14272010036ad012ec702f601003ead01162a082e0100359905bb05055201007d5afeb50bfab50b8802a0efc57367d72c43e9e00c1c3df5dcf5417d759a69ba733bc1a62748807f749e88f9caad0100506afc003a01003aad013201007db9c201003ead015601003ea30135c1050129e1fead01a2ad01820b0a8870a01f4801a4d46c03d8dda24aec7fcdb5817efeb5ba9ddc9f5915d9057aa0c09d15f9ca5e0836f4006e9001761d004601007284012ddd25822e2900051101012e1500a20100fead01a2ad0182b4068885a0cf71aaa1afe4e50a8a55ba889298b5a7b27e71fd9c801d8ffd08a334fd110624f9665e08497a2a3e3a250dc9b132e3005e010072c701be0100057d09011d0baa010036630209dd32c700fe080af2080a886ba01f5005b84ae3c77142aeae3cdebcf0d3f7694c709b17c5d793cfb9ba151725d5f9c60405000829ad2e010062d507fead0132ad011d0186ad01756d1d01fead01fead0176ad018058a0046dcf3c5f7fa2ba925630f4a972ff705b9154e44af6d85ea54f1bd828f26efe39336a0100251afead0135ad69010554010186ad014e0100153f0501fe5a03fe5a033e5a03b045a007a713bd7d3b360fb3b248c2b43a4499c2f54b9fa17c6eca1712f38b05325d89f9044df902a001830393093e222309cd356f15090901293e0501210400802e021422e735011a6a01004efe020e335b097a4a01003a8400162f2605010040c1cf1d38019f04400061f32ef6031d210d4c0d830d19f081f90195f89b94112234455c3a32fd11230c42e7bccd4a84e02010f863a0ce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82a0096e2240be03d6804812ff7b63ede4bb6fe19f1e44d0c231a85b67e964463ac4a0742c0bc8152fc0e66a4dec4400bcf435c6e2de36d86681fc72ddd8b2028e131ca0000005cd05015479073fc2117dd054fcedacad1e7018c9cbe3ec0bf87a569d00f04342a0335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0a07b689a1a3d548f912e96fc2c8ea2e8b751eecbabe2a923b27572f225fdc3c1e7a005750d015a7c005217008842a0b59bb806875ef5718727778ded48d6def0daadc637571c2265f9eaee20aaa024a00d560501500434ef9ff3ca966fffe15d3764199a977e882ed6a07e190112141f080501643ea3022e01002dca21f6460c2a6a01003a540241391d01d61604010100400d8b11014d634e010000803a84003a0100329300feaa076eaa077e631888d1f0a09703fc8c93b0e0f64a33d7104627f1b0add92ae8f050a3e219830e153a4eb682263d3e82fd450101255f362604720c013a1d00053ffe0100010100c01d4551499a5e002e60043e1f1afead016ead0182010b9074a0b0df7d23fc52528067ab75465e8bc6e6f2ad56f2588be8284506c67eb46859d5f902b6655afe7c6cbe7c6c3a010046c6013612023e01000930762400460100363000698efe5a03a25a03825b0e9832a00201eee8e698746c64ce84c952cd2732bb933b448e433592c24ebe514492ab2cf9010901837ac92afe0100fe0100fe01009a010000c026ba4d6a6604001075ca453146100c62010000029afc033653028601000588c20100366600feb902feb9023eb902881fa07c8c5994344ca7106b7e387d34a07918186ceeab94f3d884b04c63082b0d7673f916670fce761e01013af3051d0100101ec509fe010032010025a505050d015a10060e710a8a0100fe6304a263048210068865a0b1ee5f6d2324ac00a01b6d35fd0c90be39a5796aaf6d90b3192c8a27fee6a3f5f9c6670f765703361c0721ca49bf1101355bf201002ead01a60100fe5703fe5703765703880ca0b73111e2dbc041fe25288ef9365ea03c71f2b175ae42a39f559dccf38fb58c46f97ead01216f0e4e0d090125259a0405012c093efe0100460100015cc601004ead0100092e4700fe6a096e6a0982bd078007a0b77503e641bd84dc2fb90d5b8fc1ad0f031bedca7c34348d2a14347541f2e32a54496ab1063aad0136f40072010036ad01000899749aa5045e010039ad69ca36be033201007acb031993fe7219fa721988d1dea006b328ba129eba276a46ff0ec9563ba7935c7d3bffe16faa1212cba17e019ccd925e0872ad013690013a0100321d0029a1aaeb0166010039ad199c01150963ae0100fead01a2ad0182b4068854a059b17812326248f85a33d95f09e58eb22565a27391edebd996337b8988d34054f9165e087a2320499e25220050a60a0132aa0172010009609e010005886601005a1f00362502698bfeaa01a2aa017e0405b877f4a0cf43d1da4d48a6b6e7a5f79ac244e057c8b5fe3579ddacd00e50e94294bb9f67f902a3f902a00183039349b9894f1501002012b211256f764a012d04052a05015e6b14291f3201000020322e01328200195015014213000004124e140e3f5861511d600c08000010466b144601000dda0d3afe6b147a6b147c8213dd788f123c4e45f2bca883ab7fb4cd55c491f0b4b3b03b8a67c2feb66e0a324d2a52d813e66b147caf68f0896eeb026cd9a14e728eeeea9cedab82d39e2616061ee209b7f30291ef8e7c00529300ba6b144cdd9cab275c3afd873701984725e80128cd49bc4982190100f91e1411046ddba26e14325304411e660100425702aa01004d3a52010000402a0c17a601006d4f0d010960fe5304fe5304995388e1a002fb51c12133a635f67d34cc48779e9dd9968d00ab059f3fc42594696400ebd5f912141104bfe76eaa01fe0100fe0100fe01009a01002a1411feb753eeb75316b7533658027201005aed064e0100ad41010136610049b9008801191101fe100cee100c8877cea0a34d541a688b4296d0d420e5a0fcb5c6302096fdafd30b3200a87269c57f3482127715aece5e36f100724604721d00769e047201002eaa01358b2e15001d017667008d630907feaa016eaa0182600ab043a09a095c90736eeef6b8af9c6b7e83936adcbe1c2caa66070b3f4658d654f6c104f9010bf9010880829f6fb9323308fe0100fe0100fe0100d201009d65fec80e8ac80e4d21ee01000d0155a6892a11072e291c498d2a3a0d56010011270501febb026ebb02828c1b88cca0e94809023defe973d1ec4bd2452aa29f900dc4e4bb3e6e30e52c3763e1cc87b9f9921b0d090125220050090c7a010000080e3c0b726504ea01003aa06e9a0100361e0529e5feaa01a2aa01821b0d90bba07393328a9e501d7d24637d5bc6f0f8fd2adb49d843a09cb61d4f9eb19d1d17d2f902a31a862100893ecb0809cd666f01092059ca000209f9048000621b0d05010020ea3c171d8dc908b5ee4a1b0d415a00011e3b0d2e010000087d871a7f1d0dccfe1b0d7a1b0d7c31731894d5bb153aedc4c494b7b7a51967c9f999c18f057a931f543409be40d28e9f0c00114e23228a86217cda3f2b4431393caa1c76cc2020a7dcab01462501d875233a3c6eaf806965c1508e7c00fe1b0d0e1b0d4cb899cb88ef9a97c54ae70f63607a3d80402e6a5d82190166dc1f55010101491425f912d70f1d015d3a36340001010d1d36cc03ee01000d0185db0d01119c321500a20100fe5304a2530482b8088832a09d447e801d84d7b8e053f0d320ce02a48b8c3d8526583fa1db9b59eb7448198bf91ec80efe0f0cee0f0c1a0f0caa010029ad3250028a010036340289471a1f18094bfeaa076eaa0782000688a8a0a516b4fda5594b57741ed8203be22d9b19b6bb4b11b844015b00d853ab6ff39cf912c80e04c0273efd05fe0100fe0100fe0100ca01002a2b1932c80e29c8190171ca453196b90805018d66fe010042010005885a01003e740059af190a010149b9fe6604a2660482b90288a3a0df9ce4bd153e361f655a7b1298defcf4162cca5900a870063494436fb5cb2fd4f96af0301ddc32ad011d187e01003a3901321a0119013e1b0242010042b90d3ead01297952010011bb5a0100329300fe66046e660482100c88c2a04e3cb7da4ae5d1f4f6de41a3a443573a40696e657ef02081b3c3171f76245698f92e100c5a860111ef2522fe57037d575a6f008201000588c20100366e0000220540feaa01a2aa018257038890a0ac1f24d759efd9ea9fab3f1d8d8db725bc1dbdf340c12a99bf5a1c04885d4be7f96a57031d01e2ad01362001fe01001501eead012dad044020121a0afead01fead0139ad887da06c7db4f837a07a414ba635d2c231beb6611d2be760bf21d552538ae44997e325f92e57035a010032aa01367e013ae404360100421d00363c005601004287014621052e2300119c321500a20100feaa01a2aa0182140b8821a0de44354b90a6b66d0f29bc9184562e21bbf06154721664fb26851f34dc06a5f8f97e3323090131112525760405325a0642ad01040040114bf201000588c20100362a02c9e2fead01a2ad01820405886aa06b9290a369a8592706dcfa45aad66ffa3467d003c3358fe04248d30e4165a26cf9caad0136f400469001050109255a1d001d0146360366010059082ead0135fe2e1500a20100fead01a2ad01825a038810a0cf9da45284a917021b168e41d5caa8bd3a2ad01c5a58751429f841503324e5fcf935ad32b50b3e0100311125105e5a0329a032010086ad017201004e3f0005830505c2010036a100fe5a03fe5a033e5a038857a0a2008890549979eb30a829cdeb4fd1331991436a74212266596639f30b20ba48f935adfec5174ac5170010366e01000436c7022e01004e96016e01003ead01297952010051685a0100fe5a03a25a0382b50b88b0a027d45b213546082fbac07c73b4b0a2dc87e2136e75aa0dda5e27a14d085449f2f9220b0a8e5a0300202525615a9992720100be850111013243014a01000588c20100fe5a03fe5a03765a03883fa07c26e8d793cf5250753a00755edd071cce7225d607749e6688a822e53ee64efcf9160b0aa6eb2e21aa3201006638014aaa017e850192010066720011013696010901361400698b328f00fe0c0f6e0c0f825e088044a06d152c5f9f6c6e8cf14f4694c9a9e169ccb43ce45f9583e958dee1b80124db2acc164657039d3e110b252536f4004a90011901721d00ea010005880d01119c04004016ab08327f01820100322e00fead016ead01825e088801a00c18826cd98791cf191b6f7434320b408377008abbe9f243f4fcff43d1f794e3f99eb106008025152525425a03660100fead018ead011101866c00366602fe5a03fe5a033e5a03882ca083593f6c054dec4ec0cc0b7b31bd1535cdbffce40f32e3fc8bab45c740b3672af99ead0109019aad0155ed8641012e0100293f3e010032fc020d010588c20100fead01fead0176ad018819a027017f84937a4d4295d3e8f0c4a9242ca7b590e6887c5481db4da5a394b5ef60f9225e082a0b0a460b01317e051a01f405098601003aad014e78017601005a68003e170056e701050111bb5a0100329300fe07056e0705820b0a889ea0faafbce4e603f5388afbfe285b8a69ecb92816f339512d736727164a98f01a6af9165e087aeb2e09010040212321aa19013a8d01360100721d0036010052180f5e400001871101358b2e1500a20100feaa01a2aa017eb106880bf0a0d4d7c27fbc2257dcedf05b47a611541fe7775a43a37956a07945bf244e916bb3662a1f32010031112510cab10636e00146010000409a050c11010588c20100368600698bfead01a2ad01820b0a8806a08fd30ab317475fb03919eecab7ffa1de9c1fc16e170a27d78fad8146f1254236f9d1b1cef22d32e9005201005e1a034e0100364b017601000e2a17c60100366200fead01fead013aad018876f3a0563ba448007eaa3f9f8f707c1c39e40310f0cd355160008d5ecca14844b0e9cffe9c35ae9c355e010036440115015a170005012e5a0371f632150072010029a70901327102feb1066eb10682070588dfa0393f0213247f895a40f1f3709fe1db25fbe9c65accafe9662b143f0e597feee5f9aeb10601dfae040500040131ea010005714601005a1700090162740036fc0129b0feaa01a2aa017e04058876e0a09a0bf9b4969ce9fbb5c659c59c5cf38072372e4150748e4a4a66fffe35925130feb106c5b1cd6e4a4201ae0405ae01004a6b008a0100001011aa0501fead01fead013ead0188dba0b2c80efe0934d52f70c18fa96e87fcd543da9cc6a4e34889437831cc64d03aadf94eb50b4601009168252536a1027201002dad49bf363537f2010005880d010164297952010011bb5a0100099b0d01fe04056e040582b50b888ca0eaacb272bbffcc41e9709014c1b926d689377fd1f0719c731547bb8544aaeb9af9fe0405b1044a140121467201008221005601002eaa014e01004a8b0042eb2929defeaa01a2aa0182040588c8a0efe1a90528737448dd0ba9ff5f1ad5d5ced73ecbf8dfd3f1f71b3881ce3819a3f91e080a2e0c0f46010009fd00202925aeb106464b0009016255067a01000d517ead01560100361004fead01fead013ead0188b5a03fae9cc95cc8fb82878490f359348ef22ad437479796ae3b47930b196a43293bf9a6ad0141842525e6ad01352e29fde601000588c20100157f0501fead01fead013ead0188a2a0c77940e8bf62e778494f4ec44b44bd7a01858acfaa1159e6ca16c23b5ee0f010f9a6ad01010125250df42d714dec560100721d00de5e031ec12e0d010d885ab50b299366010041831501feb1066eb10682b50b88cea03992a511416036f719cb28e798fedf453ccc5f1c6e9c1ff4b9533b47099063f6f9caad01925a0329a709061501ea9f013601004535820100328901feb406feb40682b406888fa021997c1773fcd3861ae1d87e3dafe557af1d72fe3d696c32c60a70f4e37f8decf9caad016d5a8e01003aad01313e00204ed0333a0100112c5201003ead016a40037579560100326700fe5a036e5a03820b0a887aa07af9556104d05d33f0a171f685cfea75d0db448ed79878a861c54318ca0fc7a7f935ad46741c1d0111f22525925a0309013aad01760100055d960100aa2b001d0136660225e1000432d1adfead016ead01820e0a887ca04a4f1addd725b15c5f525e07396baa925be440f6ffaf94a2efe39800381e8e52f935ad2a1a194601003dad002021ad9285010002ea7d377a0100fead0135adfe5a03a65a0382ad018877a0a331bb727ee86568324cb96818bce2b7dc6de3d954e2014265c1ab8f915bdcd3f9ca120ffe5a035e5a035a010049193216030001fead01fead01fead014ead018864a097dc76e20cb78f0834de23dd7c8d4cd6981551f1d4d85367c57b752bee4464eaf9be120f32350125496239012966fe01004601002e710071f30d1585db6201001a14131901feb106a2b106820b0a88bda07ac89d2fce7ac6a82e8db84fd698e50a75d59d447538a59e308dd756c65d13d0f9b504feb1066ab10625de764501ba01002ead017a01001d78058815010919fead01a2ad018204058051a0eaef69d8541cf7b3ed5e3573bf26eda2843752a62743caa851b3d300ff53292a8670a6ad0136f400723d03091daa5b013e010029524201002e52006d5a0004321500a20100fead01a2ad01825a0388aca022aa311e36b6915fae4658d1e466af00a736864d12625fd6d8ee89e2e64672fbf9feb1063ab1063a670429adfe01004601002ead01960100416201041901490821ad1518fe0b0af20b0a803ea091230f72faf0a4c75238d59b9a6e3de76180ee0a6bc79060cfc03b65ae24461e377796782101e915d986010039aa050a2117ee01006d42d19c1901297652010015340582420100329300feaa016eaa0182620d8868a0eb0828c038ff60e94fddda8b144544ad9634233e0da97cd48bdd61281a707496f9d5b19eb50b12c15825b58a01000002aeda014e01003aa70311019e800036010036660229e1fead01a2ad0182b106902ba0c21ada7e9ae4ae938ab79c4cf5d1cdf64eb4682fa5bc50ac3acd9c9be3835497f906a812074b4a70172e8a02519f252536f4002e2700420100721d000101da7b1205880d01119c3215005a0100469000fead01a2ad0182b106889da05ea3eb9118ad8cce0aa50abeeebf4413be0d6b90bab90918159922cbeec7adfbf9beb50baa5f0d00825a32016e010049ef7601002eaa016201004225003663020968feaa01a2aa018257038013a02ffbb2868a145601d903b3ae807d8b0e80170aaec4ab3e69976d8276ef87b116079808044b11164c4209c03eec0251b805fdaaaa0146c402fe010009010588c2010029aab15409eafeaa01feaa0139aa8818a0a449e0d0209cbce3dac8a8e399a5854dfa2cf09b214d21a678197ee3c2c08a5af961540805b96c29aa56010032aa0109f19201003aaa013217018201006a1a0529aa194f2976110732010011bb5a01001944fe125cfe125c885ea04257e3913c7774cd2ba2c517248818b4e98f18ac5ac5de2837c04604b8fef88cf92258089a5c0d00401258080d0121b76a530116d310fe01004e010029adbe010001af190129e1fead01a2ad018201058800a028bc7c01c927d50e920f38eee19ab3a7b10cf667609e2303912c9da54b5def95f9bead0116050a3e010009f94601003a5a035201009194a601000010fead01fead01fead014ead018875eda07e3d01cde93068674da233cb781a232a98b6bee4dfcb028c3c893d00612c6b2beed02916d0297201003aad0151c736e3024601007e200042ad01422d0279f0fe0705fe0705a20705884ca01c7eec43cc7f3f7870ba65f97e94d117f7285e2cef28096cb2360131ce1b6217f9c1b15e97892d0311ef857ca65b08aa40863ad4017a01000588c2010036010209db513d0501fe090f6e090f7e04058875daa04656fe329030e41febad141c9957463ac79c8a19cf762fd51b3f951b9960055c7ed0290dcc32ad0136f400726601721d00aa010000403afc062ead01119c321500a201000de10901fead016ead01825c0d888ca055f903480a4e4331ce90c8ab5c37c31c445a6915a6f7ef0b66d9ff3d8015c119f9d5b196b6102126a65a03fead0135ad3e010001871901360e006201000040366602fe5a03fe5a033e5a0388c7a01ef424fb9a3615645f199596af7e0b79fd1d9287a8b089f2137b1bba6e294e3ef9baad01210afead01aead01d9793201000588c2010021ad794a25ad00801910feb80b7ab80b82070588b4a05fedc045d6144cc74d2d2508846c615cb3f90945d37aa2f0ecba2f910f51985bf9d6ad014adf04958e2e01004a28005e8001b20100e6ad01190125ad3dbdfead01fead0188afa0c9b39ccfd6339dd965f8c6932c16cf45f2f8af326250d31c4e7c82a6e17cdc18f982141905d4318a2525aa5a0316064eae0100056f8201000588c20100615a1901096afe5a03fe5a03795a889ca0ccf12d6a5c3b0a62654fc8ee3aaa98ae5ebdcdecfc310ac64ead3f9aba1a070ff96e0b0a0d0132aa011df13ef6073e01004e5703e20100295b05012eaa01119c3215002e010072c30dfeaa01a2aa01825e08887ba0b40dc5f9b495856a95e4f830677ccbec8508ac8a028a1fe63cf1873dfb891989f9b5045ebc102570311125253dad7e0100053d3911321a01ee010005881d013dc836010016f4416a0100329300fe0b0a6e0b0a82c11a883aa03ba1a86917f002ced34d5b2ae96497652c574324ee6b3f2f007356ad54769e06f935ad960b0a01f7aa040529adfe01004601000588150100019a670036660229e129ad6d7dfead016ead01825e088889a0ac14ee798961ae1af206c1c123e94fce865330960da6756330ef9dd907216e0ef94ead01360b010101325a032dad8e22018e2400ce010046a2005201003a270066ad010d01fead01f2ad018876a0211dcac43bb53cbbda4da00393ec81b382020685dcf8763bf17f17354be2d20bf94ead0146010032ad0136f4002d903a18010d010d1d9a01005644004e01002e2a00119c2e15002e2000760100695a0d01fead016ead0182b406886aa0b79d4c1fbff47ba3558c18e01580287e9d34e3f411e6f1e814fd27c7eb2f4b86f9caad016d5a8e0100b6ad016201003252010101628d0135ba4e0100366602b907ad05fea18e76a18e8207058863a0cbaac987f9ac93e057f6bd67e1bbe6bb7f010ba9f0e95ddce64a337428ef71f3f932b80b82040105214ead01424f01090172ad01054dd60100d63b005ead011501fe5a036e5a0382ad018850a01c1fba12a871d7359caaddf1325d3250affa38981b060c4b1662b8c1f8d406bbf916b80b32a24e49731501000441ae01e8252201099a01003aaa015ad001c6010005881d013ab0002e010001bb6a0100329300feaa016eaa01820b0a8828a063074045a91fff1b86cae232cfdf6f0087abe26587b62e083d5dbc34d0666250f9d204052eff1195414e01002dad0d07fe010019013ead0196010036660229e1fead01a2ad01825703884ba0c3c4a2b78071a2380315e8a324f5f0b1f59d726c7adeafe44513657004f78375f9caad0136f400728901721d00ae01003a13022ead01753b2e15003201003a3d003201003dad0002fe5a03725a03825e088059a03e6bb43c0d4de9b68c829d8ddd8efdc0bde9db0df87b2560f984568b0b9236ae3c3c010125104eb1061d0125a10529fe7017327017359401010d5fba0100366602fe5a03fe5a033e5a038838a0ec0f85edbc71f9f9b40275db6b2e7f0906bf4728e1aa891b8c830957c4de3d86f9325e08420100311500800d1a05107aad012e010025b95201005dd2ca010005886a0100564c03fead01fead0176ad018825a0ee0be799aa3d4dcceca75605f73996d3e6571f787589d5f1add0d2b9b358aeccf9165e08de2a2d668d016957563501fa01002eaa0100801e5c0d2e150072010069510901323202fe5e086e5e088204058848a08d6cdd47d56c13b26c89af3181041c84ed33c1aee629eba6071d5e24cc07a205f9cab106fe570365575ac501323c01660100004071e8b20100fe5703fe57037657038812a04505771ae6ae1ed69994bac9ee67b34e8af3dadf9784044210df320e3e6e15a6f952ad012e7b020501311c45bd36f400725b033a7703828b019e870305881d0142b100190111bb5a0100329300fe5a036e5a0382b80b8816a01a3f46c88375f26b735b3ff10f9a515dbfbfe0ce3ce32498e45a3d48b93ab878f952ad0142010011f225257d5a7e5d013aad010d01561600ae010005887e010042c201366602091ffead01a2ad017eb80b8874ffa09283b24ed216acd6bc60400db6b6dd7628c7538515f3106b5f9f5aaffcdf1ab27e28230d0132ad0136f400567a010d160d073e0100364200ca01002ead010d9c000832150038000000000000000000000000000000000062010000082e1a00f03cf89df89b947ef66b77759e12caf3ddb3e4aff524e577c59d8df863a08a22ee899102a366ac8ad0495127319cb1ff2403cfae855f83a89cda1266674da02e49004a01000403a04a15001901c05c0b39a0e3b9a4edcd4a9e0d7cc302d376eacb21487e3d1ba990ec7dae37bfda16a5f350f90354f901a70183016e1bb901193b0d0100800d081509004001110050010596010000024227000004421200560100056a620100761e005e010000103219000020050efead01a2ad01002a76ad01b8bc74e7a04f1b9fe9e450e5acf13342e591f2af8f104071008c1fb678736488d37d6c27fff901a7018302dc76b9010005bc4e010031b3252276aa0129010d0146aa01760100323d006a010005882e01003685015a0100362500096cfeaa01feaa0139aa90eca0b397ca1eee35427f9efb9482efae35a4aa8c52d3e9a13c126448a5daa338ad5cf901aa6d57005b32570309ca1501aaad01320100bead016a010032900342ad010000367601560100fead01fead0176ad0188d4a0110b5fe013dbe95a51f09438102f17849d2857c13fe27ce6cca003da584720c8f95aad013a010032ad010014321d00729001721d00ea01002ead01119c3215000501369d014a010000013ae401feb106f2b1068828a0179dcaac4709a2f6e1690264456368ef5a40c53126e731f3e8396e88698d88c1f9caad0182040119013aad01327404ee010008400008325b003a09042e010031cc329a031901329300fead016ead01000476b1069048d104a04e0c051a9913bec4cc9e8acd3209ce6c32391ed2b4bb0293a76216876ffee0aef9caad0172b40632fd003ead01fe010015012e5a036a6b0701013dd536660229e132b000fead016ead01825e0888c1a03aa540e8a0bf0a394329ac33ed262c39e629d5387fe0a351afb3059ad656139df9fead0136ad013e39013d2a460100292ed201002ead01a601007aad010004fead01f6ad0188aea0aa1d7d585af4a8235cb88ec780bc1967ba7f2aac1f119b990e1e23ec3afbbc84f9caad0136f400729001621d005a95049e01002ead0191e83215007a01001940000a2e2a00fe5a036e5a0382650d8817a078664d6a629175dc4bbeb8c0d036e8a2427fda505f02db7fdef919bd915f2a49f9eead0125ad2e0100422c033aad010008327504ea0100396d090142790019010080761802329200fead016ead017eb40698d0faa0ae5a94b192d11f3e9d32e08d1122da485a5ca18bf2f2befa32b5284b81269f3cf901aaf90e680d00014e120f000495d651be252572b4063601003aad01fe010015010588c20100951305d829e1fead01a2ad0182b406889ba0db164b367f882c008c7f2197335e127549073995ba1e3e121b39159d0d13a7cbf922bf1036680d3a010032ad0115f400000ed810729001721d007601007290012e1d00119c3215009e01000004fead01a2ad018207058806a022a5e05afa58b31f4ce9548475e656b3febed7ebecc195b9fd3dfebfc323e5d8f961570802dc3632120f3a0100310e2522fe570352570389aa11687e010005880501ae0c022e63020000fe5703fe57034257038888a04784718c4e38000382420c3240440015932da9a2f9f932b7031318517bf9b7a7f932b10639043a0100314505216aad01360f01feb80b4eb80b0001059a0588c20100369e00fe0405fe04053e04058883a02faf90ca35ac0a0aa0902123164f9861b2448ce2b823fd84fb3ded840b2ecf71f935ad001b755a09c63201009ead013e0100aef802320100329b040d0111850000d6ef040000fead01fead017aad018870a0101003cbed3c5a48b6b0e6eb6c021cd2ccd31c39de630ae6f903d310741d5c00f9cab1066a5a033e0100a6ad01a9077201001d4d7e5a031d2b1d01fe5a03fe5a03765a03885da02e29a1121a353fd78f03f71e93d75483c1c017ca176342d605d17c995184f6bff9c9b100b67557320100897451d2252236f1007201003a32014e2d038e010009851d0105881d010020421200150111bb5a0100329300feb50bf2b50b88e8a044db790fa815dd9ace6312c8325c017abbe39556144ea00659d3d602d92ac2e1f94a04054a010011f2252535ad650b3a9001360100721d0036010032910111705e010005880d01152c2e1500a20100fead01a2ad017e080a880af5a0ed8943b28f06b00ec8e43c4348a1803a98c6d035f4fea125f0a3ed004aafacb526620da6b50ba904921b013aad014a0b077a01005a66005a17007a010055660501098dfead01a2ad0182620d884aa0ae6a1bce3b16c231842970014b011537526d1e6dd0216ee739dce4ecc8d48acef9755abead019201003aad011101322201ce01005ead017659002ead010010fead01fead0142ad018437a0342f62e3abb0c095d7477b22104b877fb16df01a705fcbc3ccf1b2f95a10ae3e0000"); - IByteBuffer input = PooledByteBufferAllocator.Default.Buffer(); - ZeroPacket output = null; - try - { - input.EnsureWritable(frame.Length); - input.WriteBytes(frame); - - ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); - output = zeroFrameMergerTestWrapper.Decode(input); - Assert.NotNull(output); - - Assert.That(output.PacketType, Is.EqualTo(32)); - output.Content.ReadAllBytesAsArray(); - } - finally - { - output?.Release(); - input.Release(); - } + IByteBuffer input = null; + try + { + TestFrameHelper frameBuilder = new(); + int totalLength = (count - 1) * Frame.DefaultMaxFrameSize + 1; + input = PooledByteBufferAllocator.Default.Buffer(1 + totalLength); + input.WriteByte(2); + input.WriteZero(totalLength); + + IByteBuffer output = PooledByteBufferAllocator.Default.Buffer(totalLength + Frame.CalculatePadding(totalLength) + count * 16); + frameBuilder.Encode(input, output); + return output; + } + finally + { + input?.Release(); + } + } + + [Test] + public void Handles_non_chunked_frames() + { + IByteBuffer input = BuildFrames(1); + ZeroPacket output = null; + try + { + ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); + output = zeroFrameMergerTestWrapper.Decode(input); + + Assert.That(output, Is.Not.Null); + } + finally + { + output?.Release(); + input.Release(); + } + } + + [Test] + public void Merges_frames_with_same_context_id() + { + IByteBuffer input = BuildFrames(3); + ZeroPacket output = null; + try + { + ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); + output = zeroFrameMergerTestWrapper.Decode(input); + Assert.That(output, Is.Not.Null); + } + finally + { + output?.Release(); + input.Release(); + } + } + + [Test] + public void Sets_data_on_non_chunked_packets() + { + IByteBuffer input = BuildFrames(1); + ZeroPacket output = null; + try + { + ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); + output = zeroFrameMergerTestWrapper.Decode(input); + Assert.That(output, Is.Not.Null); + Assert.That(output.Content.ReadableBytes, Is.EqualTo(1)); + } + finally + { + output?.Release(); + input.Release(); + } + } + + [Test] + public void Sets_data_on_chunked_packets() + { + IByteBuffer input = BuildFrames(3); + ZeroPacket output = null; + try + { + ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); + output = zeroFrameMergerTestWrapper.Decode(input); + Assert.That(output, Is.Not.Null); + Assert.That(output.Content.ReadableBytes, Is.EqualTo(2049)); + } + finally + { + output?.Release(); + input.Release(); + } + } + + [Test] + public void Sets_packet_type_on_non_chunked_packets() + { + IByteBuffer input = BuildFrames(1); + ZeroPacket output = null; + try + { + ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); + output = zeroFrameMergerTestWrapper.Decode(input); + Assert.That(output, Is.Not.Null); + Assert.That(output.PacketType, Is.EqualTo((byte)2)); + } + finally + { + output?.Release(); + input.Release(); + } + } + + [Test] + public void Can_decode_neth_message() + { + byte[] frame = Bytes.FromHexString("0000adc180000000000000000000000080f8aa05b8554e65746865726d696e642f76312e302e302d726332386465762d63396435353432612f5836342d4d6963726f736f66742057696e646f77732031302e302e3137313334202f436f7265342e362e32373631372e3035ccc5836574683ec5836574683f82765fb840824fa845597b92f99482f0d53993bf2562f8cf38e5ccb85ee4bb333df5cc51d197dc02fd0a533b3dfb6bad3f19aed405d68b72e413f8b206ae4ae31349fc7c1e000000"); + IByteBuffer input = PooledByteBufferAllocator.Default.Buffer(); + ZeroPacket output = null; + try + { + input.WriteBytes(frame); + + ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); + output = zeroFrameMergerTestWrapper.Decode(input); + Assert.That(output, Is.Not.Null); + + Assert.That(output.PacketType, Is.EqualTo(0)); + + byte[] outputBytes = output.Content.ReadAllBytesAsArray(); + HelloMessageSerializer serializer = new(); + using HelloMessage helloMessage = serializer.Deserialize(outputBytes); + + Assert.That(helloMessage.ClientId, Is.EqualTo("Nethermind/v1.0.0-rc28dev-c9d5542a/X64-Microsoft Windows 10.0.17134 /Core4.6.27617.05")); + Assert.That(input.WriterIndex, Is.EqualTo(input.ReaderIndex), "reader index == writer index"); + } + finally + { + output?.Release(); + input.Release(); + } + } + + [Test] + public void Can_merge_big_frame() + { + byte[] frame = Bytes.FromHexString("006a5ec28080000000000000000000002094c10844fa022090f901aaf901a70183016e1bb9010046010000200913008009070400400108005001059601000002112700101109fe010009010588c201000d850004093909db0008090d0901f03cf89df89b947ef66b77759e12caf3ddb3e4aff524e577c59d8df863a08a22ee899102a366ac8ad0495127319cb1ff2403cfae855f83a89cda1266674da00943620100042aa0621b00010190bc8066a062f5669702289f891823d76b2984bcabff54c28e5707e300a4fc91e4d5aab0c7f97aad010d0132ad010df4000009094ee301150135ad0901321a017a01007290013e1d00297952010011bb5a0100329300fead016ead01000476ad019048d41aa0a25049f63fb1d0dd2142dcca659b9a0f024c3800dede31a0cd53e72f02e7bdfff935ad005b525a030d0105f20002ea5a03ba010005706a01003ead011501327c013e01005566050129e1323100fead016ead01825a038853a00879faae3be6fb05e94e1735d5df7f6db727a9b209daa06631d1173244e9aa76f936ad015e25011118252536f4003a3d03360100721d00aa010005781d012e1000119c321500a2010000282e2a00fead016ead010003765a03905c0e9ba0dcba26994b312a8f2b25b83b33ba110687c7c4e674e6a4368b65c2438f958af2f936ad015e010031112525ceb406be0100cd585e010005881901321f033601002e2f02366602fe5a03fe5a033e5a038840a0a3f170e843f15a46306a6cbaee2dcf1ecab0dfca863b47567b742deba4c14d5af9b6ad010041210afead016ead017aa50111013aad016a01002e5307fead01fead0176ad01883ba0e1070d9127562e9da3611cf2ef7bde94952732d9db3ca863f7694094ad10bb4ff9b6ad01252536f4002ebb02420100721d001d012e53013201005abd0105880d0171f63215006a0100369400329503fe0705f20705888aa060bd62384f7917d063d1f201f461b0c8fcd6f17af0d1f58bf7a71008c66b22c5f98aad0104100035112525fe5a036e5a03010132400156010005888e0100324c00366602fe0705fe07053e07059028a0625372ae8243568b9b1781f4fd43305e04d8f4d9474b468a3a1d1bfc5620074df903541a680d860e0a00004dbd36f40072010036c602363b0100003e1e00110162670319010040594005012979520100757956010032ce01fe5a036e5a0382bb0ba808a048efdd24ede4feda0c347125b7cbc68be9199a1f637cfd8b0bbac9395a1a5c9af901a7018302dcb6b96a220111ef45cf465703111f4201003aaa01e201003250015132b2010021cc36630201123a3d02feaa016eaa0182b80b8815a0787c163880dce2bef053d1e04dc43afa95db49731d8fa94c363b62d35eb6b17ef9320405258c4e0100318e052136f4003e90013258013e1d0009012927ee010005880d01119c321500a2010032af00fead016ead0182b80b8879a0e1bb6a52aef623b7ada22f78fae2324fe928909ecb64c64b87a788a76ca66eacf932ad0162010031112525465a0362010052ad0125ed6ac7038a01000588c2010005791501493339ad040400fead0172ad01825a038802a001b28945b68741a379213e0d7a69fc93bd69a02e6a24e4f10c916718052fd96bf9fead019aad0139143201005aea095e0100356efead014ead010000fead01f6ad01987fefa0da3ae50c5a6bfabd5ceb294fc612c977b39ec4389611287dab8d62e7b8e783d5f90354f9c1b40001e25e08523d031e3a085a1d00ee010005012ead0171f6040040ce6e0055464109fe0705f207058868a0143bf2a54eb7df942f1a158c94c447e8297029c56d6ee3bdd069afeaf79b8385f921aaf25e08894e36010029360906fe01004601002eaa017e010079bb218d190109b635aa0101feaa016eaa017e0405887fdca04aeba5b604ce81e33cce146cb704b7f8a5c7e46247bb1dbd2c8d948c75384e7e261d19a6b50bfab106aeab062951320100257caead011901fead01fead0176ad0188d7a0bd4e2ef1fc2c493ba520a7482c032581b77a5a07d7d79bdf1faecfc2afdcf686f966b1062e55019168252532f4002e26004601003a5a0332c702ee010005881d014ad501110111bb010125e9360100329300fe5a036e5a037e620d88d3f6a075fde30f63257583acb65ee0c8de85fb24caebf88309806d444a68c4215bb0f9d5b1046ddb821d191edd0c005036af016e01003aad01fe010015013ead01960100326602000229e131ad25d4fead016ead0182070588c4a0990002233f5712556800923de52a58631405caa5957d705037f6173b407fb445f9c9b1003676aa014992252232f100768d013daa363600fa010005880d01256401012e1500420100299846010031aa0501feaa016eaa0182620d8859a0425a499934be35468ed00b5ee8e93bfa87f83d167128ec843b14619028ca54f0f96604052e010031112510cab1063db5fe010005010588a601000dbf36300229bf35ad418efead016ead0182570388b1a028bbb04cc06d21ab924fc84ab7665edcee919a01da121982dfcda0d491e9bc9bf9fead0132ad01424401fea5013ea501110142690092010039ade16729ad00182e3a00fead01f2ad01889ea0d6c6aff66735d4305d2c7b7c8de01cf5435bcd98bc40d7b7bcafd6131f294b84f962ad014d8e0901110d252519f401015a900109255a1d00e20100710805880d01119c321500a2010011520501fead016ead018207058848a01b5fa50d36909b7ea799cd9f357e5c299ae206a70314fb8af77b2fde60ec1e20f96e6d17811a090131112525b1078a8a018a2300660100056d5601006a1b006a010049411101695afead01a2ad01820705888ba02d557708ecd4ac32393f366f04825222b7d727959fd3708b8898b60db9c5a2b7f9165e08a66d1736f100360100091c35a115090901321701ee01003eaa010020421200150151655a0100329300fe57036e570382b50b88e4a0d866f8636791e5cefb81ab30024d9071729308e0f92438bb8be758dae32444d7f962040532010011f225257157110132f0003601003aad01fe0100150105888a0100493c01010132190e0101fe5703fe57033e57038878a08cf5fe4207bafb417e751de79769a7d52bb746cbd97e36504d299a9232571305f946040501d73e010032ad0109f431881108520100721d00ea01002ea400119c3215004a01001528320100326a02fe5a036e5a0382b1068837a084dba10e557feb4a5ac1282f7fdebb14b09f274e753f94a66b5bef0158f6496af9be04053e57036a010021aa2e5601fe010011015a54003277014601004963110165570040323300feaa016eaa0182ae068873a057e16c68fb03fbcd35bbb00fc70e420ee13a8c7a82a77f68dd08a3e162805b32f9ee0405a90421915e0100051c5a5a01d201006d1cd653004aad0136e001fead01f2ad018860a082e8d94c3ef4ec6d3b42c0ab1c07b2b271bae823d4b743d12ff32487cdccd7bbf972ad0135142d240911ba5a03ca01000e010d72010015994a01004521520100fead01fead0176ad01884da0458ed86f07381cab97215a75a15a0d4090ba398dbf9eca3c5143c60d983551def972ad01150132ad0136f400720100000a361e003274044a01006e84013201003e2900002015a242010011bb5a0100329300fe5a036e5a03820b0a88d2a03ee4721e4734f8b99a836c4017299dde3f4d62fc136e6459e6f55c188453dd54f9caad01ee5a03655a322101d201002ead0122080e825700366602c5b4363500fead016ead0182b406883aa08410ceab8f2aa751fdf61bea4deaf19a40011251f8b002ed52afbfd453a21a28f9caad01001032f50066760422241efe010046010004400039a4753b2ec201a201002ee2010008fead016ead01820b0a8826a0c5548462d123ca85ccf14be10ee46aecec2fafe7e7507906c154d96742785761f9caad01ba5a03828106050149e89e01003d98965f0005013265020d722ead01fe5a03f65a038827a00193e1cc72e50bbfea823ca1ada60e2e8f68dbfd0ab063a02820d32d2f607db9f9fead0136ad0155e61aaf3572770392010036610111013dadaa0100364c00491ffead01fead0139ad8814a0f4dcb6277b576d1344a172e313b32109f98cb92656425e39ec3192b81d255a39f9fead0136ad013e0100eead0129ad1901d59c1efc1c4e010001713694011d01361900fead01fead013ead01880fa0171bda1ac2eb8f25785389da959a5e0ec92e63849dd60e5da4ca6fdce0a83c69f946bf104e0100713245d236f400211f620100721d00ae01002eaa013aad01119c099d66010005bc42010000082e5b03feb406f2b4068815a0aa4aaf65987fa5ae49dff458208a700dd83954597dd30c1a4929a3be170a38b9f9bebf1036aa017201003aaa012e1601f201003d76055469233e010025df35c9560100053fadb2feaa0172aa0182b80b88c0a0c433fc3ad9da0d56c0a5b854cd0b8650aa0f01975ff1e5d2529ce6a6b4617d3ff9fe04053e040536ed073aad01fe0100150121adaa34020d0136320029e131ad0501fe57036e57037eb80b887efca050aca4a9391233f4a7ce91a5ab16d91658ec238bcf09a5815b4dd413d626437dfe7f26467f2632a001110d36c301ee0100090121ad3a01004a13003e0100fead01fead0176ad0188e9a0d95e7995a6ea85d823f2b83b2d67505ee4b2af9d322c54a4cd9f62d0fd35d46df9eeb106c5b172010025ad858e050100081d0cf201003e9a016926360100ad000d075e0100fe5a03a25a0382070588b6a04cd3ddbc49e56b7e4f15363c636dee2216e84a419565d0f1950d151dbcd037caf9d6b106311d258d5e0100321d00291536dc02da01002eaa01358b2e1500a2010009950d01fe04056e0405820f0f8804a0eee9bcdf283d302cc043712f94e2306d72cb27701b78aa8c0330c9165fd90d24f9ceb10632e10072010032ad01fe01001d013a98019a6305362802496e1dcc0001fead0172ad0182b10690d6a0bc64bcf2b630fada7a391183ed60f434f995114d4d40ec7b8a29a6bcc93ea626f9044dc2e538babc101101391729276a01008221003aad019a01007aad01fe0b0a760b0a82ad01a8c3a057197284ca4b71efe51eb5bf8ca9fbecf80c7c54d8cd1919b60475cfd0f3d4e5f902a0018304ff60b93a9d02003025008a19032d01052a8591000831490d1a150139ad8201003e3b0005010563150100802a18140040e1133de1016a04400061702ed60001160d010d1701b0088000800d3af081f90195f89b94112234455c3a32fd11230c42e7bccd4a84e02010f863a0ce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82a0096e2240be03d6804812ff7b63ede4bb6fe19f1e44d0c231a85b67e964463ac4a09baf1e07f520199b833b0d1d3733b68c45304c80acc5bb2ffa6af89478a98bd6a000000d9e6000000079073fc2117dd054fcedacad1e7018c9cbe3ec0bf87a569d00f04342a0335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0a006363f16fc0be1b72c8a8bf3be9af16421c387e75a7d68c3bfec91178fb16637a0017411015a7c005217008842a0b59bb806875ef5718727778ded48d6def0daadc637571c2265f9eaee20aaa024a011570101507633a1e4c27eab9491a1861b76363ca4bfb3ad7ca07e19016e010b5d1400801a0d09457f3641021d263601000127621d00fa010005880d01416905012e1500a201005db9fe50047650047eaa07b00df5a0fb70a4b05a8ee7788082a040b2e00657988e20edecc2e3960cb054702622200ff903aef901080182520c6e282efe0100fe0100fe01009a010004c0f9a15e0803e5d53e0c018972327a02002009143a010041a11a5d19090b625e056201000001bd29420100197500023e9c02a15405016e5e0509955601004df50d63fe5e057a5e057c69e31a4b00b5ecd4de3f5389cf674893db12b4b4307056796505d01b18ea8aaa32704852cb04e65e057c2d2b1bdcbe79740e57e534445eac934d9cc641817e5934f6c7302070a781fb3f8e7c00529300ba5e054cec4078078e6c85d1cad1669fd66d2f7d85d6c95882190108f902b66eae092dbe31cd4925daae09fe01002e01008a4905323705090136af0209dc05274dacfe5b0bf65b0ba8b0a0f3730d9296280a5c601d649c48655fd956748b090587a98878de8afb23c26074f90109018301c067b91ac108fe0100fe0100fe0100ea010000c06e17081d0131da4531feb902feb9025ab90286ce0136b902002412a04345b9110100f8feb452eab452987eaba04a2cac39e1362a42b53b08532043828f781032d09085192e037edc753f940939f9010bf9fe1708fe1708fe1708fe17082a17080404fead74126f55f56a89911501febb02febb0246bb021192ae010036bb0209e300082e4100febb02f2bb028898a04a3336516295e38b93f34e40f6c0effd75068223041200665fb60119781be522f916261400763ec4092e01003118856536f10072010032020a0e4f2416b60ed60100057d09011d0b0501297652010011bb5a0100feaa01a2aa0182d01588a4a0762b632ac622cfe210fd08e265f7f8716804c1e37324ba1be3857afcff61a824f921aa08044a91daaa013a8d013601005a1d007a3e01520100329d0100441d23154d3222009e0100feaa01a2aa0182260e88e4a056ae34678eb7a9e46f003d526a32ed74a14a01d61edfa718722e458aab14a24bf9ced0159e0901526c3c3dc0866e075e0100d298013a1004698b35ad018dfe0105f201058885a035d2e6731c95f8b1fb41d789abbbd11c38c6302fcca9aee16a8fbabf8eaf89d0f9fead01c2ad019a010075305201004aad01357666010036bd0535adf5a3fead01f6ad018872a02be9f83df26fe7b13210571b272b279ca9474fa27270cbc9e832e32aee1b98b8f976cf0d1101313b252536f4007d2a460100721d007a0100056c5a01002e1c000d9c00013215003a562366010032e401fe5a036e5a0382070588d3a05daef9766987a2f89d44d63207cbb06a77959e179cde7d6321b0781006da932ff9fecf0dfecf0dfecf0dfecf0daacf0d4d224d1d090f0050660702110151b11108b60100361a034e01000d97ba010036580095661901feb9026eb90282361a885fa0b6f13fc43a4b7c3ecdcee5fcc0a4e17850f947daae790572378512e766e98508f9ca130601f4c1ee8a01002dad0132010132d30319019a4d001d013ead01297952010051685a0100329300fead016ead0182170b8892a054d7432def2927c2f6f60f8123cc2ac641c6eb9a39603b623bcd9d32ee84f6aff9caad018a5a0311012dad6d9315013e6c01c20100d641005134099729e1fead01a2ad01825a03884ca071b831b611a35b47767bb01ca5efe75f3f28b95589343d485427b19966f2981ff976412409d13a8f1515f405013590050111310d01361d007a01007a04032e01002ead0115372e1500a20100fead01a2ad0182c00788c2a0d723c531d149620a423759d4d32986287d682fe8a3a05d2abaaa6915f0667e6bf90e710ef2c44f660100b2aa015d121d012e4b01150cd295013a6302495515530101fe04056e04058257038847a0467948cb560fe96dcbbeb781be7649feef75cab76e2c2a70b24094a2d092343df9fe04059a0405fe01003a010039ad29733a010052150066ad01152ffead01f2ad018834a0d714d6dbd30ae8a7ee0a8d915f957f3d176239920329c895611a56ca12755d03f96ead01f9f6916825256e04053a0100b65a03055e9201002e2a00119c3215008e01000545fe5a03a25a0382040588b1a02669d25c5355243dfcf1dfe91b02fa5023d66247cb95e8f901384b95601f7d84f96ead011901311105e0c25e0839f57601003606026e010005883201008e3c003624006950fead01a2ad018207058821a051a4cc4313ca9b07278d6311a86f399a947a09ed547b94c9d5593397a03ff55ef986ad0101cf32ad0136f4007201003a5a03014be601003df43ead0129793e010005b60505660100329300fe07056e070582b80b8880a0c06446c490f52dbd04f8443f132d626e5d648a793e5b2fa6556aeddd445c32b8f946ad014e8c0111f22525c25a033601000544ce01003d58d6440036da0029e11d55fe7813fa7813880ea0e133b33c6079779c2476b43afed9ca1c920cd9e8076dcb244cf1a659554f5cadf935ad12d31b5e010076ad012666140501112d56d216fe01000501a6ad012e8d01fead01fead0172ad01887dfba0ef9a1408980c570a0fc20436a126e979bcc98c0ef91e009e9d629abd34812b88227856fed25926d2592e13013a0705fe010015013dad1d0b7e01002e9a00165e3d000132cd01fe07057207057eb406887de8a05d55cb31e40e67de1a280394e3b0514a42a2631049405352543c5b7defdb66dc122a1fae650d36f100728d0100423a7203fe010011010040ddbd75c6aab40119012e7703feaa0172aa01820b0a88a0a0bb054ed3ca12cfe3d62b73a222330ca6b23c7cf7967f81a21695ba30dcef612ff9b504de295d728f0172ca01660100360f024a0100d298011557c9ab0906fead01a2ad0182570388e3a070c372db8f70b641c9437504c5c35dea386be78c27f14bd1d67c893c0e04deecf9caad01824b0112c42005013aad01321a016e0100752e5a01003ead012979520100424b00361100329300fe0b0af20b0a886ea09cbcbcbdb8c5ac10105176786df121f752e97fd31bee3a98794c980725327a34f9761614a9d73a1614fa0b0afe0100215f3ead012e0100664c02361a0029e1014e1501fead016ead01825a0380d0a043b8c8278c311c9229eadc1f683159ad5f872ab04c99257e52c4221c5f13041e57387a295d0901252236f1003a3a030101290401014a1d00fe0100050105880d016d2712ce54c67000feaa01a2aa0182b1068891a03f14b66bb3f663009a3784e700169a1d65d1d645992b45aaf8aa1679ff2e8488f9b50446b50b3d952d11292500501258342e0100399e3a0100c63d019601002ead01a601001dd19531fead01a2ad0182570380bda04d95e0cc8cad3617e5d54c472a99c22952e890c002ab2c5b64db00f06eb647721a4e1dc83ead0105018a3201fead01fead0142ad011d9149621de5fe0b0a760b0a82ad0188aaa0840fadcc0fdae7f3d6baa2cae466c0a92afdce6dbeeee562d41653ce06904a17f9755a860b0a0040795a6e01002a530b3ec74ffe010015010040d24a00fe5a03fe5a03765a038097a09faa69635b0b1e83b7aca1ee3557e957ec50580abf52dee8ba1daf1b701751b2ad011ee81d36f4005dac460100721d008a010049fe4601002ead0171f611159674001e6f0cfe5a03a25a030003320b34420100905c0d80a012adff02e7a44ce1b347bc35c6ca653b12bdd7e6612feff2ad88c90ba47b2f0df9755a46b4061d011e1f3b25253dad35295a01003a390100485a2700c2010005881d015ed5012ac60a5a0100fead01a2ad0182c315885ca06590259c94e0046e9eb0e7af6a9597ce480d6f1921715d2c6145e3c8b4004b48f935ad860705615a219efeb80b7eb80b6a7a01110132ad013270016e01005d66fe6108fe61084a61088884a08d1b14d0d2ed672ab14dfd700b8e2e928182a4b373c8684e8f445348adba7709f966ad012e694521a401012525fead017ead018a01000040268c10aa0100fead01fead0176ad01887fa0a32d6be3f4fa6420dd7bba280c5d338d449e28b85623f18a8dce94f1fca9f8dff93643335e010032ad0136f4007201003a0705a204037e010045351d015e8d0322b27d3a89001901329300fe120f6e120f8207058852a00e7900589a74e1ff344c81e68da59c253e0967654f3c1c9e2ac770ed2b16f97ff9162823a64333a2570300103a2101622f01c201003eaa0196010036630225de0010feaa01a2aa0182b80b886ca0afcf5726efe83ebb8cfb3fb7e4281f1aef1a83a8440d0f61774172467bea239ef921aa08044ad18a4333000125220014321801727f01000236b402fe0100150105880d0171f0321500a20100feaa01a2aa0182080a886fa0e1a28b41d601c004abf1e04125be813f044d2ff868cfff0d040f7e807285553bf966ae062e01003111252562570332f900050172ca012e010005590501190a6a01009225004201004a570336b400fe01056e01058257038859a048342545f1edc16bafd237451562b1f32f96825ab6f1de117d4e8c05baacec5df97ec015090196ad014601004aad01363201da01008aad012e960f0d01097b1194a504fead01fead013dad8846a0951e02ac80de4dd320c07f04336c467a1a4d24e60599a5cf5af9d902d55438bcf9a104fe711c5a711c3116fe01003e01002eaa01514605157dda1eee0e46010029a409011d31fe6612766612820405b05ea060c338436b6b0e8a12a70e6b6224c5b34f93680e0ff0634897f6c589a7af14cdf90285f902820183025e30ddb135000030190b22432100202e2a01010149ae2e010000043aaf023e01001142000226790b46450042120000021137050100010166050101293574451f150e1d0104044001290d1a01e131b3013f0d01f03cf90177f85a94dc0884f78b17913d4ee7bfcd046e13407ffab56bf842a054acb82a9e70d7c289b149758d23167c915428ae854a7aa4abe5bf2f4ef29f36729910f03e616d69f680f89c9464fde89bae3e52b3b853a0ba8f8184d72a398f5bf884a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef325c004c9533d5f75d6ff12529331fcca7fdee660fe15d1b3221004c32e5d066767dbfe5b64b77d2b09113ae7839c2b93221004a01000c2a80f87b56fa008863a04f79409f494e81c38036d80aa8a6507c2cb08d90bfb2fead5519447646b3497ea02e5000ba7d00185af3107a400080268b420e9411319b42010021b80101450a328c07111a5601004516da01006e5a000588c201005d72fee70ffee70f4ae70f8033a030a2884066ffdf701429d1c48105bedd6c2457935151054ae2e78f00d28a3cd2390915f4664405111a3aad016db35a010011358a01003ead0162660226071e5a0100329300fe39096e3909823a0e8840a0faa7c014a3c7fa5129cd6fe9867ae42d59b8684fcdbc77d12dadccc12d0f21e3f9fee60a26e60a32f7000d013aad019601008a35002eb564a601005566050129e132b600fead016ead0182e60ab020a0c680c671e1606686f1a0805a271425daec89dbde8523928a97a3483cf77dd769f9040ef902610183030fb9fd8f8e010081a609f0920100aa37030101015e5e010021cd3e5b03a2010009394a030b0ecc15f03cf90156f8b994f0ce7f5075a1419e6ddb75d8e7118999042dcbffe1a0cff3cf4c6525a5d629f6e2ff46d4ddb2d8d3deca13a243852bb07a5fa538e458b832b3004c43152a3c4678b44e5f6a54d8a1ff1f5ca2b65a230163520100102386f26fc1521a002e010001f76e01000804f8995abb008876a527b8f997064f142eb87b35d9520a142e7fc5254e0ff2bf34c6a4ba15f558b860001d594c3a5fb887a98c72cec9882b9ec5e6b5c0980650781d1f4201000c5d3478fc421500360100000112112808047e146e640200801ac40925a2326b073e0100052215017e18015a010036ba034a01003666009e01003657006921fe1104fe11049911b01ba00a140c8a860676c7d44067a63dbb080ecf2bc6b7e0addd0177deca6d8066d246f901c8f901c50183027b836ead014a0100610009f0920100fe11043a1104e2010072e70104f8bbfe10048d10b25503fe10048910769435190121b8010100420105727803360100da78038201002e91012e0c007601005e780311defe8907f689078808a05d836d5058da55f37ea245c1c6c0a09fdc39ce041badffa0c9fc9f4ae1293d37f92236090e900c15b63e01001119251925ad050a8201004aad01ba8103560100967e003e01005ead011501fe3609ee3609887cf5a0c19b603dc89cd878fcdd96404f17ffff272dba0077acc6ce4bde8fe5d738c80f363d0e3e010015de32ad01151605013213063e01003aad01722c0001019e85013e28006aae0511bb5a0100329300fead016ead0182900c882ea002e3877116a4007ae9949a50b517ed435a6b90eacecc9e545e9368d7a0f8da63f93ec9153a5f010d0111f2252536ad013a31003639033a1d009a0100116e66010005880d01152e2e1500a20100fead01a2ad01821f14884da0629db809f2d40eaae3bf0a45fcd606adb61fcdd63d13d59ea9c0cb93908a5fecf9bec915a504960100d6aa012e0100567f015616007ed40f36630200204556feaa01a2aa017e3a0e887ce2a07d8387d48fdb281b44951677ce7640ff7394f61ca76474ec787d1b47ecfa7872b904fe2823fe28232628238a01005ead0176b00139ad61fda938000801341101fe04056e040582ad0188cfa0c25b3f734b7e0829c3bb48622f95152d0f23122b03832bc5819b2c42754632a0f9225e0896ad0101d77e5a0395951ab945e201001d493a01000588320100217f7e010039ad0101fead01fead013ead0188bca0d75d03b8c48fa05629c3155afb89de47d052e1fd8c514fbeaa4c39b70b4afe9cf9baad0181d87ead0119010008012ffe01004e010046ad018e010039ad0140fead01fead013ead01b0b7a023e4d9cdd2c4bfb6b9ec30c9f1a6cf22e0e66a8f05cdda9db856b992e9580423f9010bf901080182520cb9565512fe0100fe0100fe0100ae010000c0cea63b368f2242ab312e01003abb023282054e010041538e01003e2800498752010066ad040501329300fe15066e150682190b881ca0b04c167e53e8cd45c320877118f78065c0673b729c93e155c60fc8925b134512f9fe6c09fe6c09726c095601003eaa017601001ed81499650101122635feaa01a6aa0182bf0788a4a0016444888c66e2eb81825e76e58a648274e24249811fb491cf705ded7b56783af9561206e50d15dc0040559c2525a612063e5703fe010015010588c2010015d10501698bfe5703a2570382ad018891a009230de771f7b5532bdd858f7c64b3d60ff427f3c9ff2e4cc4ccd2f8ed844f92f9c5120c8082ca97ba4115fe0100fe0100fe01004e010000c0be270c210551bb3aef0526bc211901422300fe01000d01125509c20100febb02febb0276bb02887ea028fd0f7062647554023401b52f7da3227589550ee7b794eeaedef47d8f1e752cf995680e8514010136d2000d01f10431ad69a4860100fead015aad0142202496010036db0009c4fe6804fe68049968886ba0dd81c5809028cf740ded77bfa2da6bd4af297da48702d427ecab5bd418be3800f935ada6d40d36f4007201003aad01321a019e01003a4400050145351d0129795201005168420100093409930d25fe6c09f26c09880aa0afb85fb6f41192eeaed794f2b33dea653a935aa9ef5a2e0ab84a19e7b5c5cb42f93e85145601000dcd00042525b1075601000d2b01010004526901fe010001010588c201003666022ead010d01fead016ead0182c2078853a05b33a9c75d3c7096f1b9dcf202de848fa8333a70293fe1bc5164cf31d6078515f9fe190bfe190b4e190b36550142010031aa11084e010012300a320100365500feaa01feaa013eaa018858a0177a9a7a8b6ce143404deff5b365abb25da593d6152f527ea8ba86f13e36c521f9126c09febb70febb70febb70febb7026bb7000b5fe8c10fe8c10fe8c10fe8c102e8c1061c67a796db14565367670053201003ed906465a03d6010005888e010032810061c601040901fec603fec6033ec6038840a0a19b6a3b51d491f652bbd9f9a137f4f05e5c1b8ca45922f31027fca2fc9b8ff2f9fec603fec603fec603fec60336c60304037016932704995aba410e41ce29fe920100bab502015e5e0100418fa2bc023e01000939563e15fe93272a9327fe8323ca83230002fe93271a9327b24e28180000005d34755a01086e010000f90ec9640803eb66ba6402fe0100fe0100fe01004e010000c07a51751101710245b1d92e41fd7201008221006601005616030d0105883a0100d9085e01003622008930164b0d0d01fe9e0bf29e0b882da0fefe2b5bf764cee7eaf4ad6745ad29bf6a34c6ed1a9680a2386a53af06fad6edf941b97ad807fe0100fe0100fe01009a010004c0f91aae2908033fbcbac80341cc29fc920100fe2c063a2c06e201004ef3021501feae2922ae29b2700596ae2972c9030ef61a263b1b1e7c1352010021b80101250936cb03111b5201003a840432f103ee010005880d0101556a540272a0000000fe388fa6388f7e3b1b88d2f8a08902435cc6d02fde00b003e73a5503bd6248756173cc945c7ae261c899ba5d53125c0c00025a30502107224f2200802922d92e8201003aaa01fe010015012eaa01a6010036630229de000816a83a0901fe2e06f22e06801aa0f515c99369004ca0556244803bb616d8fdfe335b3213723fbda4972d108f0fa68e3409e9252529ad2dc7760100fead01fead0192ad010ddcfe1d3c7a1d3c8279138807a07237347b24be070feabcba512aba0132bd4575b7bf1b6e9fb50fe0019a363e28f942261552780691493dad6e010005270101fead0176ad017ee2053e010049711101755a1901fe5a03ee5a03887bf4a06d50f69a3eaca216ce5e16ca2eb04e1a9f7654582b2601fd251146686f8ed784ad04e2ffa909f232010015133aaa014a8b0335d5b201003e3600157146010051655a0100329300feaa016eaa0182ae0688eea0a3186daecd7d97102ba5d888bf6736262ba42eb5d63bb5036a5147326ebebcc2f95e2a1a360f0111f20516a9049201003aad01000056b5031ef158a601000588c20100fe5703fe570376570388efa0cd2d73f190f671c3c37f15b6a816f4bface6fe5faa31a492a89dbe73219049dcf95ead013668295aad01000801276e010042ad01fe01000d01d6ad010012327e00698e32c300fe5a036e5a037eb106887bdca0811d76ce22ebe9635e5395bb8e766ee634ab347362f6a6cbf4ed04bc7c4745bd56de204264015aad014e0100323c00320d00fe01001d01d6ad016a5a0329b4fead01f2ad0188c9a048270935cd7bb1609908f74534ba8105e38d10c52302f8df52fb96fc29a510cef9425e0852010032ad010e9d2809dd8201003aad019a36005e010039a3190a0901692652010011bb5a0100329300fead016ead0182b40688dca051d8da16af021f95cf5a8723fb1f6ae3ef3355bde40c208c590fdc5a7584dea4f90ebe19aed247eeb106a601003243013eea0636aa013a2b006201006a57030901feaa016eaa0182040588b6a024b7f73b4bd2c99532a83cbbf471510cc116f22692fae2db422cc18567df0675f91abe1904698fba8312fe0100fe0100fe01004e01002cc0f9018af9018701831adee66e0f017aaa0362010026650c221a0d997800081d1f05015d91de71001d5f2ef60f0501858a1d644601000cf87df87b52954088f863a08be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e07e414800003221005499c842718aa0741548582080c96324b0b525418b80f91a111f04a4276e8c01fe0100fe0100fe01009a010000c016b10d0412826e0c01512725d6fe53059653050101454a4e010005887a010001b4362800fe5305fe530576530590a3a08ace4b22dd1fa2278ff708c7c071f402c07e4b20ca3732b20941f90e7a14015ef9010c129f1b0804063d6ead01fe0100fe0100fe01009a0100f2442c8a0100b9413e4005ee010000103a94025e010041be2e0100febc02febc0276bc028890a06dd5d84f1c6bb19bfc78a6f960af08d7d692ba31be73edc7ebc2e498e0472a72f96ac00e1d0111f765b9fe6904a669046201000588960100f57a00001a739b110189c6328607febc09f2bc09908ba0fcb383cb67776bde5c5d2cb816dce9dc9850342df3a1371c969c5276ae6ff91ff90354c516ae567151a129076d3d563f010d1da2010026de087601002e6e005149321500a2010032a50bfead016ead01821c3f883ca06f67675d7548bc2b31953a6b60a6ff9ed89c61a77045a13665183e352dcf0fd9f976130d05cb310e2522fe5703ee57036557000409885132a2010036310071571d01feaa016eaa0182130d8878a0fc34b0d58737241a896eff41d7b8a33957593a1eb94d0162393b0fb532bdc765f9edc00839a69dfec007fec007fec007fec0077ac0072e220432bc023603027201002e44000e481e01055e010089b596010065441d0149882e0100157a11bb5a0100329300febc026ebc0282791180caa024229b680aad51c39bc518838450f115305505910766ecb39295e49d43042d2a89484e5732359711f22525fe6904ee69048569a6fe0535b3050115cf050129e1fe51e5a251e58269048865a01d76b96ac99d901126a67b23448ca0ae76f53eaeda67d3a057be6b94ce44a767f9fe6d09466d092905090100820907520100364901b601004535c201004ead01fe5a03a25a0382ad018852a04a1db3dab98189c322e01b9f0c0d806343c38590f0c5edddda80508f404ee1caf9fead0146ad012e010000032e0d007e01006e6a09366801fead01fead01fead0152ad01883fa0e5efc603e17498f3ebecbbc88cf012bfa5d83b973561319d299bb8029bfe8957f9fec307fec307fec307fec3073ac30722bc674e160615014e16062e51042e01002e0504ee4d046e01002e6400a60100001032f50209c0fe6904fe690499698827a034c18727b0bc4535eb049064032a5d3c31adbe6711f10889e308732e66186648f976290c050132aa01001005135201009d29254d3aaa01321701c20100295b0501055d1d011d1b3e010011bb5a0100329300fe6d09f26d0988b8a027ac3d459cbbedc077581b038c73e10e2d6defaddef1ffbc6cb13bcbbfe0b547f921aa96bc6729220050a6c10a3aaa01fe010015013eaa011101769a0036630229de0088113b0101feaa016eaa0182bd07882ca0bf16c7b1f6fccb42f325c5a100f56ec39f9a581357d8813353d2e2a238a876a6f9f5bda69f2bfe170b9a170b294d11013687012ed680a601004ead01fe5703a2570382ad018814a0ca53be54a3b5ebda00c66c2360bb34f9186664950e805aba1703a3884be171a1f935adc2ae068e0100a65a03369b017e01005e5a037601004ead0100182e7a00fe5a03f25a038001a0617fa8ed0b70370b69bb2bebecd08b8d84777e4fbda3e430912367f6d6f5db2a0eed6a5a030002b5f62525fe5a036a5a037a5e06150105880101b2e4014ead01fe5a03fe5a03755a887aeea0000342135ba2bdacc3ef78c0a5a4547cdb3a12dfa3974e19e9420c58b2219122fe15a6fe15a6fe15a6fe15a63a15a6eeba9d12ba9d7201003a6804512859a255848201002ac7091a4a081d016ac202196c52010011930501fe68046e680482d91288a6a046106ec6c66ba20591349549ad6fe96b47d41362a07cd104d1055307e18bf0d0f90e3836083b14f8fe9215fe9215fe9215fe92157a92152e010031fe45689e740500023634224a010036a3086a7e023e01000588c20100fe7405fe740576740588dba05779bccde43d4b2a3f688b1f471711640c0f0288cf9d99f647a0e20e24f95ad4f922ce081c1bb901000000000000004e010000800d1500400108005001050000090c7a010000027a20007a0100056f4e01000440084e16007e010000103221000020050e324900f03cf89df89b947ef66b77759e12caf3ddb3e4aff524e577c59d8df863a08a22ee899102a366ac8ad0495127319cb1ff2403cfae855f83a89cda1266674da0054f660100042aa0661c00d0000000bc7ac8a07f652e8ce6d19186d5fe009a4bb51932f2e8d655635b27cd9ff0665960a6dd9af90354f901a70183016e5bb9010001365201004ead018e010062ad01363801b6010000203e29029e4d00362800fead01fead013ead0188c3a01c706350c1cacdd76756e6f13844527283795e30b43aaf2fa6c8e23b9a74e285f921aa0c02dcb6b939aa09c50501090b32aa0136f100628d010101721d00ea01002e7003119c3215007201002e3e00fe5703a257030003765703b85c0d2da0c5e13021fce9d08cf1bcc522e02e626ff7a311c6f07bd9f7f242f0f9da22de34f901aaf901a70183016e5b3dad420100311105e7ad048e0100e6ad01117256010005881501327101460100555d150905014987323c00fe0405f2040588b0a01454892f519cc972d036be8a57aa32c4bbdc428d7b3ee1a3cf961ecba588332bf9caad0136f4007201003aad01211a3a13003601009e5b0031ad2971000015084a010076f60105931501fead016ead010004765a039048d294a0af540497bb9405263b221925d64cb4e08b21ea8101fe77d1c567abef37f7a76af9caad01d25a036687013171ae010031ad0101a64000368400093841401501fead016ead01825e08889da06ce11b95a9240a28e0ce1126ee7808c6e99c9f30a6dddbf4f1b760d87e140b09f9fead019ead01321501ee0100050121ad367b018e01003632000420040134329800fead01f2ad01888aa0acec0b370c3c497ca53ce3d84496a0a9badce3e209cbf02e4cab3b6d17a62d73f935ad001ba2b40636f4007201003af404321a010d017aa7041d011d2a21ad00001d1169265201001d364e0100329300fead016ead01820705888aa0f9b6f623227190d39a8ee700ea45b3544d7479be566a92208551b002aeef11baf935ad66b80b00202d1700081a7109d20705fe010036010029adbe010036660229e135ad010ffead016ead018207058877a008788e94be79c7e92a1239cd6c63974c4cf108a6c8e98f6db5ecf5bba7f8f0f6f98aad015dc42525fead0172ad010041016f8201000588ae010065e372ad010101fead01f2ad018864a030fad52d61c42232ae35aa72aeb9ce8967230f3fe84e6ff93a30c8c169d3ce39f942ad01266e0d1d01914c2525fead016ead0155e94e0100057e0501190aae0100fead01fead0176ad01885fa0d716521ec08cfb3a803854d008e419a50cf3ef24a9c13b7803d3a709523504c7f942ad01520100d2ad0104080049d1320100114aae010081a2360100fead01fead01fead014ead01984ca02d7a744c5c627584b49c8164dd50fc56f45e1bc81c8a36574ffd63a568101d98f90354f90192150f65722525fe5a036d5a128d094e010062190019010588c20100fe5a03fe5a03765a039839a086d216db5bd924319899a42c4dfbd1069261e92c169c336985afadc6f7c77c74f901a70183366c12420100710d252205f18a4f01000042570395e215096e010011754a010005881d0146790315016a46000101328a00feb1066eb106820b0a8878a03b3e45b40dfb752f785d0bc59635b7e8f2ff2f7bd20bc6c9c60ee127349ae5acf952040565432e010011f22525fe57036d576601008609020588c201004566150129e12ead010008fead016ead01820b0a8826a0cb22c97bdc768cb08b96992466a6702f674b57cd2c01ef64f36bab02028dad83f9a204050501252536f4001265095e01003e1d00363b00e6010005880d0151493215008a01000138004032ad01fe5a03725a0382c615881ca014ca70b06b045cfef730633360481d5efc3f33826c7d7897e405ee36d8492361f9be0405fe5703825703150132d9012e9e012e0c00a601000011322b00465703feaa0172aa018257038813a095ad1ba1547b34be892411493ac379832cbfd24d3058aea201d33ee3062827eef9b504a6bc1076ad01324801695729740906fe01000901326500a20100368200fead01fead013ead018800a0ee804c6bb19f3cc814b48df36b74fc02196d0524c0b0943939ea7ad05df0d952f935ad42bc102e110181300101051476ad0132010029adfe01004601000588360100726b0029a709061101fead01fead013aad019879fba023a30dceaa6436c3585f0dda7504bb376797c36a41d04ca1693fa69a29725ad2f901aaf9a1070001aa5a0336f4007201002942f5c21509fe01002ead01217501045a0100516836010009990000fe1d19fe1d192e1d198866a07a2a7d99546c75e6036fa1b14668c3154cf52065e9efd9ed666b79c0f69e2b00f9665a032e010011f225255e5a0311251d0135146a0100aafc0115010588010186360a1d01366a0029e1324002fe0b0aee0b0a8879e8a026bb41d66a670351c86715e6f08dd69709b1ee566e78ad3cfe1782363ec81982267b21a6b40636f4003d9009f9354946650dfe010015012e640055242e15008601001a9c0c09b40d01fead016ead01820b0a880ba06c00e39c6360809d19340d40dfb59e7f67703bff510afad4aa0116658a11961df9a1040802dc76a21a195e57034a370b3dc71901b65201360100690cda4300366302094bfeaa01a2aa017e0b0a8879d5a052d3af3c53c3bbf32aa6db1cfe8e91206b155e3976afc1e99187063f9b58c985d9b1425e082e010041bb01dd256866ad0142010035ad05394a0100b2c40419015e4f00760100fead01fead0176ad0188c2a0b4bc1085145bc45f5186bc222172af613ed30ecb2539f48f8e407c732ccdce91f9360f0f21914e0100008009e90040252536f40072010035ad090132c702ee010005881d015eb8002ad5195a0100329300fe04056e04058269128854a0b6f9771ebb4cd420061bfde5169ebae6a98548ee671fdaf99b4995cd96760363f9a9042e7f2642010061570101252236aa013a8d0136b2222e1d00053cfe01000d012e4c00119c321500010192b303feaa01a2aa017eae06880cfaa092e2c158ccb0f71660fe8140e96b5641c2034f5d7566d5da374cec35ce48c3804604052ebe00359731112525ce0405fe01003a01000588b2010001c215cf0501698b2eef00fe570372570382b106b0afa0e99cf3cd0a94f78406fbd428b0e937075f0286dec76bdf47a19f391480f69074f9010cf9010901833a6a3a6e5e08fe0100fe0100fe01009a010000c059bca6170bfebc0282bc023250025201004ebc028636007abc020001febc02f6bc02889ca02c31a1af6c590bfca0ea7123fb61cf1dc9854026befb252cc29157ebc8009326f9fe710e2a710e4a01002e16067601004e7f010501528401622e0019014a38007aad01fe6904fa69048897a02bc85a4a21c49a3af9496119c94d576b8c301f4c38e1dfd15570f6fa6eccd504f9caad0136f400729001461d00a19e01011af00dda01002ead011152321500a2010000082e4b00fe6d096e6d0982c30788e9a0df82cdb164fae0757e256e6ceb38e46af62e71ddfe484483b002990fb8b3661cf9caad01bd077ed30846ad01fe010009012e62014a43034a01000132366602fec307fec3073ec3078884a0873ca76a11997b6034bee72a616b7b90b666ccb51a197598da7e779cdbb43b0df936c70c5e010051be01f33af4001d0146bb0139ad053a9658018a0100054e1d0129790d0136b50311bb5a0100329300fe5a036e5a0382c70c8842a0ddc6238df140b7358a40d6229d29c3c58c16c59ee91f8eac28de7bcecb5266c4f9bec70c7d577e010039aa3201007a3e0186010032aa01320d005a01000589fe5703fe57037657038871a0ad42376c4d3eb3bc49e064ffec728a7f6d1f4bebbddddaba35d0fe53d2621a46f9325703329e022e0100315e251836f40025075e0100661d00468303ae010005880d01119c321500a201006157154efe57036e570382b10688d8a0292b36061c39cfdf6162b740e504887da5c82b8620ff0febe0822f6b5fbeece4f9d6570315df6e010066aa01f60100327d00a2f5013663024597001021aa1501feaa016eaa0182710e885ea0255c3540fc3ac66ffb3cd8e72b9ca47f4ae19afc2acdb756cca5f8793afdd430f99e5b080480002115004001d8ee0405a904ee0100050105889a010059314aad0165571501fead01f2ad01884ba09e71014f557d3afb43a11396ec442feeda31108eb27635ffc4195367fe85b9e7f99ead0109012525f6ad01363201da010005884a0100b510520100157b658c655afead01fead013dad8838a0a2e28bcc3b7a744d68e1a9a1fd243925d8c99366bd78e3b44e589b8c3def4ebcf9fead01c2ad01fe010005012ead013da10010765d00361f0035ad797bfe5a03f25a038833a043546cbb4dacc9d0ae20e67872a8246c1012f6e169c58226604e815f3bba10e6f9325e086201003111252536f40001eb09f8000046d00b011d05011141fe01000d0105880d01155b2e1500a20100feb406a2b406825e0888c9a0b20dbdd515105a6f10af738209ec35ac22b9b770e565218e10d64d71e7e8fa79f9be5e0836aa0172010035aac5ef3617010501a24c000001052f11013e9501552b46010035c9560100feaa01a2aa01825f0db030a046dfd2eeda4e6655271ca4f497cb094a63baf54ce707a1d78ac18df6282997fef902b5f901080182520cb9360f01fe0100fe0100fe0100ce010004c0f941b80801c0676eda1731fd45302ebc0711195adc3d5db8fe0100050151660588c2010036250349ec11520501fe0f06f20f068820a015308fedf6c8a3a53b25114f6160cad1b1257a1e417a49e8acace99938b706b1f9d2bc0709e88a0100bead019e5900aaad013da21d0b555efead01fead0139ad880da0026d40d11a11a4b9807020eeae68209957b45c54a057bdad98fc93cb49c1fb13f9caad0136f4002e010042a80435ad091a321a0176010076b7013ead016a2e0079fc520100329300fe5a036e5a038212068826a0ea116b250d60df6310de440143e19e23badd1539ad34b4501eeb94ee7c69e2fdf9ca6909b1077a0701010135adfe01003a8e0136ad018a890005013666020953fead01a2ad017e1d108878faa09e234c7cf0e594981bbaa326d99f7677794a57c323e93005603acbba5882742ac5b1c2f83515015a8d0112d00d1d1d6958fe010011012eaa0135a82e15003e01003291012e0100321900fe57036e570382130b88b8a0ea66d8502a040d07c8e3bafa6fafa655733509d5c2c73aacd4e13e11a21b0b16f9ca040571575201003695014eca01291f0906de01006e9801660100fe5703fe570376570380e7a0209c5ffdf94e71938224c3b42d311d5035b6edd7ba14b71035e04205449242a6221a09e9252572ad01695211014ead01fe0100010105885e01003683001d0109c41101fe0405fe04053e040588cfa044459be5ac46e8129d72e635111101edd4b03baa02b99886da0c52695e64193af90eb50bae040529aa92850192250076010029513a01004aaa01b50b660100feaa01feaa0176aa0188d4a0858dc8ed58bbed30e1fc84389fc1694d6794533546abf141f1f50fd096f63ad7f9ca5b0836f4007201000002364301f2f9042e3d003ead0152d2010901368200429e102e5600feb10672b10600047ebb4b8814a01dbd12bd7ae3d1f3f73e3270781ddf6b5f6e8afe118074047bcad4ba59fdfcf8f96957a6442f39aa21316e3a0300206e1d0072010062c504090101791101358b2e1500a20100feaa01a2aa01825b0888a7a0b69a0ca30d900f593d00af19af404644291cdf9ea628a76b2064e364fbfe1060f9ba5b0801dca904920100e2ad017a01003e980162680001b0150159660101698b322100fe080a6e080a82b20b88bca0cca696de71f1177382bf161fc4f3682864b5d43505525e40086d6e3ce3aaceeff9baad0101e64ead0136ff09150100025e1900fa01000588c201005ead01154efead01f2ad0188a9a0c826b805066afe169e51dd7e23889154ec1ba86a4ec91d351d56c18912920316f9cab1063dad5aa401150159f200047ad904b60100355fb201005ead011501fead01f2ad018896a0a862a627a6d1bed07b1fac12da181c4d4a918781f1be099aee902810d1f9751cf9c9b1fef13016f1303a900139aafe01003601002eaa017eb106764e02bd040004feaa0172aa0182b1068896a0d8fb08fe5e851eceeef1126f90d0752c35b62a16de8e4cc046d0dd60f6d2c858f96a04053d79311125257d577e010036ad01763701ae010005884a0100766200fe5703fe57037657038883a0d650986c24ac44d9f12a3d0374497e51932b4fa58e75065d58bddeee20e77fcef96aad011d0132ad0136a14272010036ad012ec702f601003ead01162a082e0100359905bb05055201007d5afeb50bfab50b8802a0efc57367d72c43e9e00c1c3df5dcf5417d759a69ba733bc1a62748807f749e88f9caad0100506afc003a01003aad013201007db9c201003ead015601003ea30135c1050129e1fead01a2ad01820b0a8870a01f4801a4d46c03d8dda24aec7fcdb5817efeb5ba9ddc9f5915d9057aa0c09d15f9ca5e0836f4006e9001761d004601007284012ddd25822e2900051101012e1500a20100fead01a2ad0182b4068885a0cf71aaa1afe4e50a8a55ba889298b5a7b27e71fd9c801d8ffd08a334fd110624f9665e08497a2a3e3a250dc9b132e3005e010072c701be0100057d09011d0baa010036630209dd32c700fe080af2080a886ba01f5005b84ae3c77142aeae3cdebcf0d3f7694c709b17c5d793cfb9ba151725d5f9c60405000829ad2e010062d507fead0132ad011d0186ad01756d1d01fead01fead0176ad018058a0046dcf3c5f7fa2ba925630f4a972ff705b9154e44af6d85ea54f1bd828f26efe39336a0100251afead0135ad69010554010186ad014e0100153f0501fe5a03fe5a033e5a03b045a007a713bd7d3b360fb3b248c2b43a4499c2f54b9fa17c6eca1712f38b05325d89f9044df902a001830393093e222309cd356f15090901293e0501210400802e021422e735011a6a01004efe020e335b097a4a01003a8400162f2605010040c1cf1d38019f04400061f32ef6031d210d4c0d830d19f081f90195f89b94112234455c3a32fd11230c42e7bccd4a84e02010f863a0ce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82a0096e2240be03d6804812ff7b63ede4bb6fe19f1e44d0c231a85b67e964463ac4a0742c0bc8152fc0e66a4dec4400bcf435c6e2de36d86681fc72ddd8b2028e131ca0000005cd05015479073fc2117dd054fcedacad1e7018c9cbe3ec0bf87a569d00f04342a0335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0a07b689a1a3d548f912e96fc2c8ea2e8b751eecbabe2a923b27572f225fdc3c1e7a005750d015a7c005217008842a0b59bb806875ef5718727778ded48d6def0daadc637571c2265f9eaee20aaa024a00d560501500434ef9ff3ca966fffe15d3764199a977e882ed6a07e190112141f080501643ea3022e01002dca21f6460c2a6a01003a540241391d01d61604010100400d8b11014d634e010000803a84003a0100329300feaa076eaa077e631888d1f0a09703fc8c93b0e0f64a33d7104627f1b0add92ae8f050a3e219830e153a4eb682263d3e82fd450101255f362604720c013a1d00053ffe0100010100c01d4551499a5e002e60043e1f1afead016ead0182010b9074a0b0df7d23fc52528067ab75465e8bc6e6f2ad56f2588be8284506c67eb46859d5f902b6655afe7c6cbe7c6c3a010046c6013612023e01000930762400460100363000698efe5a03a25a03825b0e9832a00201eee8e698746c64ce84c952cd2732bb933b448e433592c24ebe514492ab2cf9010901837ac92afe0100fe0100fe01009a010000c026ba4d6a6604001075ca453146100c62010000029afc033653028601000588c20100366600feb902feb9023eb902881fa07c8c5994344ca7106b7e387d34a07918186ceeab94f3d884b04c63082b0d7673f916670fce761e01013af3051d0100101ec509fe010032010025a505050d015a10060e710a8a0100fe6304a263048210068865a0b1ee5f6d2324ac00a01b6d35fd0c90be39a5796aaf6d90b3192c8a27fee6a3f5f9c6670f765703361c0721ca49bf1101355bf201002ead01a60100fe5703fe5703765703880ca0b73111e2dbc041fe25288ef9365ea03c71f2b175ae42a39f559dccf38fb58c46f97ead01216f0e4e0d090125259a0405012c093efe0100460100015cc601004ead0100092e4700fe6a096e6a0982bd078007a0b77503e641bd84dc2fb90d5b8fc1ad0f031bedca7c34348d2a14347541f2e32a54496ab1063aad0136f40072010036ad01000899749aa5045e010039ad69ca36be033201007acb031993fe7219fa721988d1dea006b328ba129eba276a46ff0ec9563ba7935c7d3bffe16faa1212cba17e019ccd925e0872ad013690013a0100321d0029a1aaeb0166010039ad199c01150963ae0100fead01a2ad0182b4068854a059b17812326248f85a33d95f09e58eb22565a27391edebd996337b8988d34054f9165e087a2320499e25220050a60a0132aa0172010009609e010005886601005a1f00362502698bfeaa01a2aa017e0405b877f4a0cf43d1da4d48a6b6e7a5f79ac244e057c8b5fe3579ddacd00e50e94294bb9f67f902a3f902a00183039349b9894f1501002012b211256f764a012d04052a05015e6b14291f3201000020322e01328200195015014213000004124e140e3f5861511d600c08000010466b144601000dda0d3afe6b147a6b147c8213dd788f123c4e45f2bca883ab7fb4cd55c491f0b4b3b03b8a67c2feb66e0a324d2a52d813e66b147caf68f0896eeb026cd9a14e728eeeea9cedab82d39e2616061ee209b7f30291ef8e7c00529300ba6b144cdd9cab275c3afd873701984725e80128cd49bc4982190100f91e1411046ddba26e14325304411e660100425702aa01004d3a52010000402a0c17a601006d4f0d010960fe5304fe5304995388e1a002fb51c12133a635f67d34cc48779e9dd9968d00ab059f3fc42594696400ebd5f912141104bfe76eaa01fe0100fe0100fe01009a01002a1411feb753eeb75316b7533658027201005aed064e0100ad41010136610049b9008801191101fe100cee100c8877cea0a34d541a688b4296d0d420e5a0fcb5c6302096fdafd30b3200a87269c57f3482127715aece5e36f100724604721d00769e047201002eaa01358b2e15001d017667008d630907feaa016eaa0182600ab043a09a095c90736eeef6b8af9c6b7e83936adcbe1c2caa66070b3f4658d654f6c104f9010bf9010880829f6fb9323308fe0100fe0100fe0100d201009d65fec80e8ac80e4d21ee01000d0155a6892a11072e291c498d2a3a0d56010011270501febb026ebb02828c1b88cca0e94809023defe973d1ec4bd2452aa29f900dc4e4bb3e6e30e52c3763e1cc87b9f9921b0d090125220050090c7a010000080e3c0b726504ea01003aa06e9a0100361e0529e5feaa01a2aa01821b0d90bba07393328a9e501d7d24637d5bc6f0f8fd2adb49d843a09cb61d4f9eb19d1d17d2f902a31a862100893ecb0809cd666f01092059ca000209f9048000621b0d05010020ea3c171d8dc908b5ee4a1b0d415a00011e3b0d2e010000087d871a7f1d0dccfe1b0d7a1b0d7c31731894d5bb153aedc4c494b7b7a51967c9f999c18f057a931f543409be40d28e9f0c00114e23228a86217cda3f2b4431393caa1c76cc2020a7dcab01462501d875233a3c6eaf806965c1508e7c00fe1b0d0e1b0d4cb899cb88ef9a97c54ae70f63607a3d80402e6a5d82190166dc1f55010101491425f912d70f1d015d3a36340001010d1d36cc03ee01000d0185db0d01119c321500a20100fe5304a2530482b8088832a09d447e801d84d7b8e053f0d320ce02a48b8c3d8526583fa1db9b59eb7448198bf91ec80efe0f0cee0f0c1a0f0caa010029ad3250028a010036340289471a1f18094bfeaa076eaa0782000688a8a0a516b4fda5594b57741ed8203be22d9b19b6bb4b11b844015b00d853ab6ff39cf912c80e04c0273efd05fe0100fe0100fe0100ca01002a2b1932c80e29c8190171ca453196b90805018d66fe010042010005885a01003e740059af190a010149b9fe6604a2660482b90288a3a0df9ce4bd153e361f655a7b1298defcf4162cca5900a870063494436fb5cb2fd4f96af0301ddc32ad011d187e01003a3901321a0119013e1b0242010042b90d3ead01297952010011bb5a0100329300fe66046e660482100c88c2a04e3cb7da4ae5d1f4f6de41a3a443573a40696e657ef02081b3c3171f76245698f92e100c5a860111ef2522fe57037d575a6f008201000588c20100366e0000220540feaa01a2aa018257038890a0ac1f24d759efd9ea9fab3f1d8d8db725bc1dbdf340c12a99bf5a1c04885d4be7f96a57031d01e2ad01362001fe01001501eead012dad044020121a0afead01fead0139ad887da06c7db4f837a07a414ba635d2c231beb6611d2be760bf21d552538ae44997e325f92e57035a010032aa01367e013ae404360100421d00363c005601004287014621052e2300119c321500a20100feaa01a2aa0182140b8821a0de44354b90a6b66d0f29bc9184562e21bbf06154721664fb26851f34dc06a5f8f97e3323090131112525760405325a0642ad01040040114bf201000588c20100362a02c9e2fead01a2ad01820405886aa06b9290a369a8592706dcfa45aad66ffa3467d003c3358fe04248d30e4165a26cf9caad0136f400469001050109255a1d001d0146360366010059082ead0135fe2e1500a20100fead01a2ad01825a038810a0cf9da45284a917021b168e41d5caa8bd3a2ad01c5a58751429f841503324e5fcf935ad32b50b3e0100311125105e5a0329a032010086ad017201004e3f0005830505c2010036a100fe5a03fe5a033e5a038857a0a2008890549979eb30a829cdeb4fd1331991436a74212266596639f30b20ba48f935adfec5174ac5170010366e01000436c7022e01004e96016e01003ead01297952010051685a0100fe5a03a25a0382b50b88b0a027d45b213546082fbac07c73b4b0a2dc87e2136e75aa0dda5e27a14d085449f2f9220b0a8e5a0300202525615a9992720100be850111013243014a01000588c20100fe5a03fe5a03765a03883fa07c26e8d793cf5250753a00755edd071cce7225d607749e6688a822e53ee64efcf9160b0aa6eb2e21aa3201006638014aaa017e850192010066720011013696010901361400698b328f00fe0c0f6e0c0f825e088044a06d152c5f9f6c6e8cf14f4694c9a9e169ccb43ce45f9583e958dee1b80124db2acc164657039d3e110b252536f4004a90011901721d00ea010005880d01119c04004016ab08327f01820100322e00fead016ead01825e088801a00c18826cd98791cf191b6f7434320b408377008abbe9f243f4fcff43d1f794e3f99eb106008025152525425a03660100fead018ead011101866c00366602fe5a03fe5a033e5a03882ca083593f6c054dec4ec0cc0b7b31bd1535cdbffce40f32e3fc8bab45c740b3672af99ead0109019aad0155ed8641012e0100293f3e010032fc020d010588c20100fead01fead0176ad018819a027017f84937a4d4295d3e8f0c4a9242ca7b590e6887c5481db4da5a394b5ef60f9225e082a0b0a460b01317e051a01f405098601003aad014e78017601005a68003e170056e701050111bb5a0100329300fe07056e0705820b0a889ea0faafbce4e603f5388afbfe285b8a69ecb92816f339512d736727164a98f01a6af9165e087aeb2e09010040212321aa19013a8d01360100721d0036010052180f5e400001871101358b2e1500a20100feaa01a2aa017eb106880bf0a0d4d7c27fbc2257dcedf05b47a611541fe7775a43a37956a07945bf244e916bb3662a1f32010031112510cab10636e00146010000409a050c11010588c20100368600698bfead01a2ad01820b0a8806a08fd30ab317475fb03919eecab7ffa1de9c1fc16e170a27d78fad8146f1254236f9d1b1cef22d32e9005201005e1a034e0100364b017601000e2a17c60100366200fead01fead013aad018876f3a0563ba448007eaa3f9f8f707c1c39e40310f0cd355160008d5ecca14844b0e9cffe9c35ae9c355e010036440115015a170005012e5a0371f632150072010029a70901327102feb1066eb10682070588dfa0393f0213247f895a40f1f3709fe1db25fbe9c65accafe9662b143f0e597feee5f9aeb10601dfae040500040131ea010005714601005a1700090162740036fc0129b0feaa01a2aa017e04058876e0a09a0bf9b4969ce9fbb5c659c59c5cf38072372e4150748e4a4a66fffe35925130feb106c5b1cd6e4a4201ae0405ae01004a6b008a0100001011aa0501fead01fead013ead0188dba0b2c80efe0934d52f70c18fa96e87fcd543da9cc6a4e34889437831cc64d03aadf94eb50b4601009168252536a1027201002dad49bf363537f2010005880d010164297952010011bb5a0100099b0d01fe04056e040582b50b888ca0eaacb272bbffcc41e9709014c1b926d689377fd1f0719c731547bb8544aaeb9af9fe0405b1044a140121467201008221005601002eaa014e01004a8b0042eb2929defeaa01a2aa0182040588c8a0efe1a90528737448dd0ba9ff5f1ad5d5ced73ecbf8dfd3f1f71b3881ce3819a3f91e080a2e0c0f46010009fd00202925aeb106464b0009016255067a01000d517ead01560100361004fead01fead013ead0188b5a03fae9cc95cc8fb82878490f359348ef22ad437479796ae3b47930b196a43293bf9a6ad0141842525e6ad01352e29fde601000588c20100157f0501fead01fead013ead0188a2a0c77940e8bf62e778494f4ec44b44bd7a01858acfaa1159e6ca16c23b5ee0f010f9a6ad01010125250df42d714dec560100721d00de5e031ec12e0d010d885ab50b299366010041831501feb1066eb10682b50b88cea03992a511416036f719cb28e798fedf453ccc5f1c6e9c1ff4b9533b47099063f6f9caad01925a0329a709061501ea9f013601004535820100328901feb406feb40682b406888fa021997c1773fcd3861ae1d87e3dafe557af1d72fe3d696c32c60a70f4e37f8decf9caad016d5a8e01003aad01313e00204ed0333a0100112c5201003ead016a40037579560100326700fe5a036e5a03820b0a887aa07af9556104d05d33f0a171f685cfea75d0db448ed79878a861c54318ca0fc7a7f935ad46741c1d0111f22525925a0309013aad01760100055d960100aa2b001d0136660225e1000432d1adfead016ead01820e0a887ca04a4f1addd725b15c5f525e07396baa925be440f6ffaf94a2efe39800381e8e52f935ad2a1a194601003dad002021ad9285010002ea7d377a0100fead0135adfe5a03a65a0382ad018877a0a331bb727ee86568324cb96818bce2b7dc6de3d954e2014265c1ab8f915bdcd3f9ca120ffe5a035e5a035a010049193216030001fead01fead01fead014ead018864a097dc76e20cb78f0834de23dd7c8d4cd6981551f1d4d85367c57b752bee4464eaf9be120f32350125496239012966fe01004601002e710071f30d1585db6201001a14131901feb106a2b106820b0a88bda07ac89d2fce7ac6a82e8db84fd698e50a75d59d447538a59e308dd756c65d13d0f9b504feb1066ab10625de764501ba01002ead017a01001d78058815010919fead01a2ad018204058051a0eaef69d8541cf7b3ed5e3573bf26eda2843752a62743caa851b3d300ff53292a8670a6ad0136f400723d03091daa5b013e010029524201002e52006d5a0004321500a20100fead01a2ad01825a0388aca022aa311e36b6915fae4658d1e466af00a736864d12625fd6d8ee89e2e64672fbf9feb1063ab1063a670429adfe01004601002ead01960100416201041901490821ad1518fe0b0af20b0a803ea091230f72faf0a4c75238d59b9a6e3de76180ee0a6bc79060cfc03b65ae24461e377796782101e915d986010039aa050a2117ee01006d42d19c1901297652010015340582420100329300feaa016eaa0182620d8868a0eb0828c038ff60e94fddda8b144544ad9634233e0da97cd48bdd61281a707496f9d5b19eb50b12c15825b58a01000002aeda014e01003aa70311019e800036010036660229e1fead01a2ad0182b106902ba0c21ada7e9ae4ae938ab79c4cf5d1cdf64eb4682fa5bc50ac3acd9c9be3835497f906a812074b4a70172e8a02519f252536f4002e2700420100721d000101da7b1205880d01119c3215005a0100469000fead01a2ad0182b106889da05ea3eb9118ad8cce0aa50abeeebf4413be0d6b90bab90918159922cbeec7adfbf9beb50baa5f0d00825a32016e010049ef7601002eaa016201004225003663020968feaa01a2aa018257038013a02ffbb2868a145601d903b3ae807d8b0e80170aaec4ab3e69976d8276ef87b116079808044b11164c4209c03eec0251b805fdaaaa0146c402fe010009010588c2010029aab15409eafeaa01feaa0139aa8818a0a449e0d0209cbce3dac8a8e399a5854dfa2cf09b214d21a678197ee3c2c08a5af961540805b96c29aa56010032aa0109f19201003aaa013217018201006a1a0529aa194f2976110732010011bb5a01001944fe125cfe125c885ea04257e3913c7774cd2ba2c517248818b4e98f18ac5ac5de2837c04604b8fef88cf92258089a5c0d00401258080d0121b76a530116d310fe01004e010029adbe010001af190129e1fead01a2ad018201058800a028bc7c01c927d50e920f38eee19ab3a7b10cf667609e2303912c9da54b5def95f9bead0116050a3e010009f94601003a5a035201009194a601000010fead01fead01fead014ead018875eda07e3d01cde93068674da233cb781a232a98b6bee4dfcb028c3c893d00612c6b2beed02916d0297201003aad0151c736e3024601007e200042ad01422d0279f0fe0705fe0705a20705884ca01c7eec43cc7f3f7870ba65f97e94d117f7285e2cef28096cb2360131ce1b6217f9c1b15e97892d0311ef857ca65b08aa40863ad4017a01000588c2010036010209db513d0501fe090f6e090f7e04058875daa04656fe329030e41febad141c9957463ac79c8a19cf762fd51b3f951b9960055c7ed0290dcc32ad0136f400726601721d00aa010000403afc062ead01119c321500a201000de10901fead016ead01825c0d888ca055f903480a4e4331ce90c8ab5c37c31c445a6915a6f7ef0b66d9ff3d8015c119f9d5b196b6102126a65a03fead0135ad3e010001871901360e006201000040366602fe5a03fe5a033e5a0388c7a01ef424fb9a3615645f199596af7e0b79fd1d9287a8b089f2137b1bba6e294e3ef9baad01210afead01aead01d9793201000588c2010021ad794a25ad00801910feb80b7ab80b82070588b4a05fedc045d6144cc74d2d2508846c615cb3f90945d37aa2f0ecba2f910f51985bf9d6ad014adf04958e2e01004a28005e8001b20100e6ad01190125ad3dbdfead01fead0188afa0c9b39ccfd6339dd965f8c6932c16cf45f2f8af326250d31c4e7c82a6e17cdc18f982141905d4318a2525aa5a0316064eae0100056f8201000588c20100615a1901096afe5a03fe5a03795a889ca0ccf12d6a5c3b0a62654fc8ee3aaa98ae5ebdcdecfc310ac64ead3f9aba1a070ff96e0b0a0d0132aa011df13ef6073e01004e5703e20100295b05012eaa01119c3215002e010072c30dfeaa01a2aa01825e08887ba0b40dc5f9b495856a95e4f830677ccbec8508ac8a028a1fe63cf1873dfb891989f9b5045ebc102570311125253dad7e0100053d3911321a01ee010005881d013dc836010016f4416a0100329300fe0b0a6e0b0a82c11a883aa03ba1a86917f002ced34d5b2ae96497652c574324ee6b3f2f007356ad54769e06f935ad960b0a01f7aa040529adfe01004601000588150100019a670036660229e129ad6d7dfead016ead01825e088889a0ac14ee798961ae1af206c1c123e94fce865330960da6756330ef9dd907216e0ef94ead01360b010101325a032dad8e22018e2400ce010046a2005201003a270066ad010d01fead01f2ad018876a0211dcac43bb53cbbda4da00393ec81b382020685dcf8763bf17f17354be2d20bf94ead0146010032ad0136f4002d903a18010d010d1d9a01005644004e01002e2a00119c2e15002e2000760100695a0d01fead016ead0182b406886aa0b79d4c1fbff47ba3558c18e01580287e9d34e3f411e6f1e814fd27c7eb2f4b86f9caad016d5a8e0100b6ad016201003252010101628d0135ba4e0100366602b907ad05fea18e76a18e8207058863a0cbaac987f9ac93e057f6bd67e1bbe6bb7f010ba9f0e95ddce64a337428ef71f3f932b80b82040105214ead01424f01090172ad01054dd60100d63b005ead011501fe5a036e5a0382ad018850a01c1fba12a871d7359caaddf1325d3250affa38981b060c4b1662b8c1f8d406bbf916b80b32a24e49731501000441ae01e8252201099a01003aaa015ad001c6010005881d013ab0002e010001bb6a0100329300feaa016eaa01820b0a8828a063074045a91fff1b86cae232cfdf6f0087abe26587b62e083d5dbc34d0666250f9d204052eff1195414e01002dad0d07fe010019013ead0196010036660229e1fead01a2ad01825703884ba0c3c4a2b78071a2380315e8a324f5f0b1f59d726c7adeafe44513657004f78375f9caad0136f400728901721d00ae01003a13022ead01753b2e15003201003a3d003201003dad0002fe5a03725a03825e088059a03e6bb43c0d4de9b68c829d8ddd8efdc0bde9db0df87b2560f984568b0b9236ae3c3c010125104eb1061d0125a10529fe7017327017359401010d5fba0100366602fe5a03fe5a033e5a038838a0ec0f85edbc71f9f9b40275db6b2e7f0906bf4728e1aa891b8c830957c4de3d86f9325e08420100311500800d1a05107aad012e010025b95201005dd2ca010005886a0100564c03fead01fead0176ad018825a0ee0be799aa3d4dcceca75605f73996d3e6571f787589d5f1add0d2b9b358aeccf9165e08de2a2d668d016957563501fa01002eaa0100801e5c0d2e150072010069510901323202fe5e086e5e088204058848a08d6cdd47d56c13b26c89af3181041c84ed33c1aee629eba6071d5e24cc07a205f9cab106fe570365575ac501323c01660100004071e8b20100fe5703fe57037657038812a04505771ae6ae1ed69994bac9ee67b34e8af3dadf9784044210df320e3e6e15a6f952ad012e7b020501311c45bd36f400725b033a7703828b019e870305881d0142b100190111bb5a0100329300fe5a036e5a0382b80b8816a01a3f46c88375f26b735b3ff10f9a515dbfbfe0ce3ce32498e45a3d48b93ab878f952ad0142010011f225257d5a7e5d013aad010d01561600ae010005887e010042c201366602091ffead01a2ad017eb80b8874ffa09283b24ed216acd6bc60400db6b6dd7628c7538515f3106b5f9f5aaffcdf1ab27e28230d0132ad0136f400567a010d160d073e0100364200ca01002ead010d9c000832150038000000000000000000000000000000000062010000082e1a00f03cf89df89b947ef66b77759e12caf3ddb3e4aff524e577c59d8df863a08a22ee899102a366ac8ad0495127319cb1ff2403cfae855f83a89cda1266674da02e49004a01000403a04a15001901c05c0b39a0e3b9a4edcd4a9e0d7cc302d376eacb21487e3d1ba990ec7dae37bfda16a5f350f90354f901a70183016e1bb901193b0d0100800d081509004001110050010596010000024227000004421200560100056a620100761e005e010000103219000020050efead01a2ad01002a76ad01b8bc74e7a04f1b9fe9e450e5acf13342e591f2af8f104071008c1fb678736488d37d6c27fff901a7018302dc76b9010005bc4e010031b3252276aa0129010d0146aa01760100323d006a010005882e01003685015a0100362500096cfeaa01feaa0139aa90eca0b397ca1eee35427f9efb9482efae35a4aa8c52d3e9a13c126448a5daa338ad5cf901aa6d57005b32570309ca1501aaad01320100bead016a010032900342ad010000367601560100fead01fead0176ad0188d4a0110b5fe013dbe95a51f09438102f17849d2857c13fe27ce6cca003da584720c8f95aad013a010032ad010014321d00729001721d00ea01002ead01119c3215000501369d014a010000013ae401feb106f2b1068828a0179dcaac4709a2f6e1690264456368ef5a40c53126e731f3e8396e88698d88c1f9caad0182040119013aad01327404ee010008400008325b003a09042e010031cc329a031901329300fead016ead01000476b1069048d104a04e0c051a9913bec4cc9e8acd3209ce6c32391ed2b4bb0293a76216876ffee0aef9caad0172b40632fd003ead01fe010015012e5a036a6b0701013dd536660229e132b000fead016ead01825e0888c1a03aa540e8a0bf0a394329ac33ed262c39e629d5387fe0a351afb3059ad656139df9fead0136ad013e39013d2a460100292ed201002ead01a601007aad010004fead01f6ad0188aea0aa1d7d585af4a8235cb88ec780bc1967ba7f2aac1f119b990e1e23ec3afbbc84f9caad0136f400729001621d005a95049e01002ead0191e83215007a01001940000a2e2a00fe5a036e5a0382650d8817a078664d6a629175dc4bbeb8c0d036e8a2427fda505f02db7fdef919bd915f2a49f9eead0125ad2e0100422c033aad010008327504ea0100396d090142790019010080761802329200fead016ead017eb40698d0faa0ae5a94b192d11f3e9d32e08d1122da485a5ca18bf2f2befa32b5284b81269f3cf901aaf90e680d00014e120f000495d651be252572b4063601003aad01fe010015010588c20100951305d829e1fead01a2ad0182b406889ba0db164b367f882c008c7f2197335e127549073995ba1e3e121b39159d0d13a7cbf922bf1036680d3a010032ad0115f400000ed810729001721d007601007290012e1d00119c3215009e01000004fead01a2ad018207058806a022a5e05afa58b31f4ce9548475e656b3febed7ebecc195b9fd3dfebfc323e5d8f961570802dc3632120f3a0100310e2522fe570352570389aa11687e010005880501ae0c022e63020000fe5703fe57034257038888a04784718c4e38000382420c3240440015932da9a2f9f932b7031318517bf9b7a7f932b10639043a0100314505216aad01360f01feb80b4eb80b0001059a0588c20100369e00fe0405fe04053e04058883a02faf90ca35ac0a0aa0902123164f9861b2448ce2b823fd84fb3ded840b2ecf71f935ad001b755a09c63201009ead013e0100aef802320100329b040d0111850000d6ef040000fead01fead017aad018870a0101003cbed3c5a48b6b0e6eb6c021cd2ccd31c39de630ae6f903d310741d5c00f9cab1066a5a033e0100a6ad01a9077201001d4d7e5a031d2b1d01fe5a03fe5a03765a03885da02e29a1121a353fd78f03f71e93d75483c1c017ca176342d605d17c995184f6bff9c9b100b67557320100897451d2252236f1007201003a32014e2d038e010009851d0105881d010020421200150111bb5a0100329300feb50bf2b50b88e8a044db790fa815dd9ace6312c8325c017abbe39556144ea00659d3d602d92ac2e1f94a04054a010011f2252535ad650b3a9001360100721d0036010032910111705e010005880d01152c2e1500a20100fead01a2ad017e080a880af5a0ed8943b28f06b00ec8e43c4348a1803a98c6d035f4fea125f0a3ed004aafacb526620da6b50ba904921b013aad014a0b077a01005a66005a17007a010055660501098dfead01a2ad0182620d884aa0ae6a1bce3b16c231842970014b011537526d1e6dd0216ee739dce4ecc8d48acef9755abead019201003aad011101322201ce01005ead017659002ead010010fead01fead0142ad018437a0342f62e3abb0c095d7477b22104b877fb16df01a705fcbc3ccf1b2f95a10ae3e0000"); + IByteBuffer input = PooledByteBufferAllocator.Default.Buffer(); + ZeroPacket output = null; + try + { + input.EnsureWritable(frame.Length); + input.WriteBytes(frame); + + ZeroFrameMergerTestWrapper zeroFrameMergerTestWrapper = new(); + output = zeroFrameMergerTestWrapper.Decode(input); + Assert.That(output, Is.Not.Null); + + Assert.That(output.PacketType, Is.EqualTo(32)); + output.Content.ReadAllBytesAsArray(); + } + finally + { + output?.Release(); + input.Release(); } } } diff --git a/src/Nethermind/Nethermind.Overseer.Test/Framework/ProcessBuilder.cs b/src/Nethermind/Nethermind.Overseer.Test/Framework/ProcessBuilder.cs index 03bda2e92e9..c39a33a0044 100644 --- a/src/Nethermind/Nethermind.Overseer.Test/Framework/ProcessBuilder.cs +++ b/src/Nethermind/Nethermind.Overseer.Test/Framework/ProcessBuilder.cs @@ -41,7 +41,7 @@ public NethermindProcessWrapper Create(string name, string workingDirectory, str private static void ProcessOnExited(object sender, EventArgs eventArgs) { - TestContext.WriteLine($"Process exited: {((Process)sender).StartInfo.Arguments}"); + TestContext.Out.WriteLine($"Process exited: {((Process)sender).StartInfo.Arguments}"); } private static void ProcessOnOutputDataReceived(object sender, DataReceivedEventArgs dataReceivedEventArgs) diff --git a/src/Nethermind/Nethermind.Overseer.Test/Framework/TestBuilder.cs b/src/Nethermind/Nethermind.Overseer.Test/Framework/TestBuilder.cs index 98612ee0caf..72dd3fac275 100644 --- a/src/Nethermind/Nethermind.Overseer.Test/Framework/TestBuilder.cs +++ b/src/Nethermind/Nethermind.Overseer.Test/Framework/TestBuilder.cs @@ -23,13 +23,13 @@ public void TearDown() var passedCount = _results.Count(r => r.Passed); var failedCount = _results.Count - passedCount; - TestContext.WriteLine("=========================== TESTS RESULTS ==========================="); - TestContext.WriteLine($"TESTS PASSED: {passedCount}, FAILED: {failedCount}"); + TestContext.Out.WriteLine("=========================== TESTS RESULTS ==========================="); + TestContext.Out.WriteLine($"TESTS PASSED: {passedCount}, FAILED: {failedCount}"); foreach (var testResult in _results) { string message = $"{testResult.Order}. {testResult.Name} has " + $"{(testResult.Passed ? "passed [+]" : "failed [-]")}"; - TestContext.WriteLine(message); + TestContext.Out.WriteLine(message); } } @@ -58,7 +58,7 @@ public void QueueWork(Action work) } catch (Exception e) { - TestContext.WriteLine(e.ToString()); + TestContext.Out.WriteLine(e.ToString()); throw; } @@ -81,7 +81,7 @@ public void QueueWork(Func work) } catch (Exception e) { - TestContext.WriteLine(e.ToString()); + TestContext.Out.WriteLine(e.ToString()); throw; } @@ -94,18 +94,18 @@ public void QueueWork(TestStepBase step) // queue up the work ScenarioCompletion = ScenarioCompletion.ContinueWith(async task => { - TestContext.WriteLine($"Awaiting step {step.Name}"); + TestContext.Out.WriteLine($"Awaiting step {step.Name}"); try { _results.Add(await step.ExecuteAsync()); } catch (Exception e) { - TestContext.WriteLine($"Step {step.Name} failed with error: {e}"); + TestContext.Out.WriteLine($"Step {step.Name} failed with error: {e}"); throw; } - TestContext.WriteLine($"Step {step.Name} complete"); + TestContext.Out.WriteLine($"Step {step.Name} complete"); }, TaskContinuationOptions.OnlyOnRanToCompletion).Unwrap(); } @@ -216,7 +216,7 @@ private NethermindProcessWrapper GetOrCreateNode(string name, string baseConfigF File.Copy(baseConfigFile, configPath); int p2pPort = _startPort + _nodeCounter; int httpPort = _startHttpPort + _nodeCounter; - TestContext.WriteLine($"Creating {name} at {p2pPort}, http://localhost:{httpPort}"); + TestContext.Out.WriteLine($"Creating {name} at {p2pPort}, http://localhost:{httpPort}"); value = _processBuilder.Create(name, _runnerDir, configPath, dbDir, httpPort, p2pPort, nodeKey, bootnodes); Nodes[name] = value; _nodeCounter++; @@ -277,7 +277,7 @@ private void CopyRunnerFiles(string targetDirectory) throw new IOException($"Runner not found at {sourceDirectory}"); } - TestContext.WriteLine($"Copying runner files from {sourceDirectory} to {targetDirectory}"); + TestContext.Out.WriteLine($"Copying runner files from {sourceDirectory} to {targetDirectory}"); CopyDir(sourceDirectory, targetDirectory); string chainsDir = Path.Combine(Directory.GetCurrentDirectory(), "chainspec"); CopyDir(chainsDir, Path.Combine(targetDirectory, "chainspec")); diff --git a/src/Nethermind/Nethermind.Overseer.Test/Framework/TestContextBase.cs b/src/Nethermind/Nethermind.Overseer.Test/Framework/TestContextBase.cs index 4b53488b65e..40dfc1263d9 100644 --- a/src/Nethermind/Nethermind.Overseer.Test/Framework/TestContextBase.cs +++ b/src/Nethermind/Nethermind.Overseer.Test/Framework/TestContextBase.cs @@ -60,20 +60,20 @@ protected TContext Add(TestStepBase step) private async Task> ExecuteJsonRpcAsync( string methodName, Func>> func) { - TestContext.WriteLine($"Sending JSON RPC call: '{methodName}'."); + TestContext.Out.WriteLine($"Sending JSON RPC call: '{methodName}'."); var delay = Task.Delay(20000); var funcTask = func(); var first = await Task.WhenAny(delay, funcTask); if (first == delay) { string message = $"JSON RPC call '{methodName}' timed out"; - TestContext.WriteLine(message); + TestContext.Out.WriteLine(message); throw new TimeoutException(message); } var result = await funcTask; - TestContext.WriteLine($"Received a response for JSON RPC call '{methodName}'." + + TestContext.Out.WriteLine($"Received a response for JSON RPC call '{methodName}'." + $"{Environment.NewLine}{JsonSerializer.Serialize(result)}"); return await funcTask; diff --git a/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs b/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs index 4034ab660c9..49a9cbf7d50 100644 --- a/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs @@ -25,426 +25,424 @@ using Nethermind.TxPool; using NUnit.Framework; -namespace Nethermind.Runner.Test +namespace Nethermind.Runner.Test; + +[Parallelizable(ParallelScope.All)] +public class ConfigFilesTests : ConfigFileTestsBase { - [Parallelizable(ParallelScope.All)] - [TestFixture] - public class ConfigFilesTests : ConfigFileTestsBase + [TestCase("*")] + public void Required_config_files_exist(string configWildcard) { - [TestCase("*")] - public void Required_config_files_exist(string configWildcard) + foreach (string configFile in Resolve(configWildcard)) { - foreach (string configFile in Resolve(configWildcard)) - { - var configPath = Path.Combine(TestContext.CurrentContext.TestDirectory, "configs", configFile); - Assert.True(File.Exists(configPath)); - } + var configPath = Path.Combine(TestContext.CurrentContext.TestDirectory, "configs", configFile); + Assert.That(File.Exists(configPath), Is.True); } + } - // maybe leave in test since deprecation has not fully happened? - [TestCase("validators", true)] - [TestCase("poacore_validator.cfg", true)] - [TestCase("spaceneth", false)] - [TestCase("archive", false)] - [TestCase("fast", true)] - public void Sync_defaults_are_correct(string configWildcard, bool fastSyncEnabled) - { - Test(configWildcard, c => c.FastSync, fastSyncEnabled); - } + // maybe leave in test since deprecation has not fully happened? + [TestCase("validators", true)] + [TestCase("poacore_validator.cfg", true)] + [TestCase("spaceneth", false)] + [TestCase("archive", false)] + [TestCase("fast", true)] + public void Sync_defaults_are_correct(string configWildcard, bool fastSyncEnabled) + { + Test(configWildcard, c => c.FastSync, fastSyncEnabled); + } - [TestCase("archive")] - public void Archive_configs_have_pruning_turned_off(string configWildcard) - { - Test(configWildcard, c => c.Mode, PruningMode.None); - } + [TestCase("archive")] + public void Archive_configs_have_pruning_turned_off(string configWildcard) + { + Test(configWildcard, c => c.Mode, PruningMode.None); + } - [TestCase("archive", true)] - [TestCase("fast", true)] - [TestCase("spaceneth", false)] - public void Sync_is_disabled_when_needed(string configWildcard, bool isSyncEnabled) - { - Test(configWildcard, c => c.SynchronizationEnabled, isSyncEnabled); - } + [TestCase("archive", true)] + [TestCase("fast", true)] + [TestCase("spaceneth", false)] + public void Sync_is_disabled_when_needed(string configWildcard, bool isSyncEnabled) + { + Test(configWildcard, c => c.SynchronizationEnabled, isSyncEnabled); + } - [TestCase("archive", true)] - [TestCase("fast", true)] - [TestCase("spaceneth", false)] - public void Networking_is_disabled_when_needed(string configWildcard, bool isEnabled) - { - Test(configWildcard, c => c.NetworkingEnabled, isEnabled); - } + [TestCase("archive", true)] + [TestCase("fast", true)] + [TestCase("spaceneth", false)] + public void Networking_is_disabled_when_needed(string configWildcard, bool isEnabled) + { + Test(configWildcard, c => c.NetworkingEnabled, isEnabled); + } - [TestCase("sepolia", "ws://localhost:3000/api")] - [TestCase("mainnet", "wss://ethstats.net/api")] - [TestCase("poacore", "ws://localhost:3000/api")] - [TestCase("gnosis", "ws://localhost:3000/api")] - [TestCase("spaceneth", "ws://localhost:3000/api")] - [TestCase("volta", "ws://localhost:3000/api")] - public void Ethstats_values_are_correct(string configWildcard, string host) - { - Test(configWildcard, c => c.Enabled, false); - Test(configWildcard, c => c.Server, host); - Test(configWildcard, c => c.Secret, "secret"); - Test(configWildcard, c => c.Contact, "hello@nethermind.io"); - } + [TestCase("sepolia", "ws://localhost:3000/api")] + [TestCase("mainnet", "wss://ethstats.net/api")] + [TestCase("poacore", "ws://localhost:3000/api")] + [TestCase("gnosis", "ws://localhost:3000/api")] + [TestCase("spaceneth", "ws://localhost:3000/api")] + [TestCase("volta", "ws://localhost:3000/api")] + public void Ethstats_values_are_correct(string configWildcard, string host) + { + Test(configWildcard, c => c.Enabled, false); + Test(configWildcard, c => c.Server, host); + Test(configWildcard, c => c.Secret, "secret"); + Test(configWildcard, c => c.Contact, "hello@nethermind.io"); + } - [TestCase("aura ^archive", false)] - public void Geth_limits_configs_are_correct(string configWildcard, bool useGethLimitsInFastSync) - { - Test(configWildcard, c => c.UseGethLimitsInFastBlocks, useGethLimitsInFastSync); - } + [TestCase("aura ^archive", false)] + public void Geth_limits_configs_are_correct(string configWildcard, bool useGethLimitsInFastSync) + { + Test(configWildcard, c => c.UseGethLimitsInFastBlocks, useGethLimitsInFastSync); + } - [TestCase("mainnet", "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")] - [TestCase("poacore", "0x39f02c003dde5b073b3f6e1700fc0b84b4877f6839bb23edadd3d2d82a488634")] - [TestCase("gnosis", "0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756")] - [TestCase("volta", "0xebd8b413ca7b7f84a8dd20d17519ce2b01954c74d94a0a739a3e416abe0e43e5")] - public void Genesis_hash_is_correct(string configWildcard, string genesisHash) - { - Test(configWildcard, c => c.GenesisHash, genesisHash); - } + [TestCase("mainnet", "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")] + [TestCase("poacore", "0x39f02c003dde5b073b3f6e1700fc0b84b4877f6839bb23edadd3d2d82a488634")] + [TestCase("gnosis", "0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756")] + [TestCase("volta", "0xebd8b413ca7b7f84a8dd20d17519ce2b01954c74d94a0a739a3e416abe0e43e5")] + public void Genesis_hash_is_correct(string configWildcard, string genesisHash) + { + Test(configWildcard, c => c.GenesisHash, genesisHash); + } - [TestCase("spaceneth", true)] - [TestCase("validators", true)] - [TestCase("^validators ^spaceneth", false)] - public void Mining_defaults_are_correct(string configWildcard, bool defaultValue = false) - { - Test(configWildcard, c => c.IsMining, defaultValue); - } + [TestCase("spaceneth", true)] + [TestCase("validators", true)] + [TestCase("^validators ^spaceneth", false)] + public void Mining_defaults_are_correct(string configWildcard, bool defaultValue = false) + { + Test(configWildcard, c => c.IsMining, defaultValue); + } - [TestCase("*")] - public void Eth_stats_disabled_by_default(string configWildcard) - { - Test(configWildcard, c => c.Enabled, false); - } + [TestCase("*")] + public void Eth_stats_disabled_by_default(string configWildcard) + { + Test(configWildcard, c => c.Enabled, false); + } - [TestCase("*")] - public void Analytics_defaults(string configWildcard) - { - Test(configWildcard, c => c.PluginsEnabled, false); - Test(configWildcard, c => c.StreamBlocks, false); - Test(configWildcard, c => c.StreamTransactions, false); - Test(configWildcard, c => c.LogPublishedData, false); - } + [TestCase("*")] + public void Analytics_defaults(string configWildcard) + { + Test(configWildcard, c => c.PluginsEnabled, false); + Test(configWildcard, c => c.StreamBlocks, false); + Test(configWildcard, c => c.StreamTransactions, false); + Test(configWildcard, c => c.LogPublishedData, false); + } - [TestCase("fast")] - public void Caches_in_fast_blocks(string configWildcard) - { - Test(configWildcard, c => c.HeadersDbCacheIndexAndFilterBlocks, false); - Test(configWildcard, c => c.ReceiptsDbCacheIndexAndFilterBlocks, false); - Test(configWildcard, c => c.BlocksDbCacheIndexAndFilterBlocks, false); - Test(configWildcard, c => c.BlockInfosDbCacheIndexAndFilterBlocks, false); - } + [TestCase("fast")] + public void Caches_in_fast_blocks(string configWildcard) + { + Test(configWildcard, c => c.HeadersDbCacheIndexAndFilterBlocks, false); + Test(configWildcard, c => c.ReceiptsDbCacheIndexAndFilterBlocks, false); + Test(configWildcard, c => c.BlocksDbCacheIndexAndFilterBlocks, false); + Test(configWildcard, c => c.BlockInfosDbCacheIndexAndFilterBlocks, false); + } - [TestCase("^archive", false)] - [TestCase("archive", false)] - public void Cache_state_index(string configWildcard, bool expectedValue) - { - Test(configWildcard, c => c.CacheIndexAndFilterBlocks, expectedValue); - } + [TestCase("^archive", false)] + [TestCase("archive", false)] + public void Cache_state_index(string configWildcard, bool expectedValue) + { + Test(configWildcard, c => c.CacheIndexAndFilterBlocks, expectedValue); + } - [TestCase("mainnet archive", 4096000000)] - [TestCase("mainnet ^archive", 2048000000)] - [TestCase("volta archive", 768000000)] - [TestCase("volta ^archive", 768000000)] - [TestCase("gnosis archive", 1024000000)] - [TestCase("gnosis ^archive", 768000000)] - [TestCase("poacore archive", 1024000000)] - [TestCase("poacore ^archive", 768000000)] - [TestCase("spaceneth.cfg", 64000000)] - [TestCase("spaceneth_persistent.cfg", 128000000)] - public void Memory_hint_values_are_correct(string configWildcard, long expectedValue) - { - Test(configWildcard, c => c.MemoryHint, expectedValue); - } + [TestCase("mainnet archive", 4096000000)] + [TestCase("mainnet ^archive", 2048000000)] + [TestCase("volta archive", 768000000)] + [TestCase("volta ^archive", 768000000)] + [TestCase("gnosis archive", 1024000000)] + [TestCase("gnosis ^archive", 768000000)] + [TestCase("poacore archive", 1024000000)] + [TestCase("poacore ^archive", 768000000)] + [TestCase("spaceneth.cfg", 64000000)] + [TestCase("spaceneth_persistent.cfg", 128000000)] + public void Memory_hint_values_are_correct(string configWildcard, long expectedValue) + { + Test(configWildcard, c => c.MemoryHint, expectedValue); + } - [TestCase("*")] - public void Metrics_disabled_by_default(string configWildcard) - { - Test(configWildcard, c => c.Enabled, false); - Test(configWildcard, c => c.NodeName.ToUpperInvariant(), (cf, p) => cf.Replace("_", " ").Replace(".cfg", "").ToUpperInvariant().Replace("POACORE", "POA CORE")); - Test(configWildcard, c => c.IntervalSeconds, 5); - Test(configWildcard, c => c.PushGatewayUrl, ""); - } + [TestCase("*")] + public void Metrics_disabled_by_default(string configWildcard) + { + Test(configWildcard, c => c.Enabled, false); + Test(configWildcard, c => c.NodeName.ToUpperInvariant(), (cf, p) => cf.Replace("_", " ").Replace(".cfg", "").ToUpperInvariant().Replace("POACORE", "POA CORE")); + Test(configWildcard, c => c.IntervalSeconds, 5); + Test(configWildcard, c => c.PushGatewayUrl, ""); + } - [TestCase("^spaceneth ^volta", 50)] - [TestCase("spaceneth", 4)] - [TestCase("volta", 25)] - public void Network_defaults_are_correct(string configWildcard, int activePeers = 50) - { - Test(configWildcard, c => c.DiscoveryPort, 30303); - Test(configWildcard, c => c.P2PPort, 30303); - Test(configWildcard, c => c.ExternalIp, (string)null); - Test(configWildcard, c => c.LocalIp, (string)null); - Test(configWildcard, c => c.MaxActivePeers, activePeers); - } + [TestCase("^spaceneth ^volta", 50)] + [TestCase("spaceneth", 4)] + [TestCase("volta", 25)] + public void Network_defaults_are_correct(string configWildcard, int activePeers = 50) + { + Test(configWildcard, c => c.DiscoveryPort, 30303); + Test(configWildcard, c => c.P2PPort, 30303); + Test(configWildcard, c => c.ExternalIp, (string)null); + Test(configWildcard, c => c.LocalIp, (string)null); + Test(configWildcard, c => c.MaxActivePeers, activePeers); + } - [TestCase("*")] - public void Network_diag_tracer_disabled_by_default(string configWildcard) - { - Test(configWildcard, c => c.DiagTracerEnabled, false); - } + [TestCase("*")] + public void Network_diag_tracer_disabled_by_default(string configWildcard) + { + Test(configWildcard, c => c.DiagTracerEnabled, false); + } - [TestCase("mainnet", 2048)] - [TestCase("holesky", 1024)] - [TestCase("sepolia", 1024)] - [TestCase("gnosis", 2048)] - [TestCase("poacore", 2048)] - [TestCase("energy", 2048)] - [TestCase("chiado", 1024)] - [TestCase("^mainnet ^spaceneth ^volta ^energy ^poacore ^gnosis", 1024)] - [TestCase("spaceneth", 128)] - public void Tx_pool_defaults_are_correct(string configWildcard, int poolSize) - { - Test(configWildcard, c => c.Size, poolSize); - } + [TestCase("mainnet", 2048)] + [TestCase("holesky", 1024)] + [TestCase("sepolia", 1024)] + [TestCase("gnosis", 2048)] + [TestCase("poacore", 2048)] + [TestCase("energy", 2048)] + [TestCase("chiado", 1024)] + [TestCase("^mainnet ^spaceneth ^volta ^energy ^poacore ^gnosis", 1024)] + [TestCase("spaceneth", 128)] + public void Tx_pool_defaults_are_correct(string configWildcard, int poolSize) + { + Test(configWildcard, c => c.Size, poolSize); + } - [TestCase("spaceneth", true)] - [TestCase("gnosis", true)] - [TestCase("mainnet", true)] - [TestCase("sepolia", true)] - [TestCase("holesky", true)] - [TestCase("chiado", true)] - [TestCase("^spaceneth ^mainnet ^gnosis ^sepolia ^holesky ^chiado", false)] - public void Json_defaults_are_correct(string configWildcard, bool jsonEnabled) - { - Test(configWildcard, c => c.Enabled, jsonEnabled); - Test(configWildcard, c => c.Port, 8545); - Test(configWildcard, c => c.Host, "127.0.0.1"); - } + [TestCase("spaceneth", true)] + [TestCase("gnosis", true)] + [TestCase("mainnet", true)] + [TestCase("sepolia", true)] + [TestCase("holesky", true)] + [TestCase("chiado", true)] + [TestCase("^spaceneth ^mainnet ^gnosis ^sepolia ^holesky ^chiado", false)] + public void Json_defaults_are_correct(string configWildcard, bool jsonEnabled) + { + Test(configWildcard, c => c.Enabled, jsonEnabled); + Test(configWildcard, c => c.Port, 8545); + Test(configWildcard, c => c.Host, "127.0.0.1"); + } - [TestCase("*")] - public void Tracer_timeout_default_is_correct(string configWildcard) - { - Test(configWildcard, c => c.Timeout, 20000); - } + [TestCase("*")] + public void Tracer_timeout_default_is_correct(string configWildcard) + { + Test(configWildcard, c => c.Timeout, 20000); + } - [TestCase("^mainnet ^validators ^archive", true, true)] - [TestCase("mainnet ^fast", false, false)] - [TestCase("mainnet fast", true, true)] - [TestCase("validators", true, false)] - public void Fast_sync_settings_as_expected(string configWildcard, bool downloadBodies, bool downloadsReceipts, bool downloadHeaders = true) - { - Test(configWildcard, c => c.DownloadBodiesInFastSync, downloadBodies); - Test(configWildcard, c => c.DownloadReceiptsInFastSync, downloadsReceipts); - Test(configWildcard, c => c.DownloadHeadersInFastSync, downloadHeaders); - } + [TestCase("^mainnet ^validators ^archive", true, true)] + [TestCase("mainnet ^fast", false, false)] + [TestCase("mainnet fast", true, true)] + [TestCase("validators", true, false)] + public void Fast_sync_settings_as_expected(string configWildcard, bool downloadBodies, bool downloadsReceipts, bool downloadHeaders = true) + { + Test(configWildcard, c => c.DownloadBodiesInFastSync, downloadBodies); + Test(configWildcard, c => c.DownloadReceiptsInFastSync, downloadsReceipts); + Test(configWildcard, c => c.DownloadHeadersInFastSync, downloadHeaders); + } - [TestCase("archive", false)] - [TestCase("mainnet.cfg", true)] - [TestCase("sepolia.cfg", true)] - [TestCase("gnosis.cfg", true)] - [TestCase("chiado.cfg", true)] - [TestCase("energyweb.cfg", false)] - [TestCase("volta.cfg", false)] - public void Snap_sync_settings_as_expected(string configWildcard, bool enabled) - { - Test(configWildcard, c => c.SnapSync, enabled); - } + [TestCase("archive", false)] + [TestCase("mainnet.cfg", true)] + [TestCase("sepolia.cfg", true)] + [TestCase("gnosis.cfg", true)] + [TestCase("chiado.cfg", true)] + [TestCase("energyweb.cfg", false)] + [TestCase("volta.cfg", false)] + public void Snap_sync_settings_as_expected(string configWildcard, bool enabled) + { + Test(configWildcard, c => c.SnapSync, enabled); + } - [TestCase("^aura ^sepolia ^holesky ^mainnet", false)] - [TestCase("aura ^archive", true)] - [TestCase("^archive ^spaceneth", true)] - [TestCase("sepolia ^archive", true)] - [TestCase("holesky ^archive", true)] - [TestCase("mainnet ^archive", true)] - public void Stays_on_full_sync(string configWildcard, bool stickToFullSyncAfterFastSync) - { - Test(configWildcard, c => c.FastSyncCatchUpHeightDelta, stickToFullSyncAfterFastSync ? 10_000_000_000 : 8192); - } + [TestCase("^aura ^sepolia ^holesky ^mainnet", false)] + [TestCase("aura ^archive", true)] + [TestCase("^archive ^spaceneth", true)] + [TestCase("sepolia ^archive", true)] + [TestCase("holesky ^archive", true)] + [TestCase("mainnet ^archive", true)] + public void Stays_on_full_sync(string configWildcard, bool stickToFullSyncAfterFastSync) + { + Test(configWildcard, c => c.FastSyncCatchUpHeightDelta, stickToFullSyncAfterFastSync ? 10_000_000_000 : 8192); + } - [TestCase("^spaceneth.cfg")] - public void Diagnostics_mode_is_not_enabled_by_default(string configWildcard) - { - Test(configWildcard, c => c.DiagnosticMode, DiagnosticMode.None); - } + [TestCase("^spaceneth.cfg")] + public void Diagnostics_mode_is_not_enabled_by_default(string configWildcard) + { + Test(configWildcard, c => c.DiagnosticMode, DiagnosticMode.None); + } - [TestCase("*")] - public void Migrations_are_not_enabled_by_default(string configWildcard) - { - Test(configWildcard, c => c.ReceiptsMigration, false); - Test(configWildcard, c => c.Migration, false); - Test(configWildcard, c => c.MigrationStatistics, false); - } + [TestCase("*")] + public void Migrations_are_not_enabled_by_default(string configWildcard) + { + Test(configWildcard, c => c.ReceiptsMigration, false); + Test(configWildcard, c => c.Migration, false); + Test(configWildcard, c => c.MigrationStatistics, false); + } - [TestCase("^mainnet", 0)] - [TestCase("mainnet fast", 0)] - public void Barriers_defaults_are_correct(string configWildcard, long barrier) - { - Test(configWildcard, c => c.AncientBodiesBarrier, barrier); - Test(configWildcard, c => c.AncientReceiptsBarrier, barrier); - } + [TestCase("^mainnet", 0)] + [TestCase("mainnet fast", 0)] + public void Barriers_defaults_are_correct(string configWildcard, long barrier) + { + Test(configWildcard, c => c.AncientBodiesBarrier, barrier); + Test(configWildcard, c => c.AncientReceiptsBarrier, barrier); + } - [TestCase("^spaceneth", "nethermind_db")] - [TestCase("spaceneth", "spaceneth_db")] - public void Base_db_path_is_set(string configWildcard, string startWith) - { - Test(configWildcard, c => c.BaseDbPath, (cf, p) => p.Should().StartWith(startWith)); - } + [TestCase("^spaceneth", "nethermind_db")] + [TestCase("spaceneth", "spaceneth_db")] + public void Base_db_path_is_set(string configWildcard, string startWith) + { + Test(configWildcard, c => c.BaseDbPath, (cf, p) => p.Should().StartWith(startWith)); + } - [TestCase("^sepolia", "Data/static-nodes.json")] - [TestCase("sepolia", "Data/static-nodes-sepolia.json")] - public void Static_nodes_path_is_default(string configWildcard, string staticNodesPath) - { - Test(configWildcard, c => c.StaticNodesPath, staticNodesPath); - } + [TestCase("^sepolia", "Data/static-nodes.json")] + [TestCase("sepolia", "Data/static-nodes-sepolia.json")] + public void Static_nodes_path_is_default(string configWildcard, string staticNodesPath) + { + Test(configWildcard, c => c.StaticNodesPath, staticNodesPath); + } + + [TestCase("^validators", true)] + [TestCase("validators", false)] + public void Stores_receipts(string configWildcard, bool storeReceipts) + { + Test(configWildcard, c => c.StoreReceipts, storeReceipts); + } - [TestCase("^validators", true)] - [TestCase("validators", false)] - public void Stores_receipts(string configWildcard, bool storeReceipts) + [TestCase("mainnet_archive.cfg", true)] + [TestCase("mainnet.cfg", true)] + [TestCase("poacore", true)] + [TestCase("gnosis", true)] + [TestCase("volta", false)] + public void Basic_configs_are_as_expected(string configWildcard, bool isProduction = false) + { + Test(configWildcard, c => c.DiscoveryEnabled, true); + Test(configWildcard, c => c.ProcessingEnabled, true); + Test(configWildcard, c => c.WebSocketsEnabled, true); + Test(configWildcard, c => c.PeerManagerEnabled, true); + Test(configWildcard, c => c.KeepDevWalletInMemory, false); + + if (isProduction) { - Test(configWildcard, c => c.StoreReceipts, storeReceipts); + Test(configWildcard, c => c.EnableUnsecuredDevWallet, false); } - [TestCase("mainnet_archive.cfg", true)] - [TestCase("mainnet.cfg", true)] - [TestCase("poacore", true)] - [TestCase("gnosis", true)] - [TestCase("volta", false)] - public void Basic_configs_are_as_expected(string configWildcard, bool isProduction = false) - { - Test(configWildcard, c => c.DiscoveryEnabled, true); - Test(configWildcard, c => c.ProcessingEnabled, true); - Test(configWildcard, c => c.WebSocketsEnabled, true); - Test(configWildcard, c => c.PeerManagerEnabled, true); - Test(configWildcard, c => c.KeepDevWalletInMemory, false); + Test(configWildcard, c => c.LogFileName, (cf, p) => p.Should().Be(cf.Replace("cfg", "logs.txt"), cf)); + } - if (isProduction) - { - Test(configWildcard, c => c.EnableUnsecuredDevWallet, false); - } + [TestCase("*")] + public void Simulating_block_production_on_every_slot_is_always_disabled(string configWildcard) + { + Test(configWildcard, c => c.SimulateBlockProduction, false); + } - Test(configWildcard, c => c.LogFileName, (cf, p) => p.Should().Be(cf.Replace("cfg", "logs.txt"), cf)); - } + [TestCase("sepolia", BlobsSupportMode.StorageWithReorgs)] + [TestCase("holesky", BlobsSupportMode.StorageWithReorgs)] + [TestCase("chiado", BlobsSupportMode.StorageWithReorgs)] + [TestCase("mainnet", BlobsSupportMode.StorageWithReorgs)] + [TestCase("gnosis", BlobsSupportMode.StorageWithReorgs)] + [TestCase("^sepolia ^holesky ^chiado ^mainnet ^gnosis", BlobsSupportMode.Disabled)] + public void Blob_txs_support_is_correct(string configWildcard, BlobsSupportMode blobsSupportMode) + { + Test(configWildcard, c => c.BlobsSupport, blobsSupportMode); + } - [TestCase("*")] - public void Simulating_block_production_on_every_slot_is_always_disabled(string configWildcard) - { - Test(configWildcard, c => c.SimulateBlockProduction, false); - } - [TestCase("sepolia", BlobsSupportMode.StorageWithReorgs)] - [TestCase("holesky", BlobsSupportMode.StorageWithReorgs)] - [TestCase("chiado", BlobsSupportMode.StorageWithReorgs)] - [TestCase("mainnet", BlobsSupportMode.StorageWithReorgs)] - [TestCase("gnosis", BlobsSupportMode.StorageWithReorgs)] - [TestCase("^sepolia ^holesky ^chiado ^mainnet ^gnosis", BlobsSupportMode.Disabled)] - public void Blob_txs_support_is_correct(string configWildcard, BlobsSupportMode blobsSupportMode) - { - Test(configWildcard, c => c.BlobsSupport, blobsSupportMode); - } + [TestCase("mainnet")] + [TestCase("poacore.cfg", new[] { 16, 16, 16, 16 })] + [TestCase("poacore_archive.cfg", new[] { 16, 16, 16, 16 })] + [TestCase("poacore_validator.cfg", null, false)] + [TestCase("gnosis.cfg", new[] { 16, 16, 16 })] + [TestCase("gnosis_archive.cfg", new[] { 16, 16, 16 })] + [TestCase("volta")] + public void Bloom_configs_are_as_expected(string configWildcard, int[] levels = null, bool index = true) + { + Test(configWildcard, c => c.Index, index); + Test(configWildcard, c => c.Migration, false); + Test(configWildcard, c => c.MigrationStatistics, false); + Test(configWildcard, c => c.IndexLevelBucketSizes, (cf, p) => p.Should().BeEquivalentTo(levels ?? new BloomConfig().IndexLevelBucketSizes)); + } + [TestCase("*")] + public void BufferResponses_rpc_is_off(string configWildcard) + { + Test(configWildcard, c => c.BufferResponses, false); + } - [TestCase("mainnet")] - [TestCase("poacore.cfg", new[] { 16, 16, 16, 16 })] - [TestCase("poacore_archive.cfg", new[] { 16, 16, 16, 16 })] - [TestCase("poacore_validator.cfg", null, false)] - [TestCase("gnosis.cfg", new[] { 16, 16, 16 })] - [TestCase("gnosis_archive.cfg", new[] { 16, 16, 16 })] - [TestCase("volta")] - public void Bloom_configs_are_as_expected(string configWildcard, int[] levels = null, bool index = true) - { - Test(configWildcard, c => c.Index, index); - Test(configWildcard, c => c.Migration, false); - Test(configWildcard, c => c.MigrationStatistics, false); - Test(configWildcard, c => c.IndexLevelBucketSizes, (cf, p) => p.Should().BeEquivalentTo(levels ?? new BloomConfig().IndexLevelBucketSizes)); - } + [TestCase("*")] + public void Arena_order_is_default(string configWildcard) + { + Test(configWildcard, c => c.NettyArenaOrder, -1); + } - [TestCase("*")] - public void BufferResponses_rpc_is_off(string configWildcard) - { - Test(configWildcard, c => c.BufferResponses, false); - } + [TestCase("chiado", 17_000_000L, 5UL, 3000)] + [TestCase("gnosis", 17_000_000L, 5UL, 3000)] + [TestCase("mainnet", 30_000_000L)] + [TestCase("sepolia", 30_000_000L)] + [TestCase("holesky", 30_000_000L)] + [TestCase("^chiado ^gnosis ^mainnet ^sepolia ^holesky")] + public void Blocks_defaults_are_correct(string configWildcard, long? targetBlockGasLimit = null, ulong secondsPerSlot = 12, int blockProductionTimeout = 4000) + { + Test(configWildcard, c => c.TargetBlockGasLimit, targetBlockGasLimit); + Test(configWildcard, c => c.SecondsPerSlot, secondsPerSlot); + Test(configWildcard, c => c.BlockProductionTimeoutMs, blockProductionTimeout); - [TestCase("*")] - public void Arena_order_is_default(string configWildcard) - { - Test(configWildcard, c => c.NettyArenaOrder, -1); - } + } - [TestCase("chiado", 17_000_000L, 5UL, 3000)] - [TestCase("gnosis", 17_000_000L, 5UL, 3000)] - [TestCase("mainnet", 30_000_000L)] - [TestCase("sepolia", 30_000_000L)] - [TestCase("holesky", 30_000_000L)] - [TestCase("^chiado ^gnosis ^mainnet ^sepolia ^holesky")] - public void Blocks_defaults_are_correct(string configWildcard, long? targetBlockGasLimit = null, ulong secondsPerSlot = 12, int blockProductionTimeout = 4000) - { - Test(configWildcard, c => c.TargetBlockGasLimit, targetBlockGasLimit); - Test(configWildcard, c => c.SecondsPerSlot, secondsPerSlot); - Test(configWildcard, c => c.BlockProductionTimeoutMs, blockProductionTimeout); + [Test] + public void No_additional_commas_in_config_files() + { + char pathSeparator = Path.AltDirectorySeparatorChar; + string configDirectory = $"{AppDomain.CurrentDomain.BaseDirectory}{pathSeparator}configs"; - } + IEnumerable filesPaths = Directory.EnumerateFiles(configDirectory); - [Test] - public void No_additional_commas_in_config_files() + foreach (string filePath in filesPaths) { - char pathSeparator = Path.AltDirectorySeparatorChar; - string configDirectory = $"{AppDomain.CurrentDomain.BaseDirectory}{pathSeparator}configs"; + string content = File.ReadAllText(filePath) + .Replace("\n", string.Empty) + .Replace(" ", string.Empty); - IEnumerable filesPaths = Directory.EnumerateFiles(configDirectory); + IEnumerable commaIndexes = AllIndexesOf(content, ","); - foreach (string filePath in filesPaths) + foreach (int commaIndex in commaIndexes) { - string content = File.ReadAllText(filePath) - .Replace("\n", string.Empty) - .Replace(" ", string.Empty); - - IEnumerable commaIndexes = AllIndexesOf(content, ","); - - foreach (int commaIndex in commaIndexes) - { - var nextChar = content.ElementAt(commaIndex + 1); - Assert.That(nextChar, Is.Not.EqualTo('}'), $"Additional comma found in {filePath}"); - } + var nextChar = content.ElementAt(commaIndex + 1); + Assert.That(nextChar, Is.Not.EqualTo('}'), $"Additional comma found in {filePath}"); } } + } - [TestCase("*")] - public void Memory_hint_is_enough(string configWildcard) + [TestCase("*")] + public void Memory_hint_is_enough(string configWildcard) + { + foreach (TestConfigProvider configProvider in GetConfigProviders(configWildcard)) { - foreach (TestConfigProvider configProvider in GetConfigProviders(configWildcard)) - { - MemoryHintMan memoryHintMan = new(LimboLogs.Instance); - memoryHintMan.SetMemoryAllowances( - configProvider.GetConfig(), - configProvider.GetConfig(), - configProvider.GetConfig(), - configProvider.GetConfig(), - configProvider.GetConfig(), - (uint)Environment.ProcessorCount); - } + MemoryHintMan memoryHintMan = new(LimboLogs.Instance); + memoryHintMan.SetMemoryAllowances( + configProvider.GetConfig(), + configProvider.GetConfig(), + configProvider.GetConfig(), + configProvider.GetConfig(), + configProvider.GetConfig(), + (uint)Environment.ProcessorCount); } + } - protected override IEnumerable Configs { get; } = new HashSet - { - "holesky.cfg", - "holesky_archive.cfg", - "mainnet_archive.cfg", - "mainnet.cfg", - "poacore.cfg", - "poacore_archive.cfg", - "gnosis.cfg", - "gnosis_archive.cfg", - "spaceneth.cfg", - "spaceneth_persistent.cfg", - "volta.cfg", - "volta_archive.cfg", - "energyweb.cfg", - "energyweb_archive.cfg", - "sepolia.cfg", - "sepolia_archive.cfg", - "chiado.cfg", - "chiado_archive.cfg", - }; - - public IEnumerable AllIndexesOf(string str, string searchString) + protected override IEnumerable Configs { get; } = new HashSet + { + "holesky.cfg", + "holesky_archive.cfg", + "mainnet_archive.cfg", + "mainnet.cfg", + "poacore.cfg", + "poacore_archive.cfg", + "gnosis.cfg", + "gnosis_archive.cfg", + "spaceneth.cfg", + "spaceneth_persistent.cfg", + "volta.cfg", + "volta_archive.cfg", + "energyweb.cfg", + "energyweb_archive.cfg", + "sepolia.cfg", + "sepolia_archive.cfg", + "chiado.cfg", + "chiado_archive.cfg", + }; + + public IEnumerable AllIndexesOf(string str, string searchString) + { + int minIndex = str.IndexOf(searchString); + while (minIndex != -1) { - int minIndex = str.IndexOf(searchString); - while (minIndex != -1) - { - yield return minIndex; - minIndex = str.IndexOf(searchString, minIndex + searchString.Length); - } + yield return minIndex; + minIndex = str.IndexOf(searchString, minIndex + searchString.Length); } } } diff --git a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs index 680ca5d4de9..2b2c1afbcf9 100644 --- a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs @@ -26,161 +26,139 @@ using Nethermind.Runner.Ethereum.Api; using Nethermind.TxPool; using NUnit.Framework; -using LogLevel = NLog.LogLevel; -using Nethermind.Serialization.Json; -namespace Nethermind.Runner.Test +namespace Nethermind.Runner.Test; + +[TestFixture, Parallelizable(ParallelScope.All)] +public class EthereumRunnerTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class EthereumRunnerTests + static EthereumRunnerTests() { - static EthereumRunnerTests() + AssemblyLoadContext.Default.Resolving += (context, name) => { - AssemblyLoadContext.Default.Resolving += (context, name) => - { - return null; - }; - } + return null; + }; + } - private static readonly Lazy? _cachedProviders = new(InitOnce); + private static readonly Lazy? _cachedProviders = new(InitOnce); - private static ICollection InitOnce() + private static ICollection InitOnce() + { + // by pre-caching configs providers we make the tests do lot less work + ConcurrentQueue<(string, ConfigProvider)> result = new(); + Parallel.ForEach(Directory.GetFiles("configs"), configFile => { - // by pre-caching configs providers we make the tests do lot less work - ConcurrentQueue<(string, ConfigProvider)> result = new(); - Parallel.ForEach(Directory.GetFiles("configs"), configFile => - { - var configProvider = new ConfigProvider(); - configProvider.AddSource(new JsonConfigSource(configFile)); - configProvider.Initialize(); - result.Enqueue((configFile, configProvider)); - }); + var configProvider = new ConfigProvider(); + configProvider.AddSource(new JsonConfigSource(configFile)); + configProvider.Initialize(); + result.Enqueue((configFile, configProvider)); + }); - return result; - } + return result; + } - public static IEnumerable ChainSpecRunnerTests + public static IEnumerable ChainSpecRunnerTests + { + get { - get + int index = 0; + foreach (var cachedProvider in _cachedProviders!.Value) { - int index = 0; - foreach (var cachedProvider in _cachedProviders!.Value) - { - yield return new TestCaseData(cachedProvider, index); - index++; - } + yield return new TestCaseData(cachedProvider, index); + index++; } } + } - [TestCaseSource(nameof(ChainSpecRunnerTests))] - [Timeout(300000)] // just to make sure we are not on infinite loop on steps because of incorrect dependencies - public async Task Smoke((string file, ConfigProvider configProvider) testCase, int testIndex) + [TestCaseSource(nameof(ChainSpecRunnerTests))] + [MaxTime(300000)] // just to make sure we are not on infinite loop on steps because of incorrect dependencies + public async Task Smoke((string file, ConfigProvider configProvider) testCase, int testIndex) + { + if (testCase.configProvider is null) { - if (testCase.configProvider is null) - { - // some weird thing, not worth investigating - return; - } - - await SmokeTest(testCase.configProvider, testIndex, 30330); + // some weird thing, not worth investigating + return; } - [TestCaseSource(nameof(ChainSpecRunnerTests))] - [Timeout(30000)] // just to make sure we are not on infinite loop on steps because of incorrect dependencies - public async Task Smoke_cancel((string file, ConfigProvider configProvider) testCase, int testIndex) - { - if (testCase.configProvider is null) - { - // some weird thing, not worth investigating - return; - } + await SmokeTest(testCase.configProvider, testIndex, 30330); + } - await SmokeTest(testCase.configProvider, testIndex, 30430, true); + [TestCaseSource(nameof(ChainSpecRunnerTests))] + [MaxTime(30000)] // just to make sure we are not on infinite loop on steps because of incorrect dependencies + public async Task Smoke_cancel((string file, ConfigProvider configProvider) testCase, int testIndex) + { + if (testCase.configProvider is null) + { + // some weird thing, not worth investigating + return; } - private static async Task SmokeTest(ConfigProvider configProvider, int testIndex, int basePort, bool cancel = false) + await SmokeTest(testCase.configProvider, testIndex, 30430, true); + } + + private static async Task SmokeTest(ConfigProvider configProvider, int testIndex, int basePort, bool cancel = false) + { + Type type1 = typeof(ITxPoolConfig); + Type type2 = typeof(INetworkConfig); + Type type3 = typeof(IKeyStoreConfig); + Type type4 = typeof(IDbConfig); + Type type7 = typeof(IEthStatsConfig); + Type type8 = typeof(ISyncConfig); + Type type9 = typeof(IBloomConfig); + + Console.WriteLine(type1.Name); + Console.WriteLine(type2.Name); + Console.WriteLine(type3.Name); + Console.WriteLine(type4.Name); + Console.WriteLine(type7.Name); + Console.WriteLine(type8.Name); + Console.WriteLine(type9.Name); + + var tempPath = TempPath.GetTempDirectory(); + Directory.CreateDirectory(tempPath.Path); + + Exception? exception = null; + try { - Type type1 = typeof(ITxPoolConfig); - Type type2 = typeof(INetworkConfig); - Type type3 = typeof(IKeyStoreConfig); - Type type4 = typeof(IDbConfig); - Type type7 = typeof(IEthStatsConfig); - Type type8 = typeof(ISyncConfig); - Type type9 = typeof(IBloomConfig); - - Console.WriteLine(type1.Name); - Console.WriteLine(type2.Name); - Console.WriteLine(type3.Name); - Console.WriteLine(type4.Name); - Console.WriteLine(type7.Name); - Console.WriteLine(type8.Name); - Console.WriteLine(type9.Name); - - var tempPath = TempPath.GetTempDirectory(); - Directory.CreateDirectory(tempPath.Path); - - Exception? exception = null; - try - { - IInitConfig initConfig = configProvider.GetConfig(); - initConfig.BaseDbPath = tempPath.Path; + IInitConfig initConfig = configProvider.GetConfig(); + initConfig.BaseDbPath = tempPath.Path; - INetworkConfig networkConfig = configProvider.GetConfig(); - int port = basePort + testIndex; - networkConfig.P2PPort = port; - networkConfig.DiscoveryPort = port; + INetworkConfig networkConfig = configProvider.GetConfig(); + int port = basePort + testIndex; + networkConfig.P2PPort = port; + networkConfig.DiscoveryPort = port; - INethermindApi nethermindApi = new ApiBuilder(configProvider, LimboLogs.Instance).Create(); - nethermindApi.RpcModuleProvider = new RpcModuleProvider(new FileSystem(), new JsonRpcConfig(), LimboLogs.Instance); - EthereumRunner runner = new(nethermindApi); + INethermindApi nethermindApi = new ApiBuilder(configProvider, LimboLogs.Instance).Create(); + nethermindApi.RpcModuleProvider = new RpcModuleProvider(new FileSystem(), new JsonRpcConfig(), LimboLogs.Instance); + EthereumRunner runner = new(nethermindApi); - using CancellationTokenSource cts = new(); + using CancellationTokenSource cts = new(); - try - { - Task task = runner.Start(cts.Token); - if (cancel) - { - cts.Cancel(); - } - - await task; - } - catch (Exception e) - { - exception = e; - } - finally + try + { + Task task = runner.Start(cts.Token); + if (cancel) { - try - { - await runner.StopAsync(); - } - catch (Exception e) - { - if (exception is not null) - { - await TestContext.Error.WriteLineAsync(e.ToString()); - } - else - { - throw; - } - } + cts.Cancel(); } + + await task; + } + catch (Exception e) + { + exception = e; } finally { try { - tempPath.Dispose(); + await runner.StopAsync(); } - catch + catch (Exception e) { if (exception is not null) { - // just swallow this exception as otherwise this is recognized as a pattern byt GitHub - // await TestContext.Error.WriteLineAsync(e.ToString()); + await TestContext.Error.WriteLineAsync(e.ToString()); } else { @@ -189,5 +167,24 @@ private static async Task SmokeTest(ConfigProvider configProvider, int testIndex } } } + finally + { + try + { + tempPath.Dispose(); + } + catch + { + if (exception is not null) + { + // just swallow this exception as otherwise this is recognized as a pattern byt GitHub + // await TestContext.Error.WriteLineAsync(e.ToString()); + } + else + { + throw; + } + } + } } } diff --git a/src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs b/src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs index 5d99dafc40a..dfa6ff5867b 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs @@ -199,9 +199,9 @@ public void Can_merkleize_bytes32() // ) // ); - // TestContext.WriteLine("root: {0:x}", root); - // TestContext.WriteLine("bytes: {0}", bytes.ToHexString(true)); - // TestContext.WriteLine("expected: {0}", expected.ToHexString(true)); + // TestContext.Out.WriteLine("root: {0:x}", root); + // TestContext.Out.WriteLine("bytes: {0}", bytes.ToHexString(true)); + // TestContext.Out.WriteLine("expected: {0}", expected.ToHexString(true)); // bytes.ToArray().ShouldBe(expected); //} @@ -229,9 +229,9 @@ public void Can_merkleize_bytes32() // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); // Merkle.Ize(out UInt256 root0, depositDataList[0]); - // TestContext.WriteLine("root0: {0:x}", root0); + // TestContext.Out.WriteLine("root0: {0:x}", root0); // Merkle.Ize(out UInt256 root1, depositDataList[1]); - // TestContext.WriteLine("root1: {0:x}", root1); + // TestContext.Out.WriteLine("root1: {0:x}", root1); // // assert // byte[] hash1 = HashUtility.Hash( @@ -279,8 +279,8 @@ public void Can_merkleize_bytes32() // ) // ); - // TestContext.WriteLine("Hash1: {0}", Bytes.ToHexString(hash1, true)); - // TestContext.WriteLine("Hash2: {0}", Bytes.ToHexString(hash2, true)); + // TestContext.Out.WriteLine("Hash1: {0}", Bytes.ToHexString(hash1, true)); + // TestContext.Out.WriteLine("Hash2: {0}", Bytes.ToHexString(hash2, true)); // byte[] hashList = HashUtility.Merge( // list, depth 32 // HashUtility.Hash( @@ -289,13 +289,13 @@ public void Can_merkleize_bytes32() // ), // HashUtility.ZeroHashes(1, 32) // ).ToArray(); - // TestContext.WriteLine("Hash list: {0}", Bytes.ToHexString(hashList, true)); + // TestContext.Out.WriteLine("Hash list: {0}", Bytes.ToHexString(hashList, true)); // byte[] expected = HashUtility.Hash( // hashList, // HashUtility.Chunk(new byte[] { 0x02 }) // mix in length // ); - // TestContext.WriteLine("Hash expected: {0}", Bytes.ToHexString(expected, true)); + // TestContext.Out.WriteLine("Hash expected: {0}", Bytes.ToHexString(expected, true)); // bytes.ToArray().ShouldBe(expected); //} @@ -344,9 +344,9 @@ public void Can_merkleize_bytes32() // ) // ); // - // TestContext.WriteLine("root: {0:x}", root); - // TestContext.WriteLine("bytes: {0}", bytes.ToHexString(true)); - // TestContext.WriteLine("expected: {0}", expected.ToHexString(true)); + // TestContext.Out.WriteLine("root: {0:x}", root); + // TestContext.Out.WriteLine("bytes: {0}", bytes.ToHexString(true)); + // TestContext.Out.WriteLine("expected: {0}", expected.ToHexString(true)); // // bytes.ToArray().ShouldBe(expected); // } diff --git a/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs b/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs index 2088abac567..b54165083e5 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs @@ -7,299 +7,298 @@ using Nethermind.Merkleization; using NUnit.Framework; -namespace Nethermind.Serialization.Ssz.Test +namespace Nethermind.Serialization.Ssz.Test; + +public static class UInt256Extensions { - public static class UInt256Extensions + public static string ToHexString(this UInt256 @this, bool withZeroX) { - public static string ToHexString(this UInt256 @this, bool withZeroX) - { - Span bytes = stackalloc byte[32]; - @this.ToLittleEndian(bytes); - return bytes.ToHexString(withZeroX); - } + Span bytes = stackalloc byte[32]; + @this.ToLittleEndian(bytes); + return bytes.ToHexString(withZeroX); } +} - [TestFixture] - public class MerkleTests +[TestFixture] +public class MerkleTests +{ + [TestCase(uint.MinValue, 1U)] + [TestCase(1U, 1U)] + [TestCase(2U, 2U)] + [TestCase(3U, 4U)] + [TestCase(4U, 4U)] + [TestCase(uint.MaxValue / 2, 2147483648U)] + [TestCase(uint.MaxValue / 2 + 1, 2147483648U)] + public void Can_get_the_next_power_of_two_32(uint value, uint expectedResult) { - [TestCase(uint.MinValue, 1U)] - [TestCase(1U, 1U)] - [TestCase(2U, 2U)] - [TestCase(3U, 4U)] - [TestCase(4U, 4U)] - [TestCase(uint.MaxValue / 2, 2147483648U)] - [TestCase(uint.MaxValue / 2 + 1, 2147483648U)] - public void Can_get_the_next_power_of_two_32(uint value, uint expectedResult) - { - Assert.That(Merkle.NextPowerOfTwo(value), Is.EqualTo(expectedResult)); - } + Assert.That(Merkle.NextPowerOfTwo(value), Is.EqualTo(expectedResult)); + } - [TestCase(ulong.MinValue, 1UL)] - [TestCase(1UL, 1UL)] - [TestCase(2UL, 2UL)] - [TestCase(3UL, 4UL)] - [TestCase(4UL, 4UL)] - [TestCase(ulong.MaxValue / 2, 9223372036854775808UL)] - [TestCase(ulong.MaxValue / 2 + 1, 9223372036854775808UL)] - public void Can_get_the_next_power_of_two_64(ulong value, ulong expectedResult) - { - Assert.That(Merkle.NextPowerOfTwo(value), Is.EqualTo(expectedResult)); - } + [TestCase(ulong.MinValue, 1UL)] + [TestCase(1UL, 1UL)] + [TestCase(2UL, 2UL)] + [TestCase(3UL, 4UL)] + [TestCase(4UL, 4UL)] + [TestCase(ulong.MaxValue / 2, 9223372036854775808UL)] + [TestCase(ulong.MaxValue / 2 + 1, 9223372036854775808UL)] + public void Can_get_the_next_power_of_two_64(ulong value, ulong expectedResult) + { + Assert.That(Merkle.NextPowerOfTwo(value), Is.EqualTo(expectedResult)); + } - [TestCase(ulong.MinValue, 0UL)] - [TestCase(1UL, 0UL)] - [TestCase(2UL, 1UL)] - [TestCase(3UL, 2UL)] - [TestCase(4UL, 2UL)] - [TestCase(ulong.MaxValue / 2, 63UL)] - [TestCase(ulong.MaxValue / 2 + 1, 63UL)] - public void Can_get_the_next_power_of_two_exponent(ulong value, ulong expectedResult) - { - Assert.That(Merkle.NextPowerOfTwoExponent(value), Is.EqualTo(expectedResult)); - } + [TestCase(ulong.MinValue, 0UL)] + [TestCase(1UL, 0UL)] + [TestCase(2UL, 1UL)] + [TestCase(3UL, 2UL)] + [TestCase(4UL, 2UL)] + [TestCase(ulong.MaxValue / 2, 63UL)] + [TestCase(ulong.MaxValue / 2 + 1, 63UL)] + public void Can_get_the_next_power_of_two_exponent(ulong value, ulong expectedResult) + { + Assert.That(Merkle.NextPowerOfTwoExponent(value), Is.EqualTo(expectedResult)); + } - [Test] - public void Zero_hashes_0_is_correct() - { - Assert.That(Merkle.ZeroHashes[0], Is.EqualTo(UInt256.Zero)); - } + [Test] + public void Zero_hashes_0_is_correct() + { + Assert.That(Merkle.ZeroHashes[0], Is.EqualTo(UInt256.Zero)); + } - [Test] - public void Can_merkleize_bool() - { - Merkle.Ize(out UInt256 root, true); - Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_bool() + { + Merkle.Ize(out UInt256 root, true); + Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_byte() - { - Merkle.Ize(out UInt256 root, (byte)34); - Assert.That(root.ToHexString(true), Is.EqualTo("0x2200000000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_byte() + { + Merkle.Ize(out UInt256 root, (byte)34); + Assert.That(root.ToHexString(true), Is.EqualTo("0x2200000000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_ushort() - { - Merkle.Ize(out UInt256 root, (ushort)(34 + byte.MaxValue)); - Assert.That(root.ToHexString(true), Is.EqualTo("0x2101000000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_ushort() + { + Merkle.Ize(out UInt256 root, (ushort)(34 + byte.MaxValue)); + Assert.That(root.ToHexString(true), Is.EqualTo("0x2101000000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_uint() - { - Merkle.Ize(out UInt256 root, (uint)34 + byte.MaxValue + ushort.MaxValue); - Assert.That(root.ToHexString(true), Is.EqualTo("0x2001010000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_uint() + { + Merkle.Ize(out UInt256 root, (uint)34 + byte.MaxValue + ushort.MaxValue); + Assert.That(root.ToHexString(true), Is.EqualTo("0x2001010000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_int() - { - Merkle.Ize(out UInt256 root, 34 + byte.MaxValue + ushort.MaxValue); - Assert.That(root.ToHexString(true), Is.EqualTo("0x2001010000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_int() + { + Merkle.Ize(out UInt256 root, 34 + byte.MaxValue + ushort.MaxValue); + Assert.That(root.ToHexString(true), Is.EqualTo("0x2001010000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_ulong() - { - Merkle.Ize(out UInt256 root, (ulong)34 + byte.MaxValue + ushort.MaxValue + uint.MaxValue); - Assert.That(root.ToHexString(true), Is.EqualTo("0x1f01010001000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_ulong() + { + Merkle.Ize(out UInt256 root, (ulong)34 + byte.MaxValue + ushort.MaxValue + uint.MaxValue); + Assert.That(root.ToHexString(true), Is.EqualTo("0x1f01010001000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_uint128() - { - UInt128 input = UInt128.Zero; - input += 34; - input += byte.MaxValue; - input += ushort.MaxValue; - input += uint.MaxValue; - input += ulong.MaxValue; - - Merkle.Ize(out UInt256 root, input); - Assert.That(root.ToHexString(true), Is.EqualTo("0x1e01010001000000010000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_uint128() + { + UInt128 input = UInt128.Zero; + input += 34; + input += byte.MaxValue; + input += ushort.MaxValue; + input += uint.MaxValue; + input += ulong.MaxValue; + + Merkle.Ize(out UInt256 root, input); + Assert.That(root.ToHexString(true), Is.EqualTo("0x1e01010001000000010000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_uint256() - { - UInt256 input = UInt256.Zero; - input += 34; - input += byte.MaxValue; - input += ushort.MaxValue; - input += uint.MaxValue; - input += ulong.MaxValue; - - Merkle.Ize(out UInt256 root, input); - Assert.That(root.ToHexString(true), Is.EqualTo("0x1e01010001000000010000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_uint256() + { + UInt256 input = UInt256.Zero; + input += 34; + input += byte.MaxValue; + input += ushort.MaxValue; + input += uint.MaxValue; + input += ulong.MaxValue; + + Merkle.Ize(out UInt256 root, input); + Assert.That(root.ToHexString(true), Is.EqualTo("0x1e01010001000000010000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_bool_vector() - { - Merkle.Ize(out UInt256 root, new[] { true, false }); - Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_bool_vector() + { + Merkle.Ize(out UInt256 root, new[] { true, false }); + Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_ushort_vector() - { - Merkle.Ize(out UInt256 root, new[] { (ushort)1, (ushort)3 }); - Assert.That(root.ToHexString(true), Is.EqualTo("0x0100030000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_ushort_vector() + { + Merkle.Ize(out UInt256 root, new[] { (ushort)1, (ushort)3 }); + Assert.That(root.ToHexString(true), Is.EqualTo("0x0100030000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_uint_vector() - { - Merkle.Ize(out UInt256 root, new[] { 1U, 3U }); - Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000003000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_uint_vector() + { + Merkle.Ize(out UInt256 root, new[] { 1U, 3U }); + Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000003000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_ulong_vector() - { - Merkle.Ize(out UInt256 root, new[] { 1UL, 3UL }); - Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000030000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_ulong_vector() + { + Merkle.Ize(out UInt256 root, new[] { 1UL, 3UL }); + Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000030000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_uint128_vector() - { - Merkle.Ize(out UInt256 root, new UInt128[] { 1, 3, 5 }); - Assert.That(root.ToHexString(true), Is.EqualTo("0xf189891181de961f99a35c1aa21c0d909bf30bb8bebb760050f3d06dc56e488a")); - } + [Test] + public void Can_merkleize_uint128_vector() + { + Merkle.Ize(out UInt256 root, new UInt128[] { 1, 3, 5 }); + Assert.That(root.ToHexString(true), Is.EqualTo("0xf189891181de961f99a35c1aa21c0d909bf30bb8bebb760050f3d06dc56e488a")); + } - [Test] - public void Can_merkleize_uint256_vector() - { - Merkle.Ize(out UInt256 root, new UInt256[] { 1 }); - Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_uint256_vector() + { + Merkle.Ize(out UInt256 root, new UInt256[] { 1 }); + Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_uint256_vector_longer() - { - Merkle.Ize(out UInt256 root, new UInt256[] { 1, 2, 3, 4 }); - Assert.That(root.ToHexString(true), Is.EqualTo("0xbfe3c665d2e561f13b30606c580cb703b2041287e212ade110f0bfd8563e21bb")); - } + [Test] + public void Can_merkleize_uint256_vector_longer() + { + Merkle.Ize(out UInt256 root, new UInt256[] { 1, 2, 3, 4 }); + Assert.That(root.ToHexString(true), Is.EqualTo("0xbfe3c665d2e561f13b30606c580cb703b2041287e212ade110f0bfd8563e21bb")); + } - [Test] - public void Can_merkleize_uint128_vector_full() - { - Merkle.Ize(out UInt256 root, new UInt128[] { 1, 3 }); - Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000003000000000000000000000000000000")); - } + [Test] + public void Can_merkleize_uint128_vector_full() + { + Merkle.Ize(out UInt256 root, new UInt128[] { 1, 3 }); + Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000003000000000000000000000000000000")); + } - [Test] - public void Can_merkleize_bitlist() - { - Merkle.IzeBits(out UInt256 root, new byte[] { 123 }, 0); - Assert.That(root.ToHexString(true), Is.EqualTo("0xe5e12694be373406e317c583b5fd9e7a642913dc20a5c4947edb202dafbbc0ee")); - } + [Test] + public void Can_merkleize_bitlist() + { + Merkle.IzeBits(out UInt256 root, new byte[] { 123 }, 0); + Assert.That(root.ToHexString(true), Is.EqualTo("0xe5e12694be373406e317c583b5fd9e7a642913dc20a5c4947edb202dafbbc0ee")); + } - [Test] - public void Can_merkleize_bitlist_with_limit() - { - Merkle.IzeBits(out UInt256 root, new byte[] { 17 }, 2); - Assert.That(root.ToHexString(true), Is.EqualTo("0x60d461bd1cec1a858ba48a27799c9686c15ad1625743bafa70674afc530f981a")); - } + [Test] + public void Can_merkleize_bitlist_with_limit() + { + Merkle.IzeBits(out UInt256 root, new byte[] { 17 }, 2); + Assert.That(root.ToHexString(true), Is.EqualTo("0x60d461bd1cec1a858ba48a27799c9686c15ad1625743bafa70674afc530f981a")); + } - [Test] - public void Can_merkleize_bitlist_high_limit_and_null() - { - Merkle.IzeBits(out UInt256 root, new byte[] { 0 }, 8); - Assert.That(root.ToHexString(true), Is.EqualTo("0x881690bb860e3a4f7681f51f1eccc59dac2718eeb0c0585cd698ad0650938b33")); - } + [Test] + public void Can_merkleize_bitlist_high_limit_and_null() + { + Merkle.IzeBits(out UInt256 root, new byte[] { 0 }, 8); + Assert.That(root.ToHexString(true), Is.EqualTo("0x881690bb860e3a4f7681f51f1eccc59dac2718eeb0c0585cd698ad0650938b33")); + } - [Test] - public void Can_merkleize_bitlist_high_limit_and_small() - { - Merkle.IzeBits(out UInt256 root, new byte[] { 3 }, 8); - Assert.That(root.ToHexString(true), Is.EqualTo("0x9e1ff035a32c3d3085074e676356984c077f70bed47814956a9ef8852dcb8161")); - } + [Test] + public void Can_merkleize_bitlist_high_limit_and_small() + { + Merkle.IzeBits(out UInt256 root, new byte[] { 3 }, 8); + Assert.That(root.ToHexString(true), Is.EqualTo("0x9e1ff035a32c3d3085074e676356984c077f70bed47814956a9ef8852dcb8161")); + } - [Test] - public void Can_merkleize_bitvector() + [Test] + public void Can_merkleize_bitvector() + { + Merkle.Ize(out UInt256 root, new byte[] { 123 }); + Assert.That(root.ToHexString(true), Is.EqualTo("0x7b00000000000000000000000000000000000000000000000000000000000000")); + } + + [Test] + public void Set_check() + { + Merkleizer context = new Merkleizer(1); + for (int i = 0; i < 64; i++) { - Merkle.Ize(out UInt256 root, new byte[] { 123 }); - Assert.That(root.ToHexString(true), Is.EqualTo("0x7b00000000000000000000000000000000000000000000000000000000000000")); + context.SetKthBit(i); + Assert.That(context.IsKthBitSet(i), Is.True, i.ToString()); + context.UnsetKthBit(i); + Assert.That(context.IsKthBitSet(i), Is.False, i.ToString()); } + } - [Test] - public void Set_check() + [Test] + public void Check_false() + { + Merkleizer context = new Merkleizer(1); + for (int i = 0; i < 64; i++) { - Merkleizer context = new Merkleizer(1); - for (int i = 0; i < 64; i++) - { - context.SetKthBit(i); - Assert.True(context.IsKthBitSet(i), i.ToString()); - context.UnsetKthBit(i); - Assert.False(context.IsKthBitSet(i), i.ToString()); - } + Assert.That(context.IsKthBitSet(i), Is.False, i.ToString()); } + } - [Test] - public void Check_false() + [TestCase(2, 1)] + [TestCase(4, 2)] + [TestCase(8, 3)] + [TestCase(16, 4)] + [TestCase(32, 5)] + [TestCase(64, 6)] + public void Feed_test(int leafs, int depth) + { + Merkleizer merkleizer = new Merkleizer(depth); + for (int i = 0; i < leafs; i++) { - Merkleizer context = new Merkleizer(1); - for (int i = 0; i < 64; i++) - { - Assert.False(context.IsKthBitSet(i), i.ToString()); - } + merkleizer.Feed(Merkle.ZeroHashes[0]); } - [TestCase(2, 1)] - [TestCase(4, 2)] - [TestCase(8, 3)] - [TestCase(16, 4)] - [TestCase(32, 5)] - [TestCase(64, 6)] - public void Feed_test(int leafs, int depth) + Assert.That(merkleizer.CalculateRoot(), Is.EqualTo(Merkle.ZeroHashes[depth])); + } + + [TestCase(2, 1)] + [TestCase(4, 2)] + [TestCase(8, 3)] + [TestCase(16, 4)] + [TestCase(32, 5)] + [TestCase(64, 6)] + public void Feed_test_fill(int leafs, int depth) + { + UInt256 result = UInt256.Zero; + for (int j = 0; j < leafs; j++) { Merkleizer merkleizer = new Merkleizer(depth); - for (int i = 0; i < leafs; i++) + for (int i = j; i < leafs; i++) { merkleizer.Feed(Merkle.ZeroHashes[0]); } - Assert.That(merkleizer.CalculateRoot(), Is.EqualTo(Merkle.ZeroHashes[depth])); + result = merkleizer.CalculateRoot(); } - [TestCase(2, 1)] - [TestCase(4, 2)] - [TestCase(8, 3)] - [TestCase(16, 4)] - [TestCase(32, 5)] - [TestCase(64, 6)] - public void Feed_test_fill(int leafs, int depth) - { - UInt256 result = UInt256.Zero; - for (int j = 0; j < leafs; j++) - { - Merkleizer merkleizer = new Merkleizer(depth); - for (int i = j; i < leafs; i++) - { - merkleizer.Feed(Merkle.ZeroHashes[0]); - } - - result = merkleizer.CalculateRoot(); - } - - Assert.That(result, Is.EqualTo(Merkle.ZeroHashes[depth])); - } + Assert.That(result, Is.EqualTo(Merkle.ZeroHashes[depth])); + } - [Test] - public void Fill() + [Test] + public void Fill() + { + Merkleizer merkleizer = new Merkleizer(6); + for (int i = 0; i < 7; i++) { - Merkleizer merkleizer = new Merkleizer(6); - for (int i = 0; i < 7; i++) - { - merkleizer.Feed(Merkle.ZeroHashes[0]); - } + merkleizer.Feed(Merkle.ZeroHashes[0]); + } - UInt256 result = merkleizer.CalculateRoot(); + UInt256 result = merkleizer.CalculateRoot(); - Assert.That(result, Is.EqualTo(Merkle.ZeroHashes[6])); - } + Assert.That(result, Is.EqualTo(Merkle.ZeroHashes[6])); } } diff --git a/src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs b/src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs index 106733cef42..8e7821c667f 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs @@ -549,15 +549,15 @@ // JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; // options.ConfigureNethermindCore2(); -// TestContext.WriteLine("Original state: {0}", JsonSerializer.Serialize(container, options)); +// TestContext.Out.WriteLine("Original state: {0}", JsonSerializer.Serialize(container, options)); // int encodedLength = Ssz.BeaconStateLength(container); -// TestContext.WriteLine("Encoded length: {0}", encodedLength); +// TestContext.Out.WriteLine("Encoded length: {0}", encodedLength); // Span encoded = new byte[encodedLength]; // Ssz.Encode(encoded, container); // BeaconState decoded = Ssz.DecodeBeaconState(encoded); -// TestContext.WriteLine("Decoded state: {0}", JsonSerializer.Serialize(decoded, options)); +// TestContext.Out.WriteLine("Decoded state: {0}", JsonSerializer.Serialize(decoded, options)); // AssertBeaconStateEqual(container, decoded); diff --git a/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs b/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs index 1d50e19123a..12145fc6277 100644 --- a/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs +++ b/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs @@ -17,210 +17,209 @@ using NSubstitute.Extensions; using NUnit.Framework; -namespace Nethermind.Sockets.Test +namespace Nethermind.Sockets.Test; + +public class WebSocketExtensionsTests { - public class WebSocketExtensionsTests + private class WebSocketMock : WebSocket { - private class WebSocketMock : WebSocket - { - private readonly Queue _receiveResults; - - public WebSocketMock(Queue receiveResults) - { - _receiveResults = receiveResults; - } + private readonly Queue _receiveResults; - public override void Abort() - { - throw new NotImplementedException(); - } - - public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } + public WebSocketMock(Queue receiveResults) + { + _receiveResults = receiveResults; + } - public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public override void Abort() + { + throw new NotImplementedException(); + } - public override void Dispose() - { - throw new NotImplementedException(); - } + public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } - public override Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) - { - // Had to use Array.Fill as it is more performant - Array.Fill(buffer.Array, (byte)0, buffer.Offset, buffer.Count); + public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - if (_receiveResults.Count == 0 && ReturnTaskWithFaultOnEmptyQueue) - { - Task a = new Task(() => throw new Exception()); - a.Start(); - return a; - } + public override void Dispose() + { + throw new NotImplementedException(); + } - return Task.FromResult(_receiveResults.Dequeue()); - } + public override Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) + { + // Had to use Array.Fill as it is more performant + Array.Fill(buffer.Array, (byte)0, buffer.Offset, buffer.Count); - public override Task SendAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) + if (_receiveResults.Count == 0 && ReturnTaskWithFaultOnEmptyQueue) { - throw new NotImplementedException(); + Task a = new Task(() => throw new Exception()); + a.Start(); + return a; } - public override WebSocketCloseStatus? CloseStatus { get; } - public override string CloseStatusDescription { get; } - public override WebSocketState State { get; } = WebSocketState.Open; - public override string SubProtocol { get; } - public bool ReturnTaskWithFaultOnEmptyQueue { get; set; } + return Task.FromResult(_receiveResults.Dequeue()); } - [SetUp] - public void Setup() + public override Task SendAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { + throw new NotImplementedException(); } - [Test] - public async Task Can_receive_whole_message() - { - Queue receiveResult = new Queue(); - receiveResult.Enqueue(new WebSocketReceiveResult(4096, WebSocketMessageType.Text, false)); - receiveResult.Enqueue(new WebSocketReceiveResult(4096, WebSocketMessageType.Text, false)); - receiveResult.Enqueue(new WebSocketReceiveResult(1024, WebSocketMessageType.Text, true)); - receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); - WebSocketMock mock = new(receiveResult); + public override WebSocketCloseStatus? CloseStatus { get; } + public override string CloseStatusDescription { get; } + public override WebSocketState State { get; } = WebSocketState.Open; + public override string SubProtocol { get; } + public bool ReturnTaskWithFaultOnEmptyQueue { get; set; } + } + + [SetUp] + public void Setup() + { + } - SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); + [Test] + public async Task Can_receive_whole_message() + { + Queue receiveResult = new Queue(); + receiveResult.Enqueue(new WebSocketReceiveResult(4096, WebSocketMessageType.Text, false)); + receiveResult.Enqueue(new WebSocketReceiveResult(4096, WebSocketMessageType.Text, false)); + receiveResult.Enqueue(new WebSocketReceiveResult(1024, WebSocketMessageType.Text, true)); + receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); + WebSocketMock mock = new(receiveResult); - await webSocketsClient.ReceiveLoopAsync(); - await webSocketsClient.Received().ProcessAsync(Arg.Is>(ba => ba.Count == 2 * 4096 + 1024)); - } + SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); - class Disposable : IDisposable + await webSocketsClient.ReceiveLoopAsync(); + await webSocketsClient.Received().ProcessAsync(Arg.Is>(ba => ba.Count == 2 * 4096 + 1024)); + } + + class Disposable : IDisposable + { + public void Dispose() { - public void Dispose() - { - } } + } - [Test] - public async Task Updates_Metrics_And_Stats_Successfully() - { - Queue receiveResult = new Queue(); - receiveResult.Enqueue(new WebSocketReceiveResult(1024, WebSocketMessageType.Text, true)); - receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); - WebSocketMock mock = new(receiveResult); + [Test] + public async Task Updates_Metrics_And_Stats_Successfully() + { + Queue receiveResult = new Queue(); + receiveResult.Enqueue(new WebSocketReceiveResult(1024, WebSocketMessageType.Text, true)); + receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); + WebSocketMock mock = new(receiveResult); - var processor = Substitute.For(); - processor.ProcessAsync(default, default).ReturnsForAnyArgs((x) => new List() - { - (JsonRpcResult.Single((new JsonRpcResponse()), new RpcReport())), - (JsonRpcResult.Collection(new JsonRpcBatchResult((e, c) => - new List() - { - new(new JsonRpcResponse(), new RpcReport()), - new(new JsonRpcResponse(), new RpcReport()), - new(new JsonRpcResponse(), new RpcReport()), - }.ToAsyncEnumerable().GetAsyncEnumerator(c)))) - }.ToAsyncEnumerable()); - - var service = Substitute.For(); - - var localStats = Substitute.For(); - - var webSocketsClient = Substitute.ForPartsOf>( - "TestClient", - new WebSocketMessageStream(mock, Substitute.For()), - RpcEndpoint.Ws, - processor, - localStats, - Substitute.For(), - null, - 30.MB()); - - webSocketsClient.Configure().SendJsonRpcResult(default).ReturnsForAnyArgs(async x => + var processor = Substitute.For(); + processor.ProcessAsync(default, default).ReturnsForAnyArgs((x) => new List() + { + (JsonRpcResult.Single((new JsonRpcResponse()), new RpcReport())), + (JsonRpcResult.Collection(new JsonRpcBatchResult((e, c) => + new List() { - var par = x.Arg(); - return await Task.FromResult(par.IsCollection ? par.BatchedResponses.ToListAsync().Result.Count * 100 : 100); - }); + new(new JsonRpcResponse(), new RpcReport()), + new(new JsonRpcResponse(), new RpcReport()), + new(new JsonRpcResponse(), new RpcReport()), + }.ToAsyncEnumerable().GetAsyncEnumerator(c)))) + }.ToAsyncEnumerable()); + + var service = Substitute.For(); + + var localStats = Substitute.For(); + + var webSocketsClient = Substitute.ForPartsOf>( + "TestClient", + new WebSocketMessageStream(mock, Substitute.For()), + RpcEndpoint.Ws, + processor, + localStats, + Substitute.For(), + null, + 30.MB()); + + webSocketsClient.Configure().SendJsonRpcResult(default).ReturnsForAnyArgs(async x => + { + var par = x.Arg(); + return await Task.FromResult(par.IsCollection ? par.BatchedResponses.ToListAsync().Result.Count * 100 : 100); + }); - await webSocketsClient.ReceiveLoopAsync(); + await webSocketsClient.ReceiveLoopAsync(); - Assert.That(Metrics.JsonRpcBytesReceivedWebSockets, Is.EqualTo(1024)); - Assert.That(Metrics.JsonRpcBytesSentWebSockets, Is.EqualTo(400)); - await localStats.Received(1).ReportCall(Arg.Any(), Arg.Any(), 100); - await localStats.Received(1).ReportCall(Arg.Any(), Arg.Any(), 300); - } + Assert.That(Metrics.JsonRpcBytesReceivedWebSockets, Is.EqualTo(1024)); + Assert.That(Metrics.JsonRpcBytesSentWebSockets, Is.EqualTo(400)); + await localStats.Received(1).ReportCall(Arg.Any(), Arg.Any(), 100); + await localStats.Received(1).ReportCall(Arg.Any(), Arg.Any(), 300); + } - [Test] - public async Task Can_receive_many_messages() + [Test] + public async Task Can_receive_many_messages() + { + Queue receiveResult = new Queue(); + for (int i = 0; i < 1000; i++) { - Queue receiveResult = new Queue(); - for (int i = 0; i < 1000; i++) - { - receiveResult.Enqueue(new WebSocketReceiveResult(1234, WebSocketMessageType.Text, true)); - } + receiveResult.Enqueue(new WebSocketReceiveResult(1234, WebSocketMessageType.Text, true)); + } - receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); + receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); - WebSocketMock mock = new(receiveResult); - SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); + WebSocketMock mock = new(receiveResult); + SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); - await webSocketsClient.ReceiveLoopAsync(); - await webSocketsClient.Received(1000).ProcessAsync(Arg.Is>(ba => ba.Count == 1234)); - } + await webSocketsClient.ReceiveLoopAsync(); + await webSocketsClient.Received(1000).ProcessAsync(Arg.Is>(ba => ba.Count == 1234)); + } - [Test] - public async Task Can_receive_whole_message_non_buffer_sizes() + [Test] + public async Task Can_receive_whole_message_non_buffer_sizes() + { + Queue receiveResult = new Queue(); + for (int i = 0; i < 6; i++) { - Queue receiveResult = new Queue(); - for (int i = 0; i < 6; i++) - { - receiveResult.Enqueue(new WebSocketReceiveResult(2000, WebSocketMessageType.Text, false)); - } + receiveResult.Enqueue(new WebSocketReceiveResult(2000, WebSocketMessageType.Text, false)); + } - receiveResult.Enqueue(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true)); - receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); - WebSocketMock mock = new(receiveResult); + receiveResult.Enqueue(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true)); + receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); + WebSocketMock mock = new(receiveResult); - SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); + SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); - await webSocketsClient.ReceiveLoopAsync(); - await webSocketsClient.Received().ProcessAsync(Arg.Is>(ba => ba.Count == 6 * 2000 + 1)); - } + await webSocketsClient.ReceiveLoopAsync(); + await webSocketsClient.Received().ProcessAsync(Arg.Is>(ba => ba.Count == 6 * 2000 + 1)); + } - [Test] - public async Task Throws_on_too_long_message() + [Test] + public async Task Throws_on_too_long_message() + { + Queue receiveResult = new Queue(); + for (int i = 0; i < 128 * 1024; i++) { - Queue receiveResult = new Queue(); - for (int i = 0; i < 128 * 1024; i++) - { - receiveResult.Enqueue(new WebSocketReceiveResult(1024, WebSocketMessageType.Text, false)); - } + receiveResult.Enqueue(new WebSocketReceiveResult(1024, WebSocketMessageType.Text, false)); + } - receiveResult.Enqueue(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true)); - receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); - WebSocketMock mock = new(receiveResult); + receiveResult.Enqueue(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true)); + receiveResult.Enqueue(new WebSocketReceiveResult(0, WebSocketMessageType.Close, true)); + WebSocketMock mock = new(receiveResult); - SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); + SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); - Assert.ThrowsAsync(async () => await webSocketsClient.ReceiveLoopAsync()); - await webSocketsClient.DidNotReceive().ProcessAsync(Arg.Any>()); - } + Assert.ThrowsAsync(async () => await webSocketsClient.ReceiveLoopAsync()); + await webSocketsClient.DidNotReceive().ProcessAsync(Arg.Any>()); + } - [Test, Timeout(5000)] - public async Task Stops_on_dirty_disconnect() - { - Queue receiveResult = new Queue(); - receiveResult.Enqueue(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true)); - WebSocketMock mock = new(receiveResult); - mock.ReturnTaskWithFaultOnEmptyQueue = true; + [Test, MaxTime(5000)] + public async Task Stops_on_dirty_disconnect() + { + Queue receiveResult = new Queue(); + receiveResult.Enqueue(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true)); + WebSocketMock mock = new(receiveResult); + mock.ReturnTaskWithFaultOnEmptyQueue = true; - SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); + SocketClient webSocketsClient = Substitute.ForPartsOf>("TestClient", new WebSocketMessageStream(mock, Substitute.For()), Substitute.For()); - await webSocketsClient.ReceiveLoopAsync(); - } + await webSocketsClient.ReceiveLoopAsync(); } } diff --git a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs index bbc4460bf9b..0560bacc6dd 100644 --- a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs +++ b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs @@ -15,7 +15,6 @@ namespace Nethermind.Specs.Test.ChainSpecStyle; [Parallelizable(ParallelScope.All)] -[TestFixture] public class ChainSpecLoaderTests { [Test] @@ -48,7 +47,7 @@ public void Can_load_hive() Assert.That(chainSpec.ChainId, Is.EqualTo(1), $"{nameof(chainSpec.ChainId)}"); Assert.That(chainSpec.NetworkId, Is.EqualTo(1), $"{nameof(chainSpec.NetworkId)}"); - Assert.NotNull(chainSpec.Genesis, $"{nameof(ChainSpec.Genesis)}"); + Assert.That(chainSpec.Genesis, Is.Not.Null, $"{nameof(ChainSpec.Genesis)}"); Assert.That(chainSpec.Parameters.Eip1559BaseFeeInitialValue, Is.EqualTo(1.GWei()), $"initial base fee value"); Assert.That(chainSpec.Parameters.Eip1559ElasticityMultiplier, Is.EqualTo((long)1), $"elasticity multiplier"); @@ -66,7 +65,7 @@ public void Can_load_hive() $"genesis {nameof(BlockHeader.ExtraData)}"); Assert.That(chainSpec.Genesis.Header.GasLimit, Is.EqualTo(0x8000000L), $"genesis {nameof(BlockHeader.GasLimit)}"); - Assert.NotNull(chainSpec.Allocations, $"{nameof(ChainSpec.Allocations)}"); + Assert.That(chainSpec.Allocations, Is.Not.Null, $"{nameof(ChainSpec.Allocations)}"); Assert.That(chainSpec.Allocations.Count, Is.EqualTo(1), $"allocations count"); Assert.That( chainSpec.Allocations[new Address("0x71562b71999873db5b286df957af199ec94617f7")].Balance, Is.EqualTo(new UInt256(0xf4240)), diff --git a/src/Nethermind/Nethermind.Specs.Test/CustomSpecProviderTests.cs b/src/Nethermind/Nethermind.Specs.Test/CustomSpecProviderTests.cs index df91b86c5e5..b44b1f6aa06 100644 --- a/src/Nethermind/Nethermind.Specs.Test/CustomSpecProviderTests.cs +++ b/src/Nethermind/Nethermind.Specs.Test/CustomSpecProviderTests.cs @@ -6,68 +6,66 @@ using Nethermind.Specs.Forks; using NUnit.Framework; -namespace Nethermind.Specs.Test +namespace Nethermind.Specs.Test; + +public class CustomSpecProviderTests { - [TestFixture] - public class CustomSpecProviderTests + [Test] + public void When_no_transitions_specified_throws_argument_exception() { - [Test] - public void When_no_transitions_specified_throws_argument_exception() - { - Assert.Throws(() => _ = new CustomSpecProvider()); - } + Assert.Throws(() => _ = new CustomSpecProvider()); + } - [Test] - public void When_first_release_is_not_at_block_zero_then_throws_argument_exception() - { - Assert.Throws(() => _ = new CustomSpecProvider(((ForkActivation)1, Byzantium.Instance)), "ordered"); - } + [Test] + public void When_first_release_is_not_at_block_zero_then_throws_argument_exception() + { + Assert.Throws(() => _ = new CustomSpecProvider(((ForkActivation)1, Byzantium.Instance)), "ordered"); + } - [Test] - public void When_only_one_release_is_specified_then_returns_that_release() - { - var specProvider = new CustomSpecProvider(((ForkActivation)0, Byzantium.Instance)); - Assert.IsInstanceOf(specProvider.GetSpec((ForkActivation)0), "0"); - Assert.IsInstanceOf(specProvider.GetSpec((ForkActivation)1), "1"); - } + [Test] + public void When_only_one_release_is_specified_then_returns_that_release() + { + var specProvider = new CustomSpecProvider(((ForkActivation)0, Byzantium.Instance)); + Assert.That(specProvider.GetSpec((ForkActivation)0), Is.InstanceOf(), "0"); + Assert.That(specProvider.GetSpec((ForkActivation)1), Is.InstanceOf(), "1"); + } - [Test] - public void Can_find_dao_block_number() - { - long daoBlockNumber = 100; - var specProvider = new CustomSpecProvider( - ((ForkActivation)0L, Frontier.Instance), - ((ForkActivation)daoBlockNumber, Dao.Instance)); + [Test] + public void Can_find_dao_block_number() + { + long daoBlockNumber = 100; + var specProvider = new CustomSpecProvider( + ((ForkActivation)0L, Frontier.Instance), + ((ForkActivation)daoBlockNumber, Dao.Instance)); - Assert.That(specProvider.DaoBlockNumber, Is.EqualTo(daoBlockNumber)); - } + Assert.That(specProvider.DaoBlockNumber, Is.EqualTo(daoBlockNumber)); + } - [Test] - public void If_no_dao_then_no_dao_block_number() - { - var specProvider = new CustomSpecProvider( - ((ForkActivation)0L, Frontier.Instance), - ((ForkActivation)1L, Homestead.Instance)); + [Test] + public void If_no_dao_then_no_dao_block_number() + { + var specProvider = new CustomSpecProvider( + ((ForkActivation)0L, Frontier.Instance), + ((ForkActivation)1L, Homestead.Instance)); - Assert.IsNull(specProvider.DaoBlockNumber); - } + Assert.That(specProvider.DaoBlockNumber, Is.Null); + } - [Test] - public void When_more_releases_specified_then_transitions_work() - { - var specProvider = new CustomSpecProvider( - ((ForkActivation)0, Frontier.Instance), - ((ForkActivation)1, Homestead.Instance)); - Assert.IsInstanceOf(specProvider.GetSpec((ForkActivation)0), "2 releases, block 0"); - Assert.IsInstanceOf(specProvider.GetSpec((ForkActivation)1), "2 releases, block 1"); + [Test] + public void When_more_releases_specified_then_transitions_work() + { + var specProvider = new CustomSpecProvider( + ((ForkActivation)0, Frontier.Instance), + ((ForkActivation)1, Homestead.Instance)); + Assert.That(specProvider.GetSpec((ForkActivation)0), Is.InstanceOf(), "2 releases, block 0"); + Assert.That(specProvider.GetSpec((ForkActivation)1), Is.InstanceOf(), "2 releases, block 1"); - specProvider = new CustomSpecProvider( - ((ForkActivation)0, Frontier.Instance), - ((ForkActivation)1, Homestead.Instance), - ((ForkActivation)10, Byzantium.Instance)); - Assert.IsInstanceOf(specProvider.GetSpec((ForkActivation)0), "3 releases, block 0"); - Assert.IsInstanceOf(specProvider.GetSpec((ForkActivation)1), "3 releases, block 1"); - Assert.IsInstanceOf(specProvider.GetSpec((ForkActivation)100), "3 releases, block 10"); - } + specProvider = new CustomSpecProvider( + ((ForkActivation)0, Frontier.Instance), + ((ForkActivation)1, Homestead.Instance), + ((ForkActivation)10, Byzantium.Instance)); + Assert.That(specProvider.GetSpec((ForkActivation)0), Is.InstanceOf(), "3 releases, block 0"); + Assert.That(specProvider.GetSpec((ForkActivation)1), Is.InstanceOf(), "3 releases, block 1"); + Assert.That(specProvider.GetSpec((ForkActivation)100), Is.InstanceOf(), "3 releases, block 10"); } } diff --git a/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs b/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs index c19551a2848..2e82c29714a 100644 --- a/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs +++ b/src/Nethermind/Nethermind.State.Test/Proofs/AccountProofCollectorTests.cs @@ -626,7 +626,7 @@ public void _Test_storage_failed_case(string historicallyFailingCase) addressWithStorage.StorageCells[j] = storageCell; byte[] rawKey = new byte[32]; addressWithStorage.StorageCells[j].Index.ToBigEndian(rawKey); - TestContext.WriteLine($"Set {Keccak.Compute(rawKey).Bytes.ToHexString()}"); + TestContext.Out.WriteLine($"Set {Keccak.Compute(rawKey).Bytes.ToHexString()}"); storageTree.Set(addressWithStorage.StorageCells[j].Index, new byte[] { 1 }); storageTree.UpdateRootHash(); storageTree.Commit(0); @@ -640,7 +640,7 @@ public void _Test_storage_failed_case(string historicallyFailingCase) TreeDumper treeDumper = new(); tree.Accept(treeDumper, tree.RootHash); - TestContext.WriteLine(treeDumper.ToString()); + TestContext.Out.WriteLine(treeDumper.ToString()); AccountProofCollector collector = new(address, indexes); tree.Accept(collector, tree.RootHash); @@ -659,7 +659,7 @@ public void _Test_storage_failed_case(string historicallyFailingCase) node.ResolveNode(new TrieStore(memDb, NullLogManager.Instance).GetTrieStore(null), TreePath.Empty); if (node.Value.Length != 1) { - TestContext.WriteLine($"{j}"); + TestContext.Out.WriteLine($"{j}"); // throw new InvalidDataException($"{j}"); } } @@ -738,12 +738,12 @@ public void Chaotic_test() // TestContext.Write($"|[{i},{j}]"); if (node.Value.Length != 1) { - TestContext.WriteLine(); - TestContext.WriteLine(addressesWithStorage[i].Address); - TestContext.WriteLine(i); + TestContext.Out.WriteLine(); + TestContext.Out.WriteLine(addressesWithStorage[i].Address); + TestContext.Out.WriteLine(i); foreach (StorageCell storageCell in addressesWithStorage[i].StorageCells) { - TestContext.WriteLine("storage: " + storageCell.Index); + TestContext.Out.WriteLine("storage: " + storageCell.Index); } } diff --git a/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs b/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs index 769114bd898..ff3f2558ef5 100644 --- a/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs +++ b/src/Nethermind/Nethermind.State.Test/SnapSync/RecreateStateFromAccountRangesTests.cs @@ -21,312 +21,310 @@ using Nethermind.Trie.Pruning; using NUnit.Framework; -namespace Nethermind.Store.Test +namespace Nethermind.Store.Test; + +public class RecreateStateFromAccountRangesTests { - [TestFixture] - public class RecreateStateFromAccountRangesTests + private StateTree _inputTree; + + [OneTimeSetUp] + public void Setup() { - private StateTree _inputTree; + _inputTree = TestItem.Tree.GetStateTree(); + } - [OneTimeSetUp] - public void Setup() - { - _inputTree = TestItem.Tree.GetStateTree(); - } + //[Test] + public void Test01() + { + Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - //[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 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; - 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); - MemDb db = new(); - IScopedTrieStore store = new TrieStore(db, LimboLogs.Instance).GetTrieStore(null); - StateTree tree = new(store, LimboLogs.Instance); + IList nodes = new List(); - 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); - for (int i = 0; i < (firstProof!).Length; i++) + nodes.Add(node); + if (i < (firstProof!).Length - 1) { - 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); - } + //IBatch batch = store.GetOrStartNewBatch(); + //batch[node.Keccak!.Bytes] = nodeBytes; + //db.Set(node.Keccak!, nodeBytes); } + } - for (int i = 0; i < (lastProof!).Length; i++) + 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) { - 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); - } + //IBatch batch = store.GetOrStartNewBatch(); + //batch[node.Keccak!.Bytes] = nodeBytes; + //db.Set(node.Keccak!, nodeBytes); } + } - tree.RootRef = nodes[0]; + 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.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(0); + tree.Commit(0); - 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.IsFalse(db.KeyExists(rootHash)); // the root node is a part of the proof nodes - } + 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.IsFalse(db.KeyExists(rootHash)); - } + [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.IsFalse(db.KeyExists(rootHash)); - } + [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.IsFalse(db.KeyExists(rootHash)); // the root node is NOT a part of the proof nodes - } + [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.IsFalse(db.KeyExists(rootHash)); - } + [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() + [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) { - 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.IsFalse(db.KeyExists(rootHash)); + stateTree.Set(pathWithAccount.Path, pathWithAccount.Account); } - [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(); - stateTree.UpdateRootHash(); + snapProvider.AddAccountRange(1, + stateTree.RootHash, + accountsWithPath[0].Path, + accountsWithPath); - 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); + } - 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; } - - private SnapProvider CreateSnapProvider(ProgressTracker progressTracker, IDbProvider dbProvider) + catch (ArgumentException) { - try - { - IDb _ = dbProvider.CodeDb; - } - catch (ArgumentException) - { - dbProvider.RegisterDb(DbNames.Code, new MemDb()); - } - return new(progressTracker, dbProvider.CodeDb, new NodeStorage(dbProvider.StateDb), LimboLogs.Instance); + 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/StateProviderTests.cs b/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs index ee924de5b4e..f1e5d5eaad1 100644 --- a/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs +++ b/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs @@ -19,229 +19,228 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Store.Test +namespace Nethermind.Store.Test; + +[Parallelizable(ParallelScope.All)] +public class StateProviderTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class StateProviderTests + private static readonly Hash256 Hash1 = Keccak.Compute("1"); + private static readonly Hash256 Hash2 = Keccak.Compute("2"); + private readonly Address _address1 = new(Hash1); + private static readonly ILogManager Logger = LimboLogs.Instance; + private IDb _codeDb; + + [SetUp] + public void Setup() + { + _codeDb = new MemDb(); + } + + [TearDown] + public void TearDown() => _codeDb?.Dispose(); + + [Test] + public void Eip_158_zero_value_transfer_deletes() + { + var trieStore = new TrieStore(new MemDb(), Logger); + WorldState frontierProvider = new(trieStore, _codeDb, Logger); + frontierProvider.CreateAccount(_address1, 0); + frontierProvider.Commit(Frontier.Instance); + frontierProvider.CommitTree(0); + + WorldState provider = new(trieStore, _codeDb, Logger); + provider.StateRoot = frontierProvider.StateRoot; + + provider.AddToBalance(_address1, 0, SpuriousDragon.Instance); + provider.Commit(SpuriousDragon.Instance); + Assert.That(provider.AccountExists(_address1), Is.False); + + _codeDb = Substitute.For(); + } + + [Test] + public void Eip_158_touch_zero_value_system_account_is_not_deleted() + { + TrieStore trieStore = new(new MemDb(), Logger); + WorldState provider = new(trieStore, _codeDb, Logger); + var systemUser = Address.SystemUser; + + provider.CreateAccount(systemUser, 0); + provider.Commit(Homestead.Instance); + + var releaseSpec = new ReleaseSpec() { IsEip158Enabled = true }; + provider.InsertCode(systemUser, System.Text.Encoding.UTF8.GetBytes(""), releaseSpec); + provider.Commit(releaseSpec); + + provider.GetAccount(systemUser).Should().NotBeNull(); + } + + [Test] + public void Can_dump_state() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.CreateAccount(TestItem.AddressA, 1.Ether()); + provider.Commit(MuirGlacier.Instance); + provider.CommitTree(0); + + string state = provider.DumpState(); + state.Should().NotBeEmpty(); + } + + [Test] + public void Can_accepts_visitors() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), Substitute.For(), Logger); + provider.CreateAccount(TestItem.AddressA, 1.Ether()); + provider.Commit(MuirGlacier.Instance); + provider.CommitTree(0); + + TrieStatsCollector visitor = new(new MemDb(), LimboLogs.Instance); + provider.Accept(visitor, provider.StateRoot); + } + + [Test] + public void Empty_commit_restore() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.Commit(Frontier.Instance); + provider.Restore(Snapshot.Empty); + } + + [Test] + public void Update_balance_on_non_existing_account_throws() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + Assert.Throws(() => provider.AddToBalance(TestItem.AddressA, 1.Ether(), Olympic.Instance)); + } + + [Test] + public void Is_empty_account() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.CreateAccount(_address1, 0); + provider.Commit(Frontier.Instance); + Assert.That(provider.IsEmptyAccount(_address1), Is.True); + } + + [Test] + public void Returns_empty_byte_code_for_non_existing_accounts() { - private static readonly Hash256 Hash1 = Keccak.Compute("1"); - private static readonly Hash256 Hash2 = Keccak.Compute("2"); - private readonly Address _address1 = new(Hash1); - private static readonly ILogManager Logger = LimboLogs.Instance; - private IDb _codeDb; - - [SetUp] - public void Setup() - { - _codeDb = new MemDb(); - } - - [TearDown] - public void TearDown() => _codeDb?.Dispose(); - - [Test] - public void Eip_158_zero_value_transfer_deletes() - { - var trieStore = new TrieStore(new MemDb(), Logger); - WorldState frontierProvider = new(trieStore, _codeDb, Logger); - frontierProvider.CreateAccount(_address1, 0); - frontierProvider.Commit(Frontier.Instance); - frontierProvider.CommitTree(0); - - WorldState provider = new(trieStore, _codeDb, Logger); - provider.StateRoot = frontierProvider.StateRoot; - - provider.AddToBalance(_address1, 0, SpuriousDragon.Instance); - provider.Commit(SpuriousDragon.Instance); - Assert.False(provider.AccountExists(_address1)); - - _codeDb = Substitute.For(); - } - - [Test] - public void Eip_158_touch_zero_value_system_account_is_not_deleted() - { - TrieStore trieStore = new(new MemDb(), Logger); - WorldState provider = new(trieStore, _codeDb, Logger); - var systemUser = Address.SystemUser; - - provider.CreateAccount(systemUser, 0); - provider.Commit(Homestead.Instance); - - var releaseSpec = new ReleaseSpec() { IsEip158Enabled = true }; - provider.InsertCode(systemUser, System.Text.Encoding.UTF8.GetBytes(""), releaseSpec); - provider.Commit(releaseSpec); - - provider.GetAccount(systemUser).Should().NotBeNull(); - } - - [Test] - public void Can_dump_state() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.CreateAccount(TestItem.AddressA, 1.Ether()); - provider.Commit(MuirGlacier.Instance); - provider.CommitTree(0); - - string state = provider.DumpState(); - state.Should().NotBeEmpty(); - } - - [Test] - public void Can_accepts_visitors() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), Substitute.For(), Logger); - provider.CreateAccount(TestItem.AddressA, 1.Ether()); - provider.Commit(MuirGlacier.Instance); - provider.CommitTree(0); - - TrieStatsCollector visitor = new(new MemDb(), LimboLogs.Instance); - provider.Accept(visitor, provider.StateRoot); - } - - [Test] - public void Empty_commit_restore() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.Commit(Frontier.Instance); - provider.Restore(Snapshot.Empty); - } - - [Test] - public void Update_balance_on_non_existing_account_throws() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - Assert.Throws(() => provider.AddToBalance(TestItem.AddressA, 1.Ether(), Olympic.Instance)); - } - - [Test] - public void Is_empty_account() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.CreateAccount(_address1, 0); - provider.Commit(Frontier.Instance); - Assert.True(provider.IsEmptyAccount(_address1)); - } - - [Test] - public void Returns_empty_byte_code_for_non_existing_accounts() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - byte[] code = provider.GetCode(TestItem.AddressA); - code.Should().BeEmpty(); - } - - [Test] - public void Restore_update_restore() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.CreateAccount(_address1, 0); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.Restore(new Snapshot(4, Snapshot.Storage.Empty)); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.Restore(new Snapshot(4, Snapshot.Storage.Empty)); - Assert.That(provider.GetBalance(_address1), Is.EqualTo((UInt256)4)); - } - - [Test] - public void Keep_in_cache() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.CreateAccount(_address1, 0); - provider.Commit(Frontier.Instance); - provider.GetBalance(_address1); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.Restore(Snapshot.Empty); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.Restore(Snapshot.Empty); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.Restore(Snapshot.Empty); - Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.Zero)); - } - - [Test] - public void Restore_in_the_middle() - { - byte[] code = [1]; - - IWorldState provider = new WorldState(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.CreateAccount(_address1, 1); - provider.AddToBalance(_address1, 1, Frontier.Instance); - provider.IncrementNonce(_address1); - provider.InsertCode(_address1, new byte[] { 1 }, Frontier.Instance); - provider.UpdateStorageRoot(_address1, Hash2); - - Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); - Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); - Assert.That(provider.GetCode(_address1), Is.EqualTo(code)); - provider.Restore(new Snapshot(4, Snapshot.Storage.Empty)); - Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); - Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); - Assert.That(provider.GetCode(_address1), Is.EqualTo(code)); - provider.Restore(new Snapshot(3, Snapshot.Storage.Empty)); - Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); - Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); - Assert.That(provider.GetCode(_address1), Is.EqualTo(code)); - provider.Restore(new Snapshot(2, Snapshot.Storage.Empty)); - Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); - Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); - Assert.That(provider.GetCode(_address1), Is.EqualTo(new byte[0])); - provider.Restore(new Snapshot(1, Snapshot.Storage.Empty)); - Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.Zero)); - Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); - Assert.That(provider.GetCode(_address1), Is.EqualTo(new byte[0])); - provider.Restore(new Snapshot(0, Snapshot.Storage.Empty)); - Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.Zero)); - Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One)); - Assert.That(provider.GetCode(_address1), Is.EqualTo(new byte[0])); - provider.Restore(new Snapshot(-1, Snapshot.Storage.Empty)); - Assert.That(provider.AccountExists(_address1), Is.EqualTo(false)); - } - - [Test(Description = "It was failing before as touch was marking the accounts as committed but not adding to trace list")] - public void Touch_empty_trace_does_not_throw() - { - ParityLikeTxTracer tracer = new(Build.A.Block.TestObject, null, ParityTraceTypes.StateDiff); - - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.CreateAccount(_address1, 0); - Account account = provider.GetAccount(_address1); - Assert.True(account.IsEmpty); - provider.Commit(Frontier.Instance); // commit empty account (before the empty account fix in Spurious Dragon) - Assert.True(provider.AccountExists(_address1)); - - provider.Reset(); // clear all caches - - provider.GetBalance(_address1); // justcache - provider.AddToBalance(_address1, 0, SpuriousDragon.Instance); // touch - Assert.DoesNotThrow(() => provider.Commit(SpuriousDragon.Instance, tracer)); - } - - [Test] - public void Does_not_require_recalculation_after_reset() - { - WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); - provider.CreateAccount(TestItem.AddressA, 5); - - Action action = () => { _ = provider.StateRoot; }; - action.Should().Throw(); - - provider.Reset(); - action.Should().NotThrow(); - } + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + byte[] code = provider.GetCode(TestItem.AddressA); + code.Should().BeEmpty(); + } + + [Test] + public void Restore_update_restore() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.CreateAccount(_address1, 0); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.Restore(new Snapshot(4, Snapshot.Storage.Empty)); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.Restore(new Snapshot(4, Snapshot.Storage.Empty)); + Assert.That(provider.GetBalance(_address1), Is.EqualTo((UInt256)4)); + } + + [Test] + public void Keep_in_cache() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.CreateAccount(_address1, 0); + provider.Commit(Frontier.Instance); + provider.GetBalance(_address1); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.Restore(Snapshot.Empty); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.Restore(Snapshot.Empty); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.Restore(Snapshot.Empty); + Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.Zero)); + } + + [Test] + public void Restore_in_the_middle() + { + byte[] code = [1]; + + IWorldState provider = new WorldState(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.CreateAccount(_address1, 1); + provider.AddToBalance(_address1, 1, Frontier.Instance); + provider.IncrementNonce(_address1); + provider.InsertCode(_address1, new byte[] { 1 }, Frontier.Instance); + provider.UpdateStorageRoot(_address1, Hash2); + + Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); + Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); + Assert.That(provider.GetCode(_address1), Is.EqualTo(code)); + provider.Restore(new Snapshot(4, Snapshot.Storage.Empty)); + Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); + Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); + Assert.That(provider.GetCode(_address1), Is.EqualTo(code)); + provider.Restore(new Snapshot(3, Snapshot.Storage.Empty)); + Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); + Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); + Assert.That(provider.GetCode(_address1), Is.EqualTo(code)); + provider.Restore(new Snapshot(2, Snapshot.Storage.Empty)); + Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.One)); + Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); + Assert.That(provider.GetCode(_address1), Is.EqualTo(new byte[0])); + provider.Restore(new Snapshot(1, Snapshot.Storage.Empty)); + Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.Zero)); + Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One + 1)); + Assert.That(provider.GetCode(_address1), Is.EqualTo(new byte[0])); + provider.Restore(new Snapshot(0, Snapshot.Storage.Empty)); + Assert.That(provider.GetNonce(_address1), Is.EqualTo(UInt256.Zero)); + Assert.That(provider.GetBalance(_address1), Is.EqualTo(UInt256.One)); + Assert.That(provider.GetCode(_address1), Is.EqualTo(new byte[0])); + provider.Restore(new Snapshot(-1, Snapshot.Storage.Empty)); + Assert.That(provider.AccountExists(_address1), Is.EqualTo(false)); + } + + [Test(Description = "It was failing before as touch was marking the accounts as committed but not adding to trace list")] + public void Touch_empty_trace_does_not_throw() + { + ParityLikeTxTracer tracer = new(Build.A.Block.TestObject, null, ParityTraceTypes.StateDiff); + + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.CreateAccount(_address1, 0); + Account account = provider.GetAccount(_address1); + Assert.That(account.IsEmpty, Is.True); + provider.Commit(Frontier.Instance); // commit empty account (before the empty account fix in Spurious Dragon) + Assert.That(provider.AccountExists(_address1), Is.True); + + provider.Reset(); // clear all caches + + provider.GetBalance(_address1); // justcache + provider.AddToBalance(_address1, 0, SpuriousDragon.Instance); // touch + Assert.DoesNotThrow(() => provider.Commit(SpuriousDragon.Instance, tracer)); + } + + [Test] + public void Does_not_require_recalculation_after_reset() + { + WorldState provider = new(new TrieStore(new MemDb(), Logger), _codeDb, Logger); + provider.CreateAccount(TestItem.AddressA, 5); + + Action action = () => { _ = provider.StateRoot; }; + action.Should().Throw(); + + provider.Reset(); + action.Should().NotThrow(); } } diff --git a/src/Nethermind/Nethermind.State.Test/StateTreeTests.cs b/src/Nethermind/Nethermind.State.Test/StateTreeTests.cs index c60d6d29afc..70e0244ef4d 100644 --- a/src/Nethermind/Nethermind.State.Test/StateTreeTests.cs +++ b/src/Nethermind/Nethermind.State.Test/StateTreeTests.cs @@ -11,461 +11,459 @@ using Nethermind.Trie.Pruning; using NUnit.Framework; -namespace Nethermind.Store.Test +namespace Nethermind.Store.Test; + +public class StateTreeTests { - [TestFixture] - public class StateTreeTests - { - private readonly Account _account0 = Build.An.Account.WithBalance(0).TestObject; - private readonly Account _account1 = Build.An.Account.WithBalance(1).TestObject; - private readonly Account _account2 = Build.An.Account.WithBalance(2).TestObject; - private readonly Account _account3 = Build.An.Account.WithBalance(3).TestObject; - - [SetUp] - public void Setup() - { - Trie.Metrics.TreeNodeHashCalculations = 0; - Trie.Metrics.TreeNodeRlpDecodings = 0; - Trie.Metrics.TreeNodeRlpEncodings = 0; - } - - [Test] - public void No_reads_when_setting_on_empty() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.Set(TestItem.AddressB, _account0); - tree.Set(TestItem.AddressC, _account0); - tree.Commit(0); - Assert.That(db.ReadsCount, Is.EqualTo(0), "reads"); - } - - [Test] - public void Minimal_writes_when_setting_on_empty() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.Set(TestItem.AddressB, _account0); - tree.Set(TestItem.AddressC, _account0); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(5), "writes"); // branch, branch, two leaves (one is stored as RLP) - } - - [Test] - public void Minimal_writes_when_setting_on_empty_scenario_2() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(7), "writes"); // extension, branch, leaf, extension, branch, 2x same leaf - Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(7), "hashes"); - Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(7), "encodings"); - } - - [Test] - public void Minimal_writes_when_setting_on_empty_scenario_3() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(4), "writes"); // extension, branch, 2x leaf - Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(4), "hashes"); - Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(4), "encodings"); - } - - [Test] - public void Minimal_writes_when_setting_on_empty_scenario_4() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(1), "writes"); // extension, branch, 2x leaf - Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(1), "hashes"); - Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(1), "encodings"); - } - - [Test] - public void Minimal_writes_when_setting_on_empty_scenario_5() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), null); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(0), "writes"); // extension, branch, 2x leaf - Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(0), "hashes"); - Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(0), "encodings"); - } - - [Test] - public void Scenario_traverse_extension_read_full_match() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); - Account account = tree.Get(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111")); - Assert.That(db.ReadsCount, Is.EqualTo(0)); - Assert.That(account.Balance, Is.EqualTo(_account1.Balance)); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); - } - - [Test] - public void Scenario_traverse_extension_read_missing() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); - Account account = tree.Get(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddd")); - Assert.Null(account); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); - } - - [Test] - public void Scenario_traverse_extension_new_branching() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddd"), _account2); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x543c960143a2a06b685d6b92f0c37000273e616bc23888521e7edf15ad06da46")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x543c960143a2a06b685d6b92f0c37000273e616bc23888521e7edf15ad06da46")); - } - - [Test] - public void Scenario_traverse_extension_delete_missing() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddd"), null); - Assert.That(db.ReadsCount, Is.EqualTo(0)); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); - } - - [Test] - public void Scenario_traverse_extension_create_new_extension() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab00000000"), _account2); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab11111111"), _account3); - Assert.That(db.ReadsCount, Is.EqualTo(0)); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x0918112fc898173562441709a2c1cbedb80d1aaecaeadf2f3e9492eeaa568c67")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x0918112fc898173562441709a2c1cbedb80d1aaecaeadf2f3e9492eeaa568c67")); - } - - [Test] - public void Scenario_traverse_leaf_update_new_value() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account1); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0xaa5c248d4b4b8c27a654296a8e0cc51131eb9011d9166fa0fca56a966489e169")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0xaa5c248d4b4b8c27a654296a8e0cc51131eb9011d9166fa0fca56a966489e169")); - } - - [Test] - public void Scenario_traverse_leaf_update_no_change() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - } - - [Test] - public void Scenario_traverse_leaf_read_matching_leaf() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), null); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")); - } - - [Test] - public void Scenario_traverse_leaf_delete_missing() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); - tree.Set(new Hash256("1111111111111111111111111111111ddddddddddddddddddddddddddddddddd"), null); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - } - - [Test] - public void Scenario_traverse_leaf_update_with_extension() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111111111111111111111111111"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000000000000000000000000000"), _account1); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x215a4bab4cf2d5ebbaa59c82ae94c9707fcf4cc0ca1fe7e18f918e46db428ef9")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x215a4bab4cf2d5ebbaa59c82ae94c9707fcf4cc0ca1fe7e18f918e46db428ef9")); - } - - [Test] - public void Scenario_traverse_leaf_delete_matching_leaf() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); - Account account = tree.Get(new Hash256("1111111111111111111111111111111111111111111111111111111111111111")); - Assert.NotNull(account); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - } - - [Test] - public void Scenario_traverse_leaf_read_missing() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); - Account account = tree.Get(new Hash256("111111111111111111111111111111111111111111111111111111111ddddddd")); - Assert.Null(account); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); - } - - [Test] - public void Scenario_traverse_branch_update_missing() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222"), _account2); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0xc063af0bd3dd88320bc852ff8452049c42fbc06d1a69661567bd427572824cbf")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0xc063af0bd3dd88320bc852ff8452049c42fbc06d1a69661567bd427572824cbf")); - } - - [Test] - public void Scenario_traverse_branch_read_missing() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1); - Account account = tree.Get(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222")); - Assert.Null(account); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); - } - - [Test] - public void Scenario_traverse_branch_delete_missing() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222"), null); - tree.UpdateRootHash(); - Hash256 rootHash = tree.RootHash; - Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); - tree.Commit(0); - Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); - } - - [Test] - public void Minimal_hashes_when_setting_on_empty() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.Set(TestItem.AddressB, _account0); - tree.Set(TestItem.AddressC, _account0); - tree.Commit(0); - Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(5), "hashes"); // branch, branch, three leaves - } - - [Test] - public void Minimal_encodings_when_setting_on_empty() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.Set(TestItem.AddressB, _account0); - tree.Set(TestItem.AddressC, _account0); - tree.Commit(0); - Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(5), "encodings"); // branch, branch, three leaves - } - - [Test] - public void Zero_decodings_when_setting_on_empty() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.Set(TestItem.AddressB, _account0); - tree.Set(TestItem.AddressC, _account0); - tree.Commit(0); - Assert.That(Trie.Metrics.TreeNodeRlpDecodings, Is.EqualTo(0), "decodings"); - } - - [Test] - public void No_writes_on_continues_update() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.Set(TestItem.AddressA, _account1); - tree.Set(TestItem.AddressA, _account2); - tree.Set(TestItem.AddressA, _account3); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(1), "writes"); // extension, branch, two leaves - } - - [Ignore("This is not critical")] - [Test] - public void No_writes_on_reverted_update() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(1), "writes before"); // extension, branch, two leaves - tree.Set(TestItem.AddressA, _account1); - tree.Set(TestItem.AddressA, _account0); - tree.Commit(0); - Assert.That(db.WritesCount, Is.EqualTo(1), "writes after"); // extension, branch, two leaves - } - - [Test] - public void No_writes_without_commit() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - Assert.That(db.WritesCount, Is.EqualTo(0), "writes"); - } - - [Test] - public void Can_ask_about_root_hash_without_commiting() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, _account0); - tree.UpdateRootHash(); - Assert.That(tree.RootHash.ToString(true), Is.EqualTo("0x545a417202afcb10925b2afddb70a698710bb1cf4ab32942c42e9f019d564fdc")); - } - - [Test] - public void Can_ask_about_root_hash_without_when_emptied() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); - tree.UpdateRootHash(); - Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); - tree.UpdateRootHash(); - Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); - tree.UpdateRootHash(); - Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null); - tree.UpdateRootHash(); - Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); - tree.UpdateRootHash(); - Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); - tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), null); - tree.UpdateRootHash(); - Assert.That(tree.RootHash, Is.EqualTo(PatriciaTree.EmptyTreeHash)); - tree.Commit(0); - Assert.That(tree.RootHash, Is.EqualTo(PatriciaTree.EmptyTreeHash)); - } - - [Test] - public void hash_empty_tree_root_hash_initially() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - Assert.That(tree.RootHash, Is.EqualTo(PatriciaTree.EmptyTreeHash)); - } - - [Test] - public void Can_save_null() - { - MemDb db = new(); - StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); - tree.Set(TestItem.AddressA, null); - } + private readonly Account _account0 = Build.An.Account.WithBalance(0).TestObject; + private readonly Account _account1 = Build.An.Account.WithBalance(1).TestObject; + private readonly Account _account2 = Build.An.Account.WithBalance(2).TestObject; + private readonly Account _account3 = Build.An.Account.WithBalance(3).TestObject; + + [SetUp] + public void Setup() + { + Trie.Metrics.TreeNodeHashCalculations = 0; + Trie.Metrics.TreeNodeRlpDecodings = 0; + Trie.Metrics.TreeNodeRlpEncodings = 0; + } + + [Test] + public void No_reads_when_setting_on_empty() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.Set(TestItem.AddressB, _account0); + tree.Set(TestItem.AddressC, _account0); + tree.Commit(0); + Assert.That(db.ReadsCount, Is.EqualTo(0), "reads"); + } + + [Test] + public void Minimal_writes_when_setting_on_empty() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.Set(TestItem.AddressB, _account0); + tree.Set(TestItem.AddressC, _account0); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(5), "writes"); // branch, branch, two leaves (one is stored as RLP) + } + + [Test] + public void Minimal_writes_when_setting_on_empty_scenario_2() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(7), "writes"); // extension, branch, leaf, extension, branch, 2x same leaf + Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(7), "hashes"); + Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(7), "encodings"); + } + + [Test] + public void Minimal_writes_when_setting_on_empty_scenario_3() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(4), "writes"); // extension, branch, 2x leaf + Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(4), "hashes"); + Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(4), "encodings"); + } + + [Test] + public void Minimal_writes_when_setting_on_empty_scenario_4() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(1), "writes"); // extension, branch, 2x leaf + Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(1), "hashes"); + Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(1), "encodings"); + } + + [Test] + public void Minimal_writes_when_setting_on_empty_scenario_5() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), null); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(0), "writes"); // extension, branch, 2x leaf + Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(0), "hashes"); + Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(0), "encodings"); + } + + [Test] + public void Scenario_traverse_extension_read_full_match() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); + Account account = tree.Get(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111")); + Assert.That(db.ReadsCount, Is.EqualTo(0)); + Assert.That(account.Balance, Is.EqualTo(_account1.Balance)); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); + } + + [Test] + public void Scenario_traverse_extension_read_missing() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); + Account account = tree.Get(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddd")); + Assert.That(account, Is.Null); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); + } + + [Test] + public void Scenario_traverse_extension_new_branching() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddd"), _account2); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x543c960143a2a06b685d6b92f0c37000273e616bc23888521e7edf15ad06da46")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x543c960143a2a06b685d6b92f0c37000273e616bc23888521e7edf15ad06da46")); + } + + [Test] + public void Scenario_traverse_extension_delete_missing() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddd"), null); + Assert.That(db.ReadsCount, Is.EqualTo(0)); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0xf99f1d3234bad8d63d818db36ff63eefc8916263e654db8b800d3bd03f6339a5")); + } + + [Test] + public void Scenario_traverse_extension_create_new_extension() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab00000000"), _account2); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab11111111"), _account3); + Assert.That(db.ReadsCount, Is.EqualTo(0)); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x0918112fc898173562441709a2c1cbedb80d1aaecaeadf2f3e9492eeaa568c67")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x0918112fc898173562441709a2c1cbedb80d1aaecaeadf2f3e9492eeaa568c67")); + } + + [Test] + public void Scenario_traverse_leaf_update_new_value() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account1); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0xaa5c248d4b4b8c27a654296a8e0cc51131eb9011d9166fa0fca56a966489e169")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0xaa5c248d4b4b8c27a654296a8e0cc51131eb9011d9166fa0fca56a966489e169")); + } + + [Test] + public void Scenario_traverse_leaf_update_no_change() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + } + + [Test] + public void Scenario_traverse_leaf_read_matching_leaf() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), null); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")); + } + + [Test] + public void Scenario_traverse_leaf_delete_missing() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); + tree.Set(new Hash256("1111111111111111111111111111111ddddddddddddddddddddddddddddddddd"), null); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + } + + [Test] + public void Scenario_traverse_leaf_update_with_extension() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111111111111111111111111111"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000000000000000000000000000"), _account1); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x215a4bab4cf2d5ebbaa59c82ae94c9707fcf4cc0ca1fe7e18f918e46db428ef9")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x215a4bab4cf2d5ebbaa59c82ae94c9707fcf4cc0ca1fe7e18f918e46db428ef9")); + } + + [Test] + public void Scenario_traverse_leaf_delete_matching_leaf() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); + Account account = tree.Get(new Hash256("1111111111111111111111111111111111111111111111111111111111111111")); + Assert.That(account, Is.Not.Null); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + } + + [Test] + public void Scenario_traverse_leaf_read_missing() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("1111111111111111111111111111111111111111111111111111111111111111"), _account0); + Account account = tree.Get(new Hash256("111111111111111111111111111111111111111111111111111111111ddddddd")); + Assert.That(account, Is.Null); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x491fbb33aaff22c0a7ff68d5c81ec114dddf89d022ccdee838a0e9d6cd45cab4")); + } + + [Test] + public void Scenario_traverse_branch_update_missing() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222"), _account2); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0xc063af0bd3dd88320bc852ff8452049c42fbc06d1a69661567bd427572824cbf")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0xc063af0bd3dd88320bc852ff8452049c42fbc06d1a69661567bd427572824cbf")); + } + + [Test] + public void Scenario_traverse_branch_read_missing() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1); + Account account = tree.Get(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222")); + Assert.That(account, Is.Null); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); + } + + [Test] + public void Scenario_traverse_branch_delete_missing() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222"), null); + tree.UpdateRootHash(); + Hash256 rootHash = tree.RootHash; + Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); + tree.Commit(0); + Assert.That(rootHash.ToString(true), Is.EqualTo("0x94a193704e99c219d9a21428eb37d6d2d71b3d2cea80c77ff0e201c0df70a283")); + } + + [Test] + public void Minimal_hashes_when_setting_on_empty() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.Set(TestItem.AddressB, _account0); + tree.Set(TestItem.AddressC, _account0); + tree.Commit(0); + Assert.That(Trie.Metrics.TreeNodeHashCalculations, Is.EqualTo(5), "hashes"); // branch, branch, three leaves + } + + [Test] + public void Minimal_encodings_when_setting_on_empty() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.Set(TestItem.AddressB, _account0); + tree.Set(TestItem.AddressC, _account0); + tree.Commit(0); + Assert.That(Trie.Metrics.TreeNodeRlpEncodings, Is.EqualTo(5), "encodings"); // branch, branch, three leaves + } + + [Test] + public void Zero_decodings_when_setting_on_empty() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.Set(TestItem.AddressB, _account0); + tree.Set(TestItem.AddressC, _account0); + tree.Commit(0); + Assert.That(Trie.Metrics.TreeNodeRlpDecodings, Is.EqualTo(0), "decodings"); + } + + [Test] + public void No_writes_on_continues_update() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.Set(TestItem.AddressA, _account1); + tree.Set(TestItem.AddressA, _account2); + tree.Set(TestItem.AddressA, _account3); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(1), "writes"); // extension, branch, two leaves + } + + [Ignore("This is not critical")] + [Test] + public void No_writes_on_reverted_update() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(1), "writes before"); // extension, branch, two leaves + tree.Set(TestItem.AddressA, _account1); + tree.Set(TestItem.AddressA, _account0); + tree.Commit(0); + Assert.That(db.WritesCount, Is.EqualTo(1), "writes after"); // extension, branch, two leaves + } + + [Test] + public void No_writes_without_commit() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + Assert.That(db.WritesCount, Is.EqualTo(0), "writes"); + } + + [Test] + public void Can_ask_about_root_hash_without_commiting() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, _account0); + tree.UpdateRootHash(); + Assert.That(tree.RootHash.ToString(true), Is.EqualTo("0x545a417202afcb10925b2afddb70a698710bb1cf4ab32942c42e9f019d564fdc")); + } + + [Test] + public void Can_ask_about_root_hash_without_when_emptied() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0); + tree.UpdateRootHash(); + Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0); + tree.UpdateRootHash(); + Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0); + tree.UpdateRootHash(); + Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null); + tree.UpdateRootHash(); + Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null); + tree.UpdateRootHash(); + Assert.That(tree.RootHash, Is.Not.EqualTo(PatriciaTree.EmptyTreeHash)); + tree.Set(new Hash256("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), null); + tree.UpdateRootHash(); + Assert.That(tree.RootHash, Is.EqualTo(PatriciaTree.EmptyTreeHash)); + tree.Commit(0); + Assert.That(tree.RootHash, Is.EqualTo(PatriciaTree.EmptyTreeHash)); + } + + [Test] + public void hash_empty_tree_root_hash_initially() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + Assert.That(tree.RootHash, Is.EqualTo(PatriciaTree.EmptyTreeHash)); + } + + [Test] + public void Can_save_null() + { + MemDb db = new(); + StateTree tree = new(new TrieStore(db, LimboLogs.Instance).GetTrieStore(null), LimboLogs.Instance); + tree.Set(TestItem.AddressA, null); } } diff --git a/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs b/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs index 82cf349e9c7..5b208bfc0cb 100644 --- a/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs +++ b/src/Nethermind/Nethermind.State.Test/StorageProviderTests.cs @@ -16,433 +16,432 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Store.Test +namespace Nethermind.Store.Test; + +[Parallelizable(ParallelScope.All)] +public class StorageProviderTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class StorageProviderTests + private static readonly ILogManager LogManager = LimboLogs.Instance; + + private readonly byte[][] _values = + [ + [0], + [1], + [2], + [3], + [4], + [5], + [6], + [7], + [8], + [9], + [10], + [11], + [12], + ]; + + [Test] + public void Empty_commit_restore() { - private static readonly ILogManager LogManager = LimboLogs.Instance; + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + provider.Commit(Frontier.Instance); + provider.Restore(Snapshot.Empty); + } - private readonly byte[][] _values = - { - new byte[] {0}, - new byte[] {1}, - new byte[] {2}, - new byte[] {3}, - new byte[] {4}, - new byte[] {5}, - new byte[] {6}, - new byte[] {7}, - new byte[] {8}, - new byte[] {9}, - new byte[] {10}, - new byte[] {11}, - new byte[] {12}, - }; - - [Test] - public void Empty_commit_restore() - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - provider.Commit(Frontier.Instance); - provider.Restore(Snapshot.Empty); - } + private WorldState BuildStorageProvider(Context ctx) + { + return ctx.StateProvider; + } - private WorldState BuildStorageProvider(Context ctx) - { - return ctx.StateProvider; - } + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void Same_address_same_index_different_values_restore(int snapshot) + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + provider.Set(new StorageCell(ctx.Address1, 1), _values[3]); + provider.Restore(Snapshot.EmptyPosition, snapshot, Snapshot.EmptyPosition); + + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[snapshot + 1])); + } - [TestCase(-1)] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - public void Same_address_same_index_different_values_restore(int snapshot) - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - provider.Set(new StorageCell(ctx.Address1, 1), _values[3]); - provider.Restore(Snapshot.EmptyPosition, snapshot, Snapshot.EmptyPosition); - - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[snapshot + 1])); - } + [Test] + public void Keep_in_cache() + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + provider.Commit(Frontier.Instance); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); + provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); + provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[1])); + } - [Test] - public void Keep_in_cache() - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - provider.Commit(Frontier.Instance); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); - provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); - provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[1])); - } + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void Same_address_different_index(int snapshot) + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + provider.Set(new StorageCell(ctx.Address1, 2), _values[2]); + provider.Set(new StorageCell(ctx.Address1, 3), _values[3]); + provider.Restore(Snapshot.EmptyPosition, snapshot, Snapshot.EmptyPosition); + + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[Math.Min(snapshot + 1, 1)])); + } - [TestCase(-1)] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - public void Same_address_different_index(int snapshot) - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - provider.Set(new StorageCell(ctx.Address1, 2), _values[2]); - provider.Set(new StorageCell(ctx.Address1, 3), _values[3]); - provider.Restore(Snapshot.EmptyPosition, snapshot, Snapshot.EmptyPosition); - - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[Math.Min(snapshot + 1, 1)])); - } + [Test] + public void Commit_restore() + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + provider.Set(new StorageCell(ctx.Address1, 2), _values[2]); + provider.Set(new StorageCell(ctx.Address1, 3), _values[3]); + provider.Commit(Frontier.Instance); + provider.Set(new StorageCell(ctx.Address2, 1), _values[4]); + provider.Set(new StorageCell(ctx.Address2, 2), _values[5]); + provider.Set(new StorageCell(ctx.Address2, 3), _values[6]); + provider.Commit(Frontier.Instance); + provider.Set(new StorageCell(ctx.Address1, 1), _values[7]); + provider.Set(new StorageCell(ctx.Address1, 2), _values[8]); + provider.Set(new StorageCell(ctx.Address1, 3), _values[9]); + provider.Commit(Frontier.Instance); + provider.Set(new StorageCell(ctx.Address2, 1), _values[10]); + provider.Set(new StorageCell(ctx.Address2, 2), _values[11]); + provider.Set(new StorageCell(ctx.Address2, 3), _values[12]); + provider.Commit(Frontier.Instance); + provider.Restore(Snapshot.Empty); + + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[7])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[8])); + Assert.That(provider.Get(new StorageCell(ctx.Address1, 3)).ToArray(), Is.EqualTo(_values[9])); + Assert.That(provider.Get(new StorageCell(ctx.Address2, 1)).ToArray(), Is.EqualTo(_values[10])); + Assert.That(provider.Get(new StorageCell(ctx.Address2, 2)).ToArray(), Is.EqualTo(_values[11])); + Assert.That(provider.Get(new StorageCell(ctx.Address2, 3)).ToArray(), Is.EqualTo(_values[12])); + } - [Test] - public void Commit_restore() - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - provider.Set(new StorageCell(ctx.Address1, 2), _values[2]); - provider.Set(new StorageCell(ctx.Address1, 3), _values[3]); - provider.Commit(Frontier.Instance); - provider.Set(new StorageCell(ctx.Address2, 1), _values[4]); - provider.Set(new StorageCell(ctx.Address2, 2), _values[5]); - provider.Set(new StorageCell(ctx.Address2, 3), _values[6]); - provider.Commit(Frontier.Instance); - provider.Set(new StorageCell(ctx.Address1, 1), _values[7]); - provider.Set(new StorageCell(ctx.Address1, 2), _values[8]); - provider.Set(new StorageCell(ctx.Address1, 3), _values[9]); - provider.Commit(Frontier.Instance); - provider.Set(new StorageCell(ctx.Address2, 1), _values[10]); - provider.Set(new StorageCell(ctx.Address2, 2), _values[11]); - provider.Set(new StorageCell(ctx.Address2, 3), _values[12]); - provider.Commit(Frontier.Instance); - provider.Restore(Snapshot.Empty); - - Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[7])); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[8])); - Assert.That(provider.Get(new StorageCell(ctx.Address1, 3)).ToArray(), Is.EqualTo(_values[9])); - Assert.That(provider.Get(new StorageCell(ctx.Address2, 1)).ToArray(), Is.EqualTo(_values[10])); - Assert.That(provider.Get(new StorageCell(ctx.Address2, 2)).ToArray(), Is.EqualTo(_values[11])); - Assert.That(provider.Get(new StorageCell(ctx.Address2, 3)).ToArray(), Is.EqualTo(_values[12])); - } + [Test] + public void Commit_no_changes() + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + provider.Set(new StorageCell(ctx.Address1, 2), _values[2]); + provider.Set(new StorageCell(ctx.Address1, 3), _values[3]); + provider.Restore(Snapshot.Empty); + provider.Commit(Frontier.Instance); + + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).IsZero(), Is.True); + } - [Test] - public void Commit_no_changes() - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - provider.Set(new StorageCell(ctx.Address1, 2), _values[2]); - provider.Set(new StorageCell(ctx.Address1, 3), _values[3]); - provider.Restore(Snapshot.Empty); - provider.Commit(Frontier.Instance); - - Assert.IsTrue(provider.Get(new StorageCell(ctx.Address1, 1)).IsZero()); - } + [Test] + public void Commit_no_changes_2() + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + provider.Set(new StorageCell(ctx.Address1, 1), _values[3]); + provider.Restore(Snapshot.EmptyPosition, 2, Snapshot.EmptyPosition); + provider.Restore(Snapshot.EmptyPosition, 1, Snapshot.EmptyPosition); + provider.Restore(Snapshot.EmptyPosition, 0, Snapshot.EmptyPosition); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + provider.Set(new StorageCell(ctx.Address1, 1), _values[3]); + provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Get(new StorageCell(ctx.Address1, 1)); + provider.Commit(Frontier.Instance); + + Assert.That(provider.Get(new StorageCell(ctx.Address1, 1)).IsZero(), Is.True); + } + + [Test] + public void Commit_trees_clear_caches_get_previous_root() + { + Context ctx = new(); + // block 1 + WorldState storageProvider = BuildStorageProvider(ctx); + storageProvider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + storageProvider.Commit(Frontier.Instance); - [Test] - public void Commit_no_changes_2() + ctx.StateProvider.Commit(Frontier.Instance); + ctx.StateProvider.CommitTree(0); + + // block 2 + Hash256 stateRoot = ctx.StateProvider.StateRoot; + storageProvider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + storageProvider.Commit(Frontier.Instance); + ctx.StateProvider.Commit(Frontier.Instance); + + // revert + ctx.StateProvider.Reset(); + storageProvider.Reset(); + ctx.StateProvider.StateRoot = stateRoot; + + byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)).ToArray(); + + Assert.That(valueAfter, Is.EqualTo(_values[1])); + } + + [Test] + public void Can_commit_when_exactly_at_capacity_regression() + { + Context ctx = new(); + // block 1 + WorldState storageProvider = BuildStorageProvider(ctx); + for (int i = 0; i < Resettable.StartCapacity; i++) { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - provider.Set(new StorageCell(ctx.Address1, 1), _values[3]); - provider.Restore(Snapshot.EmptyPosition, 2, Snapshot.EmptyPosition); - provider.Restore(Snapshot.EmptyPosition, 1, Snapshot.EmptyPosition); - provider.Restore(Snapshot.EmptyPosition, 0, Snapshot.EmptyPosition); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - provider.Set(new StorageCell(ctx.Address1, 1), _values[3]); - provider.Restore(Snapshot.EmptyPosition, -1, Snapshot.EmptyPosition); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Get(new StorageCell(ctx.Address1, 1)); - provider.Commit(Frontier.Instance); - - Assert.True(provider.Get(new StorageCell(ctx.Address1, 1)).IsZero()); + storageProvider.Set(new StorageCell(ctx.Address1, 1), _values[i % 2]); } - [Test] - public void Commit_trees_clear_caches_get_previous_root() - { - Context ctx = new(); - // block 1 - WorldState storageProvider = BuildStorageProvider(ctx); - storageProvider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - storageProvider.Commit(Frontier.Instance); + storageProvider.Commit(Frontier.Instance); + ctx.StateProvider.Commit(Frontier.Instance); + + byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)).ToArray(); + Assert.That(valueAfter, Is.EqualTo(_values[(Resettable.StartCapacity + 1) % 2])); + } - ctx.StateProvider.Commit(Frontier.Instance); - ctx.StateProvider.CommitTree(0); + /// + /// Transient storage should be zero if uninitialized + /// + [Test] + public void Can_tload_uninitialized_locations() + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + // Should be 0 if not set + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).IsZero(), Is.True); - // block 2 - Hash256 stateRoot = ctx.StateProvider.StateRoot; - storageProvider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - storageProvider.Commit(Frontier.Instance); - ctx.StateProvider.Commit(Frontier.Instance); + // Should be 0 if loading from the same contract but different index + provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).IsZero(), Is.True); - // revert - ctx.StateProvider.Reset(); - storageProvider.Reset(); - ctx.StateProvider.StateRoot = stateRoot; + // Should be 0 if loading from the same index but different contract + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address2, 1)).IsZero(), Is.True); + } - byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)).ToArray(); + /// + /// Simple transient storage test + /// + [Test] + public void Can_tload_after_tstore() + { + Context ctx = new Context(); + WorldState provider = BuildStorageProvider(ctx); - Assert.That(valueAfter, Is.EqualTo(_values[1])); - } + provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); + } - [Test] - public void Can_commit_when_exactly_at_capacity_regression() - { - Context ctx = new(); - // block 1 - WorldState storageProvider = BuildStorageProvider(ctx); - for (int i = 0; i < Resettable.StartCapacity; i++) - { - storageProvider.Set(new StorageCell(ctx.Address1, 1), _values[i % 2]); - } - - storageProvider.Commit(Frontier.Instance); - ctx.StateProvider.Commit(Frontier.Instance); - - byte[] valueAfter = storageProvider.Get(new StorageCell(ctx.Address1, 1)).ToArray(); - Assert.That(valueAfter, Is.EqualTo(_values[(Resettable.StartCapacity + 1) % 2])); - } + /// + /// Transient storage can be updated and restored + /// + /// Snapshot to restore to + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void Tload_same_address_same_index_different_values_restore(int snapshot) + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + Snapshot[] snapshots = new Snapshot[4]; + snapshots[0] = provider.TakeSnapshot(); + provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[1]); + snapshots[1] = provider.TakeSnapshot(); + provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[2]); + snapshots[2] = provider.TakeSnapshot(); + provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[3]); + snapshots[3] = provider.TakeSnapshot(); + + Assert.That(snapshot, Is.EqualTo(snapshots[snapshot + 1].StorageSnapshot.TransientStorageSnapshot)); + // Persistent storage is unimpacted by transient storage + Assert.That(snapshots[snapshot + 1].StorageSnapshot.PersistentStorageSnapshot, Is.EqualTo(-1)); + + provider.Restore(snapshots[snapshot + 1]); + + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[snapshot + 1])); + } - /// - /// Transient storage should be zero if uninitialized - /// - [Test] - public void Can_tload_uninitialized_locations() - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - // Should be 0 if not set - Assert.True(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).IsZero()); + /// + /// Commit will reset transient state + /// + [Test] + public void Commit_resets_transient_state() + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); - // Should be 0 if loading from the same contract but different index - provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); - Assert.True(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).IsZero()); + provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); - // Should be 0 if loading from the same index but different contract - Assert.True(provider.GetTransientState(new StorageCell(ctx.Address2, 1)).IsZero()); - } + provider.Commit(Frontier.Instance); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).IsZero(), Is.True); + } - /// - /// Simple transient storage test - /// - [Test] - public void Can_tload_after_tstore() - { - Context ctx = new Context(); - WorldState provider = BuildStorageProvider(ctx); + /// + /// Reset will reset transient state + /// + [Test] + public void Reset_resets_transient_state() + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); - provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); - } + provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); - /// - /// Transient storage can be updated and restored - /// - /// Snapshot to restore to - [TestCase(-1)] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - public void Tload_same_address_same_index_different_values_restore(int snapshot) - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - Snapshot[] snapshots = new Snapshot[4]; - snapshots[0] = provider.TakeSnapshot(); - provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[1]); - snapshots[1] = provider.TakeSnapshot(); - provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[2]); - snapshots[2] = provider.TakeSnapshot(); - provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[3]); - snapshots[3] = provider.TakeSnapshot(); - - Assert.That(snapshot, Is.EqualTo(snapshots[snapshot + 1].StorageSnapshot.TransientStorageSnapshot)); - // Persistent storage is unimpacted by transient storage - Assert.That(snapshots[snapshot + 1].StorageSnapshot.PersistentStorageSnapshot, Is.EqualTo(-1)); - - provider.Restore(snapshots[snapshot + 1]); - - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).ToArray(), Is.EqualTo(_values[snapshot + 1])); - } + provider.Reset(); + Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).IsZero(), Is.True); + } - /// - /// Commit will reset transient state - /// - [Test] - public void Commit_resets_transient_state() - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); + /// + /// Transient state does not impact persistent state + /// + /// Snapshot to restore to + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void Transient_state_restores_independent_of_persistent_state(int snapshot) + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + Snapshot[] snapshots = new Snapshot[4]; - provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); + // No updates + snapshots[0] = provider.TakeSnapshot(); - provider.Commit(Frontier.Instance); - Assert.True(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).IsZero()); - } + // Only update transient + provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[1]); + snapshots[1] = provider.TakeSnapshot(); - /// - /// Reset will reset transient state - /// - [Test] - public void Reset_resets_transient_state() - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); + // Update both + provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[2]); + provider.Set(new StorageCell(ctx.Address1, 1), _values[9]); + snapshots[2] = provider.TakeSnapshot(); - provider.SetTransientState(new StorageCell(ctx.Address1, 2), _values[1]); - Assert.That(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).ToArray(), Is.EqualTo(_values[1])); + // Only update persistent + provider.Set(new StorageCell(ctx.Address1, 1), _values[8]); + snapshots[3] = provider.TakeSnapshot(); - provider.Reset(); - Assert.True(provider.GetTransientState(new StorageCell(ctx.Address1, 2)).IsZero()); - } + provider.Restore(snapshots[snapshot + 1]); - /// - /// Transient state does not impact persistent state - /// - /// Snapshot to restore to - [TestCase(-1)] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - public void Transient_state_restores_independent_of_persistent_state(int snapshot) + // Since we didn't update transient on the 3rd snapshot + if (snapshot == 2) { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - Snapshot[] snapshots = new Snapshot[4]; - - // No updates - snapshots[0] = provider.TakeSnapshot(); - - // Only update transient - provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[1]); - snapshots[1] = provider.TakeSnapshot(); - - // Update both - provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[2]); - provider.Set(new StorageCell(ctx.Address1, 1), _values[9]); - snapshots[2] = provider.TakeSnapshot(); - - // Only update persistent - provider.Set(new StorageCell(ctx.Address1, 1), _values[8]); - snapshots[3] = provider.TakeSnapshot(); - - provider.Restore(snapshots[snapshot + 1]); - - // Since we didn't update transient on the 3rd snapshot - if (snapshot == 2) - { - snapshot--; - } - snapshots[0].StorageSnapshot.Should().BeEquivalentTo(Snapshot.Storage.Empty); - snapshots[1].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(Snapshot.EmptyPosition, 0)); - snapshots[2].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(0, 1)); - snapshots[3].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(1, 1)); - - _values[snapshot + 1].Should().BeEquivalentTo(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).ToArray()); + snapshot--; } + snapshots[0].StorageSnapshot.Should().BeEquivalentTo(Snapshot.Storage.Empty); + snapshots[1].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(Snapshot.EmptyPosition, 0)); + snapshots[2].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(0, 1)); + snapshots[3].StorageSnapshot.Should().BeEquivalentTo(new Snapshot.Storage(1, 1)); - /// - /// Persistent state does not impact transient state - /// - /// Snapshot to restore to - [TestCase(-1)] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - public void Persistent_state_restores_independent_of_transient_state(int snapshot) - { - Context ctx = new(); - WorldState provider = BuildStorageProvider(ctx); - Snapshot[] snapshots = new Snapshot[4]; - - // No updates - snapshots[0] = (provider).TakeSnapshot(); - - // Only update persistent - provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); - snapshots[1] = (provider).TakeSnapshot(); - - // Update both - provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); - provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[9]); - snapshots[2] = (provider).TakeSnapshot(); - - // Only update transient - provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[8]); - snapshots[3] = (provider).TakeSnapshot(); - - provider.Restore(snapshots[snapshot + 1]); - - // Since we didn't update persistent on the 3rd snapshot - if (snapshot == 2) - { - snapshot--; - } - - snapshots.Should().Equal( - Snapshot.Empty, - new Snapshot(Snapshot.EmptyPosition, new Snapshot.Storage(0, Snapshot.EmptyPosition)), - new Snapshot(Snapshot.EmptyPosition, new Snapshot.Storage(1, 0)), - new Snapshot(Snapshot.EmptyPosition, new Snapshot.Storage(1, 1)) - ); - - _values[snapshot + 1].Should().BeEquivalentTo(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray()); - } + _values[snapshot + 1].Should().BeEquivalentTo(provider.GetTransientState(new StorageCell(ctx.Address1, 1)).ToArray()); + } + + /// + /// Persistent state does not impact transient state + /// + /// Snapshot to restore to + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void Persistent_state_restores_independent_of_transient_state(int snapshot) + { + Context ctx = new(); + WorldState provider = BuildStorageProvider(ctx); + Snapshot[] snapshots = new Snapshot[4]; + + // No updates + snapshots[0] = (provider).TakeSnapshot(); + + // Only update persistent + provider.Set(new StorageCell(ctx.Address1, 1), _values[1]); + snapshots[1] = (provider).TakeSnapshot(); + + // Update both + provider.Set(new StorageCell(ctx.Address1, 1), _values[2]); + provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[9]); + snapshots[2] = (provider).TakeSnapshot(); + + // Only update transient + provider.SetTransientState(new StorageCell(ctx.Address1, 1), _values[8]); + snapshots[3] = (provider).TakeSnapshot(); - /// - /// Reset will reset transient state - /// - [Test] - public void Selfdestruct_clears_cache() + provider.Restore(snapshots[snapshot + 1]); + + // Since we didn't update persistent on the 3rd snapshot + if (snapshot == 2) { - PreBlockCaches preBlockCaches = new PreBlockCaches(); - Context ctx = new(preBlockCaches); - WorldState provider = BuildStorageProvider(ctx); - StorageCell accessedStorageCell = new StorageCell(TestItem.AddressA, 1); - StorageCell nonAccessedStorageCell = new StorageCell(TestItem.AddressA, 2); - preBlockCaches.StorageCache[accessedStorageCell] = [1, 2, 3]; - provider.Get(accessedStorageCell); - provider.Commit(Paris.Instance); - provider.ClearStorage(TestItem.AddressA); - provider.Get(accessedStorageCell).ToArray().Should().BeEquivalentTo(StorageTree.EmptyBytes); - provider.Get(nonAccessedStorageCell).ToArray().Should().BeEquivalentTo(StorageTree.EmptyBytes); + snapshot--; } - private class Context + snapshots.Should().Equal( + Snapshot.Empty, + new Snapshot(Snapshot.EmptyPosition, new Snapshot.Storage(0, Snapshot.EmptyPosition)), + new Snapshot(Snapshot.EmptyPosition, new Snapshot.Storage(1, 0)), + new Snapshot(Snapshot.EmptyPosition, new Snapshot.Storage(1, 1)) + ); + + _values[snapshot + 1].Should().BeEquivalentTo(provider.Get(new StorageCell(ctx.Address1, 1)).ToArray()); + } + + /// + /// Reset will reset transient state + /// + [Test] + public void Selfdestruct_clears_cache() + { + PreBlockCaches preBlockCaches = new PreBlockCaches(); + Context ctx = new(preBlockCaches); + WorldState provider = BuildStorageProvider(ctx); + StorageCell accessedStorageCell = new StorageCell(TestItem.AddressA, 1); + StorageCell nonAccessedStorageCell = new StorageCell(TestItem.AddressA, 2); + preBlockCaches.StorageCache[accessedStorageCell] = [1, 2, 3]; + provider.Get(accessedStorageCell); + provider.Commit(Paris.Instance); + provider.ClearStorage(TestItem.AddressA); + provider.Get(accessedStorageCell).ToArray().Should().BeEquivalentTo(StorageTree.EmptyBytes); + provider.Get(nonAccessedStorageCell).ToArray().Should().BeEquivalentTo(StorageTree.EmptyBytes); + } + + private class Context + { + public WorldState StateProvider { get; } + + public readonly Address Address1 = new(Keccak.Compute("1")); + public readonly Address Address2 = new(Keccak.Compute("2")); + + public Context(PreBlockCaches preBlockCaches = null) { - public WorldState StateProvider { get; } - - public readonly Address Address1 = new(Keccak.Compute("1")); - public readonly Address Address2 = new(Keccak.Compute("2")); - - public Context(PreBlockCaches preBlockCaches = null) - { - StateProvider = new WorldState(new TrieStore(new MemDb(), LimboLogs.Instance), Substitute.For(), LogManager, preBlockCaches); - StateProvider.CreateAccount(Address1, 0); - StateProvider.CreateAccount(Address2, 0); - StateProvider.Commit(Frontier.Instance); - } + StateProvider = new WorldState(new TrieStore(new MemDb(), LimboLogs.Instance), Substitute.For(), LogManager, preBlockCaches); + StateProvider.CreateAccount(Address1, 0); + StateProvider.CreateAccount(Address2, 0); + StateProvider.Commit(Frontier.Instance); } } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs index fbf2a7a6297..4638459df26 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs @@ -116,7 +116,7 @@ public async Task Can_reach_terminal_block(long headNumber, int options, int thr SyncPeerMock syncPeer = new(syncedTree, false, Response.AllCorrect, 16000000); PeerInfo peerInfo = new(syncPeer); await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); - Assert.True(ctx.PosSwitcher.HasEverReachedTerminalBlock()); + Assert.That(ctx.PosSwitcher.HasEverReachedTerminalBlock(), Is.True); } [TestCase(32L, DownloaderOptions.MoveToMain, 16, false, 16)] diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs index 113a6f3e641..4ef7a20f16e 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs @@ -39,1334 +39,1333 @@ using BlockTree = Nethermind.Blockchain.BlockTree; using System.Diagnostics.CodeAnalysis; -namespace Nethermind.Synchronization.Test +namespace Nethermind.Synchronization.Test; + +[Parallelizable(ParallelScope.All)] +public partial class BlockDownloaderTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public partial class BlockDownloaderTests + [TestCase(1L, DownloaderOptions.Process, 0)] + [TestCase(32L, DownloaderOptions.Process, 0)] + [TestCase(32L, DownloaderOptions.None, 0)] + [TestCase(1L, DownloaderOptions.WithReceipts, 0)] + [TestCase(2L, DownloaderOptions.WithReceipts, 0)] + [TestCase(3L, DownloaderOptions.WithReceipts, 0)] + [TestCase(32L, DownloaderOptions.WithReceipts, 0)] + [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.WithReceipts, 0)] + [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.Process, 0)] + [TestCase(1L, DownloaderOptions.Process, 32)] + [TestCase(32L, DownloaderOptions.Process, 32)] + [TestCase(32L, DownloaderOptions.None, 32)] + [TestCase(1L, DownloaderOptions.WithReceipts, 32)] + [TestCase(2L, DownloaderOptions.WithReceipts, 32)] + [TestCase(3L, DownloaderOptions.WithReceipts, 32)] + [TestCase(32L, DownloaderOptions.WithReceipts, 32)] + [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.WithReceipts, 32)] + [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.Process, 32)] + public async Task Happy_path(long headNumber, int options, int threshold) { - [TestCase(1L, DownloaderOptions.Process, 0)] - [TestCase(32L, DownloaderOptions.Process, 0)] - [TestCase(32L, DownloaderOptions.None, 0)] - [TestCase(1L, DownloaderOptions.WithReceipts, 0)] - [TestCase(2L, DownloaderOptions.WithReceipts, 0)] - [TestCase(3L, DownloaderOptions.WithReceipts, 0)] - [TestCase(32L, DownloaderOptions.WithReceipts, 0)] - [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.WithReceipts, 0)] - [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.Process, 0)] - [TestCase(1L, DownloaderOptions.Process, 32)] - [TestCase(32L, DownloaderOptions.Process, 32)] - [TestCase(32L, DownloaderOptions.None, 32)] - [TestCase(1L, DownloaderOptions.WithReceipts, 32)] - [TestCase(2L, DownloaderOptions.WithReceipts, 32)] - [TestCase(3L, DownloaderOptions.WithReceipts, 32)] - [TestCase(32L, DownloaderOptions.WithReceipts, 32)] - [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.WithReceipts, 32)] - [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.Process, 32)] - public async Task Happy_path(long headNumber, int options, int threshold) - { - Context ctx = new(); - DownloaderOptions downloaderOptions = (DownloaderOptions)options; - bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts; - BlockDownloader downloader = ctx.BlockDownloader; - - Response responseOptions = Response.AllCorrect; - if (withReceipts) - { - responseOptions |= Response.WithTransactions; - } + Context ctx = new(); + DownloaderOptions downloaderOptions = (DownloaderOptions)options; + bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts; + BlockDownloader downloader = ctx.BlockDownloader; + + Response responseOptions = Response.AllCorrect; + if (withReceipts) + { + responseOptions |= Response.WithTransactions; + } - // normally chain length should be head number + 1 so here we setup a slightly shorter chain which - // will only be fixed slightly later - long chainLength = headNumber + 1; - SyncPeerMock syncPeer = new(chainLength, withReceipts, responseOptions); + // normally chain length should be head number + 1 so here we setup a slightly shorter chain which + // will only be fixed slightly later + long chainLength = headNumber + 1; + SyncPeerMock syncPeer = new(chainLength, withReceipts, responseOptions); - PeerInfo peerInfo = new(syncPeer); + PeerInfo peerInfo = new(syncPeer); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); - ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(Math.Max(0, Math.Min(headNumber, headNumber - threshold))); + ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(Math.Max(0, Math.Min(headNumber, headNumber - threshold))); - syncPeer.ExtendTree(chainLength * 2); - await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); - ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(Math.Max(0, peerInfo.HeadNumber)); - ctx.BlockTree.IsMainChain(ctx.BlockTree.BestSuggestedHeader!.Hash!).Should().Be(downloaderOptions != DownloaderOptions.Process); + syncPeer.ExtendTree(chainLength * 2); + await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); + ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(Math.Max(0, peerInfo.HeadNumber)); + ctx.BlockTree.IsMainChain(ctx.BlockTree.BestSuggestedHeader!.Hash!).Should().Be(downloaderOptions != DownloaderOptions.Process); - int receiptCount = 0; - for (int i = (int)Math.Max(0, headNumber - threshold); i < peerInfo.HeadNumber; i++) + int receiptCount = 0; + for (int i = (int)Math.Max(0, headNumber - threshold); i < peerInfo.HeadNumber; i++) + { + if (i % 3 == 0) { - if (i % 3 == 0) - { - receiptCount += 2; - } + receiptCount += 2; } - - ctx.ReceiptStorage.Count.Should().Be(withReceipts ? receiptCount : 0); } - [Test] - public async Task Ancestor_lookup_simple() - { - Context ctx = new() - { - BlockTree = Build.A.BlockTree().OfChainLength(1024).TestObject, - }; - BlockDownloader downloader = ctx.BlockDownloader; + ctx.ReceiptStorage.Count.Should().Be(withReceipts ? receiptCount : 0); + } - Response blockResponseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new(2048 + 1, false, blockResponseOptions); + [Test] + public async Task Ancestor_lookup_simple() + { + Context ctx = new() + { + BlockTree = Build.A.BlockTree().OfChainLength(1024).TestObject, + }; + BlockDownloader downloader = ctx.BlockDownloader; - PeerInfo peerInfo = new(syncPeer); + Response blockResponseOptions = Response.AllCorrect; + SyncPeerMock syncPeer = new(2048 + 1, false, blockResponseOptions); - Block block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head!).WithDifficulty(ctx.BlockTree.Head!.Difficulty + 1).TestObject; - Block block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; - Block block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; - ctx.BlockTree.SuggestBlock(block1024); - ctx.BlockTree.SuggestBlock(block1025); - ctx.BlockTree.SuggestBlock(block1026); + PeerInfo peerInfo = new(syncPeer); - for (int i = 0; i < 1023; i++) - { - Assert.That(syncPeer.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash, Is.EqualTo(ctx.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash), i.ToString()); - } + Block block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head!).WithDifficulty(ctx.BlockTree.Head!.Difficulty + 1).TestObject; + Block block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; + Block block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; + ctx.BlockTree.SuggestBlock(block1024); + ctx.BlockTree.SuggestBlock(block1025); + ctx.BlockTree.SuggestBlock(block1026); - await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithReceipts, 0), CancellationToken.None); - ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(peerInfo.HeadNumber); - ctx.BlockTree.IsMainChain(ctx.BlockTree.BestSuggestedHeader.GetOrCalculateHash()).Should().Be(true); + for (int i = 0; i < 1023; i++) + { + Assert.That(syncPeer.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash, Is.EqualTo(ctx.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash), i.ToString()); } - [Test] - public async Task Ancestor_lookup_headers() + await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithReceipts, 0), CancellationToken.None); + ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(peerInfo.HeadNumber); + ctx.BlockTree.IsMainChain(ctx.BlockTree.BestSuggestedHeader.GetOrCalculateHash()).Should().Be(true); + } + + [Test] + public async Task Ancestor_lookup_headers() + { + Context ctx = new() { - Context ctx = new() - { - BlockTree = Build.A.BlockTree().OfChainLength(1024).TestObject, - }; - BlockDownloader downloader = ctx.BlockDownloader; + BlockTree = Build.A.BlockTree().OfChainLength(1024).TestObject, + }; + BlockDownloader downloader = ctx.BlockDownloader; + + Response responseOptions = Response.AllCorrect; + SyncPeerMock syncPeer = new(2048 + 1, false, responseOptions); + PeerInfo peerInfo = new(syncPeer); + + Block block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head!).WithDifficulty(ctx.BlockTree.Head!.Difficulty + 1).TestObject; + Block block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; + Block block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; + ctx.BlockTree.SuggestBlock(block1024); + ctx.BlockTree.SuggestBlock(block1025); + ctx.BlockTree.SuggestBlock(block1026); + + for (int i = 0; i < 1023; i++) + { + Assert.That(syncPeer.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash, Is.EqualTo(ctx.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash), i.ToString()); + } - Response responseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new(2048 + 1, false, responseOptions); - PeerInfo peerInfo = new(syncPeer); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(), CancellationToken.None); + ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(peerInfo.HeadNumber); + } - Block block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head!).WithDifficulty(ctx.BlockTree.Head!.Difficulty + 1).TestObject; - Block block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; - Block block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; - ctx.BlockTree.SuggestBlock(block1024); - ctx.BlockTree.SuggestBlock(block1025); - ctx.BlockTree.SuggestBlock(block1026); + [Test] + public void Ancestor_failure() + { + Context ctx = new() + { + BlockTree = Build.A.BlockTree().OfChainLength(2048 + 1).TestObject, + }; + BlockDownloader downloader = ctx.BlockDownloader; - for (int i = 0; i < 1023; i++) - { - Assert.That(syncPeer.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash, Is.EqualTo(ctx.BlockTree.FindBlock(i, BlockTreeLookupOptions.None)!.Hash), i.ToString()); - } + Response blockResponseOptions = Response.AllCorrect; + SyncPeerMock syncPeer = new(2072 + 1, true, blockResponseOptions); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(), CancellationToken.None); - ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(peerInfo.HeadNumber); - } + PeerInfo peerInfo = new(syncPeer); - [Test] - public void Ancestor_failure() - { - Context ctx = new() - { - BlockTree = Build.A.BlockTree().OfChainLength(2048 + 1).TestObject, - }; - BlockDownloader downloader = ctx.BlockDownloader; + Assert.ThrowsAsync(() => downloader.DownloadHeaders(peerInfo, new BlocksRequest(), CancellationToken.None)); + ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(2048); + } - Response blockResponseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new(2072 + 1, true, blockResponseOptions); + [Test] + public void Ancestor_failure_blocks() + { + Context ctx = new() + { + BlockTree = Build.A.BlockTree().OfChainLength(2048 + 1).TestObject, + }; + BlockDownloader downloader = ctx.BlockDownloader; - PeerInfo peerInfo = new(syncPeer); + Response responseOptions = Response.AllCorrect; + SyncPeerMock syncPeer = new(2072 + 1, true, responseOptions); - Assert.ThrowsAsync(() => downloader.DownloadHeaders(peerInfo, new BlocksRequest(), CancellationToken.None)); - ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(2048); - } + PeerInfo peerInfo = new(syncPeer); - [Test] - public void Ancestor_failure_blocks() - { - Context ctx = new() - { - BlockTree = Build.A.BlockTree().OfChainLength(2048 + 1).TestObject, - }; - BlockDownloader downloader = ctx.BlockDownloader; + Assert.ThrowsAsync(() => downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None)); + ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(2048); + } - Response responseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new(2072 + 1, true, responseOptions); + [TestCase(32, true)] + [TestCase(1, true)] + [TestCase(0, true)] + [TestCase(32, false)] + [TestCase(1, false)] + [TestCase(0, false)] + public async Task Can_sync_with_peer_when_it_times_out_on_full_batch(int ignoredBlocks, bool mergeDownloader) + { + Context ctx = mergeDownloader ? new PostMergeContext() : new Context(); + SyncBatchSize syncBatchSize = new SyncBatchSize(LimboLogs.Instance); + syncBatchSize.ExpandUntilMax(); + ctx.SyncBatchSize = syncBatchSize; + BlockDownloader downloader = ctx.BlockDownloader; - PeerInfo peerInfo = new(syncPeer); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(async ci => await ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.TimeoutOnFullBatch)); - Assert.ThrowsAsync(() => downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None)); - ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(2048); - } + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.TimeoutOnFullBatch)); - [TestCase(32, true)] - [TestCase(1, true)] - [TestCase(0, true)] - [TestCase(32, false)] - [TestCase(1, false)] - [TestCase(0, false)] - public async Task Can_sync_with_peer_when_it_times_out_on_full_batch(int ignoredBlocks, bool mergeDownloader) - { - Context ctx = mergeDownloader ? new PostMergeContext() : new Context(); - SyncBatchSize syncBatchSize = new SyncBatchSize(LimboLogs.Instance); - syncBatchSize.ExpandUntilMax(); - ctx.SyncBatchSize = syncBatchSize; - BlockDownloader downloader = ctx.BlockDownloader; + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.HeadNumber.Returns((int)Math.Ceiling(SyncBatchSize.Max * SyncBatchSize.AdjustmentFactor) + ignoredBlocks); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(async ci => await ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.TimeoutOnFullBatch)); + PeerInfo peerInfo = new(syncPeer); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.TimeoutOnFullBatch)); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, ignoredBlocks), CancellationToken.None).ContinueWith(_ => { }); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, ignoredBlocks), CancellationToken.None); + Assert.That(ctx.BlockTree.BestSuggestedHeader!.Number, Is.EqualTo(Math.Max(0, peerInfo.HeadNumber - ignoredBlocks))); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.HeadNumber.Returns((int)Math.Ceiling(SyncBatchSize.Max * SyncBatchSize.AdjustmentFactor) + ignoredBlocks); + syncPeer.HeadNumber.Returns((int)Math.Ceiling(SyncBatchSize.Max * SyncBatchSize.AdjustmentFactor) + ignoredBlocks); + await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None).ContinueWith(continuationAction: _ => { }); + await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); + Assert.That(ctx.BlockTree.BestSuggestedHeader.Number, Is.EqualTo(Math.Max(0, peerInfo.HeadNumber))); + } - PeerInfo peerInfo = new(syncPeer); + [TestCase(32, 32, 0, true)] + [TestCase(32, 16, 0, true)] + [TestCase(500, 250, 0, true)] + [TestCase(32, 32, 0, false)] + [TestCase(32, 16, 0, false)] + [TestCase(500, 250, 0, false)] + [TestCase(32, 16, 100, true)] + [TestCase(32, 16, 100, false)] + public async Task Can_sync_partially_when_only_some_bodies_is_available(int blockCount, int availableBlock, int minResponseLength, bool mergeDownloader) + { + Context ctx = mergeDownloader ? new PostMergeContext() : new Context(); + BlockDownloader downloader = ctx.BlockDownloader; - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, ignoredBlocks), CancellationToken.None).ContinueWith(_ => { }); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, ignoredBlocks), CancellationToken.None); - Assert.That(ctx.BlockTree.BestSuggestedHeader!.Number, Is.EqualTo(Math.Max(0, peerInfo.HeadNumber - ignoredBlocks))); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(async ci => await ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions & ~Response.AllKnown)); - syncPeer.HeadNumber.Returns((int)Math.Ceiling(SyncBatchSize.Max * SyncBatchSize.AdjustmentFactor) + ignoredBlocks); - await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None).ContinueWith(continuationAction: _ => { }); - await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); - Assert.That(ctx.BlockTree.BestSuggestedHeader.Number, Is.EqualTo(Math.Max(0, peerInfo.HeadNumber))); - } + List requestedHashes = new(); + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => + { + IList blockHashes = ci.ArgAt>(0); + int toTake = availableBlock - requestedHashes.Count; + blockHashes = blockHashes.Take(toTake).ToList(); + requestedHashes.AddRange(blockHashes); - [TestCase(32, 32, 0, true)] - [TestCase(32, 16, 0, true)] - [TestCase(500, 250, 0, true)] - [TestCase(32, 32, 0, false)] - [TestCase(32, 16, 0, false)] - [TestCase(500, 250, 0, false)] - [TestCase(32, 16, 100, true)] - [TestCase(32, 16, 100, false)] - public async Task Can_sync_partially_when_only_some_bodies_is_available(int blockCount, int availableBlock, int minResponseLength, bool mergeDownloader) - { - Context ctx = mergeDownloader ? new PostMergeContext() : new Context(); - BlockDownloader downloader = ctx.BlockDownloader; - - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(async ci => await ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions & ~Response.AllKnown)); - - List requestedHashes = new(); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => + if (blockHashes.Count == 0) { - IList blockHashes = ci.ArgAt>(0); - int toTake = availableBlock - requestedHashes.Count; - blockHashes = blockHashes.Take(toTake).ToList(); - requestedHashes.AddRange(blockHashes); + return new OwnedBlockBodies(Array.Empty()); + } - if (blockHashes.Count == 0) + BlockBody?[] response = ctx.ResponseBuilder + .BuildBlocksResponse(blockHashes, Response.AllCorrect | Response.WithTransactions & ~Response.AllKnown) + .Result + .Bodies!; + + if (response.Length < minResponseLength) + { + BlockBody?[] nullPaddedResponse = new BlockBody[minResponseLength]; + for (int i = 0; i < response.Length; i++) { - return new OwnedBlockBodies(Array.Empty()); + nullPaddedResponse[i] = response[i]; } + response = nullPaddedResponse; + } - BlockBody?[] response = ctx.ResponseBuilder - .BuildBlocksResponse(blockHashes, Response.AllCorrect | Response.WithTransactions & ~Response.AllKnown) - .Result - .Bodies!; + return new OwnedBlockBodies(response); + }); - if (response.Length < minResponseLength) - { - BlockBody?[] nullPaddedResponse = new BlockBody[minResponseLength]; - for (int i = 0; i < response.Length; i++) - { - nullPaddedResponse[i] = response[i]; - } - response = nullPaddedResponse; - } + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.HeadNumber.Returns(blockCount); - return new OwnedBlockBodies(response); - }); + PeerInfo peerInfo = new(syncPeer); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.HeadNumber.Returns(blockCount); + ctx.BlockTree.BestSuggestedBody!.Number.Should().Be(0); + await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.Process), CancellationToken.None).ContinueWith(_ => { }); + ctx.BlockTree.BestSuggestedBody.Number.Should().Be(availableBlock); + } - PeerInfo peerInfo = new(syncPeer); + [Test] + public async Task Headers_already_known() + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - ctx.BlockTree.BestSuggestedBody!.Number.Should().Be(0); - await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.Process), CancellationToken.None).ContinueWith(_ => { }); - ctx.BlockTree.BestSuggestedBody.Number.Should().Be(availableBlock); - } + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.AllKnown)); - [Test] - public async Task Headers_already_known() - { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.AllKnown)); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.AllKnown)); + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(64); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.AllKnown)); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None) + .ContinueWith(t => Assert.That(t.IsCompletedSuccessfully, Is.True)); - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(64); + syncPeer.HeadNumber.Returns(128); + await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None) + .ContinueWith(t => Assert.That(t.IsCompletedSuccessfully, Is.True)); + } - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None) - .ContinueWith(t => Assert.True(t.IsCompletedSuccessfully)); + [Test] + public async Task Peer_only_advertise_one_header() + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - syncPeer.HeadNumber.Returns(128); - await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None) - .ContinueWith(t => Assert.True(t.IsCompletedSuccessfully)); - } + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(_ => ctx.ResponseBuilder.BuildHeaderResponse(0, 1, Response.AllCorrect)); - [Test] - public async Task Peer_only_advertise_one_header() - { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; + PeerInfo peerInfo = new(syncPeer); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.HeadNumber.Returns(1); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(_ => ctx.ResponseBuilder.BuildHeaderResponse(0, 1, Response.AllCorrect)); + long blockSynced = await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); - PeerInfo peerInfo = new(syncPeer); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.HeadNumber.Returns(1); + Assert.That(blockSynced, Is.EqualTo(0)); + } - long blockSynced = await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); + [TestCase(33L)] + [TestCase(65L)] + public async Task Peer_sends_just_one_item_when_advertising_more_blocks_but_no_bodies(long headNumber) + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - Assert.That(blockSynced, Is.EqualTo(0)); - } + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.NoBody)); - [TestCase(33L)] - [TestCase(65L)] - public async Task Peer_sends_just_one_item_when_advertising_more_blocks_but_no_bodies(long headNumber) - { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.JustFirst)); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.NoBody)); + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(headNumber); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.JustFirst)); + Task task = downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); + await task.ContinueWith(t => Assert.That(t.IsFaulted, Is.False)); - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(headNumber); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + Assert.That(ctx.BlockTree.BestSuggestedHeader!.Number, Is.EqualTo(headNumber)); + } - Task task = downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); - await task.ContinueWith(t => Assert.False(t.IsFaulted)); + [Test] + public async Task Throws_on_null_best_peer() + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; + Task task1 = downloader.DownloadHeaders(null, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + await task1.ContinueWith(t => Assert.That(t.IsFaulted, Is.True)); - Assert.That(ctx.BlockTree.BestSuggestedHeader!.Number, Is.EqualTo(headNumber)); - } + Task task2 = downloader.DownloadBlocks(null, new BlocksRequest(), CancellationToken.None); + await task2.ContinueWith(t => Assert.That(t.IsFaulted, Is.True)); + } - [Test] - public async Task Throws_on_null_best_peer() + [Test] + public async Task Throws_on_inconsistent_batch() + { + Context ctx = new(); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect ^ Response.Consistent)); + + PeerInfo peerInfo = new(syncPeer); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.HeadNumber.Returns(1024); + + BlockDownloader downloader = ctx.BlockDownloader; + Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + await task.ContinueWith(t => Assert.That(t.IsFaulted, Is.True)); + } + + [Test] + public async Task Throws_on_invalid_seal() + { + Context ctx = new() { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; - Task task1 = downloader.DownloadHeaders(null, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); - await task1.ContinueWith(t => Assert.True(t.IsFaulted)); + SealValidator = Always.Invalid, + }; + BlockDownloader downloader = ctx.BlockDownloader; - Task task2 = downloader.DownloadBlocks(null, new BlocksRequest(), CancellationToken.None); - await task2.ContinueWith(t => Assert.True(t.IsFaulted)); - } + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); + + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(1000); + + Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + await task.ContinueWith(t => Assert.That(t.IsFaulted, Is.True)); + } - [Test] - public async Task Throws_on_inconsistent_batch() + [Test] + public async Task Throws_on_invalid_header() + { + Context ctx = new() { - Context ctx = new(); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect ^ Response.Consistent)); + BlockValidator = Always.Invalid, + }; + BlockDownloader downloader = ctx.BlockDownloader; - PeerInfo peerInfo = new(syncPeer); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.HeadNumber.Returns(1024); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); - BlockDownloader downloader = ctx.BlockDownloader; - Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); - await task.ContinueWith(t => Assert.True(t.IsFaulted)); - } + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(1000); + + Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + await task.ContinueWith(t => Assert.That(t.IsFaulted, Is.True)); + } - [Test] - public async Task Throws_on_invalid_seal() + private class SlowSealValidator : ISealValidator + { + public bool ValidateParams(BlockHeader parent, BlockHeader header, bool isUncle = false) { - Context ctx = new() - { - SealValidator = Always.Invalid, - }; - BlockDownloader downloader = ctx.BlockDownloader; + Thread.Sleep(1000); + return true; + } - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); + public bool ValidateSeal(BlockHeader header, bool force) + { + Thread.Sleep(1000); + return true; + } + } - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(1000); + private class SlowHeaderValidator : IBlockValidator + { - Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); - await task.ContinueWith(t => Assert.True(t.IsFaulted)); + public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle) + { + Thread.Sleep(1000); + return true; } - [Test] - public async Task Throws_on_invalid_header() + public bool Validate(BlockHeader header, bool isUncle) { - Context ctx = new() - { - BlockValidator = Always.Invalid, - }; - BlockDownloader downloader = ctx.BlockDownloader; + Thread.Sleep(1000); + return true; + } - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); + public bool ValidateSuggestedBlock(Block block) + { + Thread.Sleep(1000); + return true; + } - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(1000); + public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock) + { + Thread.Sleep(1000); + return true; + } - Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); - await task.ContinueWith(t => Assert.True(t.IsFaulted)); + public bool ValidateWithdrawals(Block block, out string? error) + { + Thread.Sleep(1000); + error = string.Empty; + return true; } - private class SlowSealValidator : ISealValidator + public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) { - public bool ValidateParams(BlockHeader parent, BlockHeader header, bool isUncle = false) - { - Thread.Sleep(1000); - return true; - } + Thread.Sleep(1000); + error = null; + return true; + } - public bool ValidateSeal(BlockHeader header, bool force) - { - Thread.Sleep(1000); - return true; - } + public bool ValidateSuggestedBlock(Block block, [NotNullWhen(false)] out string? error, bool validateHashes = true) + { + Thread.Sleep(1000); + error = null; + return true; } - private class SlowHeaderValidator : IBlockValidator + public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, [NotNullWhen(false)] out string? error) { + Thread.Sleep(1000); + error = null; + return true; + } - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle) - { - Thread.Sleep(1000); - return true; - } + public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error) + { + Thread.Sleep(1000); + error = null; + return true; + } - public bool Validate(BlockHeader header, bool isUncle) - { - Thread.Sleep(1000); - return true; - } + public bool Validate(BlockHeader header, bool isUncle, [NotNullWhen(false)] out string? error) + { + Thread.Sleep(1000); + error = null; + return true; + } + } - public bool ValidateSuggestedBlock(Block block) - { - Thread.Sleep(1000); - return true; - } + [Test, MaxTime(7000)] + [Ignore("Fails OneLoggerLogManager Travis only")] + public async Task Can_cancel_seal_validation() + { + Context ctx = new() + { + SealValidator = new SlowSealValidator(), + }; + BlockDownloader downloader = ctx.BlockDownloader; + + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); + + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect)); + + PeerInfo peerInfo = new(syncPeer); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.HeadNumber.Returns(1000); + + CancellationTokenSource cancellation = new(); + cancellation.CancelAfter(1000); + Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); + await task.ContinueWith(t => Assert.That(t.IsCanceled, Is.True, $"headers {t.Status}")); + + syncPeer.HeadNumber.Returns(2000); + cancellation = new CancellationTokenSource(); + cancellation.CancelAfter(1000); + task = downloader.DownloadBlocks(peerInfo, new BlocksRequest(), cancellation.Token); + await task.ContinueWith(t => Assert.That(t.IsCanceled, Is.True, $"blocks {t.Status}")); + } - public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock) - { - Thread.Sleep(1000); - return true; - } + [Test, MaxTime(15000)] + public async Task Can_cancel_adding_headers() + { + Context ctx = new() + { + BlockValidator = new SlowHeaderValidator(), + }; + BlockDownloader downloader = ctx.BlockDownloader; - public bool ValidateWithdrawals(Block block, out string? error) - { - Thread.Sleep(1000); - error = string.Empty; - return true; - } + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); - public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect)); - public bool ValidateSuggestedBlock(Block block, [NotNullWhen(false)] out string? error, bool validateHashes = true) - { - Thread.Sleep(1000); - error = null; - return true; - } + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.HeadNumber.Returns(1000); - public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } + PeerInfo peerInfo = new(syncPeer); - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } + CancellationTokenSource cancellation = new(); + cancellation.CancelAfter(990); + Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); + await task.ContinueWith(t => Assert.That(t.IsCanceled, Is.True, "headers")); - public bool Validate(BlockHeader header, bool isUncle, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } - } + syncPeer.HeadNumber.Returns(2000); + // peerInfo.HeadNumber *= 2; + cancellation = new CancellationTokenSource(); + cancellation.CancelAfter(990); + task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); + await task.ContinueWith(t => Assert.That(t.IsCanceled, Is.True, "blocks")); + } - [Test, MaxTime(7000)] - [Ignore("Fails OneLoggerLogManager Travis only")] - public async Task Can_cancel_seal_validation() + [Test] + public async Task Validate_always_the_last_seal_and_random_seal_in_the_package() + { + ISealValidator sealValidator = Substitute.For(); + sealValidator.ValidateSeal(Arg.Any(), Arg.Any()).Returns(true); + Context ctx = new() { - Context ctx = new() - { - SealValidator = new SlowSealValidator(), - }; - BlockDownloader downloader = ctx.BlockDownloader; + SealValidator = sealValidator, + }; + BlockDownloader downloader = ctx.BlockDownloader; + + using IOwnedReadOnlyList? blockHeaders = await ctx.ResponseBuilder.BuildHeaderResponse(0, 512, Response.AllCorrect); + BlockHeader[] blockHeadersCopy = blockHeaders?.ToArray() ?? Array.Empty(); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(blockHeaders); + + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(511); + + Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + await task; + + sealValidator.Received(2).ValidateSeal(Arg.Any(), true); + sealValidator.Received(510).ValidateSeal(Arg.Any(), false); + sealValidator.Received().ValidateSeal(blockHeadersCopy![^1], true); + } - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); + private class ThrowingPeer : ISyncPeer + { + public ThrowingPeer(long number, UInt256? totalDiff, Hash256? headHash = null) + { + HeadNumber = number; + TotalDifficulty = totalDiff ?? UInt256.MaxValue; + HeadHash = headHash ?? Keccak.Zero; + } - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect)); + public string Name => "Throwing"; + public string ClientId => "EX peer"; + public Node Node { get; } = null!; + public string ProtocolCode { get; } = null!; + public byte ProtocolVersion { get; } = default; + public Hash256 HeadHash { get; set; } + public long HeadNumber { get; set; } + public UInt256 TotalDifficulty { get; set; } + public bool IsInitialized { get; set; } + public bool IsPriority { get; set; } + + public void Disconnect(DisconnectReason reason, string details) + { + throw new NotImplementedException(); + } - PeerInfo peerInfo = new(syncPeer); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.HeadNumber.Returns(1000); + public Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) + { + throw new NotImplementedException(); + } - CancellationTokenSource cancellation = new(); - cancellation.CancelAfter(1000); - Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); - await task.ContinueWith(t => Assert.True(t.IsCanceled, $"headers {t.Status}")); + public Task?> GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) + { + throw new NotImplementedException(); + } - syncPeer.HeadNumber.Returns(2000); - cancellation = new CancellationTokenSource(); - cancellation.CancelAfter(1000); - task = downloader.DownloadBlocks(peerInfo, new BlocksRequest(), cancellation.Token); - await task.ContinueWith(t => Assert.True(t.IsCanceled, $"blocks {t.Status}")); + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + { + throw new Exception(); } - [Test, MaxTime(15000)] - public async Task Can_cancel_adding_headers() + public Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) { - Context ctx = new() - { - BlockValidator = new SlowHeaderValidator(), - }; - BlockDownloader downloader = ctx.BlockDownloader; + throw new NotImplementedException(); + } - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); + public void NotifyOfNewBlock(Block block, SendBlockMode mode) + { + throw new NotImplementedException(); + } - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect)); + public PublicKey Id => Node.Id; - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.HeadNumber.Returns(1000); + public void SendNewTransactions(IEnumerable txs, bool sendFullTx) + { + throw new NotImplementedException(); + } - PeerInfo peerInfo = new(syncPeer); + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) + { + throw new NotImplementedException(); + } - CancellationTokenSource cancellation = new(); - cancellation.CancelAfter(990); - Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); - await task.ContinueWith(t => Assert.True(t.IsCanceled, "headers")); + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) + { + throw new NotImplementedException(); + } - syncPeer.HeadNumber.Returns(2000); - // peerInfo.HeadNumber *= 2; - cancellation = new CancellationTokenSource(); - cancellation.CancelAfter(990); - task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); - await task.ContinueWith(t => Assert.True(t.IsCanceled, "blocks")); + public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class + { + throw new NotImplementedException(); } - [Test] - public async Task Validate_always_the_last_seal_and_random_seal_in_the_package() + public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class { - ISealValidator sealValidator = Substitute.For(); - sealValidator.ValidateSeal(Arg.Any(), Arg.Any()).Returns(true); - Context ctx = new() - { - SealValidator = sealValidator, - }; - BlockDownloader downloader = ctx.BlockDownloader; + throw new NotImplementedException(); + } + } - using IOwnedReadOnlyList? blockHeaders = await ctx.ResponseBuilder.BuildHeaderResponse(0, 512, Response.AllCorrect); - BlockHeader[] blockHeadersCopy = blockHeaders?.ToArray() ?? Array.Empty(); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(blockHeaders); + [Test] + public async Task Faults_on_get_headers_faulting() + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(511); + ISyncPeer syncPeer = new ThrowingPeer(1000, UInt256.MaxValue); + PeerInfo peerInfo = new(syncPeer); - Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); - await task; + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None) + .ContinueWith(t => Assert.That(t.IsFaulted, Is.True)); + } - sealValidator.Received(2).ValidateSeal(Arg.Any(), true); - sealValidator.Received(510).ValidateSeal(Arg.Any(), false); - sealValidator.Received().ValidateSeal(blockHeadersCopy![^1], true); - } + [Test] + public async Task Throws_on_block_task_exception() + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - private class ThrowingPeer : ISyncPeer - { - public ThrowingPeer(long number, UInt256? totalDiff, Hash256? headHash = null) - { - HeadNumber = number; - TotalDifficulty = totalDiff ?? UInt256.MaxValue; - HeadHash = headHash ?? Keccak.Zero; - } + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); - public string Name => "Throwing"; - public string ClientId => "EX peer"; - public Node Node { get; } = null!; - public string ProtocolCode { get; } = null!; - public byte ProtocolVersion { get; } = default; - public Hash256 HeadHash { get; set; } - public long HeadNumber { get; set; } - public UInt256 TotalDifficulty { get; set; } - public bool IsInitialized { get; set; } - public bool IsPriority { get; set; } - - public void Disconnect(DisconnectReason reason, string details) - { - throw new NotImplementedException(); - } + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(Task.FromException(new TimeoutException())); - public Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) - { - throw new NotImplementedException(); - } + syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); - public Task?> GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) - { - throw new NotImplementedException(); - } + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(1); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); - public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) - { - throw new Exception(); - } + syncPeer.HeadNumber.Returns(2); - public Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) - { - throw new NotImplementedException(); - } + Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); + await action.Should().ThrowAsync(); + } - public void NotifyOfNewBlock(Block block, SendBlockMode mode) - { - throw new NotImplementedException(); - } + [TestCase(DownloaderOptions.WithReceipts, true)] + [TestCase(DownloaderOptions.None, false)] + [TestCase(DownloaderOptions.Process, false)] + public async Task Throws_on_receipt_task_exception_when_downloading_receipts(int options, bool shouldThrow) + { + Context ctx = new(); + DownloaderOptions downloaderOptions = (DownloaderOptions)options; + BlockDownloader downloader = ctx.BlockDownloader; - public PublicKey Id => Node.Id; + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - public void SendNewTransactions(IEnumerable txs, bool sendFullTx) - { - throw new NotImplementedException(); - } + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); - public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) - { - throw new NotImplementedException(); - } + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); - public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) - { - throw new NotImplementedException(); - } + syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) + .Returns(Task.FromException>(new TimeoutException())); - public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class - { - throw new NotImplementedException(); - } + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(1); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); - public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class - { - throw new NotImplementedException(); - } - } + syncPeer.HeadNumber.Returns(2); - [Test] - public async Task Faults_on_get_headers_faulting() + Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); + if (shouldThrow) { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; - - ISyncPeer syncPeer = new ThrowingPeer(1000, UInt256.MaxValue); - PeerInfo peerInfo = new(syncPeer); - - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None) - .ContinueWith(t => Assert.True(t.IsFaulted)); + await action.Should().ThrowAsync(); } - - [Test] - public async Task Throws_on_block_task_exception() + else { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; - - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); - - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(Task.FromException(new TimeoutException())); - - syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); - - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(1); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + await action.Should().NotThrowAsync(); + } + } - syncPeer.HeadNumber.Returns(2); + [TestCase(DownloaderOptions.WithReceipts, true)] + [TestCase(DownloaderOptions.None, false)] + [TestCase(DownloaderOptions.Process, false)] + public async Task Throws_on_null_receipt_downloaded(int options, bool shouldThrow) + { + Context ctx = new(); + DownloaderOptions downloaderOptions = (DownloaderOptions)options; + bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts; + BlockDownloader downloader = ctx.BlockDownloader; - Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None); - await action.Should().ThrowAsync(); + Response responseOptions = Response.AllCorrect; + if (withReceipts) + { + responseOptions |= Response.WithTransactions; } - [TestCase(DownloaderOptions.WithReceipts, true)] - [TestCase(DownloaderOptions.None, false)] - [TestCase(DownloaderOptions.Process, false)] - public async Task Throws_on_receipt_task_exception_when_downloading_receipts(int options, bool shouldThrow) - { - Context ctx = new(); - DownloaderOptions downloaderOptions = (DownloaderOptions)options; - BlockDownloader downloader = ctx.BlockDownloader; + int headNumber = 5; - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + // normally chain length should be head number + 1 so here we setup a slightly shorter chain which + // will only be fixed slightly later + long chainLength = headNumber + 1; + SyncPeerMock syncPeerInternal = new(chainLength, withReceipts, responseOptions); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => syncPeerInternal.GetBlockHeaders(ci.ArgAt(0), ci.ArgAt(1), ci.ArgAt(2), ci.ArgAt(3))); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => syncPeerInternal.GetBlockBodies(ci.ArgAt>(0), ci.ArgAt(1))); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); + syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) + .Returns(async ci => + { + ArrayPoolList receipts = (await syncPeerInternal + .GetReceipts(ci.ArgAt>(0), ci.ArgAt(1))) + .ToPooledList(); + receipts[^1] = null; + return (IOwnedReadOnlyList)receipts; + }); - syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(Task.FromException>(new TimeoutException())); + syncPeer.TotalDifficulty.Returns(_ => syncPeerInternal.TotalDifficulty); + syncPeer.HeadHash.Returns(_ => syncPeerInternal.HeadHash); + syncPeer.HeadNumber.Returns(_ => syncPeerInternal.HeadNumber); - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(1); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(2); + int threshold = 2; + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); + ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(Math.Max(0, Math.Min(headNumber, headNumber - threshold))); - Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); - if (shouldThrow) - { - await action.Should().ThrowAsync(); - } - else - { - await action.Should().NotThrowAsync(); - } - } + syncPeerInternal.ExtendTree(chainLength * 2); + Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); - [TestCase(DownloaderOptions.WithReceipts, true)] - [TestCase(DownloaderOptions.None, false)] - [TestCase(DownloaderOptions.Process, false)] - public async Task Throws_on_null_receipt_downloaded(int options, bool shouldThrow) + if (shouldThrow) { - Context ctx = new(); - DownloaderOptions downloaderOptions = (DownloaderOptions)options; - bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts; - BlockDownloader downloader = ctx.BlockDownloader; + await action.Should().ThrowAsync(); + } + else + { + await action.Should().NotThrowAsync(); + } + } - Response responseOptions = Response.AllCorrect; - if (withReceipts) - { - responseOptions |= Response.WithTransactions; - } + [TestCase(32)] + [TestCase(1)] + [TestCase(0)] + public async Task Throws_on_block_bodies_count_higher_than_receipts_list_count(int threshold) + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - int headNumber = 5; + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - // normally chain length should be head number + 1 so here we setup a slightly shorter chain which - // will only be fixed slightly later - long chainLength = headNumber + 1; - SyncPeerMock syncPeerInternal = new(chainLength, withReceipts, responseOptions); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => syncPeerInternal.GetBlockHeaders(ci.ArgAt(0), ci.ArgAt(1), ci.ArgAt(2), ci.ArgAt(3))); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => syncPeerInternal.GetBlockBodies(ci.ArgAt>(0), ci.ArgAt(1))); + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); - syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(async ci => - { - ArrayPoolList receipts = (await syncPeerInternal - .GetReceipts(ci.ArgAt>(0), ci.ArgAt(1))) - .ToPooledList(); - receipts[^1] = null; - return (IOwnedReadOnlyList)receipts; - }); + syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result.Skip(1).ToPooledList(10)); - syncPeer.TotalDifficulty.Returns(_ => syncPeerInternal.TotalDifficulty); - syncPeer.HeadHash.Returns(_ => syncPeerInternal.HeadHash); - syncPeer.HeadNumber.Returns(_ => syncPeerInternal.HeadNumber); + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(1); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None); - PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(2); - int threshold = 2; - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); - ctx.BlockTree.BestSuggestedHeader!.Number.Should().Be(Math.Max(0, Math.Min(headNumber, headNumber - threshold))); + Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies | DownloaderOptions.WithReceipts), CancellationToken.None); + await action.Should().ThrowAsync(); + } - syncPeerInternal.ExtendTree(chainLength * 2); - Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); + [TestCase(32)] + [TestCase(1)] + public async Task Does_throw_on_transaction_count_different_than_receipts_count_in_block(int threshold) + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - if (shouldThrow) - { - await action.Should().ThrowAsync(); - } - else - { - await action.Should().NotThrowAsync(); - } - } + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); - [TestCase(32)] - [TestCase(1)] - [TestCase(0)] - public async Task Throws_on_block_bodies_count_higher_than_receipts_list_count(int threshold) - { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions) + .Result.Select(r => r is null || r.Length == 0 ? r : r.Skip(1).ToArray()).ToPooledList(10)); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(1); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); + syncPeer.HeadNumber.Returns(2); - syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result.Skip(1).ToPooledList(10)); + Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithReceipts), CancellationToken.None); + await action.Should().ThrowAsync(); + } - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(1); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None); + [TestCase(32)] + [TestCase(1)] + public async Task Throws_on_incorrect_receipts_root(int threshold) + { + Context ctx = new(); + BlockDownloader downloader = ctx.BlockDownloader; - syncPeer.HeadNumber.Returns(2); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies | DownloaderOptions.WithReceipts), CancellationToken.None); - await action.Should().ThrowAsync(); - } + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.IncorrectReceiptRoot)); - [TestCase(32)] - [TestCase(1)] - public async Task Does_throw_on_transaction_count_different_than_receipts_count_in_block(int threshold) - { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; + syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect | Response.WithTransactions)); + syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) + .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(1); + await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None); - syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions) - .Result.Select(r => r is null || r.Length == 0 ? r : r.Skip(1).ToArray()).ToPooledList(10)); + syncPeer.HeadNumber.Returns(2); - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(1); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); + Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithReceipts), CancellationToken.None); + await action.Should().ThrowAsync(); + } - syncPeer.HeadNumber.Returns(2); + [Flags] + private enum Response + { + Consistent = 1, + AllCorrect = 7, + JustFirst = 8, + AllKnown = 16, + TimeoutOnFullBatch = 32, + NoBody = 64, + WithTransactions = 128, + IncorrectReceiptRoot = 256 + } - Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithReceipts), CancellationToken.None); - await action.Should().ThrowAsync(); + private class Context + { + private readonly Block _genesis = Build.A.Block.Genesis.TestObject; + private readonly MemDb _blockInfoDb = new(); + private IBlockTree? _blockTree { get; set; } + private Dictionary TestHeaderMapping { get; } + public InMemoryReceiptStorage ReceiptStorage { get; } = new(); + + private SyncBatchSize? _syncBatchSize; + + public SyncBatchSize? SyncBatchSize + { + get => _syncBatchSize ??= new SyncBatchSize(LimboLogs.Instance); + set => _syncBatchSize = value; } - [TestCase(32)] - [TestCase(1)] - public async Task Throws_on_incorrect_receipts_root(int threshold) + protected ISpecProvider? _specProvider; + protected virtual ISpecProvider SpecProvider => _specProvider ??= MainnetSpecProvider.Instance; + + public virtual IBlockTree BlockTree { - Context ctx = new(); - BlockDownloader downloader = ctx.BlockDownloader; + get + { + if (_blockTree is null) + { + _blockTree = Build.A.BlockTree() + .WithoutSettingHead + .WithSpecProvider(SpecProvider) + .WithBlockInfoDb(_blockInfoDb) + .TestObject; + _blockTree.SuggestBlock(_genesis); + } - ISyncPeer syncPeer = Substitute.For(); - syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + return _blockTree; + } + set + { + _blockTree = value; + } + } - syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.IncorrectReceiptRoot)); + private ISyncPeerPool? _peerPool; + public ISyncPeerPool PeerPool => _peerPool ??= Substitute.For(); - syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); + private ResponseBuilder? _responseBuilder; + public ResponseBuilder ResponseBuilder => + _responseBuilder ??= new ResponseBuilder(BlockTree, TestHeaderMapping); - syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result); + protected IBetterPeerStrategy? _betterPeerStrategy; - PeerInfo peerInfo = new(syncPeer); - syncPeer.HeadNumber.Returns(1); - await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None); + protected virtual IBetterPeerStrategy BetterPeerStrategy => + _betterPeerStrategy ??= new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance); - syncPeer.HeadNumber.Returns(2); + private ActivatedSyncFeed? _feed; - Func action = async () => await downloader.DownloadBlocks(peerInfo, new BlocksRequest(DownloaderOptions.WithReceipts), CancellationToken.None); - await action.Should().ThrowAsync(); + public ActivatedSyncFeed Feed + { + get => _feed ??= new FullSyncFeed(); + set => _feed = value; } - [Flags] - private enum Response - { - Consistent = 1, - AllCorrect = 7, - JustFirst = 8, - AllKnown = 16, - TimeoutOnFullBatch = 32, - NoBody = 64, - WithTransactions = 128, - IncorrectReceiptRoot = 256 + private ISealValidator? _sealValidator; + public ISealValidator SealValidator + { + get => _sealValidator ??= Always.Valid; + set => _sealValidator = value; } - private class Context + private IBlockValidator? _blockValidator; + public IBlockValidator BlockValidator { - private readonly Block _genesis = Build.A.Block.Genesis.TestObject; - private readonly MemDb _blockInfoDb = new(); - private IBlockTree? _blockTree { get; set; } - private Dictionary TestHeaderMapping { get; } - public InMemoryReceiptStorage ReceiptStorage { get; } = new(); - - private SyncBatchSize? _syncBatchSize; - - public SyncBatchSize? SyncBatchSize - { - get => _syncBatchSize ??= new SyncBatchSize(LimboLogs.Instance); - set => _syncBatchSize = value; - } - - protected ISpecProvider? _specProvider; - protected virtual ISpecProvider SpecProvider => _specProvider ??= MainnetSpecProvider.Instance; + get => _blockValidator ??= Always.Valid; + set => _blockValidator = value; + } - public virtual IBlockTree BlockTree + private BlockDownloader? _blockDownloader; + public virtual BlockDownloader BlockDownloader => _blockDownloader ??= new BlockDownloader( + Feed, + PeerPool, + BlockTree, + BlockValidator, + SealValidator, + NullSyncReport.Instance, + ReceiptStorage, + SpecProvider, + BetterPeerStrategy, + LimboLogs.Instance, + SyncBatchSize + ); + + private SyncDispatcher? _dispatcher; + public SyncDispatcher Dispatcher => _dispatcher ??= new SyncDispatcher( + 0, + Feed!, + BlockDownloader, + PeerPool, + PeerAllocationStrategy, + LimboLogs.Instance + ); + + private IPeerAllocationStrategyFactory? _peerAllocationStrategy; + + protected virtual IPeerAllocationStrategyFactory PeerAllocationStrategy => + _peerAllocationStrategy ??= new BlocksSyncPeerAllocationStrategyFactory(); + + public Context() + { + TestHeaderMapping = new Dictionary { - get { - if (_blockTree is null) - { - _blockTree = Build.A.BlockTree() - .WithoutSettingHead - .WithSpecProvider(SpecProvider) - .WithBlockInfoDb(_blockInfoDb) - .TestObject; - _blockTree.SuggestBlock(_genesis); - } - - return _blockTree; - } - set - { - _blockTree = value; - } - } + 0, _genesis.Hash! + }, + }; + } + } - private ISyncPeerPool? _peerPool; - public ISyncPeerPool PeerPool => _peerPool ??= Substitute.For(); + private class SyncPeerMock : ISyncPeer + { + private readonly bool _withReceipts; + private readonly bool _withWithdrawals; + private readonly BlockHeadersMessageSerializer _headersSerializer = new(); + private readonly BlockBodiesMessageSerializer _bodiesSerializer = new(); + private readonly ReceiptsMessageSerializer _receiptsSerializer = new(MainnetSpecProvider.Instance); + private readonly Response _flags; - private ResponseBuilder? _responseBuilder; - public ResponseBuilder ResponseBuilder => - _responseBuilder ??= new ResponseBuilder(BlockTree, TestHeaderMapping); + public BlockTree BlockTree { get; private set; } = null!; + private IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); - protected IBetterPeerStrategy? _betterPeerStrategy; + public string Name => "Mock"; - protected virtual IBetterPeerStrategy BetterPeerStrategy => - _betterPeerStrategy ??= new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance); + public SyncPeerMock(long chainLength, bool withReceipts, Response flags, bool withWithdrawals = false) + { + _withReceipts = withReceipts; + _withWithdrawals = withWithdrawals; + _flags = flags; + BuildTree(chainLength, withReceipts); + } - private ActivatedSyncFeed? _feed; + public SyncPeerMock(BlockTree blockTree, bool withReceipts, Response flags, UInt256 peerTotalDifficulty, bool withWithdrawals = false) + { + _withReceipts = withReceipts; + _withWithdrawals = withWithdrawals; + _flags = flags; + BlockTree = blockTree; + HeadNumber = BlockTree.Head!.Number; + HeadHash = BlockTree.HeadHash!; + TotalDifficulty = peerTotalDifficulty; + } - public ActivatedSyncFeed Feed + private void BuildTree(long chainLength, bool withReceipts) + { + _receiptStorage = new InMemoryReceiptStorage(); + BlockTreeBuilder builder = Build.A.BlockTree(MainnetSpecProvider.Instance); + if (withReceipts) { - get => _feed ??= new FullSyncFeed(); - set => _feed = value; + builder = builder.WithTransactions(_receiptStorage); } - private ISealValidator? _sealValidator; - public ISealValidator SealValidator - { - get => _sealValidator ??= Always.Valid; - set => _sealValidator = value; - } + builder = builder.OfChainLength((int)chainLength, 0, 0, _withWithdrawals); + BlockTree = builder.TestObject; - private IBlockValidator? _blockValidator; - public IBlockValidator BlockValidator - { - get => _blockValidator ??= Always.Valid; - set => _blockValidator = value; - } + HeadNumber = BlockTree.Head!.Number; + HeadHash = BlockTree.HeadHash!; + TotalDifficulty = BlockTree.Head.TotalDifficulty ?? 0; + } - private BlockDownloader? _blockDownloader; - public virtual BlockDownloader BlockDownloader => _blockDownloader ??= new BlockDownloader( - Feed, - PeerPool, - BlockTree, - BlockValidator, - SealValidator, - NullSyncReport.Instance, - ReceiptStorage, - SpecProvider, - BetterPeerStrategy, - LimboLogs.Instance, - SyncBatchSize - ); - - private SyncDispatcher? _dispatcher; - public SyncDispatcher Dispatcher => _dispatcher ??= new SyncDispatcher( - 0, - Feed!, - BlockDownloader, - PeerPool, - PeerAllocationStrategy, - LimboLogs.Instance - ); - - private IPeerAllocationStrategyFactory? _peerAllocationStrategy; - - protected virtual IPeerAllocationStrategyFactory PeerAllocationStrategy => - _peerAllocationStrategy ??= new BlocksSyncPeerAllocationStrategyFactory(); - - public Context() - { - TestHeaderMapping = new Dictionary - { - { - 0, _genesis.Hash! - }, - }; - } + public void ExtendTree(long newLength) + { + BuildTree(newLength, _withReceipts); } - private class SyncPeerMock : ISyncPeer + public Node Node { get; } = null!; + public string ClientId { get; } = null!; + public byte ProtocolVersion { get; } = default; + public string ProtocolCode { get; } = null!; + public Hash256 HeadHash { get; set; } = null!; + public PublicKey Id => Node.Id; + public long HeadNumber { get; set; } + public UInt256 TotalDifficulty { get; set; } + public bool IsInitialized { get; set; } + public bool IsPriority { get; set; } + + public async Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) { - private readonly bool _withReceipts; - private readonly bool _withWithdrawals; - private readonly BlockHeadersMessageSerializer _headersSerializer = new(); - private readonly BlockBodiesMessageSerializer _bodiesSerializer = new(); - private readonly ReceiptsMessageSerializer _receiptsSerializer = new(MainnetSpecProvider.Instance); - private readonly Response _flags; + BlockBody[] headers = new BlockBody[blockHashes.Count]; + int i = 0; + foreach (Hash256 blockHash in blockHashes) + { + headers[i++] = BlockTree.FindBlock(blockHash, BlockTreeLookupOptions.None)!.Body; + } - public BlockTree BlockTree { get; private set; } = null!; - private IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); + using BlockBodiesMessage message = new(headers); + byte[] messageSerialized = _bodiesSerializer.Serialize(message); + return await Task.FromResult(_bodiesSerializer.Deserialize(messageSerialized).Bodies!); + } - public string Name => "Mock"; + public async Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + { + bool justFirst = _flags.HasFlag(Response.JustFirst); + bool timeoutOnFullBatch = _flags.HasFlag(Response.TimeoutOnFullBatch); - public SyncPeerMock(long chainLength, bool withReceipts, Response flags, bool withWithdrawals = false) + if (timeoutOnFullBatch && number == SyncBatchSize.Max) { - _withReceipts = withReceipts; - _withWithdrawals = withWithdrawals; - _flags = flags; - BuildTree(chainLength, withReceipts); + throw new TimeoutException(); } - public SyncPeerMock(BlockTree blockTree, bool withReceipts, Response flags, UInt256 peerTotalDifficulty, bool withWithdrawals = false) + BlockHeader[] headers = new BlockHeader[maxBlocks]; + for (int i = 0; i < (justFirst ? 1 : maxBlocks); i++) { - _withReceipts = withReceipts; - _withWithdrawals = withWithdrawals; - _flags = flags; - BlockTree = blockTree; - HeadNumber = BlockTree.Head!.Number; - HeadHash = BlockTree.HeadHash!; - TotalDifficulty = peerTotalDifficulty; + headers[i] = BlockTree.FindHeader(number + i, BlockTreeLookupOptions.None)!; } - private void BuildTree(long chainLength, bool withReceipts) + using BlockHeadersMessage message = new(headers.ToPooledList()); + byte[] messageSerialized = _headersSerializer.Serialize(message); + return await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders); + } + + public async Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) + { + TxReceipt[][] receipts = new TxReceipt[blockHash.Count][]; + int i = 0; + foreach (Hash256 keccak in blockHash) { - _receiptStorage = new InMemoryReceiptStorage(); - BlockTreeBuilder builder = Build.A.BlockTree(MainnetSpecProvider.Instance); - if (withReceipts) - { - builder = builder.WithTransactions(_receiptStorage); - } + Block? block = BlockTree.FindBlock(keccak, BlockTreeLookupOptions.None); + TxReceipt[] blockReceipts = _receiptStorage.Get(block!); + receipts[i++] = blockReceipts; + } - builder = builder.OfChainLength((int)chainLength, 0, 0, _withWithdrawals); - BlockTree = builder.TestObject; + using ReceiptsMessage message = new(receipts.ToPooledList()); + byte[] messageSerialized = _receiptsSerializer.Serialize(message); + return await Task.FromResult(_receiptsSerializer.Deserialize(messageSerialized).TxReceipts); + } - HeadNumber = BlockTree.Head!.Number; - HeadHash = BlockTree.HeadHash!; - TotalDifficulty = BlockTree.Head.TotalDifficulty ?? 0; - } + public void Disconnect(DisconnectReason reason, string details) + { + throw new NotImplementedException(); + } - public void ExtendTree(long newLength) - { - BuildTree(newLength, _withReceipts); - } + public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + { + throw new NotImplementedException(); + } - public Node Node { get; } = null!; - public string ClientId { get; } = null!; - public byte ProtocolVersion { get; } = default; - public string ProtocolCode { get; } = null!; - public Hash256 HeadHash { get; set; } = null!; - public PublicKey Id => Node.Id; - public long HeadNumber { get; set; } - public UInt256 TotalDifficulty { get; set; } - public bool IsInitialized { get; set; } - public bool IsPriority { get; set; } - - public async Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) - { - BlockBody[] headers = new BlockBody[blockHashes.Count]; - int i = 0; - foreach (Hash256 blockHash in blockHashes) - { - headers[i++] = BlockTree.FindBlock(blockHash, BlockTreeLookupOptions.None)!.Body; - } + public Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) + { + throw new NotImplementedException(); + } - using BlockBodiesMessage message = new(headers); - byte[] messageSerialized = _bodiesSerializer.Serialize(message); - return await Task.FromResult(_bodiesSerializer.Deserialize(messageSerialized).Bodies!); - } + public void NotifyOfNewBlock(Block block, SendBlockMode mode) + { + throw new NotImplementedException(); + } - public async Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) - { - bool justFirst = _flags.HasFlag(Response.JustFirst); - bool timeoutOnFullBatch = _flags.HasFlag(Response.TimeoutOnFullBatch); + public void SendNewTransactions(IEnumerable txs, bool sendFullTx) + { + throw new NotImplementedException(); + } - if (timeoutOnFullBatch && number == SyncBatchSize.Max) - { - throw new TimeoutException(); - } + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) + { + throw new NotImplementedException(); + } - BlockHeader[] headers = new BlockHeader[maxBlocks]; - for (int i = 0; i < (justFirst ? 1 : maxBlocks); i++) - { - headers[i] = BlockTree.FindHeader(number + i, BlockTreeLookupOptions.None)!; - } + public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class + { + throw new NotImplementedException(); + } - using BlockHeadersMessage message = new(headers.ToPooledList()); - byte[] messageSerialized = _headersSerializer.Serialize(message); - return await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders); - } + public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class + { + throw new NotImplementedException(); + } + } - public async Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) - { - TxReceipt[][] receipts = new TxReceipt[blockHash.Count][]; - int i = 0; - foreach (Hash256 keccak in blockHash) - { - Block? block = BlockTree.FindBlock(keccak, BlockTreeLookupOptions.None); - TxReceipt[] blockReceipts = _receiptStorage.Get(block!); - receipts[i++] = blockReceipts; - } + private class ResponseBuilder + { + private readonly IBlockTree _blockTree; + private readonly Dictionary _testHeaderMapping; - using ReceiptsMessage message = new(receipts.ToPooledList()); - byte[] messageSerialized = _receiptsSerializer.Serialize(message); - return await Task.FromResult(_receiptsSerializer.Deserialize(messageSerialized).TxReceipts); - } + public ResponseBuilder(IBlockTree blockTree, Dictionary testHeaderMapping) + { + _blockTree = blockTree; + _testHeaderMapping = testHeaderMapping; + } - public void Disconnect(DisconnectReason reason, string details) - { - throw new NotImplementedException(); - } + public async Task?> BuildHeaderResponse(long startNumber, int number, Response flags) + { + bool consistent = flags.HasFlag(Response.Consistent); + bool justFirst = flags.HasFlag(Response.JustFirst); + bool allKnown = flags.HasFlag(Response.AllKnown); + bool timeoutOnFullBatch = flags.HasFlag(Response.TimeoutOnFullBatch); + bool withTransaction = flags.HasFlag(Response.WithTransactions); - public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + if (timeoutOnFullBatch && number == SyncBatchSize.Max) { - throw new NotImplementedException(); + throw new TimeoutException(); } - public Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) + BlockHeader startBlock = _blockTree.FindHeader(_testHeaderMapping[startNumber], BlockTreeLookupOptions.None)!; + BlockHeader[] headers = new BlockHeader[number]; + headers[0] = startBlock; + if (!justFirst) { - throw new NotImplementedException(); - } + for (int i = 1; i < number; i++) + { + Hash256 receiptRoot = i == 1 ? Keccak.EmptyTreeHash : new Hash256("0x9904791428367d3f36f2be68daf170039dd0b3d6b23da00697de816a05fb5cc1"); + BlockHeaderBuilder blockHeaderBuilder = consistent + ? Build.A.BlockHeader.WithReceiptsRoot(receiptRoot).WithParent(headers[i - 1]) + : Build.A.BlockHeader.WithReceiptsRoot(receiptRoot).WithNumber(headers[i - 1].Number + 1); - public void NotifyOfNewBlock(Block block, SendBlockMode mode) - { - throw new NotImplementedException(); - } + if (withTransaction) + { + // We don't know the TX root yet, it should be populated by `BuildBlocksResponse` and `BuildReceiptsResponse`. + blockHeaderBuilder.WithTransactionsRoot(Keccak.Compute("something")); + blockHeaderBuilder.WithReceiptsRoot(Keccak.Compute("something")); + } - public void SendNewTransactions(IEnumerable txs, bool sendFullTx) - { - throw new NotImplementedException(); - } + headers[i] = blockHeaderBuilder.TestObject; - public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) - { - throw new NotImplementedException(); - } + if (allKnown) + { + _blockTree.SuggestHeader(headers[i]); + } - public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class - { - throw new NotImplementedException(); + _testHeaderMapping[startNumber + i] = headers[i].Hash!; + } } - public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class + foreach (BlockHeader header in headers) { - throw new NotImplementedException(); + _headers[header.Hash!] = header; } + + using BlockHeadersMessage message = new(headers.ToPooledList()); + byte[] messageSerialized = _headersSerializer.Serialize(message); + return await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders); } - private class ResponseBuilder + private readonly BlockHeadersMessageSerializer _headersSerializer = new(); + private readonly BlockBodiesMessageSerializer _bodiesSerializer = new(); + private readonly ReceiptsMessageSerializer _receiptsSerializer = new(MainnetSpecProvider.Instance); + private readonly Dictionary _headers = new(); + private readonly Dictionary _bodies = new(); + + public async Task BuildBlocksResponse(IList blockHashes, Response flags) { - private readonly IBlockTree _blockTree; - private readonly Dictionary _testHeaderMapping; + bool consistent = flags.HasFlag(Response.Consistent); + bool justFirst = flags.HasFlag(Response.JustFirst); + bool allKnown = flags.HasFlag(Response.AllKnown); + bool timeoutOnFullBatch = flags.HasFlag(Response.TimeoutOnFullBatch); + bool withTransactions = flags.HasFlag(Response.WithTransactions); - public ResponseBuilder(IBlockTree blockTree, Dictionary testHeaderMapping) + if (timeoutOnFullBatch && blockHashes.Count == SyncBatchSize.Max) { - _blockTree = blockTree; - _testHeaderMapping = testHeaderMapping; + throw new TimeoutException(); } - public async Task?> BuildHeaderResponse(long startNumber, int number, Response flags) - { - bool consistent = flags.HasFlag(Response.Consistent); - bool justFirst = flags.HasFlag(Response.JustFirst); - bool allKnown = flags.HasFlag(Response.AllKnown); - bool timeoutOnFullBatch = flags.HasFlag(Response.TimeoutOnFullBatch); - bool withTransaction = flags.HasFlag(Response.WithTransactions); + BlockHeader? startHeader = _blockTree.FindHeader(blockHashes[0], BlockTreeLookupOptions.None); + startHeader ??= _headers[blockHashes[0]]; - if (timeoutOnFullBatch && number == SyncBatchSize.Max) - { - throw new TimeoutException(); - } + BlockHeader[] blockHeaders = new BlockHeader[blockHashes.Count]; + BlockBody[] blockBodies = new BlockBody[blockHashes.Count]; - BlockHeader startBlock = _blockTree.FindHeader(_testHeaderMapping[startNumber], BlockTreeLookupOptions.None)!; - BlockHeader[] headers = new BlockHeader[number]; - headers[0] = startBlock; - if (!justFirst) - { - for (int i = 1; i < number; i++) - { - Hash256 receiptRoot = i == 1 ? Keccak.EmptyTreeHash : new Hash256("0x9904791428367d3f36f2be68daf170039dd0b3d6b23da00697de816a05fb5cc1"); - BlockHeaderBuilder blockHeaderBuilder = consistent - ? Build.A.BlockHeader.WithReceiptsRoot(receiptRoot).WithParent(headers[i - 1]) - : Build.A.BlockHeader.WithReceiptsRoot(receiptRoot).WithNumber(headers[i - 1].Number + 1); - - if (withTransaction) - { - // We don't know the TX root yet, it should be populated by `BuildBlocksResponse` and `BuildReceiptsResponse`. - blockHeaderBuilder.WithTransactionsRoot(Keccak.Compute("something")); - blockHeaderBuilder.WithReceiptsRoot(Keccak.Compute("something")); - } - - headers[i] = blockHeaderBuilder.TestObject; - - if (allKnown) - { - _blockTree.SuggestHeader(headers[i]); - } - - _testHeaderMapping[startNumber + i] = headers[i].Hash!; - } - } + Block BuildBlockForHeader(BlockHeader header, int txSeed) + { + BlockBuilder blockBuilder = Build.A.Block.WithHeader(header); - foreach (BlockHeader header in headers) + if (withTransactions && header.TxRoot != Keccak.EmptyTreeHash) { - _headers[header.Hash!] = header; + blockBuilder.WithTransactions(Build.A.Transaction.WithValue(txSeed * 2).SignedAndResolved().TestObject, + Build.A.Transaction.WithValue(txSeed * 2 + 1).SignedAndResolved().TestObject); } - using BlockHeadersMessage message = new(headers.ToPooledList()); - byte[] messageSerialized = _headersSerializer.Serialize(message); - return await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders); + return blockBuilder.TestObject; } - private readonly BlockHeadersMessageSerializer _headersSerializer = new(); - private readonly BlockBodiesMessageSerializer _bodiesSerializer = new(); - private readonly ReceiptsMessageSerializer _receiptsSerializer = new(MainnetSpecProvider.Instance); - private readonly Dictionary _headers = new(); - private readonly Dictionary _bodies = new(); + blockBodies[0] = BuildBlockForHeader(startHeader, 0).Body; + blockHeaders[0] = startHeader; - public async Task BuildBlocksResponse(IList blockHashes, Response flags) + _bodies[startHeader.Hash!] = blockBodies[0]; + _headers[startHeader.Hash!] = blockHeaders[0]; + if (!justFirst) { - bool consistent = flags.HasFlag(Response.Consistent); - bool justFirst = flags.HasFlag(Response.JustFirst); - bool allKnown = flags.HasFlag(Response.AllKnown); - bool timeoutOnFullBatch = flags.HasFlag(Response.TimeoutOnFullBatch); - bool withTransactions = flags.HasFlag(Response.WithTransactions); - - if (timeoutOnFullBatch && blockHashes.Count == SyncBatchSize.Max) - { - throw new TimeoutException(); - } - - BlockHeader? startHeader = _blockTree.FindHeader(blockHashes[0], BlockTreeLookupOptions.None); - startHeader ??= _headers[blockHashes[0]]; - - BlockHeader[] blockHeaders = new BlockHeader[blockHashes.Count]; - BlockBody[] blockBodies = new BlockBody[blockHashes.Count]; - - Block BuildBlockForHeader(BlockHeader header, int txSeed) + for (int i = 0; i < blockHashes.Count; i++) { - BlockBuilder blockBuilder = Build.A.Block.WithHeader(header); + blockHeaders[i] = consistent + ? _headers[blockHashes[i]] + : Build.A.BlockHeader.WithNumber(blockHeaders[i - 1].Number + 1).WithHash(blockHashes[i]).TestObject; - if (withTransactions && header.TxRoot != Keccak.EmptyTreeHash) - { - blockBuilder.WithTransactions(Build.A.Transaction.WithValue(txSeed * 2).SignedAndResolved().TestObject, - Build.A.Transaction.WithValue(txSeed * 2 + 1).SignedAndResolved().TestObject); - } + _testHeaderMapping[startHeader.Number + i] = blockHeaders[i].Hash!; - return blockBuilder.TestObject; - } + BlockHeader header = consistent + ? blockHeaders[i] + : blockHeaders[i - 1]; - blockBodies[0] = BuildBlockForHeader(startHeader, 0).Body; - blockHeaders[0] = startHeader; + Block block = BuildBlockForHeader(header, i); + blockBodies[i] = block.Body; + _bodies[blockHashes[i]] = blockBodies[i]; - _bodies[startHeader.Hash!] = blockBodies[0]; - _headers[startHeader.Hash!] = blockHeaders[0]; - if (!justFirst) - { - for (int i = 0; i < blockHashes.Count; i++) + if (allKnown) { - blockHeaders[i] = consistent - ? _headers[blockHashes[i]] - : Build.A.BlockHeader.WithNumber(blockHeaders[i - 1].Number + 1).WithHash(blockHashes[i]).TestObject; - - _testHeaderMapping[startHeader.Number + i] = blockHeaders[i].Hash!; - - BlockHeader header = consistent - ? blockHeaders[i] - : blockHeaders[i - 1]; - - Block block = BuildBlockForHeader(header, i); - blockBodies[i] = block.Body; - _bodies[blockHashes[i]] = blockBodies[i]; - - if (allKnown) - { - _blockTree.SuggestBlock(block); - } + _blockTree.SuggestBlock(block); } } - - using BlockBodiesMessage message = new(blockBodies); - byte[] messageSerialized = _bodiesSerializer.Serialize(message); - return await Task.FromResult(_bodiesSerializer.Deserialize(messageSerialized).Bodies!); } - public async Task> BuildReceiptsResponse(IList blockHashes, Response flags = Response.AllCorrect) - { - TxReceipt[][] receipts = new TxReceipt[blockHashes.Count][]; - for (int i = 0; i < receipts.Length; i++) - { - BlockBody body = _bodies[blockHashes[i]]; - receipts[i] = body.Transactions - .Select(t => Build.A.Receipt - .WithStatusCode(StatusCode.Success) - .WithGasUsed(10) - .WithBloom(Bloom.Empty) - .WithLogs(Build.A.LogEntry.WithAddress(t.SenderAddress!).WithTopics(TestItem.KeccakA).TestObject) - .TestObject) - .ToArray(); - - _headers[blockHashes[i]].ReceiptsRoot = flags.HasFlag(Response.IncorrectReceiptRoot) - ? Keccak.EmptyTreeHash - : ReceiptTrie.CalculateRoot(MainnetSpecProvider.Instance.GetSpec((ForkActivation)_headers[blockHashes[i]].Number), receipts[i], Rlp.GetStreamDecoder()!); - } + using BlockBodiesMessage message = new(blockBodies); + byte[] messageSerialized = _bodiesSerializer.Serialize(message); + return await Task.FromResult(_bodiesSerializer.Deserialize(messageSerialized).Bodies!); + } - using ReceiptsMessage message = new(receipts.ToPooledList()); - byte[] messageSerialized = _receiptsSerializer.Serialize(message); - return await Task.FromResult(_receiptsSerializer.Deserialize(messageSerialized).TxReceipts); + public async Task> BuildReceiptsResponse(IList blockHashes, Response flags = Response.AllCorrect) + { + TxReceipt[][] receipts = new TxReceipt[blockHashes.Count][]; + for (int i = 0; i < receipts.Length; i++) + { + BlockBody body = _bodies[blockHashes[i]]; + receipts[i] = body.Transactions + .Select(t => Build.A.Receipt + .WithStatusCode(StatusCode.Success) + .WithGasUsed(10) + .WithBloom(Bloom.Empty) + .WithLogs(Build.A.LogEntry.WithAddress(t.SenderAddress!).WithTopics(TestItem.KeccakA).TestObject) + .TestObject) + .ToArray(); + + _headers[blockHashes[i]].ReceiptsRoot = flags.HasFlag(Response.IncorrectReceiptRoot) + ? Keccak.EmptyTreeHash + : ReceiptTrie.CalculateRoot(MainnetSpecProvider.Instance.GetSpec((ForkActivation)_headers[blockHashes[i]].Number), receipts[i], Rlp.GetStreamDecoder()!); } + + using ReceiptsMessage message = new(receipts.ToPooledList()); + byte[] messageSerialized = _receiptsSerializer.Serialize(message); + return await Task.FromResult(_receiptsSerializer.Deserialize(messageSerialized).TxReceipts); } } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs index adeab5f2552..6a048cf5a72 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs @@ -26,589 +26,587 @@ using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; -namespace Nethermind.Synchronization.Test.FastBlocks +namespace Nethermind.Synchronization.Test.FastBlocks; + +[Parallelizable(ParallelScope.Self)] +public class FastHeadersSyncTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class FastHeadersSyncTests + [Test] + public Task Will_fail_if_launched_without_fast_blocks_enabled() { - [Test] - public Task Will_fail_if_launched_without_fast_blocks_enabled() - { - BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; - - Assert.Throws(() => - { - HeadersSyncFeed _ = new HeadersSyncFeed( - blockTree: blockTree, - syncPeerPool: Substitute.For(), - syncConfig: new SyncConfig(), - syncReport: Substitute.For(), - logManager: LimboLogs.Instance); - }); - - return Task.CompletedTask; - } + BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; - [Test] - public async Task Can_prepare_3_requests_in_a_row() + Assert.Throws(() => { - BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; - - HeadersSyncFeed feed = new( + HeadersSyncFeed _ = new HeadersSyncFeed( blockTree: blockTree, syncPeerPool: Substitute.For(), - syncConfig: new SyncConfig - { - FastSync = true, - PivotNumber = "1000", - PivotHash = Keccak.Zero.ToString(), - PivotTotalDifficulty = "1000" - }, + syncConfig: new SyncConfig(), syncReport: Substitute.For(), logManager: LimboLogs.Instance); + }); - await feed.PrepareRequest(); - await feed.PrepareRequest(); - await feed.PrepareRequest(); - } + return Task.CompletedTask; + } + + [Test] + public async Task Can_prepare_3_requests_in_a_row() + { + BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + + HeadersSyncFeed feed = new( + blockTree: blockTree, + syncPeerPool: Substitute.For(), + syncConfig: new SyncConfig + { + FastSync = true, + PivotNumber = "1000", + PivotHash = Keccak.Zero.ToString(), + PivotTotalDifficulty = "1000" + }, + syncReport: Substitute.For(), + logManager: LimboLogs.Instance); + + await feed.PrepareRequest(); + await feed.PrepareRequest(); + await feed.PrepareRequest(); + } - [Test] - public async Task When_next_header_hash_update_is_delayed_do_not_drop_peer() + [Test] + public async Task When_next_header_hash_update_is_delayed_do_not_drop_peer() + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(1001).TestObject; + BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + + ISyncReport syncReport = Substitute.For(); + syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); + syncReport.HeadersInQueue.Returns(new MeasuredProgress()); + + ISyncPeerPool syncPeerPool = Substitute.For(); + PeerInfo peerInfo = new PeerInfo(Substitute.For()); + + ManualResetEventSlim hangLatch = new(false); + BlockHeader pivot = remoteBlockTree.FindHeader(1000, BlockTreeLookupOptions.None)!; + ResettableHeaderSyncFeed feed = new( + blockTree: blockTree, + syncPeerPool: syncPeerPool, + syncConfig: new SyncConfig + { + FastSync = true, + PivotNumber = "1000", + PivotHash = pivot.Hash!.Bytes.ToHexString(), + PivotTotalDifficulty = pivot.TotalDifficulty.ToString()! + }, + syncReport: syncReport, + logManager: LimboLogs.Instance, + hangOnBlockNumberAfterInsert: 425, + hangLatch: hangLatch + ); + + feed.InitializeFeed(); + + void FulfillBatch(HeadersSyncBatch batch) { - BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(1001).TestObject; - BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + batch.Response = remoteBlockTree.FindHeaders( + remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, + false)!; + batch.ResponseSourcePeer = peerInfo; + } - ISyncReport syncReport = Substitute.For(); - syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); - syncReport.HeadersInQueue.Returns(new MeasuredProgress()); + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch3 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch4 = (await feed.PrepareRequest())!; - ISyncPeerPool syncPeerPool = Substitute.For(); - PeerInfo peerInfo = new PeerInfo(Substitute.For()); + FulfillBatch(batch1); + FulfillBatch(batch2); + FulfillBatch(batch3); + FulfillBatch(batch4); - ManualResetEventSlim hangLatch = new(false); - BlockHeader pivot = remoteBlockTree.FindHeader(1000, BlockTreeLookupOptions.None)!; - ResettableHeaderSyncFeed feed = new( - blockTree: blockTree, - syncPeerPool: syncPeerPool, - syncConfig: new SyncConfig - { - FastSync = true, - PivotNumber = "1000", - PivotHash = pivot.Hash!.Bytes.ToHexString(), - PivotTotalDifficulty = pivot.TotalDifficulty.ToString()! - }, - syncReport: syncReport, - logManager: LimboLogs.Instance, - hangOnBlockNumberAfterInsert: 425, - hangLatch: hangLatch - ); - - feed.InitializeFeed(); - - void FulfillBatch(HeadersSyncBatch batch) - { - batch.Response = remoteBlockTree.FindHeaders( - remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false)!; - batch.ResponseSourcePeer = peerInfo; - } + // Need to be triggered via `HandleDependencies` as there is a lock for `HandleResponse` that prevent this. + feed.HandleResponse(batch1); + feed.HandleResponse(batch3); + feed.HandleResponse(batch2); + Task _ = Task.Factory.StartNew(() => feed.PrepareRequest(), TaskCreationOptions.LongRunning); - using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; - using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; - using HeadersSyncBatch batch3 = (await feed.PrepareRequest())!; - using HeadersSyncBatch batch4 = (await feed.PrepareRequest())!; + await Task.Delay(TimeSpan.FromMilliseconds(100)); - FulfillBatch(batch1); - FulfillBatch(batch2); - FulfillBatch(batch3); - FulfillBatch(batch4); + feed.HandleResponse(batch4); - // Need to be triggered via `HandleDependencies` as there is a lock for `HandleResponse` that prevent this. - feed.HandleResponse(batch1); - feed.HandleResponse(batch3); - feed.HandleResponse(batch2); - Task _ = Task.Factory.StartNew(() => feed.PrepareRequest(), TaskCreationOptions.LongRunning); + syncPeerPool.DidNotReceive().ReportBreachOfProtocol(peerInfo, Arg.Any(), Arg.Any()); + } - await Task.Delay(TimeSpan.FromMilliseconds(100)); + [Test] + public async Task Can_prepare_several_request_and_ignore_request_from_previous_sequence() + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(501).TestObject; + BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + + ISyncReport syncReport = Substitute.For(); + syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); + syncReport.HeadersInQueue.Returns(new MeasuredProgress()); + + BlockHeader pivot = remoteBlockTree.FindHeader(500, BlockTreeLookupOptions.None)!; + using ResettableHeaderSyncFeed feed = new( + blockTree: blockTree, + syncPeerPool: Substitute.For(), + syncConfig: new SyncConfig + { + FastSync = true, + PivotNumber = "500", + PivotHash = pivot.Hash!.Bytes.ToHexString(), + PivotTotalDifficulty = pivot.TotalDifficulty!.ToString()! + }, + syncReport: syncReport, + logManager: LimboLogs.Instance); - feed.HandleResponse(batch4); + feed.InitializeFeed(); - syncPeerPool.DidNotReceive().ReportBreachOfProtocol(peerInfo, Arg.Any(), Arg.Any()); + void FulfillBatch(HeadersSyncBatch batch) + { + batch.Response = remoteBlockTree.FindHeaders( + remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, + false)!; } - [Test] - public async Task Can_prepare_several_request_and_ignore_request_from_previous_sequence() - { - BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(501).TestObject; - BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + using HeadersSyncBatch? r = await feed.PrepareRequest(); + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + FulfillBatch(batch1); - ISyncReport syncReport = Substitute.For(); - syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); - syncReport.HeadersInQueue.Returns(new MeasuredProgress()); + feed.Reset(); - BlockHeader pivot = remoteBlockTree.FindHeader(500, BlockTreeLookupOptions.None)!; - using ResettableHeaderSyncFeed feed = new( - blockTree: blockTree, - syncPeerPool: Substitute.For(), - syncConfig: new SyncConfig - { - FastSync = true, - PivotNumber = "500", - PivotHash = pivot.Hash!.Bytes.ToHexString(), - PivotTotalDifficulty = pivot.TotalDifficulty!.ToString()! - }, - syncReport: syncReport, - logManager: LimboLogs.Instance); + await feed.PrepareRequest(); + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + FulfillBatch(batch2); - feed.InitializeFeed(); + feed.HandleResponse(batch2); + feed.HandleResponse(batch1); + } - void FulfillBatch(HeadersSyncBatch batch) + [Test] + public async Task Will_dispatch_when_only_partially_processed_dependency() + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(2001).TestObject; + BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + + ISyncReport syncReport = Substitute.For(); + syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); + syncReport.HeadersInQueue.Returns(new MeasuredProgress()); + + BlockHeader pivot = remoteBlockTree.FindHeader(2000, BlockTreeLookupOptions.None)!; + using HeadersSyncFeed feed = new( + blockTree: blockTree, + syncPeerPool: Substitute.For(), + syncConfig: new SyncConfig { - batch.Response = remoteBlockTree.FindHeaders( - remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false)!; - } + FastSync = true, + PivotNumber = pivot.Number.ToString(), + PivotHash = pivot.Hash!.ToString(), + PivotTotalDifficulty = pivot.TotalDifficulty.ToString()!, + }, + syncReport: syncReport, + logManager: LimboLogs.Instance); - using HeadersSyncBatch? r = await feed.PrepareRequest(); - using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; - FulfillBatch(batch1); + feed.InitializeFeed(); - feed.Reset(); + void FulfillBatch(HeadersSyncBatch batch) + { + batch.Response = remoteBlockTree.FindHeaders( + remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, + false)!; + } - await feed.PrepareRequest(); - using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; - FulfillBatch(batch2); + // First batch need to be handled first before handle dependencies can do anything + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + FulfillBatch(batch1); + feed.HandleResponse(batch1); - feed.HandleResponse(batch2); - feed.HandleResponse(batch1); - } + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + FulfillBatch(batch2); + + int maxHeaderBatchToProcess = 4; - [Test] - public async Task Will_dispatch_when_only_partially_processed_dependency() + HeadersSyncBatch[] batches = Enumerable.Range(0, maxHeaderBatchToProcess + 1).Select(_ => { - BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(2001).TestObject; - BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + HeadersSyncBatch batch = feed.PrepareRequest().Result!; + FulfillBatch(batch); + return batch; + }).ToArray(); - ISyncReport syncReport = Substitute.For(); - syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); - syncReport.HeadersInQueue.Returns(new MeasuredProgress()); + // Disconnected chain so they all go to dependencies + foreach (HeadersSyncBatch headersSyncBatch in batches) + { + feed.HandleResponse(headersSyncBatch); + } - BlockHeader pivot = remoteBlockTree.FindHeader(2000, BlockTreeLookupOptions.None)!; - using HeadersSyncFeed feed = new( - blockTree: blockTree, - syncPeerPool: Substitute.For(), - syncConfig: new SyncConfig - { - FastSync = true, - PivotNumber = pivot.Number.ToString(), - PivotHash = pivot.Hash!.ToString(), - PivotTotalDifficulty = pivot.TotalDifficulty.ToString()!, - }, - syncReport: syncReport, - logManager: LimboLogs.Instance); + // Batch2 would get processed + feed.HandleResponse(batch2); - feed.InitializeFeed(); + // HandleDependantBatch would start from first batch in batches, stopped at second last, not processing the last one + using HeadersSyncBatch newBatch = (await feed.PrepareRequest())!; + blockTree.LowestInsertedHeader!.Number.Should().Be(batches[^2].StartNumber); - void FulfillBatch(HeadersSyncBatch batch) - { - batch.Response = remoteBlockTree.FindHeaders( - remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false)!; - } + // New batch would be at end of batch 5 (batch 6). + newBatch.EndNumber.Should().Be(batches[^1].StartNumber - 1); + batches.DisposeItems(); + } - // First batch need to be handled first before handle dependencies can do anything - using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; - FulfillBatch(batch1); - feed.HandleResponse(batch1); + [Test] + public async Task Can_reset_and_not_hang_when_a_batch_is_processing() + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(501).TestObject; - using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; - FulfillBatch(batch2); + BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; - int maxHeaderBatchToProcess = 4; + ISyncReport syncReport = Substitute.For(); + syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); + syncReport.HeadersInQueue.Returns(new MeasuredProgress()); - HeadersSyncBatch[] batches = Enumerable.Range(0, maxHeaderBatchToProcess + 1).Select(_ => - { - HeadersSyncBatch batch = feed.PrepareRequest().Result!; - FulfillBatch(batch); - return batch; - }).ToArray(); + ManualResetEventSlim hangLatch = new(false); - // Disconnected chain so they all go to dependencies - foreach (HeadersSyncBatch headersSyncBatch in batches) + BlockHeader pivot = remoteBlockTree.FindHeader(500, BlockTreeLookupOptions.None)!; + ResettableHeaderSyncFeed feed = new( + blockTree: blockTree, + syncPeerPool: Substitute.For(), + syncConfig: new SyncConfig { - feed.HandleResponse(headersSyncBatch); - } + FastSync = true, + PivotNumber = "500", + PivotHash = pivot.Hash!.Bytes.ToHexString(), + PivotTotalDifficulty = pivot.TotalDifficulty!.ToString()! + }, + syncReport: syncReport, + logManager: LimboLogs.Instance, + hangOnBlockNumber: 400, + hangLatch: hangLatch + ); + + feed.InitializeFeed(); + + void FulfillBatch(HeadersSyncBatch batch) + { + batch.Response = remoteBlockTree.FindHeaders( + remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, + false)!; + } - // Batch2 would get processed - feed.HandleResponse(batch2); + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + FulfillBatch(batch1); - // HandleDependantBatch would start from first batch in batches, stopped at second last, not processing the last one - using HeadersSyncBatch newBatch = (await feed.PrepareRequest())!; - blockTree.LowestInsertedHeader!.Number.Should().Be(batches[^2].StartNumber); + // Initiate a process batch which should hang in the middle + Task responseTask = Task.Factory.StartNew(() => feed.HandleResponse(batch1), TaskCreationOptions.RunContinuationsAsynchronously); + await Task.Delay(TimeSpan.FromMilliseconds(50)); - // New batch would be at end of batch 5 (batch 6). - newBatch.EndNumber.Should().Be(batches[^1].StartNumber - 1); - batches.DisposeItems(); - } + // Initiate a reset at the same time. Without protection, the _nextHeaderHash would be updated here, but so do at `InsertHeader` via `HandleResponse`. + Task resetTask = Task.Factory.StartNew(() => feed.Reset(), TaskCreationOptions.RunContinuationsAsynchronously); + await Task.Delay(TimeSpan.FromMilliseconds(50)); - [Test] - public async Task Can_reset_and_not_hang_when_a_batch_is_processing() - { - BlockTree remoteBlockTree = Build.A.BlockTree().OfHeadersOnly.OfChainLength(501).TestObject; + hangLatch.Set(); + await responseTask; + await resetTask; - BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + // A new batch is creating, starting at hang block + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; - ISyncReport syncReport = Substitute.For(); - syncReport.FastBlocksHeaders.Returns(new MeasuredProgress()); - syncReport.HeadersInQueue.Returns(new MeasuredProgress()); + FulfillBatch(batch2); + feed.HandleResponse(batch2); - ManualResetEventSlim hangLatch = new(false); + // The whole new batch should get processed instead of skipping due to concurrently modified _nextHeaderHash. + blockTree.LowestInsertedHeader!.Number.Should().Be(batch2.StartNumber); + } - BlockHeader pivot = remoteBlockTree.FindHeader(500, BlockTreeLookupOptions.None)!; - ResettableHeaderSyncFeed feed = new( - blockTree: blockTree, - syncPeerPool: Substitute.For(), - syncConfig: new SyncConfig - { - FastSync = true, - PivotNumber = "500", - PivotHash = pivot.Hash!.Bytes.ToHexString(), - PivotTotalDifficulty = pivot.TotalDifficulty!.ToString()! - }, - syncReport: syncReport, - logManager: LimboLogs.Instance, - hangOnBlockNumber: 400, - hangLatch: hangLatch - ); - - feed.InitializeFeed(); - - void FulfillBatch(HeadersSyncBatch batch) + [Test] + public async Task Can_keep_returning_nulls_after_all_batches_were_prepared() + { + BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; + HeadersSyncFeed feed = new( + blockTree: blockTree, + syncPeerPool: Substitute.For(), + syncConfig: new SyncConfig { - batch.Response = remoteBlockTree.FindHeaders( - remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false)!; - } + FastSync = true, + PivotNumber = "1000", + PivotHash = Keccak.Zero.ToString(), + PivotTotalDifficulty = "1000" + }, + syncReport: Substitute.For(), + logManager: LimboLogs.Instance); + + for (int i = 0; i < 10; i++) + { + await feed.PrepareRequest(); + } - using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; - FulfillBatch(batch1); + using HeadersSyncBatch? result = await feed.PrepareRequest(); + result.Should().BeNull(); + } - // Initiate a process batch which should hang in the middle - Task responseTask = Task.Factory.StartNew(() => feed.HandleResponse(batch1), TaskCreationOptions.RunContinuationsAsynchronously); - await Task.Delay(TimeSpan.FromMilliseconds(50)); + [Test] + public async Task Finishes_when_all_downloaded() + { + IBlockTree blockTree = Substitute.For(); + blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1000).TestObject); + ISyncReport report = Substitute.For(); + report.HeadersInQueue.Returns(new MeasuredProgress()); + MeasuredProgress measuredProgress = new(); + report.FastBlocksHeaders.Returns(measuredProgress); + HeadersSyncFeed feed = new(blockTree, Substitute.For(), new SyncConfig { FastSync = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }, report, LimboLogs.Instance); + await feed.PrepareRequest(); + blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).TestObject); + using HeadersSyncBatch? result = await feed.PrepareRequest(); + + result.Should().BeNull(); + feed.CurrentState.Should().Be(SyncFeedState.Finished); + measuredProgress.HasEnded.Should().BeTrue(); + } - // Initiate a reset at the same time. Without protection, the _nextHeaderHash would be updated here, but so do at `InsertHeader` via `HandleResponse`. - Task resetTask = Task.Factory.StartNew(() => feed.Reset(), TaskCreationOptions.RunContinuationsAsynchronously); - await Task.Delay(TimeSpan.FromMilliseconds(50)); + [Test] + public async Task Can_resume_downloading_from_parent_of_lowest_inserted_header() + { + IBlockTree blockTree = Substitute.For(); + blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader + .WithNumber(500) + .WithTotalDifficulty(10_000_000) + .TestObject); + + ISyncReport report = Substitute.For(); + report.HeadersInQueue.Returns(new MeasuredProgress()); + report.FastBlocksHeaders.Returns(new MeasuredProgress()); + + HeadersSyncFeed feed = new(blockTree, Substitute.For(), new SyncConfig { FastSync = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }, report, LimboLogs.Instance); + feed.InitializeFeed(); + using HeadersSyncBatch? result = await feed.PrepareRequest(); + + result.Should().NotBeNull(); + result!.EndNumber.Should().Be(499); + } - hangLatch.Set(); - await responseTask; - await resetTask; + //Missing headers in the start is not allowed + [TestCase(0, 1, 1, true, false)] + [TestCase(0, 1, 1, false, true)] + //Missing headers in the start is not allowed + [TestCase(0, 2, 1, true, false)] + [TestCase(0, 2, 1, false, true)] + //Missing headers in the start is not allowed + [TestCase(0, 2, 191, true, false)] + [TestCase(0, 2, 191, false, true)] + //Gaps are not allowed + [TestCase(1, 1, 1, true, false)] + [TestCase(1, 1, 1, true, true)] + [TestCase(187, 5, 1, false, false)] + [TestCase(187, 5, 1, false, true)] + [TestCase(191, 1, 1, false, false)] + [TestCase(191, 1, 1, false, true)] + [TestCase(190, 1, 1, true, false)] + [TestCase(190, 1, 1, true, true)] + [TestCase(80, 1, 1, true, false)] + [TestCase(80, 1, 1, true, true)] + //All empty reponse + [TestCase(0, 192, 1, false, false)] + //All null reponse + [TestCase(0, 192, 1, false, true)] + public async Task Can_insert_all_good_headers_from_dependent_batch_with_missing_or_null_headers(int nullIndex, int count, int increment, bool shouldReport, bool useNulls) + { + var peerChain = Build.A.BlockTree().OfChainLength(1000).TestObject; + var syncConfig = new SyncConfig { FastSync = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }; - // A new batch is creating, starting at hang block - using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + IBlockTree localBlockTree = Build.A.BlockTree(peerChain.FindBlock(0, BlockTreeLookupOptions.None)!, null).WithSyncConfig(syncConfig).TestObject; + const int lowestInserted = 999; + localBlockTree.Insert(peerChain.Head!, BlockTreeInsertBlockOptions.SaveHeader); - FulfillBatch(batch2); - feed.HandleResponse(batch2); + ISyncReport report = Substitute.For(); + report.HeadersInQueue.Returns(new MeasuredProgress()); + report.FastBlocksHeaders.Returns(new MeasuredProgress()); - // The whole new batch should get processed instead of skipping due to concurrently modified _nextHeaderHash. - blockTree.LowestInsertedHeader!.Number.Should().Be(batch2.StartNumber); - } + ISyncPeerPool syncPeerPool = Substitute.For(); + using HeadersSyncFeed feed = new(localBlockTree, syncPeerPool, syncConfig, report, LimboLogs.Instance); + feed.InitializeFeed(); + using HeadersSyncBatch? firstBatch = await feed.PrepareRequest(); + using HeadersSyncBatch? dependentBatch = await feed.PrepareRequest(); + dependentBatch!.ResponseSourcePeer = new PeerInfo(Substitute.For()); - [Test] - public async Task Can_keep_returning_nulls_after_all_batches_were_prepared() + void FillBatch(HeadersSyncBatch batch, long start, bool applyNulls) { - BlockTree blockTree = Build.A.BlockTree().WithoutSettingHead.TestObject; - HeadersSyncFeed feed = new( - blockTree: blockTree, - syncPeerPool: Substitute.For(), - syncConfig: new SyncConfig + int c = count; + List list = Enumerable.Range((int)start, batch.RequestSize) + .Select(i => peerChain.FindBlock(i, BlockTreeLookupOptions.None)!.Header) + .ToList(); + if (applyNulls) + for (int i = nullIndex; 0 < c; i += increment) { - FastSync = true, - PivotNumber = "1000", - PivotHash = Keccak.Zero.ToString(), - PivotTotalDifficulty = "1000" - }, - syncReport: Substitute.For(), - logManager: LimboLogs.Instance); + list[i] = null; + c--; + } + if (!useNulls) + list = list.Where(h => h is not null).ToList(); + batch.Response = list.ToPooledList(); + } - for (int i = 0; i < 10; i++) - { - await feed.PrepareRequest(); - } + FillBatch(firstBatch!, lowestInserted - firstBatch!.RequestSize, false); + FillBatch(dependentBatch, lowestInserted - dependentBatch.RequestSize * 2, true); + long targetHeaderInDependentBatch = dependentBatch.StartNumber; - using HeadersSyncBatch? result = await feed.PrepareRequest(); - result.Should().BeNull(); - } + feed.HandleResponse(dependentBatch); + feed.HandleResponse(firstBatch); - [Test] - public async Task Finishes_when_all_downloaded() - { - IBlockTree blockTree = Substitute.For(); - blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1000).TestObject); - ISyncReport report = Substitute.For(); - report.HeadersInQueue.Returns(new MeasuredProgress()); - MeasuredProgress measuredProgress = new(); - report.FastBlocksHeaders.Returns(measuredProgress); - HeadersSyncFeed feed = new(blockTree, Substitute.For(), new SyncConfig { FastSync = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }, report, LimboLogs.Instance); - await feed.PrepareRequest(); - blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).TestObject); - using HeadersSyncBatch? result = await feed.PrepareRequest(); + using HeadersSyncBatch? thirdbatch = await feed.PrepareRequest(); + FillBatch(thirdbatch!, thirdbatch!.StartNumber, false); + feed.HandleResponse(thirdbatch); + using HeadersSyncBatch? fourthbatch = await feed.PrepareRequest(); + FillBatch(fourthbatch!, fourthbatch!.StartNumber, false); + feed.HandleResponse(fourthbatch); + using HeadersSyncBatch? fifthbatch = await feed.PrepareRequest(); - result.Should().BeNull(); - feed.CurrentState.Should().Be(SyncFeedState.Finished); - measuredProgress.HasEnded.Should().BeTrue(); - } + Assert.That(localBlockTree.LowestInsertedHeader!.Number, Is.LessThanOrEqualTo(targetHeaderInDependentBatch)); + syncPeerPool.Received(shouldReport ? 1 : 0).ReportBreachOfProtocol(Arg.Any(), Arg.Any(), Arg.Any()); + } - [Test] - public async Task Can_resume_downloading_from_parent_of_lowest_inserted_header() + [Test] + public async Task Will_never_lose_batch_on_invalid_batch() + { + IBlockTree blockTree = Substitute.For(); + blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1000).TestObject); + ISyncReport report = Substitute.For(); + report.HeadersInQueue.Returns(new MeasuredProgress()); + MeasuredProgress measuredProgress = new(); + report.FastBlocksHeaders.Returns(measuredProgress); + HeadersSyncFeed feed = new( + blockTree, + Substitute.For(), + new SyncConfig + { + FastSync = true, + PivotNumber = "1000", + PivotHash = Keccak.Zero.ToString(), + PivotTotalDifficulty = "1000" + }, report, LimboLogs.Instance); + feed.InitializeFeed(); + + List batches = new(); + while (true) { - IBlockTree blockTree = Substitute.For(); - blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader - .WithNumber(500) - .WithTotalDifficulty(10_000_000) - .TestObject); - - ISyncReport report = Substitute.For(); - report.HeadersInQueue.Returns(new MeasuredProgress()); - report.FastBlocksHeaders.Returns(new MeasuredProgress()); - - HeadersSyncFeed feed = new(blockTree, Substitute.For(), new SyncConfig { FastSync = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }, report, LimboLogs.Instance); - feed.InitializeFeed(); - using HeadersSyncBatch? result = await feed.PrepareRequest(); - - result.Should().NotBeNull(); - result!.EndNumber.Should().Be(499); + HeadersSyncBatch? batch = await feed.PrepareRequest(); + if (batch is null) break; + batches.Add(batch); } + int totalBatchCount = batches.Count; - //Missing headers in the start is not allowed - [TestCase(0, 1, 1, true, false)] - [TestCase(0, 1, 1, false, true)] - //Missing headers in the start is not allowed - [TestCase(0, 2, 1, true, false)] - [TestCase(0, 2, 1, false, true)] - //Missing headers in the start is not allowed - [TestCase(0, 2, 191, true, false)] - [TestCase(0, 2, 191, false, true)] - //Gaps are not allowed - [TestCase(1, 1, 1, true, false)] - [TestCase(1, 1, 1, true, true)] - [TestCase(187, 5, 1, false, false)] - [TestCase(187, 5, 1, false, true)] - [TestCase(191, 1, 1, false, false)] - [TestCase(191, 1, 1, false, true)] - [TestCase(190, 1, 1, true, false)] - [TestCase(190, 1, 1, true, true)] - [TestCase(80, 1, 1, true, false)] - [TestCase(80, 1, 1, true, true)] - //All empty reponse - [TestCase(0, 192, 1, false, false)] - //All null reponse - [TestCase(0, 192, 1, false, true)] - public async Task Can_insert_all_good_headers_from_dependent_batch_with_missing_or_null_headers(int nullIndex, int count, int increment, bool shouldReport, bool useNulls) + Channel batchToProcess = Channel.CreateBounded(batches.Count); + foreach (HeadersSyncBatch headersSyncBatch in batches) { - var peerChain = Build.A.BlockTree().OfChainLength(1000).TestObject; - var syncConfig = new SyncConfig { FastSync = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }; - - IBlockTree localBlockTree = Build.A.BlockTree(peerChain.FindBlock(0, BlockTreeLookupOptions.None)!, null).WithSyncConfig(syncConfig).TestObject; - const int lowestInserted = 999; - localBlockTree.Insert(peerChain.Head!, BlockTreeInsertBlockOptions.SaveHeader); - - ISyncReport report = Substitute.For(); - report.HeadersInQueue.Returns(new MeasuredProgress()); - report.FastBlocksHeaders.Returns(new MeasuredProgress()); - - ISyncPeerPool syncPeerPool = Substitute.For(); - using HeadersSyncFeed feed = new(localBlockTree, syncPeerPool, syncConfig, report, LimboLogs.Instance); - feed.InitializeFeed(); - using HeadersSyncBatch? firstBatch = await feed.PrepareRequest(); - using HeadersSyncBatch? dependentBatch = await feed.PrepareRequest(); - dependentBatch!.ResponseSourcePeer = new PeerInfo(Substitute.For()); - - void FillBatch(HeadersSyncBatch batch, long start, bool applyNulls) - { - int c = count; - List list = Enumerable.Range((int)start, batch.RequestSize) - .Select(i => peerChain.FindBlock(i, BlockTreeLookupOptions.None)!.Header) - .ToList(); - if (applyNulls) - for (int i = nullIndex; 0 < c; i += increment) - { - list[i] = null; - c--; - } - if (!useNulls) - list = list.Where(h => h is not null).ToList(); - batch.Response = list.ToPooledList(); - } - - FillBatch(firstBatch!, lowestInserted - firstBatch!.RequestSize, false); - FillBatch(dependentBatch, lowestInserted - dependentBatch.RequestSize * 2, true); - long targetHeaderInDependentBatch = dependentBatch.StartNumber; - - feed.HandleResponse(dependentBatch); - feed.HandleResponse(firstBatch); - - using HeadersSyncBatch? thirdbatch = await feed.PrepareRequest(); - FillBatch(thirdbatch!, thirdbatch!.StartNumber, false); - feed.HandleResponse(thirdbatch); - using HeadersSyncBatch? fourthbatch = await feed.PrepareRequest(); - FillBatch(fourthbatch!, fourthbatch!.StartNumber, false); - feed.HandleResponse(fourthbatch); - using HeadersSyncBatch? fifthbatch = await feed.PrepareRequest(); - - Assert.That(localBlockTree.LowestInsertedHeader!.Number, Is.LessThanOrEqualTo(targetHeaderInDependentBatch)); - syncPeerPool.Received(shouldReport ? 1 : 0).ReportBreachOfProtocol(Arg.Any(), Arg.Any(), Arg.Any()); + await batchToProcess.Writer.WriteAsync(headersSyncBatch); } + batches.Clear(); - [Test] - public async Task Will_never_lose_batch_on_invalid_batch() + Task requestTasks = Task.Run(async () => { - IBlockTree blockTree = Substitute.For(); - blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1000).TestObject); - ISyncReport report = Substitute.For(); - report.HeadersInQueue.Returns(new MeasuredProgress()); - MeasuredProgress measuredProgress = new(); - report.FastBlocksHeaders.Returns(measuredProgress); - HeadersSyncFeed feed = new( - blockTree, - Substitute.For(), - new SyncConfig - { - FastSync = true, - PivotNumber = "1000", - PivotHash = Keccak.Zero.ToString(), - PivotTotalDifficulty = "1000" - }, report, LimboLogs.Instance); - feed.InitializeFeed(); - - List batches = new(); - while (true) + for (int i = 0; i < 100000; i++) { HeadersSyncBatch? batch = await feed.PrepareRequest(); - if (batch is null) break; - batches.Add(batch); - } - int totalBatchCount = batches.Count; - - Channel batchToProcess = Channel.CreateBounded(batches.Count); - foreach (HeadersSyncBatch headersSyncBatch in batches) - { - await batchToProcess.Writer.WriteAsync(headersSyncBatch); - } - batches.Clear(); - - Task requestTasks = Task.Run(async () => - { - for (int i = 0; i < 100000; i++) + if (batch is null) { - HeadersSyncBatch? batch = await feed.PrepareRequest(); - if (batch is null) - { - await Task.Delay(1); - continue; - } - - await batchToProcess.Writer.WriteAsync(batch); + await Task.Delay(1); + continue; } - batchToProcess.Writer.Complete(); - }); - - BlockHeader randomBlockHeader = Build.A.BlockHeader.WithNumber(999999).TestObject; - await foreach (HeadersSyncBatch headersSyncBatch in batchToProcess.Reader.ReadAllAsync()) - { - headersSyncBatch.Response = new ArrayPoolList(1) { randomBlockHeader }; - feed.HandleResponse(headersSyncBatch); + await batchToProcess.Writer.WriteAsync(batch); } - await requestTasks; - - while (true) - { - using HeadersSyncBatch? batch = await feed.PrepareRequest(); - if (batch is null) break; - batches.Add(batch); - } + batchToProcess.Writer.Complete(); + }); - batches.Count.Should().Be(totalBatchCount); + BlockHeader randomBlockHeader = Build.A.BlockHeader.WithNumber(999999).TestObject; + await foreach (HeadersSyncBatch headersSyncBatch in batchToProcess.Reader.ReadAllAsync()) + { + headersSyncBatch.Response = new ArrayPoolList(1) { randomBlockHeader }; + feed.HandleResponse(headersSyncBatch); } + await requestTasks; - [Test] - public void IsFinished_returns_false_when_headers_not_downloaded() + while (true) { - IBlockTree blockTree = Substitute.For(); - SyncConfig syncConfig = new() - { - FastSync = true, - DownloadBodiesInFastSync = true, - DownloadReceiptsInFastSync = true, - PivotNumber = "1", - }; + using HeadersSyncBatch? batch = await feed.PrepareRequest(); + if (batch is null) break; + batches.Add(batch); + } - blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(2).WithStateRoot(TestItem.KeccakA).TestObject); + batches.Count.Should().Be(totalBatchCount); + } - HeadersSyncFeed feed = new( - blockTree, - Substitute.For(), - syncConfig, - Substitute.For(), - LimboLogs.Instance); - Assert.False(feed.IsFinished); + [Test] + public void IsFinished_returns_false_when_headers_not_downloaded() + { + IBlockTree blockTree = Substitute.For(); + SyncConfig syncConfig = new() + { + FastSync = true, + DownloadBodiesInFastSync = true, + DownloadReceiptsInFastSync = true, + PivotNumber = "1", + }; + + blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(2).WithStateRoot(TestItem.KeccakA).TestObject); + + HeadersSyncFeed feed = new( + blockTree, + Substitute.For(), + syncConfig, + Substitute.For(), + LimboLogs.Instance); + + Assert.That(feed.IsFinished, Is.False); + } + + private class ResettableHeaderSyncFeed : HeadersSyncFeed + { + private readonly ManualResetEventSlim? _hangLatch; + private readonly long? _hangOnBlockNumber; + private readonly long? _hangOnBlockNumberAfterInsert; + + public ResettableHeaderSyncFeed( + IBlockTree? blockTree, + ISyncPeerPool? syncPeerPool, + ISyncConfig? syncConfig, + ISyncReport? syncReport, + ILogManager? logManager, + long? hangOnBlockNumber = null, + long? hangOnBlockNumberAfterInsert = null, + ManualResetEventSlim? hangLatch = null, + bool alwaysStartHeaderSync = false + ) : base(blockTree, syncPeerPool, syncConfig, syncReport, logManager, alwaysStartHeaderSync) + { + _hangOnBlockNumber = hangOnBlockNumber; + _hangOnBlockNumberAfterInsert = hangOnBlockNumberAfterInsert; + _hangLatch = hangLatch; + } + + public void Reset() + { + base.PostFinishCleanUp(); + InitializeFeed(); } - private class ResettableHeaderSyncFeed : HeadersSyncFeed + protected override AddBlockResult InsertToBlockTree(BlockHeader header) { - private readonly ManualResetEventSlim? _hangLatch; - private readonly long? _hangOnBlockNumber; - private readonly long? _hangOnBlockNumberAfterInsert; - - public ResettableHeaderSyncFeed( - IBlockTree? blockTree, - ISyncPeerPool? syncPeerPool, - ISyncConfig? syncConfig, - ISyncReport? syncReport, - ILogManager? logManager, - long? hangOnBlockNumber = null, - long? hangOnBlockNumberAfterInsert = null, - ManualResetEventSlim? hangLatch = null, - bool alwaysStartHeaderSync = false - ) : base(blockTree, syncPeerPool, syncConfig, syncReport, logManager, alwaysStartHeaderSync) + if (header.Number == _hangOnBlockNumber) { - _hangOnBlockNumber = hangOnBlockNumber; - _hangOnBlockNumberAfterInsert = hangOnBlockNumberAfterInsert; - _hangLatch = hangLatch; + _hangLatch!.Wait(); } - public void Reset() + AddBlockResult insertOutcome = _blockTree.Insert(header); + if (header.Number == _hangOnBlockNumberAfterInsert) { - base.PostFinishCleanUp(); - InitializeFeed(); + _hangLatch!.Wait(); } - - protected override AddBlockResult InsertToBlockTree(BlockHeader header) + if (insertOutcome is AddBlockResult.Added or AddBlockResult.AlreadyKnown) { - if (header.Number == _hangOnBlockNumber) - { - _hangLatch!.Wait(); - } - - AddBlockResult insertOutcome = _blockTree.Insert(header); - if (header.Number == _hangOnBlockNumberAfterInsert) - { - _hangLatch!.Wait(); - } - if (insertOutcome is AddBlockResult.Added or AddBlockResult.AlreadyKnown) - { - SetExpectedNextHeaderToParent(header); - } - - return insertOutcome; + SetExpectedNextHeaderToParent(header); } - } + return insertOutcome; + } } + } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs index f120286404c..894426992aa 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs @@ -29,426 +29,424 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Synchronization.Test.FastBlocks +namespace Nethermind.Synchronization.Test.FastBlocks; + +public class ReceiptsSyncFeedTests { - [TestFixture] - public class ReceiptsSyncFeedTests + private class Scenario { - private class Scenario + public Scenario(ISpecProvider specProvider, int nonEmptyBlocks, int txPerBlock, int emptyBlocks = 0) { - public Scenario(ISpecProvider specProvider, int nonEmptyBlocks, int txPerBlock, int emptyBlocks = 0) - { - Blocks = new Block[_pivotNumber + 1]; - Blocks[0] = Build.A.Block.Genesis.TestObject; - - Block parent = Blocks[0]!; - for (int blockNumber = 1; blockNumber <= _pivotNumber; blockNumber++) - { - Block block = Build.A.Block - .WithParent(parent) - .WithTransactions(blockNumber > _pivotNumber - nonEmptyBlocks ? txPerBlock : 0, specProvider).TestObject; + Blocks = new Block[_pivotNumber + 1]; + Blocks[0] = Build.A.Block.Genesis.TestObject; - if (blockNumber > _pivotNumber - nonEmptyBlocks - emptyBlocks) - Blocks[blockNumber] = block; + Block parent = Blocks[0]!; + for (int blockNumber = 1; blockNumber <= _pivotNumber; blockNumber++) + { + Block block = Build.A.Block + .WithParent(parent) + .WithTransactions(blockNumber > _pivotNumber - nonEmptyBlocks ? txPerBlock : 0, specProvider).TestObject; - if (blockNumber == _pivotNumber - nonEmptyBlocks - emptyBlocks + 1) - LowestInsertedBody = block; + if (blockNumber > _pivotNumber - nonEmptyBlocks - emptyBlocks) + Blocks[blockNumber] = block; - parent = block; - } + if (blockNumber == _pivotNumber - nonEmptyBlocks - emptyBlocks + 1) + LowestInsertedBody = block; - BlocksByHash = Blocks - .Where(b => b is not null) - .ToDictionary(b => b!.Hash!, b => b!); + parent = block; } - public Dictionary BlocksByHash { get; } - public Block?[] Blocks { get; } - public Block? LowestInsertedBody { get; } + BlocksByHash = Blocks + .Where(b => b is not null) + .ToDictionary(b => b!.Hash!, b => b!); } - private static readonly ISpecProvider _specProvider; - private IReceiptStorage _receiptStorage = null!; - private ISyncPeerPool _syncPeerPool = null!; - private ReceiptsSyncFeed _feed = null!; - private ISyncConfig _syncConfig = null!; - private ISyncReport _syncReport = null!; - private IBlockTree _blockTree = null!; - private IDb _metadataDb = null!; + public Dictionary BlocksByHash { get; } + public Block?[] Blocks { get; } + public Block? LowestInsertedBody { get; } + } - private static long _pivotNumber = 1024; + private static readonly ISpecProvider _specProvider; + private IReceiptStorage _receiptStorage = null!; + private ISyncPeerPool _syncPeerPool = null!; + private ReceiptsSyncFeed _feed = null!; + private ISyncConfig _syncConfig = null!; + private ISyncReport _syncReport = null!; + private IBlockTree _blockTree = null!; + private IDb _metadataDb = null!; - private static readonly Scenario _1024BodiesWithOneTxEach; - private static readonly Scenario _256BodiesWithOneTxEach; - private static readonly Scenario _64BodiesWithOneTxEach; - private static readonly Scenario _64BodiesWithOneTxEachFollowedByEmpty; + private static long _pivotNumber = 1024; - private MeasuredProgress _measuredProgress = null!; - private MeasuredProgress _measuredProgressQueue = null!; + private static readonly Scenario _1024BodiesWithOneTxEach; + private static readonly Scenario _256BodiesWithOneTxEach; + private static readonly Scenario _64BodiesWithOneTxEach; + private static readonly Scenario _64BodiesWithOneTxEachFollowedByEmpty; - static ReceiptsSyncFeedTests() - { - _specProvider = new TestSingleReleaseSpecProvider(Istanbul.Instance); - _1024BodiesWithOneTxEach = new Scenario(_specProvider, 1024, 1); - _256BodiesWithOneTxEach = new Scenario(_specProvider, 256, 1); - _64BodiesWithOneTxEach = new Scenario(_specProvider, 64, 1); - _64BodiesWithOneTxEachFollowedByEmpty = new Scenario(_specProvider, 64, 1, 1024 - 64); - } + private MeasuredProgress _measuredProgress = null!; + private MeasuredProgress _measuredProgressQueue = null!; - [SetUp] - public void Setup() - { - _receiptStorage = Substitute.For(); - _blockTree = Substitute.For(); - _metadataDb = new TestMemDb(); + static ReceiptsSyncFeedTests() + { + _specProvider = new TestSingleReleaseSpecProvider(Istanbul.Instance); + _1024BodiesWithOneTxEach = new Scenario(_specProvider, 1024, 1); + _256BodiesWithOneTxEach = new Scenario(_specProvider, 256, 1); + _64BodiesWithOneTxEach = new Scenario(_specProvider, 64, 1); + _64BodiesWithOneTxEachFollowedByEmpty = new Scenario(_specProvider, 64, 1, 1024 - 64); + } - _syncConfig = new SyncConfig { FastSync = true }; - _syncConfig.PivotNumber = _pivotNumber.ToString(); - _syncConfig.PivotHash = Keccak.Zero.ToString(); + [SetUp] + public void Setup() + { + _receiptStorage = Substitute.For(); + _blockTree = Substitute.For(); + _metadataDb = new TestMemDb(); - _syncPeerPool = Substitute.For(); - _syncReport = Substitute.For(); + _syncConfig = new SyncConfig { FastSync = true }; + _syncConfig.PivotNumber = _pivotNumber.ToString(); + _syncConfig.PivotHash = Keccak.Zero.ToString(); - _measuredProgress = new MeasuredProgress(); - _measuredProgressQueue = new MeasuredProgress(); - _syncReport.FastBlocksReceipts.Returns(_measuredProgress); - _syncReport.ReceiptsInQueue.Returns(_measuredProgressQueue); + _syncPeerPool = Substitute.For(); + _syncReport = Substitute.For(); - _feed = CreateFeed(); - } + _measuredProgress = new MeasuredProgress(); + _measuredProgressQueue = new MeasuredProgress(); + _syncReport.FastBlocksReceipts.Returns(_measuredProgress); + _syncReport.ReceiptsInQueue.Returns(_measuredProgressQueue); - [TearDown] - public void TearDown() - { - _feed?.Dispose(); - _syncPeerPool?.Dispose(); - _syncReport?.Dispose(); - _metadataDb?.Dispose(); - } + _feed = CreateFeed(); + } - private ReceiptsSyncFeed CreateFeed() - { - return new ReceiptsSyncFeed( - _specProvider, - _blockTree, - _receiptStorage, - _syncPeerPool, - _syncConfig, - _syncReport, - _metadataDb, - LimboLogs.Instance); - } + [TearDown] + public void TearDown() + { + _feed?.Dispose(); + _syncPeerPool?.Dispose(); + _syncReport?.Dispose(); + _metadataDb?.Dispose(); + } - [Test] - public void Should_throw_when_fast_block_not_enabled() - { - _syncConfig = new SyncConfig { FastSync = false }; - Assert.Throws( - () => _feed = new ReceiptsSyncFeed( - _specProvider, - _blockTree, - _receiptStorage, - _syncPeerPool, - _syncConfig, - _syncReport, - _metadataDb, - LimboLogs.Instance)); - } + private ReceiptsSyncFeed CreateFeed() + { + return new ReceiptsSyncFeed( + _specProvider, + _blockTree, + _receiptStorage, + _syncPeerPool, + _syncConfig, + _syncReport, + _metadataDb, + LimboLogs.Instance); + } - [Test] - public async Task Should_finish_on_start_when_receipts_not_stored() - { - _feed = new ReceiptsSyncFeed( + [Test] + public void Should_throw_when_fast_block_not_enabled() + { + _syncConfig = new SyncConfig { FastSync = false }; + Assert.Throws( + () => _feed = new ReceiptsSyncFeed( _specProvider, _blockTree, - NullReceiptStorage.Instance, + _receiptStorage, _syncPeerPool, _syncConfig, _syncReport, _metadataDb, - LimboLogs.Instance); - _feed.InitializeFeed(); - - using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); - request.Should().BeNull(); - _feed.CurrentState.Should().Be(SyncFeedState.Finished); - } + LimboLogs.Instance)); + } - [Test] - public void Contexts_are_correct() - { - _feed.Contexts.Should().Be(AllocationContexts.Receipts); - } + [Test] + public async Task Should_finish_on_start_when_receipts_not_stored() + { + _feed = new ReceiptsSyncFeed( + _specProvider, + _blockTree, + NullReceiptStorage.Instance, + _syncPeerPool, + _syncConfig, + _syncReport, + _metadataDb, + LimboLogs.Instance); + _feed.InitializeFeed(); + + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + request.Should().BeNull(); + _feed.CurrentState.Should().Be(SyncFeedState.Finished); + } - [Test] - public void Should_be_multifeed() - { - _feed.IsMultiFeed.Should().BeTrue(); - } + [Test] + public void Contexts_are_correct() + { + _feed.Contexts.Should().Be(AllocationContexts.Receipts); + } - [Test] - public void Should_start_dormant() - { - _feed.CurrentState.Should().Be(SyncFeedState.Dormant); - } + [Test] + public void Should_be_multifeed() + { + _feed.IsMultiFeed.Should().BeTrue(); + } - [Test] - public void When_activating_should_emit_an_event() - { - SyncFeedState state = SyncFeedState.Dormant; - _feed.StateChanged += (_, e) => state = e.NewState; - _feed.Activate(); - state.Should().Be(SyncFeedState.Active); - } + [Test] + public void Should_start_dormant() + { + _feed.CurrentState.Should().Be(SyncFeedState.Dormant); + } - [Test] - public void When_no_bodies_downloaded_then_request_will_be_empty() - { - _feed.InitializeFeed(); - _feed.PrepareRequest().Result.Should().BeNull(); - } + [Test] + public void When_activating_should_emit_an_event() + { + SyncFeedState state = SyncFeedState.Dormant; + _feed.StateChanged += (_, e) => state = e.NewState; + _feed.Activate(); + state.Should().Be(SyncFeedState.Active); + } - [Test] - public async Task Returns_same_batch_until_filled() - { - LoadScenario(_256BodiesWithOneTxEach); - using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); - _feed.HandleResponse(request); - using ReceiptsSyncBatch? request2 = await _feed.PrepareRequest(); - request2?.MinNumber.Should().Be(request?.MinNumber); - } + [Test] + public void When_no_bodies_downloaded_then_request_will_be_empty() + { + _feed.InitializeFeed(); + _feed.PrepareRequest().Result.Should().BeNull(); + } - [Test] - public async Task Can_create_a_final_batch() - { - LoadScenario(_64BodiesWithOneTxEachFollowedByEmpty); - using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); - request.Should().NotBeNull(); - request!.MinNumber.Should().Be(1024); - request.Prioritized.Should().Be(true); - } + [Test] + public async Task Returns_same_batch_until_filled() + { + LoadScenario(_256BodiesWithOneTxEach); + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + _feed.HandleResponse(request); + using ReceiptsSyncBatch? request2 = await _feed.PrepareRequest(); + request2?.MinNumber.Should().Be(request?.MinNumber); + } - [Test] - public async Task When_configured_to_skip_receipts_then_finishes_immediately() - { - LoadScenario(_256BodiesWithOneTxEach); - _syncConfig.DownloadReceiptsInFastSync = false; - - using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); - request.Should().BeNull(); - _feed.CurrentState.Should().Be(SyncFeedState.Finished); - _measuredProgress.HasEnded.Should().BeTrue(); - _measuredProgressQueue.HasEnded.Should().BeTrue(); - } + [Test] + public async Task Can_create_a_final_batch() + { + LoadScenario(_64BodiesWithOneTxEachFollowedByEmpty); + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + request.Should().NotBeNull(); + request!.MinNumber.Should().Be(1024); + request.Prioritized.Should().Be(true); + } - [TestCase(1, 1024, false, null, false)] - [TestCase(1, 11051474, false, null, true)] - [TestCase(1, 11052984, false, null, true)] - [TestCase(11051474, 11052984, false, null, false)] - [TestCase(11051474, 11051474, false, null, true)] - [TestCase(1, 11052985, false, null, false)] - [TestCase(1, 1024, false, 11052984, false)] - [TestCase(1, 11051474, false, 11052984, true)] - [TestCase(1, 11052984, false, 11052984, true)] - [TestCase(11051474, 11052984, false, 11052984, false)] - [TestCase(11051474, 11051474, false, 11052984, true)] - [TestCase(1, 11052985, false, 11052984, false)] - [TestCase(1, 1024, true, null, false)] - [TestCase(1, 11051474, true, null, false)] - [TestCase(1, 11052984, true, null, false)] - [TestCase(11051474, 11052984, true, null, false)] - [TestCase(11051474, 11051474, true, null, true)] - [TestCase(1, 11052985, true, null, false)] - [TestCase(1, 1024, false, 0, false)] - [TestCase(1, 11051474, false, 0, false)] - [TestCase(1, 11052984, false, 0, false)] - [TestCase(11051474, 11052984, false, 0, false)] - [TestCase(11051474, 11051474, false, 0, true)] - [TestCase(1, 11052985, false, 0, false)] - public void When_finished_sync_with_old_default_barrier_then_finishes_imedietely( - long AncientBarrierInConfig, - long? lowestInsertedReceiptBlockNumber, - bool JustStarted, - long? previousBarrierInDb, - bool shouldfinish) - { - _syncConfig.AncientBodiesBarrier = AncientBarrierInConfig; - _syncConfig.AncientReceiptsBarrier = AncientBarrierInConfig; - _pivotNumber = AncientBarrierInConfig + 1_000_000; - _receiptStorage.HasBlock(Arg.Is(_pivotNumber), Arg.Any()).Returns(!JustStarted); - if (previousBarrierInDb is not null) - _metadataDb.Set(MetadataDbKeys.ReceiptsBarrierWhenStarted, previousBarrierInDb.Value.ToBigEndianByteArrayWithoutLeadingZeros()); - LoadScenario(_256BodiesWithOneTxEach); - _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(lowestInsertedReceiptBlockNumber); - _feed.IsFinished.Should().Be(shouldfinish); - } + [Test] + public async Task When_configured_to_skip_receipts_then_finishes_immediately() + { + LoadScenario(_256BodiesWithOneTxEach); + _syncConfig.DownloadReceiptsInFastSync = false; + + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + request.Should().BeNull(); + _feed.CurrentState.Should().Be(SyncFeedState.Finished); + _measuredProgress.HasEnded.Should().BeTrue(); + _measuredProgressQueue.HasEnded.Should().BeTrue(); + } - private void LoadScenario(Scenario scenario) - { - LoadScenario(scenario, _syncConfig); - } + [TestCase(1, 1024, false, null, false)] + [TestCase(1, 11051474, false, null, true)] + [TestCase(1, 11052984, false, null, true)] + [TestCase(11051474, 11052984, false, null, false)] + [TestCase(11051474, 11051474, false, null, true)] + [TestCase(1, 11052985, false, null, false)] + [TestCase(1, 1024, false, 11052984, false)] + [TestCase(1, 11051474, false, 11052984, true)] + [TestCase(1, 11052984, false, 11052984, true)] + [TestCase(11051474, 11052984, false, 11052984, false)] + [TestCase(11051474, 11051474, false, 11052984, true)] + [TestCase(1, 11052985, false, 11052984, false)] + [TestCase(1, 1024, true, null, false)] + [TestCase(1, 11051474, true, null, false)] + [TestCase(1, 11052984, true, null, false)] + [TestCase(11051474, 11052984, true, null, false)] + [TestCase(11051474, 11051474, true, null, true)] + [TestCase(1, 11052985, true, null, false)] + [TestCase(1, 1024, false, 0, false)] + [TestCase(1, 11051474, false, 0, false)] + [TestCase(1, 11052984, false, 0, false)] + [TestCase(11051474, 11052984, false, 0, false)] + [TestCase(11051474, 11051474, false, 0, true)] + [TestCase(1, 11052985, false, 0, false)] + public void When_finished_sync_with_old_default_barrier_then_finishes_imedietely( + long AncientBarrierInConfig, + long? lowestInsertedReceiptBlockNumber, + bool JustStarted, + long? previousBarrierInDb, + bool shouldfinish) + { + _syncConfig.AncientBodiesBarrier = AncientBarrierInConfig; + _syncConfig.AncientReceiptsBarrier = AncientBarrierInConfig; + _pivotNumber = AncientBarrierInConfig + 1_000_000; + _receiptStorage.HasBlock(Arg.Is(_pivotNumber), Arg.Any()).Returns(!JustStarted); + if (previousBarrierInDb is not null) + _metadataDb.Set(MetadataDbKeys.ReceiptsBarrierWhenStarted, previousBarrierInDb.Value.ToBigEndianByteArrayWithoutLeadingZeros()); + LoadScenario(_256BodiesWithOneTxEach); + _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(lowestInsertedReceiptBlockNumber); + _feed.IsFinished.Should().Be(shouldfinish); + } - private void LoadScenario(Scenario scenario, ISyncConfig syncConfig) - { - _syncConfig = syncConfig; - _syncConfig.PivotNumber = _pivotNumber.ToString(); - _syncConfig.PivotHash = scenario.Blocks.Last()?.Hash?.ToString(); + private void LoadScenario(Scenario scenario) + { + LoadScenario(scenario, _syncConfig); + } - _feed = new ReceiptsSyncFeed( - _specProvider, - _blockTree, - _receiptStorage, - _syncPeerPool, - _syncConfig, - _syncReport, - _metadataDb, - LimboLogs.Instance); - _feed.InitializeFeed(); + private void LoadScenario(Scenario scenario, ISyncConfig syncConfig) + { + _syncConfig = syncConfig; + _syncConfig.PivotNumber = _pivotNumber.ToString(); + _syncConfig.PivotHash = scenario.Blocks.Last()?.Hash?.ToString(); + + _feed = new ReceiptsSyncFeed( + _specProvider, + _blockTree, + _receiptStorage, + _syncPeerPool, + _syncConfig, + _syncReport, + _metadataDb, + LimboLogs.Instance); + _feed.InitializeFeed(); + + _blockTree.Genesis.Returns(scenario.Blocks[0]!.Header); + _blockTree.FindCanonicalBlockInfo(Arg.Any()).Returns( + ci => + { + Block? block = scenario.Blocks[ci.Arg()]; + if (block is null) + return null; - _blockTree.Genesis.Returns(scenario.Blocks[0]!.Header); - _blockTree.FindCanonicalBlockInfo(Arg.Any()).Returns( - ci => + BlockInfo blockInfo = new(block.Hash!, block.TotalDifficulty ?? 0) { - Block? block = scenario.Blocks[ci.Arg()]; - if (block is null) - return null; - - BlockInfo blockInfo = new(block.Hash!, block.TotalDifficulty ?? 0) - { - BlockNumber = ci.Arg(), - }; - return blockInfo; - }); - - _blockTree.FindBlock(Keccak.Zero, BlockTreeLookupOptions.None) - .ReturnsForAnyArgs(ci => - scenario.BlocksByHash.TryGetValue(ci.Arg(), out Block? value) ? value : null); - - _blockTree.FindHeader(Keccak.Zero, BlockTreeLookupOptions.None) - .ReturnsForAnyArgs(ci => - scenario.BlocksByHash.TryGetValue(ci.Arg(), out Block? value) ? value.Header - : null); - - _receiptStorage.LowestInsertedReceiptBlockNumber.Returns((long?)null); - _blockTree.LowestInsertedBodyNumber.Returns(scenario.LowestInsertedBody!.Number); - } - - [Test] - public async Task Can_create_receipts_batches_for_all_bodies_inserted_and_then_generate_null_batches_for_other_peers() - { - LoadScenario(_256BodiesWithOneTxEach); + BlockNumber = ci.Arg(), + }; + return blockInfo; + }); + + _blockTree.FindBlock(Keccak.Zero, BlockTreeLookupOptions.None) + .ReturnsForAnyArgs(ci => + scenario.BlocksByHash.TryGetValue(ci.Arg(), out Block? value) ? value : null); + + _blockTree.FindHeader(Keccak.Zero, BlockTreeLookupOptions.None) + .ReturnsForAnyArgs(ci => + scenario.BlocksByHash.TryGetValue(ci.Arg(), out Block? value) ? value.Header + : null); + + _receiptStorage.LowestInsertedReceiptBlockNumber.Returns((long?)null); + _blockTree.LowestInsertedBodyNumber.Returns(scenario.LowestInsertedBody!.Number); + } - /* we have only 256 receipts altogether but we start with many peers - so most of our requests will be empty */ + [Test] + public async Task Can_create_receipts_batches_for_all_bodies_inserted_and_then_generate_null_batches_for_other_peers() + { + LoadScenario(_256BodiesWithOneTxEach); - List batches = new(); - for (int i = 0; i < 100; i++) - { - batches.Add(await _feed.PrepareRequest()); - } + /* we have only 256 receipts altogether but we start with many peers + so most of our requests will be empty */ - for (int i = 0; i < 2; i++) - { - batches[i].Should().NotBeNull(); - batches[i]!.ToString().Should().NotBeNull(); - } + List batches = new(); + for (int i = 0; i < 100; i++) + { + batches.Add(await _feed.PrepareRequest()); + } - for (int i = 2; i < 100; i++) - { - batches[i].Should().BeNull(); - } + for (int i = 0; i < 2; i++) + { + batches[i].Should().NotBeNull(); + batches[i]!.ToString().Should().NotBeNull(); } - [Test] - public async Task If_receipts_root_comes_invalid_then_reports_breach_of_protocol() + for (int i = 2; i < 100; i++) { - LoadScenario(_1024BodiesWithOneTxEach); - using ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); - var response = new ArrayPoolList(batch!.Infos.Length, batch!.Infos.Length); + batches[i].Should().BeNull(); + } + } - // default receipts that we use when constructing receipt root for tests have stats code 0 - // so by using 1 here we create a different tx root - response[0] = new[] { Build.A.Receipt.WithStatusCode(1).TestObject }; + [Test] + public async Task If_receipts_root_comes_invalid_then_reports_breach_of_protocol() + { + LoadScenario(_1024BodiesWithOneTxEach); + using ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); + var response = new ArrayPoolList(batch!.Infos.Length, batch!.Infos.Length); - batch!.Response = response!; + // default receipts that we use when constructing receipt root for tests have stats code 0 + // so by using 1 here we create a different tx root + response[0] = new[] { Build.A.Receipt.WithStatusCode(1).TestObject }; - PeerInfo peerInfo = new(Substitute.For()); - batch.ResponseSourcePeer = peerInfo; + batch!.Response = response!; - SyncResponseHandlingResult handlingResult = _feed.HandleResponse(batch); - handlingResult.Should().Be(SyncResponseHandlingResult.NoProgress); + PeerInfo peerInfo = new(Substitute.For()); + batch.ResponseSourcePeer = peerInfo; - _syncPeerPool.Received().ReportBreachOfProtocol(peerInfo, DisconnectReason.InvalidReceiptRoot, Arg.Any()); - } + SyncResponseHandlingResult handlingResult = _feed.HandleResponse(batch); + handlingResult.Should().Be(SyncResponseHandlingResult.NoProgress); - private static void FillBatchResponses(ReceiptsSyncBatch batch) - { - var response = new ArrayPoolList(batch.Infos.Length, batch.Infos.Length); - for (int i = 0; i < response.Count; i++) - { - response[i] = new[] { Build.A.Receipt.TestObject }; - } + _syncPeerPool.Received().ReportBreachOfProtocol(peerInfo, DisconnectReason.InvalidReceiptRoot, Arg.Any()); + } - batch.Response = response; + private static void FillBatchResponses(ReceiptsSyncBatch batch) + { + var response = new ArrayPoolList(batch.Infos.Length, batch.Infos.Length); + for (int i = 0; i < response.Count; i++) + { + response[i] = new[] { Build.A.Receipt.TestObject }; } - [Test] - public async Task Can_sync_final_batch() - { - LoadScenario(_64BodiesWithOneTxEach); - using ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); + batch.Response = response; + } + + [Test] + public async Task Can_sync_final_batch() + { + LoadScenario(_64BodiesWithOneTxEach); + using ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); - FillBatchResponses(batch!); - _feed.HandleResponse(batch); - _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(1); - _feed.PrepareRequest().Result.Should().Be(null); + FillBatchResponses(batch!); + _feed.HandleResponse(batch); + _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(1); + _feed.PrepareRequest().Result.Should().Be(null); - _feed.CurrentState.Should().Be(SyncFeedState.Finished); - } + _feed.CurrentState.Should().Be(SyncFeedState.Finished); + } - [Test] - public void Is_fast_block_receipts_finished_returns_false_when_receipts_not_downloaded() + [Test] + public void Is_fast_block_receipts_finished_returns_false_when_receipts_not_downloaded() + { + _blockTree = Substitute.For(); + _syncConfig = new SyncConfig() { - _blockTree = Substitute.For(); - _syncConfig = new SyncConfig() - { - FastSync = true, - DownloadBodiesInFastSync = true, - DownloadReceiptsInFastSync = true, - PivotNumber = "1", - }; + FastSync = true, + DownloadBodiesInFastSync = true, + DownloadReceiptsInFastSync = true, + PivotNumber = "1", + }; - _blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).WithStateRoot(TestItem.KeccakA).TestObject); - _blockTree.LowestInsertedBodyNumber.Returns(1); + _blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).WithStateRoot(TestItem.KeccakA).TestObject); + _blockTree.LowestInsertedBodyNumber.Returns(1); - _receiptStorage = Substitute.For(); - _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(2); + _receiptStorage = Substitute.For(); + _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(2); - ReceiptsSyncFeed feed = CreateFeed(); - Assert.False(feed.IsFinished); - } + ReceiptsSyncFeed feed = CreateFeed(); + Assert.That(feed.IsFinished, Is.False); + } - [Test] - public void Is_fast_block_bodies_finished_returns_true_when_bodies_not_downloaded_and_we_do_not_want_to_download_bodies() + [Test] + public void Is_fast_block_bodies_finished_returns_true_when_bodies_not_downloaded_and_we_do_not_want_to_download_bodies() + { + _blockTree = Substitute.For(); + _syncConfig = new SyncConfig() { - _blockTree = Substitute.For(); - _syncConfig = new SyncConfig() - { - FastSync = true, - DownloadBodiesInFastSync = false, - DownloadReceiptsInFastSync = true, - PivotNumber = "1", - }; - - _blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).WithStateRoot(TestItem.KeccakA).TestObject); - _blockTree.LowestInsertedBodyNumber.Returns(2); - _receiptStorage = Substitute.For(); - _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(1); - - ReceiptsSyncFeed feed = CreateFeed(); - feed.InitializeFeed(); - Assert.True(feed.IsFinished); - } - + FastSync = true, + DownloadBodiesInFastSync = false, + DownloadReceiptsInFastSync = true, + PivotNumber = "1", + }; + + _blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).WithStateRoot(TestItem.KeccakA).TestObject); + _blockTree.LowestInsertedBodyNumber.Returns(2); + _receiptStorage = Substitute.For(); + _receiptStorage.LowestInsertedReceiptBlockNumber.Returns(1); + + ReceiptsSyncFeed feed = CreateFeed(); + feed.InitializeFeed(); + Assert.That(feed.IsFinished, Is.True); } + } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/SyncStatusListTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/SyncStatusListTests.cs index 60b564155f4..98a375ba26a 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/SyncStatusListTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/SyncStatusListTests.cs @@ -7,149 +7,146 @@ using FluentAssertions; using Nethermind.Blockchain; using Nethermind.Core; -using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Synchronization.FastBlocks; using NSubstitute; using NUnit.Framework; -namespace Nethermind.Synchronization.Test.FastBlocks +namespace Nethermind.Synchronization.Test.FastBlocks; + +[Parallelizable(ParallelScope.Self)] +public class SyncStatusListTests { - [Parallelizable(ParallelScope.Self)] - [TestFixture] - public class SyncStatusListTests + [Test] + public void Out_of_range_access_throws() { - [Test] - public void Out_of_range_access_throws() - { - FastBlockStatusList list = new(1); + FastBlockStatusList list = new(1); - FastBlockStatus a = list[0]; - list.TrySet(0, a); + FastBlockStatus a = list[0]; + list.TrySet(0, a); - Assert.Throws(() => { FastBlockStatus a = list[-1]; }); - Assert.Throws(() => { FastBlockStatus a = list[1]; }); - Assert.Throws(() => { list.TrySet(-1, FastBlockStatus.Pending); }); - Assert.Throws(() => { list.TrySet(1, FastBlockStatus.Pending); }); - } + Assert.Throws(() => { FastBlockStatus a = list[-1]; }); + Assert.Throws(() => { FastBlockStatus a = list[1]; }); + Assert.Throws(() => { list.TrySet(-1, FastBlockStatus.Pending); }); + Assert.Throws(() => { list.TrySet(1, FastBlockStatus.Pending); }); + } - [Test] - public void Can_read_back_all_set_values() - { - const int length = 4096; + [Test] + public void Can_read_back_all_set_values() + { + const int length = 4096; - FastBlockStatusList list = CreateFastBlockStatusList(length, false); - for (int i = 0; i < length; i++) - { - Assert.IsTrue((FastBlockStatus)(i % 3) == list[i]); - } + FastBlockStatusList list = CreateFastBlockStatusList(length, false); + for (int i = 0; i < length; i++) + { + Assert.That((FastBlockStatus)(i % 3) == list[i], Is.True); } + } - [Test] - public void Will_not_go_below_ancient_barrier() - { - IBlockTree blockTree = Substitute.For(); - blockTree.FindCanonicalBlockInfo(Arg.Any()).Returns(new BlockInfo(TestItem.KeccakA, 0)); - SyncStatusList syncStatusList = new SyncStatusList(blockTree, 1000, null, 900); + [Test] + public void Will_not_go_below_ancient_barrier() + { + IBlockTree blockTree = Substitute.For(); + blockTree.FindCanonicalBlockInfo(Arg.Any()).Returns(new BlockInfo(TestItem.KeccakA, 0)); + SyncStatusList syncStatusList = new SyncStatusList(blockTree, 1000, null, 900); - BlockInfo?[] infos = new BlockInfo?[500]; - syncStatusList.GetInfosForBatch(infos); + BlockInfo?[] infos = new BlockInfo?[500]; + syncStatusList.GetInfosForBatch(infos); - infos.Count((it) => it is not null).Should().Be(101); - } + infos.Count((it) => it is not null).Should().Be(101); + } - [Test] - public void Can_read_back_all_parallel_set_values() - { - const long length = 4096; + [Test] + public void Can_read_back_all_parallel_set_values() + { + const long length = 4096; - for (var len = 0; len < length; len++) + for (var len = 0; len < length; len++) + { + FastBlockStatusList list = CreateFastBlockStatusList(len); + Parallel.For(0, len, (i) => { - FastBlockStatusList list = CreateFastBlockStatusList(len); - Parallel.For(0, len, (i) => - { - Assert.IsTrue((FastBlockStatus)(i % 3) == list[i]); - }); - } + Assert.That((FastBlockStatus)(i % 3) == list[i], Is.True); + }); } + } - [Test] - public void State_transitions_are_enforced() - { - const long length = 4096; + [Test] + public void State_transitions_are_enforced() + { + const long length = 4096; - for (var len = 0; len < length; len++) + for (var len = 0; len < length; len++) + { + FastBlockStatusList list = CreateFastBlockStatusList(len, false); + for (int i = 0; i < len; i++) { - FastBlockStatusList list = CreateFastBlockStatusList(len, false); - for (int i = 0; i < len; i++) + switch (list[i]) { - switch (list[i]) - { - case FastBlockStatus.Pending: - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Pending)); - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Inserted)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Sent)); - goto case FastBlockStatus.Sent; - - case FastBlockStatus.Sent: - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Sent)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Pending)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Sent)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Inserted)); - goto case FastBlockStatus.Inserted; - - case FastBlockStatus.Inserted: - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Pending)); - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Sent)); - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Inserted)); - break; - - default: - throw new ArgumentOutOfRangeException(); - } + case FastBlockStatus.Pending: + Assert.That(list.TrySet(i, FastBlockStatus.Pending), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Inserted), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.True); + goto case FastBlockStatus.Sent; + + case FastBlockStatus.Sent: + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Pending), Is.True); + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.True); + Assert.That(list.TrySet(i, FastBlockStatus.Inserted), Is.True); + goto case FastBlockStatus.Inserted; + + case FastBlockStatus.Inserted: + Assert.That(list.TrySet(i, FastBlockStatus.Pending), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Inserted), Is.False); + break; + + default: + throw new ArgumentOutOfRangeException(); } } } + } - [Test] - public void State_transitions_are_enforced_in_parallel() - { - const long length = 4096; + [Test] + public void State_transitions_are_enforced_in_parallel() + { + const long length = 4096; - for (var len = 0; len < length; len++) + for (var len = 0; len < length; len++) + { + FastBlockStatusList list = CreateFastBlockStatusList(len); + Parallel.For(0, len, (i) => { - FastBlockStatusList list = CreateFastBlockStatusList(len); - Parallel.For(0, len, (i) => + switch (list[i]) { - switch (list[i]) - { - case FastBlockStatus.Pending: - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Pending)); - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Inserted)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Sent)); - goto case FastBlockStatus.Sent; - - case FastBlockStatus.Sent: - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Sent)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Pending)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Sent)); - Assert.IsTrue(list.TrySet(i, FastBlockStatus.Inserted)); - goto case FastBlockStatus.Inserted; - - case FastBlockStatus.Inserted: - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Pending)); - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Sent)); - Assert.IsFalse(list.TrySet(i, FastBlockStatus.Inserted)); - break; - - default: - throw new ArgumentOutOfRangeException(); - } - }); - } + case FastBlockStatus.Pending: + Assert.That(list.TrySet(i, FastBlockStatus.Pending), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Inserted), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.True); + goto case FastBlockStatus.Sent; + + case FastBlockStatus.Sent: + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Pending), Is.True); + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.True); + Assert.That(list.TrySet(i, FastBlockStatus.Inserted), Is.True); + goto case FastBlockStatus.Inserted; + + case FastBlockStatus.Inserted: + Assert.That(list.TrySet(i, FastBlockStatus.Pending), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Sent), Is.False); + Assert.That(list.TrySet(i, FastBlockStatus.Inserted), Is.False); + break; + + default: + throw new ArgumentOutOfRangeException(); + } + }); } - - private static FastBlockStatusList CreateFastBlockStatusList(int length, bool parallel = true) => - new(Enumerable.Range(0, length).Select(i => (FastBlockStatus)(i % 3)).ToList(), parallel); } + + private static FastBlockStatusList CreateFastBlockStatusList(int length, bool parallel = true) => + new(Enumerable.Range(0, length).Select(i => (FastBlockStatus)(i % 3)).ToList(), parallel); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedHealingTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedHealingTests.cs index c2145f9de76..3c7a2ea1cb2 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedHealingTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedHealingTests.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -16,153 +15,151 @@ using Nethermind.Synchronization.SnapSync; using NUnit.Framework; -namespace Nethermind.Synchronization.Test.FastSync +namespace Nethermind.Synchronization.Test.FastSync; + +[Parallelizable(ParallelScope.All)] +public class StateSyncFeedHealingTests : StateSyncFeedTestsBase { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class StateSyncFeedHealingTests : StateSyncFeedTestsBase + [Test] + public async Task HealTreeWithoutBoundaryProofs() { - [Test] - public async Task HealTreeWithoutBoundaryProofs() - { - DbContext dbContext = new DbContext(_logger, _logManager); - TestItem.Tree.FillStateTreeWithTestAccounts(dbContext.RemoteStateTree); + DbContext dbContext = new DbContext(_logger, _logManager); + TestItem.Tree.FillStateTreeWithTestAccounts(dbContext.RemoteStateTree); + + Hash256 rootHash = dbContext.RemoteStateTree.RootHash; + + ProcessAccountRange(dbContext.RemoteStateTree, dbContext.LocalStateTree, 1, rootHash, TestItem.Tree.AccountsWithPaths); - Hash256 rootHash = dbContext.RemoteStateTree.RootHash; + SafeContext ctx = PrepareDownloader(dbContext); + await ActivateAndWait(ctx, dbContext, 1024); - ProcessAccountRange(dbContext.RemoteStateTree, dbContext.LocalStateTree, 1, rootHash, TestItem.Tree.AccountsWithPaths); + DetailedProgress data = ctx.TreeFeed.GetDetailedProgress(); - SafeContext ctx = PrepareDownloader(dbContext); - await ActivateAndWait(ctx, dbContext, 1024); - DetailedProgress data = ctx.TreeFeed.GetDetailedProgress(); + dbContext.CompareTrees("END"); + Assert.That(dbContext.LocalStateTree.RootHash, Is.EqualTo(dbContext.RemoteStateTree.RootHash)); + // I guess state root will be requested regardless + Assert.That(data.RequestedNodesCount, Is.EqualTo(1)); // 4 boundary proof nodes stitched together => 0 + } + + [Test] + public async Task HealBigSqueezedRandomTree() + { + DbContext dbContext = new DbContext(_logger, _logManager); - dbContext.CompareTrees("END"); - Assert.That(dbContext.LocalStateTree.RootHash, Is.EqualTo(dbContext.RemoteStateTree.RootHash)); + int pathPoolCount = 100_000; + Hash256[] pathPool = new Hash256[pathPoolCount]; + SortedDictionary accounts = new(); - // I guess state root will be requested regardless - Assert.That(data.RequestedNodesCount, Is.EqualTo(1)); // 4 boundary proof nodes stitched together => 0 + for (int i = 0; i < pathPoolCount; i++) + { + byte[] key = new byte[32]; + // Snap can't actually use GetTrieNodes where the path is exactly 64 nibble. So *255. + ((UInt256)(i * 255)).ToBigEndian(key); + Hash256 keccak = new Hash256(key); + pathPool[i] = keccak; } - [Test] - public async Task HealBigSqueezedRandomTree() + // generate Remote Tree + for (int accountIndex = 0; accountIndex < 10000; accountIndex++) { - DbContext dbContext = new DbContext(_logger, _logManager); + Account account = TestItem.GenerateRandomAccount(); + Hash256 path = pathPool[TestItem.Random.Next(pathPool.Length - 1)]; - int pathPoolCount = 100_000; - Hash256[] pathPool = new Hash256[pathPoolCount]; - SortedDictionary accounts = new(); + dbContext.RemoteStateTree.Set(path, account); + accounts[path] = account; + } - for (int i = 0; i < pathPoolCount; i++) - { - byte[] key = new byte[32]; - // Snap can't actually use GetTrieNodes where the path is exactly 64 nibble. So *255. - ((UInt256)(i * 255)).ToBigEndian(key); - Hash256 keccak = new Hash256(key); - pathPool[i] = keccak; - } + dbContext.RemoteStateTree.Commit(0); - // generate Remote Tree - for (int accountIndex = 0; accountIndex < 10000; accountIndex++) + int startingHashIndex = 0; + int endHashIndex; + int blockJumps = 5; + for (int blockNumber = 1; blockNumber <= blockJumps; blockNumber++) + { + for (int i = 0; i < 19; i++) { - Account account = TestItem.GenerateRandomAccount(); - Hash256 path = pathPool[TestItem.Random.Next(pathPool.Length - 1)]; + endHashIndex = startingHashIndex + 1000; - dbContext.RemoteStateTree.Set(path, account); - accounts[path] = account; - } + ProcessAccountRange(dbContext.RemoteStateTree, dbContext.LocalStateTree, blockNumber, dbContext.RemoteStateTree.RootHash, + accounts.Where(a => a.Key >= pathPool[startingHashIndex] && a.Key <= pathPool[endHashIndex]).Select(a => new PathWithAccount(a.Key, a.Value)).ToArray()); - dbContext.RemoteStateTree.Commit(0); + startingHashIndex = endHashIndex + 1; + } - int startingHashIndex = 0; - int endHashIndex; - int blockJumps = 5; - for (int blockNumber = 1; blockNumber <= blockJumps; blockNumber++) + for (int accountIndex = 0; accountIndex < 1000; accountIndex++) { - for (int i = 0; i < 19; i++) - { - endHashIndex = startingHashIndex + 1000; - - ProcessAccountRange(dbContext.RemoteStateTree, dbContext.LocalStateTree, blockNumber, dbContext.RemoteStateTree.RootHash, - accounts.Where(a => a.Key >= pathPool[startingHashIndex] && a.Key <= pathPool[endHashIndex]).Select(a => new PathWithAccount(a.Key, a.Value)).ToArray()); - - startingHashIndex = endHashIndex + 1; - } + Account account = TestItem.GenerateRandomAccount(); + Hash256 path = pathPool[TestItem.Random.Next(pathPool.Length - 1)]; - for (int accountIndex = 0; accountIndex < 1000; accountIndex++) + if (accounts.ContainsKey(path)) { - Account account = TestItem.GenerateRandomAccount(); - Hash256 path = pathPool[TestItem.Random.Next(pathPool.Length - 1)]; - - if (accounts.ContainsKey(path)) + if (TestItem.Random.NextSingle() > 0.5) { - if (TestItem.Random.NextSingle() > 0.5) - { - dbContext.RemoteStateTree.Set(path, account); - accounts[path] = account; - } - else - { - dbContext.RemoteStateTree.Set(path, null); - accounts.Remove(path); - } - - + dbContext.RemoteStateTree.Set(path, account); + accounts[path] = account; } else { - dbContext.RemoteStateTree.Set(path, account); - accounts[path] = account; + dbContext.RemoteStateTree.Set(path, null); + accounts.Remove(path); } - } - dbContext.RemoteStateTree.Commit(blockNumber); + + } + else + { + dbContext.RemoteStateTree.Set(path, account); + accounts[path] = account; + } } + dbContext.RemoteStateTree.Commit(blockNumber); + } + + endHashIndex = startingHashIndex + 1000; + while (endHashIndex < pathPool.Length - 1) + { endHashIndex = startingHashIndex + 1000; - while (endHashIndex < pathPool.Length - 1) + if (endHashIndex > pathPool.Length - 1) { - endHashIndex = startingHashIndex + 1000; - if (endHashIndex > pathPool.Length - 1) - { - endHashIndex = pathPool.Length - 1; - } + endHashIndex = pathPool.Length - 1; + } - ProcessAccountRange(dbContext.RemoteStateTree, dbContext.LocalStateTree, blockJumps, dbContext.RemoteStateTree.RootHash, - accounts.Where(a => a.Key >= pathPool[startingHashIndex] && a.Key <= pathPool[endHashIndex]).Select(a => new PathWithAccount(a.Key, a.Value)).ToArray()); + ProcessAccountRange(dbContext.RemoteStateTree, dbContext.LocalStateTree, blockJumps, dbContext.RemoteStateTree.RootHash, + accounts.Where(a => a.Key >= pathPool[startingHashIndex] && a.Key <= pathPool[endHashIndex]).Select(a => new PathWithAccount(a.Key, a.Value)).ToArray()); - startingHashIndex += 1000; - } + startingHashIndex += 1000; + } - dbContext.LocalStateTree.RootHash = dbContext.RemoteStateTree.RootHash; + dbContext.LocalStateTree.RootHash = dbContext.RemoteStateTree.RootHash; - SafeContext ctx = PrepareDownloader(dbContext); - await ActivateAndWait(ctx, dbContext, 9, timeout: 10000); + SafeContext ctx = PrepareDownloader(dbContext); + await ActivateAndWait(ctx, dbContext, 9, timeout: 10000); - DetailedProgress data = ctx.TreeFeed.GetDetailedProgress(); + DetailedProgress data = ctx.TreeFeed.GetDetailedProgress(); - dbContext.LocalStateTree.UpdateRootHash(); - dbContext.CompareTrees("END"); - _logger.Info($"REQUESTED NODES TO HEAL: {data.RequestedNodesCount}"); - Assert.IsTrue(data.RequestedNodesCount < accounts.Count / 2); - } + dbContext.LocalStateTree.UpdateRootHash(); + dbContext.CompareTrees("END"); + _logger.Info($"REQUESTED NODES TO HEAL: {data.RequestedNodesCount}"); + Assert.That(data.RequestedNodesCount, Is.LessThan(accounts.Count / 2)); + } - private static void ProcessAccountRange(StateTree remoteStateTree, StateTree localStateTree, int blockNumber, Hash256 rootHash, PathWithAccount[] accounts) - { - ValueHash256 startingHash = accounts.First().Path; - ValueHash256 endHash = accounts.Last().Path; - Hash256 limitHash = Keccak.MaxValue; - - AccountProofCollector accountProofCollector = new(startingHash.Bytes); - remoteStateTree.Accept(accountProofCollector, remoteStateTree.RootHash); - byte[][] firstProof = accountProofCollector.BuildResult().Proof!; - accountProofCollector = new(endHash.Bytes); - remoteStateTree.Accept(accountProofCollector, remoteStateTree.RootHash); - byte[][] lastProof = accountProofCollector.BuildResult().Proof!; - - _ = SnapProviderHelper.AddAccountRange(localStateTree, blockNumber, rootHash, startingHash, limitHash, accounts, firstProof.Concat(lastProof).ToArray()); - } + private static void ProcessAccountRange(StateTree remoteStateTree, StateTree localStateTree, int blockNumber, Hash256 rootHash, PathWithAccount[] accounts) + { + ValueHash256 startingHash = accounts.First().Path; + ValueHash256 endHash = accounts.Last().Path; + Hash256 limitHash = Keccak.MaxValue; + + AccountProofCollector accountProofCollector = new(startingHash.Bytes); + remoteStateTree.Accept(accountProofCollector, remoteStateTree.RootHash); + byte[][] firstProof = accountProofCollector.BuildResult().Proof!; + accountProofCollector = new(endHash.Bytes); + remoteStateTree.Accept(accountProofCollector, remoteStateTree.RootHash); + byte[][] lastProof = accountProofCollector.BuildResult().Proof!; + + _ = SnapProviderHelper.AddAccountRange(localStateTree, blockNumber, rootHash, startingHash, limitHash, accounts, firstProof.Concat(lastProof).ToArray()); } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs index ac4e5fe7099..c4dc10be746 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs @@ -21,278 +21,277 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Synchronization.Test.ParallelSync +namespace Nethermind.Synchronization.Test.ParallelSync; + +[Parallelizable(ParallelScope.All)] +public class SyncDispatcherTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class SyncDispatcherTests + private class TestSyncPeerPool : ISyncPeerPool { - private class TestSyncPeerPool : ISyncPeerPool + private readonly SemaphoreSlim _peerSemaphore; + + public TestSyncPeerPool(int peerCount = 1) { - private readonly SemaphoreSlim _peerSemaphore; + _peerSemaphore = new SemaphoreSlim(peerCount, peerCount); + } - public TestSyncPeerPool(int peerCount = 1) - { - _peerSemaphore = new SemaphoreSlim(peerCount, peerCount); - } + public void Dispose() + { + } - public void Dispose() - { - } + public async Task Allocate( + IPeerAllocationStrategy peerAllocationStrategy, + AllocationContexts contexts, + int timeoutMilliseconds = 0, + CancellationToken cancellationToken = default) + { + await _peerSemaphore.WaitAsync(); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.ClientId.Returns("Nethermind"); + syncPeer.TotalDifficulty.Returns(UInt256.One); + SyncPeerAllocation allocation = new(new PeerInfo(syncPeer), contexts); + allocation.AllocateBestPeer( + Substitute.For>(), + Substitute.For(), + Substitute.For()); + return allocation; + } - public async Task Allocate( - IPeerAllocationStrategy peerAllocationStrategy, - AllocationContexts contexts, - int timeoutMilliseconds = 0, - CancellationToken cancellationToken = default) - { - await _peerSemaphore.WaitAsync(); - ISyncPeer syncPeer = Substitute.For(); - syncPeer.ClientId.Returns("Nethermind"); - syncPeer.TotalDifficulty.Returns(UInt256.One); - SyncPeerAllocation allocation = new(new PeerInfo(syncPeer), contexts); - allocation.AllocateBestPeer( - Substitute.For>(), - Substitute.For(), - Substitute.For()); - return allocation; - } + public void Free(SyncPeerAllocation syncPeerAllocation) + { + _peerSemaphore.Release(); + } - public void Free(SyncPeerAllocation syncPeerAllocation) - { - _peerSemaphore.Release(); - } + public void ReportNoSyncProgress(PeerInfo peerInfo, AllocationContexts contexts) + { + } - public void ReportNoSyncProgress(PeerInfo peerInfo, AllocationContexts contexts) - { - } + public void ReportBreachOfProtocol(PeerInfo peerInfo, DisconnectReason disconnectReason, string details) + { + } - public void ReportBreachOfProtocol(PeerInfo peerInfo, DisconnectReason disconnectReason, string details) - { - } + public void ReportWeakPeer(PeerInfo peerInfo, AllocationContexts contexts) + { + } - public void ReportWeakPeer(PeerInfo peerInfo, AllocationContexts contexts) - { - } + public void WakeUpAll() + { + throw new NotImplementedException(); + } - public void WakeUpAll() - { - throw new NotImplementedException(); - } + public IEnumerable AllPeers { get; } = Array.Empty(); + public IEnumerable InitializedPeers { get; } = Array.Empty(); + public int PeerCount { get; } = 0; + public int InitializedPeersCount { get; } = 0; + public int PeerMaxCount { get; } = 0; - public IEnumerable AllPeers { get; } = Array.Empty(); - public IEnumerable InitializedPeers { get; } = Array.Empty(); - public int PeerCount { get; } = 0; - public int InitializedPeersCount { get; } = 0; - public int PeerMaxCount { get; } = 0; + public void AddPeer(ISyncPeer syncPeer) + { + } - public void AddPeer(ISyncPeer syncPeer) - { - } + public void RemovePeer(ISyncPeer syncPeer) + { + } - public void RemovePeer(ISyncPeer syncPeer) - { - } + public void SetPeerPriority(PublicKey id) + { + } - public void SetPeerPriority(PublicKey id) - { - } + public void RefreshTotalDifficulty(ISyncPeer syncPeer, Hash256 hash) + { + } - public void RefreshTotalDifficulty(ISyncPeer syncPeer, Hash256 hash) - { - } + public void Start() + { + } - public void Start() - { - } + public Task StopAsync() + { + return Task.CompletedTask; + } - public Task StopAsync() - { - return Task.CompletedTask; - } + public PeerInfo? GetPeer(Node node) + { + return null; + } - public PeerInfo? GetPeer(Node node) - { - return null; - } + public event EventHandler NotifyPeerBlock = delegate { }; + public event EventHandler PeerRefreshed = delegate { }; + } - public event EventHandler NotifyPeerBlock = delegate { }; - public event EventHandler PeerRefreshed = delegate { }; + private class TestBatch + { + public TestBatch(int start, int length) + { + Start = start; + Length = length; } - private class TestBatch + public int Start { get; } + public int Length { get; } + public int[]? Result { get; set; } + } + + private class TestDownloader : ISyncDownloader + { + private int _failureSwitch; + public async Task Dispatch(PeerInfo peerInfo, TestBatch request, CancellationToken cancellationToken) { - public TestBatch(int start, int length) + if (++_failureSwitch % 2 == 0) { - Start = start; - Length = length; + throw new Exception(); } - public int Start { get; } - public int Length { get; } - public int[]? Result { get; set; } - } - - private class TestDownloader : ISyncDownloader - { - private int _failureSwitch; - public async Task Dispatch(PeerInfo peerInfo, TestBatch request, CancellationToken cancellationToken) + await Task.CompletedTask; + int[] result = new int[request.Length]; + for (int i = 0; i < request.Length; i++) { - if (++_failureSwitch % 2 == 0) - { - throw new Exception(); - } - - await Task.CompletedTask; - int[] result = new int[request.Length]; - for (int i = 0; i < request.Length; i++) - { - result[i] = request.Start + i; - } - - request.Result = result; + result[i] = request.Start + i; } + + request.Result = result; } + } - private class TestSyncFeed : SyncFeed + private class TestSyncFeed : SyncFeed + { + public TestSyncFeed(bool isMultiFeed = true, int max = 64) { - public TestSyncFeed(bool isMultiFeed = true, int max = 64) - { - IsMultiFeed = isMultiFeed; - Max = max; - } + IsMultiFeed = isMultiFeed; + Max = max; + } - public int Max { get; } - public int HighestRequested { get; private set; } + public int Max { get; } + public int HighestRequested { get; private set; } - public readonly HashSet _results = new(); - private readonly ConcurrentQueue _returned = new(); - private readonly ManualResetEvent _responseLock = new ManualResetEvent(true); + public readonly HashSet _results = new(); + private readonly ConcurrentQueue _returned = new(); + private readonly ManualResetEvent _responseLock = new ManualResetEvent(true); - public void LockResponse() - { - _responseLock.Reset(); - } + public void LockResponse() + { + _responseLock.Reset(); + } - public void UnlockResponse() + public void UnlockResponse() + { + _responseLock.Set(); + } + + public override SyncResponseHandlingResult HandleResponse(TestBatch response, PeerInfo? peer = null) + { + _responseLock.WaitOne(); + if (response.Result is null) { - _responseLock.Set(); + _returned.Enqueue(response); } - - public override SyncResponseHandlingResult HandleResponse(TestBatch response, PeerInfo? peer = null) + else { - _responseLock.WaitOne(); - if (response.Result is null) - { - _returned.Enqueue(response); - } - else + for (int i = 0; i < response.Length; i++) { - for (int i = 0; i < response.Length; i++) + lock (_results) { - lock (_results) - { - _results.Add(response.Result[i]); - } + _results.Add(response.Result[i]); } } - - Interlocked.Decrement(ref _pendingRequests); - return SyncResponseHandlingResult.OK; } - public override bool IsMultiFeed { get; } - public override AllocationContexts Contexts => AllocationContexts.All; - public override void SyncModeSelectorOnChanged(SyncMode current) - { - } + Interlocked.Decrement(ref _pendingRequests); + return SyncResponseHandlingResult.OK; + } + + public override bool IsMultiFeed { get; } + public override AllocationContexts Contexts => AllocationContexts.All; + public override void SyncModeSelectorOnChanged(SyncMode current) + { + } - public override bool IsFinished => false; + public override bool IsFinished => false; - private int _pendingRequests; + private int _pendingRequests; - public override async Task PrepareRequest(CancellationToken token = default) + public override async Task PrepareRequest(CancellationToken token = default) + { + TestBatch testBatch; + if (_returned.TryDequeue(out TestBatch? returned)) { - TestBatch testBatch; - if (_returned.TryDequeue(out TestBatch? returned)) - { - testBatch = returned; - } - else - { - await Task.CompletedTask; + testBatch = returned; + } + else + { + await Task.CompletedTask; - int start; + int start; - if (HighestRequested >= Max) + if (HighestRequested >= Max) + { + if (_pendingRequests == 0) { - if (_pendingRequests == 0) - { - Finish(); - } - - return null!; + Finish(); } - lock (_results) - { - start = HighestRequested; - HighestRequested += 8; - } + return null!; + } - testBatch = new TestBatch(start, 8); + lock (_results) + { + start = HighestRequested; + HighestRequested += 8; } - Interlocked.Increment(ref _pendingRequests); - return testBatch; + testBatch = new TestBatch(start, 8); } - } - [Test, Timeout(10000)] - public async Task Simple_test_sync() - { - TestSyncFeed syncFeed = new(); - TestDownloader downloader = new TestDownloader(); - SyncDispatcher dispatcher = new( - 0, - syncFeed, - downloader, - new TestSyncPeerPool(), - new StaticPeerAllocationStrategyFactory(FirstFree.Instance), - LimboLogs.Instance); - Task executorTask = dispatcher.Start(CancellationToken.None); - syncFeed.Activate(); - await executorTask; - for (int i = 0; i < syncFeed.Max; i++) - { - syncFeed._results.Contains(i).Should().BeTrue(i.ToString()); - } + Interlocked.Increment(ref _pendingRequests); + return testBatch; } + } - [Retry(tryCount: 5)] - [TestCase(false, 1, 1, 8)] - [TestCase(true, 1, 1, 24)] - [TestCase(true, 2, 1, 32)] - [TestCase(true, 1, 2, 32)] - public async Task Test_release_before_processing_complete(bool isMultiSync, int processingThread, int peerCount, int expectedHighestRequest) + [Test, MaxTime(10000)] + public async Task Simple_test_sync() + { + TestSyncFeed syncFeed = new(); + TestDownloader downloader = new TestDownloader(); + SyncDispatcher dispatcher = new( + 0, + syncFeed, + downloader, + new TestSyncPeerPool(), + new StaticPeerAllocationStrategyFactory(FirstFree.Instance), + LimboLogs.Instance); + Task executorTask = dispatcher.Start(CancellationToken.None); + syncFeed.Activate(); + await executorTask; + for (int i = 0; i < syncFeed.Max; i++) { - TestSyncFeed syncFeed = new(isMultiSync, 999999); - syncFeed.LockResponse(); - - TestDownloader downloader = new TestDownloader(); - SyncDispatcher dispatcher = new( - processingThread, - syncFeed, - downloader, - new TestSyncPeerPool(peerCount), - new StaticPeerAllocationStrategyFactory(FirstFree.Instance), - LimboLogs.Instance); - - Task _ = dispatcher.Start(CancellationToken.None); - syncFeed.Activate(); - await Task.Delay(100); - - Assert.That(() => syncFeed.HighestRequested, Is.EqualTo(expectedHighestRequest).After(4000, 100)); - syncFeed.UnlockResponse(); + syncFeed._results.Contains(i).Should().BeTrue(i.ToString()); } } + + [Retry(tryCount: 5)] + [TestCase(false, 1, 1, 8)] + [TestCase(true, 1, 1, 24)] + [TestCase(true, 2, 1, 32)] + [TestCase(true, 1, 2, 32)] + public async Task Test_release_before_processing_complete(bool isMultiSync, int processingThread, int peerCount, int expectedHighestRequest) + { + TestSyncFeed syncFeed = new(isMultiSync, 999999); + syncFeed.LockResponse(); + + TestDownloader downloader = new TestDownloader(); + SyncDispatcher dispatcher = new( + processingThread, + syncFeed, + downloader, + new TestSyncPeerPool(peerCount), + new StaticPeerAllocationStrategyFactory(FirstFree.Instance), + LimboLogs.Instance); + + Task _ = dispatcher.Start(CancellationToken.None); + syncFeed.Activate(); + await Task.Delay(100); + + Assert.That(() => syncFeed.HighestRequested, Is.EqualTo(expectedHighestRequest).After(4000, 100)); + syncFeed.UnlockResponse(); + } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs index db122629336..cdb1aad7a51 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs @@ -21,444 +21,442 @@ using Nethermind.Trie.Pruning; using NUnit.Framework; -namespace Nethermind.Synchronization.Test.SnapSync +namespace Nethermind.Synchronization.Test.SnapSync; + +public class RecreateStateFromAccountRangesTests { - [TestFixture] - public class RecreateStateFromAccountRangesTests + private StateTree _inputTree; + + [OneTimeSetUp] + public void Setup() { - private StateTree _inputTree; + _inputTree = TestItem.Tree.GetStateTree(); + } - [OneTimeSetUp] - public void Setup() + private byte[][] CreateProofForPath(ReadOnlySpan path, StateTree tree = null) + { + AccountProofCollector accountProofCollector = new(path); + if (tree is null) { - _inputTree = TestItem.Tree.GetStateTree(); + tree = _inputTree; } + tree.Accept(accountProofCollector, tree.RootHash); + return accountProofCollector.BuildResult().Proof; + } - private byte[][] CreateProofForPath(ReadOnlySpan path, StateTree tree = null) - { - AccountProofCollector accountProofCollector = new(path); - if (tree is null) - { - tree = _inputTree; - } - tree.Accept(accountProofCollector, tree.RootHash); - return accountProofCollector.BuildResult().Proof; - } + //[Test] + public void Test01() + { + Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - //[Test] - public void Test01() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" + byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[0].Path.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[0].Path.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + MemDb db = new(); + TrieStore fullStore = new(db, LimboLogs.Instance); + IScopedTrieStore store = fullStore.GetTrieStore(null); + StateTree tree = new(store, LimboLogs.Instance); - MemDb db = new(); - TrieStore fullStore = new(db, LimboLogs.Instance); - IScopedTrieStore store = fullStore.GetTrieStore(null); - StateTree tree = new(store, LimboLogs.Instance); + IList nodes = new List(); + TreePath emptyPath = TreePath.Empty; - IList nodes = new List(); - TreePath emptyPath = TreePath.Empty; + for (int i = 0; i < (firstProof!).Length; i++) + { + byte[] nodeBytes = (firstProof!)[i]; + var node = new TrieNode(NodeType.Unknown, nodeBytes); + node.ResolveKey(store, ref emptyPath, i == 0); - for (int i = 0; i < (firstProof!).Length; i++) + nodes.Add(node); + if (i < (firstProof!).Length - 1) { - byte[] nodeBytes = (firstProof!)[i]; - var node = new TrieNode(NodeType.Unknown, nodeBytes); - 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); - } + //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); + node.ResolveKey(store, ref emptyPath, i == 0); - for (int i = 0; i < (lastProof!).Length; i++) + nodes.Add(node); + if (i < (lastProof!).Length - 1) { - byte[] nodeBytes = (lastProof!)[i]; - var node = new TrieNode(NodeType.Unknown, nodeBytes); - 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); - } + //IBatch batch = store.GetOrStartNewBatch(); + //batch[node.Keccak!.Bytes] = nodeBytes; + //db.Set(node.Keccak!, nodeBytes); } + } - tree.RootRef = nodes[0]; + 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.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(0); + tree.Commit(0); - 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.IsFalse(db.KeyExists(rootHash)); // the root node is a part of the proof nodes - } + 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" + [Test] + public void RecreateAccountStateFromOneRangeWithNonExistenceProof() + { + Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - 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()); + 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.IsFalse(db.KeyExists(rootHash)); - } + 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" + [Test] + public void RecreateAccountStateFromOneRangeWithExistenceProof() + { + Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" - byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[0].Path.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[0].Path.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - 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, firstProof!.Concat(lastProof!).ToArray()); + 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, 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.IsFalse(db.KeyExists(rootHash)); - } + 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.IsFalse(db.KeyExists(rootHash)); // the root node is NOT a part of the proof nodes - } + [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" + [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); + // 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); - byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); + byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); - var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], firstProof!.Concat(lastProof!).ToArray()); + 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)); + Assert.That(db.Keys.Count, Is.EqualTo(2)); - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2..4], firstProof!.Concat(lastProof!).ToArray()); + 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) + Assert.That(db.Keys.Count, Is.EqualTo(5)); // we don't persist proof nodes (boundary nodes) - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); + 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.IsFalse(db.KeyExists(rootHash)); - } + 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 RecreateAccountStateFromMultipleRange_InReverseOrder() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" + [Test] + public void RecreateAccountStateFromMultipleRange_InReverseOrder() + { + 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); + // 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); - byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); + byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); - Assert.That(db.Keys.Count, Is.EqualTo(4)); + Assert.That(db.Keys.Count, Is.EqualTo(4)); - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2..4], firstProof!.Concat(lastProof!).ToArray()); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); + 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(6)); // we don't persist proof nodes (boundary nodes) + Assert.That(db.Keys.Count, Is.EqualTo(6)); // we don't persist proof nodes (boundary nodes) - firstProof = CreateProofForPath(Keccak.Zero.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); - var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], firstProof!.Concat(lastProof!).ToArray()); + firstProof = CreateProofForPath(Keccak.Zero.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); + var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], 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.IsFalse(db.KeyExists(rootHash)); - } + 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 RecreateAccountStateFromMultipleRange_OutOfOrder() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" + [Test] + public void RecreateAccountStateFromMultipleRange_OutOfOrder() + { + 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); + // 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); - byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); + byte[][] firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); - Assert.That(db.Keys.Count, Is.EqualTo(4)); + Assert.That(db.Keys.Count, Is.EqualTo(4)); - firstProof = CreateProofForPath(Keccak.Zero.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); - var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], firstProof!.Concat(lastProof!).ToArray()); + firstProof = CreateProofForPath(Keccak.Zero.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); + var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], firstProof!.Concat(lastProof!).ToArray()); - Assert.That(db.Keys.Count, Is.EqualTo(6)); // we don't persist proof nodes (boundary nodes) + Assert.That(db.Keys.Count, Is.EqualTo(6)); // we don't persist proof nodes (boundary nodes) - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2..4], firstProof!.Concat(lastProof!).ToArray()); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); + var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2..4], 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.IsFalse(db.KeyExists(rootHash)); - } + 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 RecreateAccountStateFromMultipleOverlappingRange() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" + [Test] + public void RecreateAccountStateFromMultipleOverlappingRange() + { + 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); + // 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); - byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); + byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..3], firstProof!.Concat(lastProof!).ToArray()); + var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..3], firstProof!.Concat(lastProof!).ToArray()); - Assert.That(db.Keys.Count, Is.EqualTo(3)); + Assert.That(db.Keys.Count, Is.EqualTo(3)); - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2..4], firstProof!.Concat(lastProof!).ToArray()); + var result2 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[2].Path, TestItem.Tree.AccountsWithPaths[2..4], firstProof!.Concat(lastProof!).ToArray()); - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[3].Path, TestItem.Tree.AccountsWithPaths[3..5], firstProof!.Concat(lastProof!).ToArray()); + var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[3].Path, TestItem.Tree.AccountsWithPaths[3..5], firstProof!.Concat(lastProof!).ToArray()); - Assert.That(db.Keys.Count, Is.EqualTo(6)); // we don't persist proof nodes (boundary nodes) + Assert.That(db.Keys.Count, Is.EqualTo(6)); // we don't persist proof nodes (boundary nodes) - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - var result4 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); + var result4 = 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(result4, Is.EqualTo(AddRangeResult.OK)); - Assert.That(db.Keys.Count, Is.EqualTo(10)); // we persist proof nodes (boundary nodes) via stitching - Assert.IsFalse(db.KeyExists(rootHash)); - } + Assert.That(result1, Is.EqualTo(AddRangeResult.OK)); + Assert.That(result2, Is.EqualTo(AddRangeResult.OK)); + Assert.That(result3, Is.EqualTo(AddRangeResult.OK)); + Assert.That(result4, 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 CorrectlyDetermineHasMoreChildren() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" + [Test] + public void CorrectlyDetermineHasMoreChildren() + { + 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); + // 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); - byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); - byte[][] proofs = firstProof.Concat(lastProof).ToArray(); + byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); + byte[][] proofs = firstProof.Concat(lastProof).ToArray(); - StateTree newTree = new(new TrieStore(new MemDb(), LimboLogs.Instance), LimboLogs.Instance); + StateTree newTree = new(new TrieStore(new MemDb(), LimboLogs.Instance), LimboLogs.Instance); - PathWithAccount[] receiptAccounts = TestItem.Tree.AccountsWithPaths[0..2]; + PathWithAccount[] receiptAccounts = TestItem.Tree.AccountsWithPaths[0..2]; - bool HasMoreChildren(ValueHash256 limitHash) - { - (AddRangeResult _, bool moreChildrenToRight, IList _, IList _) = - SnapProviderHelper.AddAccountRange(newTree, 0, rootHash, Keccak.Zero, limitHash.ToCommitment(), receiptAccounts, proofs); - return moreChildrenToRight; - } + bool HasMoreChildren(ValueHash256 limitHash) + { + (AddRangeResult _, bool moreChildrenToRight, IList _, IList _) = + SnapProviderHelper.AddAccountRange(newTree, 0, rootHash, Keccak.Zero, limitHash.ToCommitment(), receiptAccounts, proofs); + return moreChildrenToRight; + } - HasMoreChildren(TestItem.Tree.AccountsWithPaths[1].Path).Should().BeFalse(); - HasMoreChildren(TestItem.Tree.AccountsWithPaths[2].Path).Should().BeFalse(); - HasMoreChildren(TestItem.Tree.AccountsWithPaths[3].Path).Should().BeTrue(); - HasMoreChildren(TestItem.Tree.AccountsWithPaths[4].Path).Should().BeTrue(); + HasMoreChildren(TestItem.Tree.AccountsWithPaths[1].Path).Should().BeFalse(); + HasMoreChildren(TestItem.Tree.AccountsWithPaths[2].Path).Should().BeFalse(); + HasMoreChildren(TestItem.Tree.AccountsWithPaths[3].Path).Should().BeTrue(); + HasMoreChildren(TestItem.Tree.AccountsWithPaths[4].Path).Should().BeTrue(); - UInt256 between2and3 = new UInt256(TestItem.Tree.AccountsWithPaths[1].Path.Bytes, true); - between2and3 += 5; + UInt256 between2and3 = new UInt256(TestItem.Tree.AccountsWithPaths[1].Path.Bytes, true); + between2and3 += 5; - HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); + HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); - between2and3 = new UInt256(TestItem.Tree.AccountsWithPaths[2].Path.Bytes, true); - between2and3 -= 1; + between2and3 = new UInt256(TestItem.Tree.AccountsWithPaths[2].Path.Bytes, true); + between2and3 -= 1; - HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); - } + HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); + } - [Test] - public void CorrectlyDetermineMaxKeccakExist() - { - StateTree tree = new StateTree(new TrieStore(new MemDb(), LimboLogs.Instance), LimboLogs.Instance); + [Test] + public void CorrectlyDetermineMaxKeccakExist() + { + StateTree tree = new StateTree(new TrieStore(new MemDb(), LimboLogs.Instance), LimboLogs.Instance); - PathWithAccount ac1 = new PathWithAccount(Keccak.Zero, Build.An.Account.WithBalance(1).TestObject); - PathWithAccount ac2 = new PathWithAccount(Keccak.Compute("anything"), Build.An.Account.WithBalance(2).TestObject); - PathWithAccount ac3 = new PathWithAccount(Keccak.MaxValue, Build.An.Account.WithBalance(2).TestObject); + PathWithAccount ac1 = new PathWithAccount(Keccak.Zero, Build.An.Account.WithBalance(1).TestObject); + PathWithAccount ac2 = new PathWithAccount(Keccak.Compute("anything"), Build.An.Account.WithBalance(2).TestObject); + PathWithAccount ac3 = new PathWithAccount(Keccak.MaxValue, Build.An.Account.WithBalance(2).TestObject); - tree.Set(ac1.Path, ac1.Account); - tree.Set(ac2.Path, ac2.Account); - tree.Set(ac3.Path, ac3.Account); - tree.Commit(0); + tree.Set(ac1.Path, ac1.Account); + tree.Set(ac2.Path, ac2.Account); + tree.Set(ac3.Path, ac3.Account); + tree.Commit(0); - Hash256 rootHash = tree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" + Hash256 rootHash = tree.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); + // 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); - byte[][] firstProof = CreateProofForPath(ac1.Path.Bytes, tree); - byte[][] lastProof = CreateProofForPath(ac2.Path.Bytes, tree); - byte[][] proofs = firstProof.Concat(lastProof).ToArray(); + byte[][] firstProof = CreateProofForPath(ac1.Path.Bytes, tree); + byte[][] lastProof = CreateProofForPath(ac2.Path.Bytes, tree); + byte[][] proofs = firstProof.Concat(lastProof).ToArray(); - StateTree newTree = new(new TrieStore(new MemDb(), LimboLogs.Instance), LimboLogs.Instance); + StateTree newTree = new(new TrieStore(new MemDb(), LimboLogs.Instance), LimboLogs.Instance); - PathWithAccount[] receiptAccounts = { ac1, ac2 }; + PathWithAccount[] receiptAccounts = { ac1, ac2 }; - bool HasMoreChildren(ValueHash256 limitHash) - { - (AddRangeResult _, bool moreChildrenToRight, IList _, IList _) = - SnapProviderHelper.AddAccountRange(newTree, 0, rootHash, Keccak.Zero, limitHash.ToCommitment(), receiptAccounts, proofs); - return moreChildrenToRight; - } + bool HasMoreChildren(ValueHash256 limitHash) + { + (AddRangeResult _, bool moreChildrenToRight, IList _, IList _) = + SnapProviderHelper.AddAccountRange(newTree, 0, rootHash, Keccak.Zero, limitHash.ToCommitment(), receiptAccounts, proofs); + return moreChildrenToRight; + } - HasMoreChildren(ac1.Path).Should().BeFalse(); - HasMoreChildren(ac2.Path).Should().BeFalse(); + HasMoreChildren(ac1.Path).Should().BeFalse(); + HasMoreChildren(ac2.Path).Should().BeFalse(); - UInt256 between2and3 = new UInt256(ac2.Path.Bytes, true); - between2and3 += 5; + UInt256 between2and3 = new UInt256(ac2.Path.Bytes, true); + between2and3 += 5; - HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); + HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); - // The special case - HasMoreChildren(Keccak.MaxValue).Should().BeTrue(); - } + // The special case + HasMoreChildren(Keccak.MaxValue).Should().BeTrue(); + } - [Test] - public void MissingAccountFromRange() - { - Hash256 rootHash = _inputTree.RootHash; // "0x8c81279168edc449089449bc0f2136fc72c9645642845755633cf259cd97988b" + [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); + // 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); - byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); - byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); + byte[][] firstProof = CreateProofForPath(Keccak.Zero.Bytes); + byte[][] lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[1].Path.Bytes); - var result1 = snapProvider.AddAccountRange(1, rootHash, Keccak.Zero, TestItem.Tree.AccountsWithPaths[0..2], firstProof!.Concat(lastProof!).ToArray()); + 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)); + Assert.That(db.Keys.Count, Is.EqualTo(2)); - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[2].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[3].Path.Bytes); - // 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()); + // 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)); + Assert.That(db.Keys.Count, Is.EqualTo(2)); - firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); - lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); + firstProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[4].Path.Bytes); + lastProof = CreateProofForPath(TestItem.Tree.AccountsWithPaths[5].Path.Bytes); - var result3 = snapProvider.AddAccountRange(1, rootHash, TestItem.Tree.AccountsWithPaths[4].Path, TestItem.Tree.AccountsWithPaths[4..6], firstProof!.Concat(lastProof!).ToArray()); + 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.IsFalse(db.KeyExists(rootHash)); - } + 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); + } - private SnapProvider CreateSnapProvider(ProgressTracker progressTracker, IDbProvider dbProvider) + private SnapProvider CreateSnapProvider(ProgressTracker progressTracker, IDbProvider dbProvider) + { + try { - try - { - IDb _ = dbProvider.CodeDb; - } - catch (ArgumentException) - { - dbProvider.RegisterDb(DbNames.Code, new MemDb()); - } - return new(progressTracker, dbProvider.CodeDb, new NodeStorage(dbProvider.StateDb), LimboLogs.Instance); + 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/SyncBatchSizeTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncBatchSizeTests.cs index cbbac2e96fe..52fd198264a 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncBatchSizeTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncBatchSizeTests.cs @@ -6,47 +6,46 @@ using Nethermind.Synchronization.Blocks; using NUnit.Framework; -namespace Nethermind.Synchronization.Test +namespace Nethermind.Synchronization.Test; + +[Parallelizable(ParallelScope.All)] +public class SyncBatchSizeTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class SyncBatchSizeTests + [Test] + public void Can_shrink_and_expand() + { + SyncBatchSize syncBatchSize = new(LimboLogs.Instance); + int beforeShrink = syncBatchSize.Current; + syncBatchSize.Shrink(); + Assert.That(syncBatchSize.Current, Is.EqualTo(Math.Floor(beforeShrink / SyncBatchSize.AdjustmentFactor))); + int beforeExpand = syncBatchSize.Current; + syncBatchSize.Expand(); + Assert.That(syncBatchSize.Current, Is.EqualTo(Math.Ceiling(beforeExpand * SyncBatchSize.AdjustmentFactor))); + } + + [Test] + public void Cannot_go_below_min() { - [Test] - public void Can_shrink_and_expand() + SyncBatchSize syncBatchSize = new(LimboLogs.Instance); + for (int i = 0; i < 100; i++) { - SyncBatchSize syncBatchSize = new(LimboLogs.Instance); - int beforeShrink = syncBatchSize.Current; syncBatchSize.Shrink(); - Assert.That(syncBatchSize.Current, Is.EqualTo(Math.Floor(beforeShrink / SyncBatchSize.AdjustmentFactor))); - int beforeExpand = syncBatchSize.Current; - syncBatchSize.Expand(); - Assert.That(syncBatchSize.Current, Is.EqualTo(Math.Ceiling(beforeExpand * SyncBatchSize.AdjustmentFactor))); } - [Test] - public void Cannot_go_below_min() - { - SyncBatchSize syncBatchSize = new(LimboLogs.Instance); - for (int i = 0; i < 100; i++) - { - syncBatchSize.Shrink(); - } - - Assert.That(syncBatchSize.Current, Is.EqualTo(SyncBatchSize.Min), "current is min"); - Assert.True(syncBatchSize.IsMin, "is min"); - } + Assert.That(syncBatchSize.Current, Is.EqualTo(SyncBatchSize.Min), "current is min"); + Assert.That(syncBatchSize.IsMin, Is.True, "is min"); + } - [Test] - public void Cannot_go_above_max() + [Test] + public void Cannot_go_above_max() + { + SyncBatchSize syncBatchSize = new(LimboLogs.Instance); + for (int i = 0; i < 100; i++) { - SyncBatchSize syncBatchSize = new(LimboLogs.Instance); - for (int i = 0; i < 100; i++) - { - syncBatchSize.Expand(); - } - - Assert.That(syncBatchSize.Current, Is.EqualTo(SyncBatchSize.Max), "current is max"); - Assert.True(syncBatchSize.IsMax, "is max"); + syncBatchSize.Expand(); } + + Assert.That(syncBatchSize.Current, Is.EqualTo(SyncBatchSize.Max), "current is max"); + Assert.That(syncBatchSize.IsMax, Is.True, "is max"); } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs index 943f2786062..147846e2ddf 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs @@ -23,821 +23,820 @@ using NSubstitute; using NUnit.Framework; -namespace Nethermind.Synchronization.Test +namespace Nethermind.Synchronization.Test; + +[Parallelizable(ParallelScope.All)] +public class SyncPeerPoolTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class SyncPeerPoolTests + private class Context : IAsyncDisposable { - private class Context : IAsyncDisposable - { - public INodeStatsManager Stats { get; } - public IBlockTree BlockTree { get; } - public IBetterPeerStrategy PeerStrategy { get; } - public SyncPeerPool Pool { get; set; } + public INodeStatsManager Stats { get; } + public IBlockTree BlockTree { get; } + public IBetterPeerStrategy PeerStrategy { get; } + public SyncPeerPool Pool { get; set; } - public Context() - { - BlockTree = Substitute.For(); - Stats = Substitute.For(); - PeerStrategy = new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance); - Pool = new SyncPeerPool(BlockTree, Stats, PeerStrategy, LimboLogs.Instance, 25, 50); - } + public Context() + { + BlockTree = Substitute.For(); + Stats = Substitute.For(); + PeerStrategy = new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance); + Pool = new SyncPeerPool(BlockTree, Stats, PeerStrategy, LimboLogs.Instance, 25, 50); + } - public async ValueTask DisposeAsync() - { - await Pool.StopAsync(); - } + public async ValueTask DisposeAsync() + { + await Pool.StopAsync(); } + } - private class SimpleSyncPeerMock : ISyncPeer + private class SimpleSyncPeerMock : ISyncPeer + { + public string Name => "SimpleMock"; + public SimpleSyncPeerMock(PublicKey publicKey, string description = "simple mock") { - public string Name => "SimpleMock"; - public SimpleSyncPeerMock(PublicKey publicKey, string description = "simple mock") - { - Node = new Node(publicKey, "127.0.0.1", 30303); - ClientId = description; - } + Node = new Node(publicKey, "127.0.0.1", 30303); + ClientId = description; + } - public Hash256 HeadHash { get; set; } = null!; - public byte ProtocolVersion { get; } = default; - public string ProtocolCode { get; } = null!; - public Node Node { get; } - public string ClientId { get; } - public long HeadNumber { get; set; } - public UInt256 TotalDifficulty { get; set; } = 1; - public bool IsInitialized { get; set; } - public bool IsPriority { get; set; } + public Hash256 HeadHash { get; set; } = null!; + public byte ProtocolVersion { get; } = default; + public string ProtocolCode { get; } = null!; + public Node Node { get; } + public string ClientId { get; } + public long HeadNumber { get; set; } + public UInt256 TotalDifficulty { get; set; } = 1; + public bool IsInitialized { get; set; } + public bool IsPriority { get; set; } - public bool DisconnectRequested { get; private set; } + public bool DisconnectRequested { get; private set; } - public void Disconnect(DisconnectReason reason, string details) - { - DisconnectRequested = true; - } + public void Disconnect(DisconnectReason reason, string details) + { + DisconnectRequested = true; + } - public Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) - { - return Task.FromResult(new OwnedBlockBodies(Array.Empty())); - } + public Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) + { + return Task.FromResult(new OwnedBlockBodies(Array.Empty())); + } - public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) - { - return Task.FromResult?>(ArrayPoolList.Empty()); - } + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + { + return Task.FromResult?>(ArrayPoolList.Empty()); + } - public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) - { - return Task.FromResult?>(ArrayPoolList.Empty()); - } + public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + { + return Task.FromResult?>(ArrayPoolList.Empty()); + } - public async Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) + public async Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) + { + if (_shouldFail) { - if (_shouldFail) - { - throw new Exception("Failed"); - } - - if (_shouldTimeout) - { - throw new TimeoutException("Timed out"); - } - - if (_headerResponseTime.HasValue) - { - await Task.Delay(_headerResponseTime.Value); - } - - IsInitialized = true; - return await Task.FromResult(Build.A.BlockHeader.TestObject); + throw new Exception("Failed"); } - public void NotifyOfNewBlock(Block block, SendBlockMode mode) + if (_shouldTimeout) { + throw new TimeoutException("Timed out"); } - public PublicKey Id => Node.Id; - - public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { } - - public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) + if (_headerResponseTime.HasValue) { - return Task.FromResult>(ArrayPoolList.Empty()); + await Task.Delay(_headerResponseTime.Value); } - public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) - { - return Task.FromResult>(ArrayPoolList.Empty()); - } + IsInitialized = true; + return await Task.FromResult(Build.A.BlockHeader.TestObject); + } - private int? _headerResponseTime; + public void NotifyOfNewBlock(Block block, SendBlockMode mode) + { + } - private bool _shouldFail; + public PublicKey Id => Node.Id; - private bool _shouldTimeout; + public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { } - public void SetHeaderResponseTime(int responseTime) - { - if (responseTime > 5000) - { - _shouldTimeout = true; - } + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) + { + return Task.FromResult>(ArrayPoolList.Empty()); + } - _headerResponseTime = responseTime; - } + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) + { + return Task.FromResult>(ArrayPoolList.Empty()); + } - public void SetHeaderFailure(bool shouldFail) - { - _shouldFail = shouldFail; - } + private int? _headerResponseTime; - public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class - { - throw new NotImplementedException(); - } + private bool _shouldFail; - public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class - { - throw new NotImplementedException(); - } - } + private bool _shouldTimeout; - [Test] - public async Task Cannot_add_when_not_started() + public void SetHeaderResponseTime(int responseTime) { - await using Context ctx = new(); - for (int i = 0; i < 3; i++) + if (responseTime > 5000) { - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeys[i])); + _shouldTimeout = true; } - } - [Test] - public async Task Will_disconnect_one_when_at_max() - { - await using Context ctx = new(); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 25); - await WaitForPeersInitialization(ctx); - ctx.Pool.DropUselessPeers(true); - Assert.True(peers.Any(p => p.DisconnectRequested)); + _headerResponseTime = responseTime; } - [TestCase(true, false)] - [TestCase(false, true)] - public async Task Will_disconnect_when_refresh_exception_is_not_cancelled(bool isExceptionOperationCanceled, bool isDisconnectRequested) + public void SetHeaderFailure(bool shouldFail) { - await using Context ctx = new(); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 25); - SimpleSyncPeerMock peer = peers[0]; - - Exception refreshException = isExceptionOperationCanceled ? new OperationCanceledException() : new Exception(); - ctx.Pool.ReportRefreshFailed(peer, "test with cancellation", refreshException); - peer.DisconnectRequested.Should().Be(isDisconnectRequested); + _shouldFail = shouldFail; } - [TestCase(0)] - [TestCase(10)] - [TestCase(24)] - public async Task Will_not_disconnect_any_priority_peer_if_their_amount_is_lower_than_max(byte number) + public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class { - const int peersMaxCount = 25; - const int priorityPeersMaxCount = 25; - await using Context ctx = new(); - ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, peersMaxCount); - - // setting priority to all peers except one - peers[number] - for (int i = 0; i < priorityPeersMaxCount; i++) - { - if (i != number) - { - ctx.Pool.SetPeerPriority(peers[i].Id); - } - } - await WaitForPeersInitialization(ctx); - ctx.Pool.DropUselessPeers(true); - Assert.True(peers[number].DisconnectRequested); + throw new NotImplementedException(); } - [Test] - public async Task Can_disconnect_priority_peer_if_their_amount_is_max() + public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class { - const int peersMaxCount = 25; - const int priorityPeersMaxCount = 25; - await using Context ctx = new(); - ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, peersMaxCount); - - foreach (SimpleSyncPeerMock peer in peers) - { - ctx.Pool.SetPeerPriority(peer.Id); - } - await WaitForPeersInitialization(ctx); - ctx.Pool.DropUselessPeers(true); - Assert.True(peers.Any(p => p.DisconnectRequested)); + throw new NotImplementedException(); } + } - [Test] - public async Task Should_increment_PriorityPeerCount_when_added_priority_peer_and_decrement_after_removal() + [Test] + public async Task Cannot_add_when_not_started() + { + await using Context ctx = new(); + for (int i = 0; i < 3; i++) { - const int peersMaxCount = 1; - const int priorityPeersMaxCount = 1; - await using Context ctx = new(); - ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); - - SimpleSyncPeerMock peer = new(TestItem.PublicKeyA) { IsPriority = true }; - ctx.Pool.Start(); - ctx.Pool.AddPeer(peer); - await WaitForPeersInitialization(ctx); - ctx.Pool.PriorityPeerCount.Should().Be(1); - - ctx.Pool.RemovePeer(peer); - ctx.Pool.PriorityPeerCount.Should().Be(0); + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeys[i])); } + } - [Test] - public async Task Should_increment_PriorityPeerCount_when_called_SetPriorityPeer() - { - const int peersMaxCount = 1; - const int priorityPeersMaxCount = 1; - await using Context ctx = new(); - ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); + [Test] + public async Task Will_disconnect_one_when_at_max() + { + await using Context ctx = new(); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 25); + await WaitForPeersInitialization(ctx); + ctx.Pool.DropUselessPeers(true); + Assert.That(peers.Any(p => p.DisconnectRequested), Is.True); + } - SimpleSyncPeerMock peer = new(TestItem.PublicKeyA) { IsPriority = false }; - ctx.Pool.Start(); - ctx.Pool.AddPeer(peer); - await WaitForPeersInitialization(ctx); - ctx.Pool.PriorityPeerCount.Should().Be(0); + [TestCase(true, false)] + [TestCase(false, true)] + public async Task Will_disconnect_when_refresh_exception_is_not_cancelled(bool isExceptionOperationCanceled, bool isDisconnectRequested) + { + await using Context ctx = new(); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 25); + SimpleSyncPeerMock peer = peers[0]; - ctx.Pool.SetPeerPriority(peer.Id); - ctx.Pool.PriorityPeerCount.Should().Be(1); - } + Exception refreshException = isExceptionOperationCanceled ? new OperationCanceledException() : new Exception(); + ctx.Pool.ReportRefreshFailed(peer, "test with cancellation", refreshException); + peer.DisconnectRequested.Should().Be(isDisconnectRequested); + } + + [TestCase(0)] + [TestCase(10)] + [TestCase(24)] + public async Task Will_not_disconnect_any_priority_peer_if_their_amount_is_lower_than_max(byte number) + { + const int peersMaxCount = 25; + const int priorityPeersMaxCount = 25; + await using Context ctx = new(); + ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, peersMaxCount); - [Test] - public async Task Cannot_remove_when_stopped() + // setting priority to all peers except one - peers[number] + for (int i = 0; i < priorityPeersMaxCount; i++) { - await using Context ctx = new(); - ctx.Pool.Start(); - ISyncPeer[] syncPeers = new ISyncPeer[3]; - for (int i = 0; i < 3; i++) + if (i != number) { - syncPeers[i] = new SimpleSyncPeerMock(TestItem.PublicKeys[i]); - ctx.Pool.AddPeer(syncPeers[i]); + ctx.Pool.SetPeerPriority(peers[i].Id); } + } + await WaitForPeersInitialization(ctx); + ctx.Pool.DropUselessPeers(true); + Assert.That(peers[number].DisconnectRequested, Is.True); + } - await ctx.Pool.StopAsync(); + [Test] + public async Task Can_disconnect_priority_peer_if_their_amount_is_max() + { + const int peersMaxCount = 25; + const int priorityPeersMaxCount = 25; + await using Context ctx = new(); + ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, peersMaxCount); - for (int i = 3; i > 0; i--) - { - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(3), $"Remove {i}"); - ctx.Pool.RemovePeer(syncPeers[i - 1]); - } + foreach (SimpleSyncPeerMock peer in peers) + { + ctx.Pool.SetPeerPriority(peer.Id); } + await WaitForPeersInitialization(ctx); + ctx.Pool.DropUselessPeers(true); + Assert.That(peers.Any(p => p.DisconnectRequested), Is.True); + } - [Test] - public async Task Peer_count_is_valid_when_adding() + [Test] + public async Task Should_increment_PriorityPeerCount_when_added_priority_peer_and_decrement_after_removal() + { + const int peersMaxCount = 1; + const int priorityPeersMaxCount = 1; + await using Context ctx = new(); + ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); + + SimpleSyncPeerMock peer = new(TestItem.PublicKeyA) { IsPriority = true }; + ctx.Pool.Start(); + ctx.Pool.AddPeer(peer); + await WaitForPeersInitialization(ctx); + ctx.Pool.PriorityPeerCount.Should().Be(1); + + ctx.Pool.RemovePeer(peer); + ctx.Pool.PriorityPeerCount.Should().Be(0); + } + + [Test] + public async Task Should_increment_PriorityPeerCount_when_called_SetPriorityPeer() + { + const int peersMaxCount = 1; + const int priorityPeersMaxCount = 1; + await using Context ctx = new(); + ctx.Pool = new SyncPeerPool(ctx.BlockTree, ctx.Stats, ctx.PeerStrategy, LimboLogs.Instance, peersMaxCount, priorityPeersMaxCount, 50); + + SimpleSyncPeerMock peer = new(TestItem.PublicKeyA) { IsPriority = false }; + ctx.Pool.Start(); + ctx.Pool.AddPeer(peer); + await WaitForPeersInitialization(ctx); + ctx.Pool.PriorityPeerCount.Should().Be(0); + + ctx.Pool.SetPeerPriority(peer.Id); + ctx.Pool.PriorityPeerCount.Should().Be(1); + } + + [Test] + public async Task Cannot_remove_when_stopped() + { + await using Context ctx = new(); + ctx.Pool.Start(); + ISyncPeer[] syncPeers = new ISyncPeer[3]; + for (int i = 0; i < 3; i++) { - await using Context ctx = new(); - ctx.Pool.Start(); - for (int i = 0; i < 3; i++) - { - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(i)); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeys[i])); - } + syncPeers[i] = new SimpleSyncPeerMock(TestItem.PublicKeys[i]); + ctx.Pool.AddPeer(syncPeers[i]); } - [Test] - public async Task Does_not_crash_when_adding_twice_same_peer() - { - await using Context ctx = new(); - ctx.Pool.Start(); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); + await ctx.Pool.StopAsync(); - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(1)); + for (int i = 3; i > 0; i--) + { + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(3), $"Remove {i}"); + ctx.Pool.RemovePeer(syncPeers[i - 1]); } + } - [Test] - public async Task Does_not_crash_when_removing_non_existing_peer() + [Test] + public async Task Peer_count_is_valid_when_adding() + { + await using Context ctx = new(); + ctx.Pool.Start(); + for (int i = 0; i < 3; i++) { - await using Context ctx = new(); - ctx.Pool.Start(); - ctx.Pool.RemovePeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(i)); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeys[i])); } + } - [Test] - public async Task Peer_count_is_valid_when_removing() - { - await using Context ctx = new(); - ctx.Pool.Start(); - ISyncPeer[] syncPeers = new ISyncPeer[3]; - for (int i = 0; i < 3; i++) - { - syncPeers[i] = new SimpleSyncPeerMock(TestItem.PublicKeys[i]); - ctx.Pool.AddPeer(syncPeers[i]); - } + [Test] + public async Task Does_not_crash_when_adding_twice_same_peer() + { + await using Context ctx = new(); + ctx.Pool.Start(); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); - for (int i = 3; i > 0; i--) - { - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(i), $"Remove {i}"); - ctx.Pool.RemovePeer(syncPeers[i - 1]); - } - } + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(1)); + } - [Test] - public async Task Can_start() + [Test] + public async Task Does_not_crash_when_removing_non_existing_peer() + { + await using Context ctx = new(); + ctx.Pool.Start(); + ctx.Pool.RemovePeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); + } + + [Test] + public async Task Peer_count_is_valid_when_removing() + { + await using Context ctx = new(); + ctx.Pool.Start(); + ISyncPeer[] syncPeers = new ISyncPeer[3]; + for (int i = 0; i < 3; i++) { - await using Context ctx = new(); - ctx.Pool.Start(); + syncPeers[i] = new SimpleSyncPeerMock(TestItem.PublicKeys[i]); + ctx.Pool.AddPeer(syncPeers[i]); } - [Test] - public async Task Can_start_and_stop() + for (int i = 3; i > 0; i--) { - await using Context ctx = new(); - ctx.Pool.Start(); - await ctx.Pool.StopAsync(); + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(i), $"Remove {i}"); + ctx.Pool.RemovePeer(syncPeers[i - 1]); } + } - [Test, Retry(3)] - public async Task Can_refresh() - { - await using Context ctx = new(); - ctx.Pool.Start(); - ISyncPeer? syncPeer = Substitute.For(); - syncPeer.Node.Returns(new Node(TestItem.PublicKeyA, "127.0.0.1", 30303)); - ctx.Pool.AddPeer(syncPeer); - ctx.Pool.RefreshTotalDifficulty(syncPeer, Keccak.Zero); - await Task.Delay(100); + [Test] + public async Task Can_start() + { + await using Context ctx = new(); + ctx.Pool.Start(); + } - Assert.That(() => - syncPeer.ReceivedCalls().Count(call => call.GetMethodInfo().Name == "GetHeadBlockHeader"), - Is.EqualTo(2).After(1000, 100) - ); - } + [Test] + public async Task Can_start_and_stop() + { + await using Context ctx = new(); + ctx.Pool.Start(); + await ctx.Pool.StopAsync(); + } - private void SetupSpeedStats(Context ctx, PublicKey publicKey, int transferSpeed) - { + [Test, Retry(3)] + public async Task Can_refresh() + { + await using Context ctx = new(); + ctx.Pool.Start(); + ISyncPeer? syncPeer = Substitute.For(); + syncPeer.Node.Returns(new Node(TestItem.PublicKeyA, "127.0.0.1", 30303)); + ctx.Pool.AddPeer(syncPeer); + ctx.Pool.RefreshTotalDifficulty(syncPeer, Keccak.Zero); + await Task.Delay(100); + + Assert.That(() => + syncPeer.ReceivedCalls().Count(call => call.GetMethodInfo().Name == "GetHeadBlockHeader"), + Is.EqualTo(2).After(1000, 100) + ); + } - Node node = new(publicKey, "127.0.0.1", 30303); - NodeStatsLight stats = new(node); - stats.AddTransferSpeedCaptureEvent(TransferSpeedType.Headers, transferSpeed); + private void SetupSpeedStats(Context ctx, PublicKey publicKey, int transferSpeed) + { - ctx.Stats.GetOrAdd(Arg.Is(n => n.Id == publicKey)).Returns(stats); - } + Node node = new(publicKey, "127.0.0.1", 30303); + NodeStatsLight stats = new(node); + stats.AddTransferSpeedCaptureEvent(TransferSpeedType.Headers, transferSpeed); - [Test] - public async Task Can_replace_peer_with_better() - { - await using Context ctx = new(); - SetupSpeedStats(ctx, TestItem.PublicKeyA, 50); - SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + ctx.Stats.GetOrAdd(Arg.Is(n => n.Id == publicKey)).Returns(stats); + } - ctx.Pool.Start(); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA, "A")); - await WaitForPeersInitialization(ctx); - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BlocksSyncPeerAllocationStrategy(null)); - bool replaced = false; - allocation.Replaced += (_, _) => replaced = true; - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB, "B")); + [Test] + public async Task Can_replace_peer_with_better() + { + await using Context ctx = new(); + SetupSpeedStats(ctx, TestItem.PublicKeyA, 50); + SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + + ctx.Pool.Start(); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA, "A")); + await WaitForPeersInitialization(ctx); + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BlocksSyncPeerAllocationStrategy(null)); + bool replaced = false; + allocation.Replaced += (_, _) => replaced = true; + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB, "B")); + + await WaitFor(() => replaced); + Assert.That(replaced, Is.True); + } - await WaitFor(() => replaced); - Assert.True(replaced); - } + [Test] + public async Task Does_not_replace_with_a_worse_peer() + { + await using Context ctx = new(); + SetupSpeedStats(ctx, TestItem.PublicKeyA, 200); + SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + + ctx.Pool.Start(); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); + await WaitForPeersInitialization(ctx); + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + bool replaced = false; + allocation.Replaced += (_, _) => replaced = true; + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); + await WaitForPeersInitialization(ctx); + + Assert.That(replaced, Is.False); + } - [Test] - public async Task Does_not_replace_with_a_worse_peer() - { - await using Context ctx = new(); - SetupSpeedStats(ctx, TestItem.PublicKeyA, 200); - SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + [Test] + public async Task Does_not_replace_if_too_small_percentage_change() + { + await using Context ctx = new(); + SetupSpeedStats(ctx, TestItem.PublicKeyA, 91); + SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + + ctx.Pool.Start(); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); + await WaitForPeersInitialization(ctx); + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + bool replaced = false; + allocation.Replaced += (_, _) => replaced = true; + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); + await WaitForPeersInitialization(ctx); + + Assert.That(replaced, Is.False); + } - ctx.Pool.Start(); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); - await WaitForPeersInitialization(ctx); - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - bool replaced = false; - allocation.Replaced += (_, _) => replaced = true; - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); - await WaitForPeersInitialization(ctx); + [Test, Retry(3)] + public async Task Does_not_replace_on_small_difference_in_low_numbers() + { + await using Context ctx = new(); + SetupSpeedStats(ctx, TestItem.PublicKeyA, 5); + SetupSpeedStats(ctx, TestItem.PublicKeyB, 4); + + ctx.Pool.Start(); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); + await WaitForPeersInitialization(ctx); + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + bool replaced = false; + allocation.Replaced += (_, _) => replaced = true; + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); + await WaitForPeersInitialization(ctx); + + Assert.That(replaced, Is.False); + } - Assert.False(replaced); - } + [Test] + public async Task Can_stay_when_current_is_best() + { + await using Context ctx = new(); + SetupSpeedStats(ctx, TestItem.PublicKeyA, 100); + SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + + ctx.Pool.Start(); + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); + await WaitForPeersInitialization(ctx); + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + bool replaced = false; + allocation.Replaced += (_, _) => replaced = true; + ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); + await WaitForPeersInitialization(ctx); + Assert.That(replaced, Is.False); + } - [Test] - public async Task Does_not_replace_if_too_small_percentage_change() - { - await using Context ctx = new(); - SetupSpeedStats(ctx, TestItem.PublicKeyA, 91); - SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + [Test] + public async Task Can_list_all_peers() + { + await using Context ctx = new(); + _ = await SetupPeers(ctx, 3); + Assert.That(ctx.Pool.AllPeers.Count(), Is.EqualTo(3)); + } - ctx.Pool.Start(); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); - await WaitForPeersInitialization(ctx); - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - bool replaced = false; - allocation.Replaced += (_, _) => replaced = true; - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); - await WaitForPeersInitialization(ctx); + [Test] + public async Task Can_borrow_peer() + { + await using Context ctx = new(); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); - Assert.False(replaced); - } + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - [Test, Retry(3)] - public async Task Does_not_replace_on_small_difference_in_low_numbers() - { - await using Context ctx = new(); - SetupSpeedStats(ctx, TestItem.PublicKeyA, 5); - SetupSpeedStats(ctx, TestItem.PublicKeyB, 4); + Assert.That(allocation.Current?.SyncPeer, Is.SameAs(peers[0])); + } - ctx.Pool.Start(); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); - await WaitForPeersInitialization(ctx); - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - bool replaced = false; - allocation.Replaced += (_, _) => replaced = true; - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); - await WaitForPeersInitialization(ctx); + [Test] + public async Task Can_borrow_return_and_borrow_again() + { + await using Context ctx = new(); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); - Assert.False(replaced); - } + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + ctx.Pool.Free(allocation); + allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + ctx.Pool.Free(allocation); + allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - [Test] - public async Task Can_stay_when_current_is_best() - { - await using Context ctx = new(); - SetupSpeedStats(ctx, TestItem.PublicKeyA, 100); - SetupSpeedStats(ctx, TestItem.PublicKeyB, 100); + Assert.That(allocation.Current?.SyncPeer, Is.SameAs(peers[0])); + } - ctx.Pool.Start(); - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); - await WaitForPeersInitialization(ctx); - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - bool replaced = false; - allocation.Replaced += (_, _) => replaced = true; - ctx.Pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); - await WaitForPeersInitialization(ctx); - Assert.False(replaced); - } + [Test] + public async Task Can_borrow_many() + { + await using Context ctx = new(); + await SetupPeers(ctx, 2); + + SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + Assert.That(allocation2.Current, Is.Not.SameAs(allocation1.Current), "first"); + Assert.That(allocation1.Current, Is.Not.Null, "first A"); + Assert.That(allocation2.Current, Is.Not.Null, "first B"); + + ctx.Pool.Free(allocation1); + ctx.Pool.Free(allocation2); + Assert.That(allocation1.Current, Is.Null, "null A"); + Assert.That(allocation2.Current, Is.Null, "null B"); + + allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + Assert.That(allocation2.Current, Is.Not.SameAs(allocation1.Current)); + Assert.That(allocation1.Current, Is.Not.Null, "second A"); + Assert.That(allocation2.Current, Is.Not.Null, "second B"); + } - [Test] - public async Task Can_list_all_peers() + [Test] + public async Task Does_not_allocate_sleeping_peers() + { + await using Context ctx = new(); + _ = await SetupPeers(ctx, 3); + for (int i = 0; i < PeerInfo.SleepThreshold + 1; i++) { - await using Context ctx = new(); - _ = await SetupPeers(ctx, 3); - Assert.That(ctx.Pool.AllPeers.Count(), Is.EqualTo(3)); + ctx.Pool.ReportNoSyncProgress(ctx.Pool.InitializedPeers.First(), AllocationContexts.All); } - [Test] - public async Task Can_borrow_peer() - { - await using Context ctx = new(); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); + SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + SyncPeerAllocation allocation3 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - - Assert.That(allocation.Current?.SyncPeer, Is.SameAs(peers[0])); - } - - [Test] - public async Task Can_borrow_return_and_borrow_again() - { - await using Context ctx = new(); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); + Assert.That(allocation1.HasPeer, Is.True); + Assert.That(allocation2.HasPeer, Is.True); + Assert.That(allocation3.HasPeer, Is.False); + } - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - ctx.Pool.Free(allocation); - allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - ctx.Pool.Free(allocation); - allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + [Test] + public async Task Can_wake_up_all_sleeping_peers() + { + await using Context ctx = new(); + _ = await SetupPeers(ctx, 3); + ctx.Pool.ReportNoSyncProgress(ctx.Pool.InitializedPeers.First(), AllocationContexts.All); + ctx.Pool.ReportNoSyncProgress(ctx.Pool.InitializedPeers.Last(), AllocationContexts.All); - Assert.That(allocation.Current?.SyncPeer, Is.SameAs(peers[0])); - } + ctx.Pool.WakeUpAll(); - [Test] - public async Task Can_borrow_many() - { - await using Context ctx = new(); - await SetupPeers(ctx, 2); + SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + SyncPeerAllocation allocation3 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - Assert.That(allocation2.Current, Is.Not.SameAs(allocation1.Current), "first"); - Assert.NotNull(allocation1.Current, "first A"); - Assert.NotNull(allocation2.Current, "first B"); + Assert.That(allocation1.HasPeer, Is.True); + Assert.That(allocation2.HasPeer, Is.True); + Assert.That(allocation3.HasPeer, Is.True); + } - ctx.Pool.Free(allocation1); - ctx.Pool.Free(allocation2); - Assert.Null(allocation1.Current, "null A"); - Assert.Null(allocation2.Current, "null B"); + [Test] + public async Task Initialized_peers() + { + await using Context ctx = new(); + _ = await SetupPeers(ctx, 3); + Assert.That(ctx.Pool.InitializedPeers.Count(), Is.EqualTo(3)); + } - allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - Assert.That(allocation2.Current, Is.Not.SameAs(allocation1.Current)); - Assert.NotNull(allocation1.Current, "second A"); - Assert.NotNull(allocation2.Current, "second B"); - } + [Test] + public async Task Report_invalid_invokes_disconnection() + { + await using Context ctx = new(); + SimpleSyncPeerMock[] _ = await SetupPeers(ctx, 3); + PeerInfo peerInfo = ctx.Pool.InitializedPeers.First(); + ctx.Pool.ReportBreachOfProtocol(peerInfo, DisconnectReason.Other, "issue details"); - [Test] - public async Task Does_not_allocate_sleeping_peers() - { - await using Context ctx = new(); - _ = await SetupPeers(ctx, 3); - for (int i = 0; i < PeerInfo.SleepThreshold + 1; i++) - { - ctx.Pool.ReportNoSyncProgress(ctx.Pool.InitializedPeers.First(), AllocationContexts.All); - } + Assert.That(((SimpleSyncPeerMock)peerInfo.SyncPeer).DisconnectRequested, Is.True); + } - SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation3 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + [Test] + public async Task Will_not_allocate_same_peer_to_two_allocations() + { + await using Context ctx = new(); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); - Assert.True(allocation1.HasPeer); - Assert.True(allocation2.HasPeer); - Assert.False(allocation3.HasPeer); - } + SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - [Test] - public async Task Can_wake_up_all_sleeping_peers() - { - await using Context ctx = new(); - _ = await SetupPeers(ctx, 3); - ctx.Pool.ReportNoSyncProgress(ctx.Pool.InitializedPeers.First(), AllocationContexts.All); - ctx.Pool.ReportNoSyncProgress(ctx.Pool.InitializedPeers.Last(), AllocationContexts.All); + Assert.That(allocation1.Current?.SyncPeer, Is.SameAs(peers[0])); + Assert.That(allocation2.Current, Is.Null); + } - ctx.Pool.WakeUpAll(); + [Test] + public async Task Can_remove_borrowed_peer() + { + await using Context ctx = new(); + SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); - SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation3 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BlocksSyncPeerAllocationStrategy(null)); + ctx.Pool.RemovePeer(peers[0]); - Assert.True(allocation1.HasPeer); - Assert.True(allocation2.HasPeer); - Assert.True(allocation3.HasPeer); - } + Assert.That(allocation.Current, Is.Null); + } - [Test] - public async Task Initialized_peers() - { - await using Context ctx = new(); - _ = await SetupPeers(ctx, 3); - Assert.That(ctx.Pool.InitializedPeers.Count(), Is.EqualTo(3)); - } + [Test] + public async Task Will_remove_peer_if_times_out_on_init() + { + await using Context ctx = new(); + SimpleSyncPeerMock peer = new SimpleSyncPeerMock(TestItem.PublicKeyA); + peer.SetHeaderResponseTime(int.MaxValue); + ctx.Pool.Start(); + ctx.Pool.AddPeer(peer); + + await WaitFor(() => peer.DisconnectRequested); + Assert.That(peer.DisconnectRequested, Is.True); + } - [Test] - public async Task Report_invalid_invokes_disconnection() - { - await using Context ctx = new(); - SimpleSyncPeerMock[] _ = await SetupPeers(ctx, 3); - PeerInfo peerInfo = ctx.Pool.InitializedPeers.First(); - ctx.Pool.ReportBreachOfProtocol(peerInfo, DisconnectReason.Other, "issue details"); + [Test] + public async Task Can_remove_during_init() + { + await using Context ctx = new(); + SimpleSyncPeerMock peer = new SimpleSyncPeerMock(TestItem.PublicKeyA); + peer.SetHeaderResponseTime(500); + ctx.Pool.Start(); + ctx.Pool.AddPeer(peer); - Assert.True(((SimpleSyncPeerMock)peerInfo.SyncPeer).DisconnectRequested); - } + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + ctx.Pool.RemovePeer(peer); - [Test] - public async Task Will_not_allocate_same_peer_to_two_allocations() - { - await using Context ctx = new(); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); + Assert.That(allocation.Current, Is.EqualTo(null)); + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); + } - SyncPeerAllocation allocation1 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - SyncPeerAllocation allocation2 = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + [Test] + public async Task It_is_fine_to_fail_init() + { + await using Context ctx = new(); + SimpleSyncPeerMock peer = new SimpleSyncPeerMock(TestItem.PublicKeyA); + peer.SetHeaderFailure(true); + ctx.Pool.Start(); + ctx.Pool.AddPeer(peer); + await WaitForPeersInitialization(ctx); + + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + ctx.Pool.RemovePeer(peer); + + Assert.That(allocation.Current, Is.EqualTo(null)); + Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); + } - Assert.That(allocation1.Current?.SyncPeer, Is.SameAs(peers[0])); - Assert.Null(allocation2.Current); - } + [Test] + public async Task Can_return() + { + await using Context ctx = new(); + await SetupPeers(ctx, 1); - [Test] - public async Task Can_remove_borrowed_peer() - { - await using Context ctx = new(); - SimpleSyncPeerMock[] peers = await SetupPeers(ctx, 1); + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + ctx.Pool.Free(allocation); + } - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BlocksSyncPeerAllocationStrategy(null)); - ctx.Pool.RemovePeer(peers[0]); + [Test] + public async Task Does_not_fail_when_receiving_a_new_block_and_allocation_has_no_peer() + { + await using Context ctx = new(); + await SetupPeers(ctx, 1); - Assert.Null(allocation.Current); - } + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + allocation.Cancel(); - [Test] - public async Task Will_remove_peer_if_times_out_on_init() - { - await using Context ctx = new(); - SimpleSyncPeerMock peer = new SimpleSyncPeerMock(TestItem.PublicKeyA); - peer.SetHeaderResponseTime(int.MaxValue); - ctx.Pool.Start(); - ctx.Pool.AddPeer(peer); + ctx.BlockTree.NewHeadBlock += Raise.EventWith(new object(), new BlockEventArgs(Build.A.Block.WithTotalDifficulty(1L).TestObject)); + } - await WaitFor(() => peer.DisconnectRequested); - Assert.True(peer.DisconnectRequested); - } + [Test] + public async Task Can_borrow_async_many() + { + await using Context ctx = new(); + await SetupPeers(ctx, 2); - [Test] - public async Task Can_remove_during_init() + Task[] allocationTasks = new Task[3]; + for (int i = 0; i < allocationTasks.Length; i++) { - await using Context ctx = new(); - SimpleSyncPeerMock peer = new SimpleSyncPeerMock(TestItem.PublicKeyA); - peer.SetHeaderResponseTime(500); - ctx.Pool.Start(); - ctx.Pool.AddPeer(peer); - - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - ctx.Pool.RemovePeer(peer); - - Assert.That(allocation.Current, Is.EqualTo(null)); - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); + allocationTasks[i] = ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true), AllocationContexts.All, 50); } - [Test] - public async Task It_is_fine_to_fail_init() - { - await using Context ctx = new(); - SimpleSyncPeerMock peer = new SimpleSyncPeerMock(TestItem.PublicKeyA); - peer.SetHeaderFailure(true); - ctx.Pool.Start(); - ctx.Pool.AddPeer(peer); - await WaitForPeersInitialization(ctx); + await Task.WhenAll(allocationTasks); - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - ctx.Pool.RemovePeer(peer); + SyncPeerAllocation[] allocations = allocationTasks.Select(t => t.Result).ToArray(); + SyncPeerAllocation[] successfulAllocations = allocations.Where(r => r.Current is not null).ToArray(); - Assert.That(allocation.Current, Is.EqualTo(null)); - Assert.That(ctx.Pool.PeerCount, Is.EqualTo(0)); - } + // we had only two peers and 3 borrow calls so only two are successful + Assert.That(successfulAllocations.Length, Is.EqualTo(2)); - [Test] - public async Task Can_return() + foreach (SyncPeerAllocation allocation in successfulAllocations) { - await using Context ctx = new(); - await SetupPeers(ctx, 1); - - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); + // free allocated peers ctx.Pool.Free(allocation); } - [Test] - public async Task Does_not_fail_when_receiving_a_new_block_and_allocation_has_no_peer() + foreach (SyncPeerAllocation allocation in allocations) { - await using Context ctx = new(); - await SetupPeers(ctx, 1); - - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true)); - allocation.Cancel(); - - ctx.BlockTree.NewHeadBlock += Raise.EventWith(new object(), new BlockEventArgs(Build.A.Block.WithTotalDifficulty(1L).TestObject)); + // no peer assigned any more after calling free + Assert.That(allocation.Current, Is.Null, "null A"); } + } - [Test] - public async Task Can_borrow_async_many() - { - await using Context ctx = new(); - await SetupPeers(ctx, 2); - - Task[] allocationTasks = new Task[3]; - for (int i = 0; i < allocationTasks.Length; i++) - { - allocationTasks[i] = ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true), AllocationContexts.All, 50); - } - - await Task.WhenAll(allocationTasks); - - SyncPeerAllocation[] allocations = allocationTasks.Select(t => t.Result).ToArray(); - SyncPeerAllocation[] successfulAllocations = allocations.Where(r => r.Current is not null).ToArray(); + private int _pendingRequests; - // we had only two peers and 3 borrow calls so only two are successful - Assert.That(successfulAllocations.Length, Is.EqualTo(2)); + private readonly Random _workRandomDelay = new(42); - foreach (SyncPeerAllocation allocation in successfulAllocations) - { - // free allocated peers - ctx.Pool.Free(allocation); - } - - foreach (SyncPeerAllocation allocation in allocations) - { - // no peer assigned any more after calling free - Assert.Null(allocation.Current, "null A"); - } + private async Task DoWork(string desc, SyncPeerAllocation allocation) + { + await using Context ctx = new(); + if (allocation.HasPeer) + { + int workTime = _workRandomDelay.Next(1000); + Console.WriteLine($"{desc} will work for {workTime} ms"); + await Task.Delay(workTime); + Console.WriteLine($"{desc} finished work after {workTime} ms"); } - private int _pendingRequests; + ctx.Pool.Free(allocation); + Console.WriteLine($"{desc} freed allocation"); + } - private readonly Random _workRandomDelay = new(42); + [Test, Retry(3)] + public async Task Try_to_break_multithreaded() + { + await using Context ctx = new(); + await SetupPeers(ctx, 25); - private async Task DoWork(string desc, SyncPeerAllocation allocation) + int failures = 0; + int iterations = 100; + do { - await using Context ctx = new(); - if (allocation.HasPeer) + if (iterations > 0) { - int workTime = _workRandomDelay.Next(1000); - Console.WriteLine($"{desc} will work for {workTime} ms"); - await Task.Delay(workTime); - Console.WriteLine($"{desc} finished work after {workTime} ms"); - } + SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true), AllocationContexts.All, 10); + if (!allocation.HasPeer) + { + failures++; + } - ctx.Pool.Free(allocation); - Console.WriteLine($"{desc} freed allocation"); - } + Interlocked.Increment(ref _pendingRequests); + int iterationsLocal = iterations; - [Test, Retry(3)] - public async Task Try_to_break_multithreaded() - { - await using Context ctx = new(); - await SetupPeers(ctx, 25); - int failures = 0; - int iterations = 100; - do - { - if (iterations > 0) + Task task = DoWork(iterationsLocal.ToString(), allocation); + Task _ = task.ContinueWith(t => { - SyncPeerAllocation allocation = await ctx.Pool.Allocate(new BySpeedStrategy(TransferSpeedType.Headers, true), AllocationContexts.All, 10); - if (!allocation.HasPeer) - { - failures++; - } - - Interlocked.Increment(ref _pendingRequests); - int iterationsLocal = iterations; - - - Task task = DoWork(iterationsLocal.ToString(), allocation); - Task _ = task.ContinueWith(t => - { - Console.WriteLine($"{iterationsLocal} Decrement on {t.IsCompleted}"); - Interlocked.Decrement(ref _pendingRequests); - }); - } + Console.WriteLine($"{iterationsLocal} Decrement on {t.IsCompleted}"); + Interlocked.Decrement(ref _pendingRequests); + }); + } - Console.WriteLine(iterations + " " + failures + " " + ctx.Pool.ReplaceableAllocations.Count() + " " + _pendingRequests); - await Task.Delay(10); - } while (iterations-- > 0 || _pendingRequests > 0); + Console.WriteLine(iterations + " " + failures + " " + ctx.Pool.ReplaceableAllocations.Count() + " " + _pendingRequests); + await Task.Delay(10); + } while (iterations-- > 0 || _pendingRequests > 0); - Assert.That(ctx.Pool.ReplaceableAllocations.Count(), Is.EqualTo(0), "allocations"); - Assert.That(_pendingRequests, Is.EqualTo(0), "pending requests"); - Assert.GreaterOrEqual(failures, 0, "pending requests"); - } - - [Test] - public async Task When_no_peer_will_cancel_on_cancellation_token() - { - await using Context ctx = new(); - using CancellationTokenSource cts = new CancellationTokenSource(); - cts.CancelAfter(100); + Assert.That(ctx.Pool.ReplaceableAllocations.Count(), Is.EqualTo(0), "allocations"); + Assert.That(_pendingRequests, Is.EqualTo(0), "pending requests"); + Assert.That(failures, Is.GreaterThanOrEqualTo(0), "pending requests"); + } - bool wasCancelled = false; - try - { - await ctx.Pool.AllocateAndRun( - (peer) => { return peer.GetBlockHeaders(0, 1, 1, CancellationToken.None); }, - BySpeedStrategy.FastestHeader, AllocationContexts.Headers, cts.Token); - } - catch (OperationCanceledException) - { - wasCancelled = true; - } + [Test] + public async Task When_no_peer_will_cancel_on_cancellation_token() + { + await using Context ctx = new(); + using CancellationTokenSource cts = new CancellationTokenSource(); + cts.CancelAfter(100); - wasCancelled.Should().BeTrue(); + bool wasCancelled = false; + try + { + await ctx.Pool.AllocateAndRun( + (peer) => { return peer.GetBlockHeaders(0, 1, 1, CancellationToken.None); }, + BySpeedStrategy.FastestHeader, AllocationContexts.Headers, cts.Token); } - - private async Task SetupPeers(Context ctx, int count) + catch (OperationCanceledException) { - SimpleSyncPeerMock[] peers = new SimpleSyncPeerMock[count]; - for (int i = 0; i < count; i++) - { - peers[i] = new SimpleSyncPeerMock(TestItem.PublicKeys[i]); - } - - ctx.Pool.Start(); + wasCancelled = true; + } - for (int i = 0; i < count; i++) - { - ctx.Pool.AddPeer(peers[i]); - } + wasCancelled.Should().BeTrue(); + } - await WaitForPeersInitialization(ctx); - return peers; + private async Task SetupPeers(Context ctx, int count) + { + SimpleSyncPeerMock[] peers = new SimpleSyncPeerMock[count]; + for (int i = 0; i < count; i++) + { + peers[i] = new SimpleSyncPeerMock(TestItem.PublicKeys[i]); } - private async Task WaitForPeersInitialization(Context ctx) + ctx.Pool.Start(); + + for (int i = 0; i < count; i++) { - await WaitFor(() => ctx.Pool.AllPeers.All(p => p.IsInitialized)); + ctx.Pool.AddPeer(peers[i]); } - private async Task WaitFor(Func isConditionMet) + await WaitForPeersInitialization(ctx); + return peers; + } + + private async Task WaitForPeersInitialization(Context ctx) + { + await WaitFor(() => ctx.Pool.AllPeers.All(p => p.IsInitialized)); + } + + private async Task WaitFor(Func isConditionMet) + { + const int waitInterval = 50; + for (int i = 0; i < 20; i++) { - const int waitInterval = 50; - for (int i = 0; i < 20; i++) + if (isConditionMet()) { - if (isConditionMet()) - { - return; - } - - await Task.Delay(waitInterval); + return; } + + await Task.Delay(waitInterval); } } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs index f15625b556a..4ab8f3a901a 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs @@ -124,9 +124,9 @@ public void Is_fast_block_finished_returns_true_when_no_fast_sync_is_used() }; SyncProgressResolver syncProgressResolver = CreateProgressResolver(blockTree, stateReader, false, syncConfig, LimboLogs.Instance); - Assert.True(syncProgressResolver.IsFastBlocksHeadersFinished()); - Assert.True(syncProgressResolver.IsFastBlocksBodiesFinished()); - Assert.True(syncProgressResolver.IsFastBlocksReceiptsFinished()); + Assert.That(syncProgressResolver.IsFastBlocksHeadersFinished(), Is.True); + Assert.That(syncProgressResolver.IsFastBlocksBodiesFinished(), Is.True); + Assert.That(syncProgressResolver.IsFastBlocksReceiptsFinished(), Is.True); } [Test] @@ -146,7 +146,7 @@ public void Is_fast_block_bodies_finished_returns_false_when_blocks_not_download blockTree.LowestInsertedBodyNumber.Returns(2); SyncProgressResolver syncProgressResolver = CreateProgressResolver(blockTree, stateReader, false, syncConfig, LimboLogs.Instance); - Assert.False(syncProgressResolver.IsFastBlocksBodiesFinished()); + Assert.That(syncProgressResolver.IsFastBlocksBodiesFinished(), Is.False); } [Test] @@ -166,7 +166,7 @@ public void Is_fast_block_receipts_finished_returns_true_when_receipts_not_downl blockTree.LowestInsertedBodyNumber.Returns(1); SyncProgressResolver syncProgressResolver = CreateProgressResolver(blockTree, stateReader, true, syncConfig, LimboLogs.Instance); - Assert.True(syncProgressResolver.IsFastBlocksReceiptsFinished()); + Assert.That(syncProgressResolver.IsFastBlocksReceiptsFinished(), Is.True); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs index 46cadf01253..e3540377184 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs @@ -25,7 +25,6 @@ using Nethermind.Specs; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Specs.Forks; -using Nethermind.State; using Nethermind.Stats.Model; using Nethermind.Synchronization.FastSync; using Nethermind.Synchronization.ParallelSync; @@ -36,713 +35,711 @@ using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; -namespace Nethermind.Synchronization.Test +namespace Nethermind.Synchronization.Test; + +[Parallelizable(ParallelScope.All)] +public class SyncServerTests { - [Parallelizable(ParallelScope.All)] - [TestFixture] - public class SyncServerTests + [Test] + public void When_finding_hash_it_does_not_load_headers() { - [Test] - public void When_finding_hash_it_does_not_load_headers() - { - Context ctx = new(); - ctx.BlockTree.FindHash(123).Returns(TestItem.KeccakA); - Hash256 result = ctx.SyncServer.FindHash(123)!; - - ctx.BlockTree.DidNotReceive().FindHeader(Arg.Any(), Arg.Any()); - ctx.BlockTree.DidNotReceive().FindHeader(Arg.Any(), Arg.Any()); - ctx.BlockTree.DidNotReceive().FindBlock(Arg.Any(), Arg.Any()); - Assert.That(result, Is.EqualTo(TestItem.KeccakA)); - } + Context ctx = new(); + ctx.BlockTree.FindHash(123).Returns(TestItem.KeccakA); + Hash256 result = ctx.SyncServer.FindHash(123)!; + + ctx.BlockTree.DidNotReceive().FindHeader(Arg.Any(), Arg.Any()); + ctx.BlockTree.DidNotReceive().FindHeader(Arg.Any(), Arg.Any()); + ctx.BlockTree.DidNotReceive().FindBlock(Arg.Any(), Arg.Any()); + Assert.That(result, Is.EqualTo(TestItem.KeccakA)); + } - [Test] - public void Does_not_request_peer_refresh_on_known_hints() - { - Context ctx = new(); - ctx.BlockTree.IsKnownBlock(1, TestItem.KeccakA).ReturnsForAnyArgs(true); - ctx.SyncServer.HintBlock(TestItem.KeccakA, 1, ctx.NodeWhoSentTheBlock); - ctx.PeerPool.DidNotReceiveWithAnyArgs().RefreshTotalDifficulty(null!, null!); - } + [Test] + public void Does_not_request_peer_refresh_on_known_hints() + { + Context ctx = new(); + ctx.BlockTree.IsKnownBlock(1, TestItem.KeccakA).ReturnsForAnyArgs(true); + ctx.SyncServer.HintBlock(TestItem.KeccakA, 1, ctx.NodeWhoSentTheBlock); + ctx.PeerPool.DidNotReceiveWithAnyArgs().RefreshTotalDifficulty(null!, null!); + } - [Test] - public void Requests_peer_refresh_on_unknown_hints() - { - Context ctx = new(); - ctx.BlockTree.IsKnownBlock(1, TestItem.KeccakA).ReturnsForAnyArgs(false); - ctx.SyncServer.HintBlock(TestItem.KeccakA, 1, ctx.NodeWhoSentTheBlock); - ctx.PeerPool.Received().ReceivedWithAnyArgs(); - } + [Test] + public void Requests_peer_refresh_on_unknown_hints() + { + Context ctx = new(); + ctx.BlockTree.IsKnownBlock(1, TestItem.KeccakA).ReturnsForAnyArgs(false); + ctx.SyncServer.HintBlock(TestItem.KeccakA, 1, ctx.NodeWhoSentTheBlock); + ctx.PeerPool.Received().ReceivedWithAnyArgs(); + } - [Test] - public void When_finding_by_hash_block_info_is_not_loaded() - { - Context ctx = new(); - ctx.SyncServer.Find(TestItem.KeccakA); - ctx.BlockTree.Received().FindBlock(Arg.Any(), BlockTreeLookupOptions.TotalDifficultyNotNeeded | BlockTreeLookupOptions.ExcludeTxHashes); - } + [Test] + public void When_finding_by_hash_block_info_is_not_loaded() + { + Context ctx = new(); + ctx.SyncServer.Find(TestItem.KeccakA); + ctx.BlockTree.Received().FindBlock(Arg.Any(), BlockTreeLookupOptions.TotalDifficultyNotNeeded | BlockTreeLookupOptions.ExcludeTxHashes); + } - [TestCase(true, true, true)] - [TestCase(false, true, false)] - [TestCase(true, false, false)] - public void Can_accept_new_valid_blocks(bool sealOk, bool validationOk, bool accepted) + [TestCase(true, true, true)] + [TestCase(false, true, false)] + [TestCase(true, false, false)] + public void Can_accept_new_valid_blocks(bool sealOk, bool validationOk, bool accepted) + { + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + + ISealValidator sealValidator = sealOk ? Always.Valid : Always.Invalid; + IBlockValidator blockValidator = validationOk ? Always.Valid : Always.Invalid; + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + blockValidator, + sealValidator, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + + if (!accepted) { - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - - ISealValidator sealValidator = sealOk ? Always.Valid : Always.Invalid; - IBlockValidator blockValidator = validationOk ? Always.Valid : Always.Invalid; - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - blockValidator, - sealValidator, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - - if (!accepted) - { - Assert.Throws(() => ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock)); - } - else - { - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - } - - if (accepted) - { - Assert.That(block.Header, Is.EqualTo(localBlockTree.BestSuggestedHeader)); - } - else - { - Assert.That(block.Header, Is.Not.EqualTo(localBlockTree.BestSuggestedHeader)); - } + Assert.Throws(() => ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock)); } - - [Test] - public void Can_accept_blocks_that_are_fine() + else { - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - Always.Valid, - Always.Valid, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - - Assert.That(block.Header, Is.EqualTo(localBlockTree.BestSuggestedHeader)); } - [TestCase(SyncMode.SnapSync, false)] - [TestCase(SyncMode.FastSync, false)] - [TestCase(SyncMode.StateNodes, false)] - [TestCase(SyncMode.Full, true)] - public void Should_accept_or_not_blocks_depends_on_sync_mode(SyncMode syncMode, bool expectBlockAccepted) + if (accepted) { - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - - StaticSelector staticSelector; - switch (syncMode) - { - case SyncMode.SnapSync: - staticSelector = StaticSelector.SnapSync; - break; - case SyncMode.FastSync: - staticSelector = StaticSelector.FastSync; - break; - case SyncMode.StateNodes: - staticSelector = StaticSelector.StateNodesWithFastBlocks; - break; - default: - staticSelector = StaticSelector.Full; - break; - } - - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - Always.Valid, - Always.Valid, - ctx.PeerPool, - staticSelector, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - - block.Header.Equals(localBlockTree.BestSuggestedHeader).Should().Be(expectBlockAccepted); + Assert.That(block.Header, Is.EqualTo(localBlockTree.BestSuggestedHeader)); } - - [Test] - public void Terminal_block_with_lower_td_should_not_change_best_suggested_but_should_be_added_to_block_tree() + else { - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - TestSpecProvider testSpecProvider = new(London.Instance) - { - TerminalTotalDifficulty = 10_000_000, - }; - - Block newBestLocalBlock = Build.A.Block - .WithNumber(localBlockTree.Head!.Number + 1) - .WithParent(localBlockTree.Head!).WithDifficulty(10_000_002L).TestObject; - localBlockTree.SuggestBlock(newBestLocalBlock); - - PoSSwitcher poSSwitcher = new( - new MergeConfig - { - TerminalTotalDifficulty = $"{testSpecProvider.TerminalTotalDifficulty}" - }, - new SyncConfig(), - new MemDb(), - localBlockTree, - testSpecProvider, - new ChainSpec(), - LimboLogs.Instance); - HeaderValidator headerValidator = new( - localBlockTree, - Always.Valid, - testSpecProvider, - LimboLogs.Instance); - - MergeHeaderValidator mergeHeaderValidator = new( - poSSwitcher, - headerValidator, - localBlockTree, - testSpecProvider, - Always.Valid, - LimboLogs.Instance); - BlockValidator blockValidator = new( - Always.Valid, - mergeHeaderValidator, - Always.Valid, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - blockValidator, - Always.Valid, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - testSpecProvider, - LimboLogs.Instance); - - Block? remoteBestBlock = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None); - - ctx.SyncServer.AddNewBlock(remoteBestBlock!, ctx.NodeWhoSentTheBlock); - Assert.That(localBlockTree.BestSuggestedHeader!.Hash, Is.EqualTo(newBestLocalBlock.Header.Hash)); - Assert.That(localBlockTree.FindBlock(remoteBestBlock!.Hash, BlockTreeLookupOptions.None)!.Hash, Is.EqualTo(remoteBestBlock.Hash)); + Assert.That(block.Header, Is.Not.EqualTo(localBlockTree.BestSuggestedHeader)); } + } - [TestCase(10000000)] - [TestCase(20000000)] - public void Fake_total_difficulty_from_peer_does_not_trick_the_node(long ttd) - { - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - Context ctx = CreateMergeContext(9, (UInt256)ttd); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; + [Test] + public void Can_accept_blocks_that_are_fine() + { + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + Always.Valid, + Always.Valid, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + + Assert.That(block.Header, Is.EqualTo(localBlockTree.BestSuggestedHeader)); + } - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - Assert.That(block.Header.Hash, Is.EqualTo(ctx.LocalBlockTree.BestSuggestedHeader!.Hash)); + [TestCase(SyncMode.SnapSync, false)] + [TestCase(SyncMode.FastSync, false)] + [TestCase(SyncMode.StateNodes, false)] + [TestCase(SyncMode.Full, true)] + public void Should_accept_or_not_blocks_depends_on_sync_mode(SyncMode syncMode, bool expectBlockAccepted) + { + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - Block parentBlock = remoteBlockTree.FindBlock(8, BlockTreeLookupOptions.None)!; - Assert.That(ctx.LocalBlockTree.BestSuggestedHeader.TotalDifficulty, Is.EqualTo(parentBlock.TotalDifficulty + block.Difficulty)); + StaticSelector staticSelector; + switch (syncMode) + { + case SyncMode.SnapSync: + staticSelector = StaticSelector.SnapSync; + break; + case SyncMode.FastSync: + staticSelector = StaticSelector.FastSync; + break; + case SyncMode.StateNodes: + staticSelector = StaticSelector.StateNodesWithFastBlocks; + break; + default: + staticSelector = StaticSelector.Full; + break; } - [TestCase(9000000, true)] - [TestCase(9000000, false)] - [TestCase(8000010, true)] - public void Can_reject_block_POW_block_after_TTD(long ttd, bool sendFakeTd) + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + Always.Valid, + Always.Valid, + ctx.PeerPool, + staticSelector, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + + block.Header.Equals(localBlockTree.BestSuggestedHeader).Should().Be(expectBlockAccepted); + } + + [Test] + public void Terminal_block_with_lower_td_should_not_change_best_suggested_but_should_be_added_to_block_tree() + { + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + TestSpecProvider testSpecProvider = new(London.Instance) { - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - Context ctx = CreateMergeContext(9, (UInt256)ttd); + TerminalTotalDifficulty = 10_000_000, + }; - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - if (sendFakeTd) + Block newBestLocalBlock = Build.A.Block + .WithNumber(localBlockTree.Head!.Number + 1) + .WithParent(localBlockTree.Head!).WithDifficulty(10_000_002L).TestObject; + localBlockTree.SuggestBlock(newBestLocalBlock); + + PoSSwitcher poSSwitcher = new( + new MergeConfig { - block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; - } + TerminalTotalDifficulty = $"{testSpecProvider.TerminalTotalDifficulty}" + }, + new SyncConfig(), + new MemDb(), + localBlockTree, + testSpecProvider, + new ChainSpec(), + LimboLogs.Instance); + HeaderValidator headerValidator = new( + localBlockTree, + Always.Valid, + testSpecProvider, + LimboLogs.Instance); + + MergeHeaderValidator mergeHeaderValidator = new( + poSSwitcher, + headerValidator, + localBlockTree, + testSpecProvider, + Always.Valid, + LimboLogs.Instance); + BlockValidator blockValidator = new( + Always.Valid, + mergeHeaderValidator, + Always.Valid, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + blockValidator, + Always.Valid, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + testSpecProvider, + LimboLogs.Instance); + + Block? remoteBestBlock = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None); + + ctx.SyncServer.AddNewBlock(remoteBestBlock!, ctx.NodeWhoSentTheBlock); + Assert.That(localBlockTree.BestSuggestedHeader!.Hash, Is.EqualTo(newBestLocalBlock.Header.Hash)); + Assert.That(localBlockTree.FindBlock(remoteBestBlock!.Hash, BlockTreeLookupOptions.None)!.Hash, Is.EqualTo(remoteBestBlock.Hash)); + } - Assert.Throws(() => ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock)); - Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(8)); - } + [TestCase(10000000)] + [TestCase(20000000)] + public void Fake_total_difficulty_from_peer_does_not_trick_the_node(long ttd) + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + Context ctx = CreateMergeContext(9, (UInt256)ttd); - [TestCase(9000000, true)] - [TestCase(9000000, false)] - [TestCase(8000010, true)] - public void Post_merge_blocks_wont_be_accepted_by_gossip(long ttd, bool sendFakeTd) - { - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - Block postMergeBlock = Build.A.Block - .WithDifficulty(0) - .WithParent(remoteBlockTree.Head!) - .WithTotalDifficulty(remoteBlockTree.Head!.TotalDifficulty) - .WithNonce(0u) - .TestObject; - remoteBlockTree.SuggestBlock(postMergeBlock); - Context ctx = CreateMergeContext(9, (UInt256)ttd); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - if (sendFakeTd) - { - block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; - } + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(8)); - ctx.LocalBlockTree.FindBlock(postMergeBlock.Hash!, BlockTreeLookupOptions.None).Should().BeNull(); - } + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + Assert.That(block.Header.Hash, Is.EqualTo(ctx.LocalBlockTree.BestSuggestedHeader!.Hash)); - [TestCase(9000010, true, 100)] - [TestCase(9000010, false, 100)] - [TestCase(9000010, false, 1000000)] - [TestCase(9000010, true, 1000000)] - public void Can_inject_terminal_block_with_not_higher_td_than_head(long ttd, bool sendFakeTd, long difficulty) - { - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - Block terminalBlockWithLowerDifficulty = Build.A.Block - .WithDifficulty((UInt256)difficulty) - .WithParent(remoteBlockTree.Head!) - .WithGasLimit(remoteBlockTree.Head!.GasLimit + 1) - .WithTotalDifficulty(remoteBlockTree.Head.TotalDifficulty + (UInt256)difficulty) - .TestObject; - remoteBlockTree.SuggestBlock(terminalBlockWithLowerDifficulty); - Context ctx = CreateMergeContext(10, (UInt256)ttd); - Assert.True(terminalBlockWithLowerDifficulty.IsTerminalBlock(ctx.SpecProvider)); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - if (sendFakeTd) - { - block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; - } + Block parentBlock = remoteBlockTree.FindBlock(8, BlockTreeLookupOptions.None)!; + Assert.That(ctx.LocalBlockTree.BestSuggestedHeader.TotalDifficulty, Is.EqualTo(parentBlock.TotalDifficulty + block.Difficulty)); + } - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(9)); - ctx.LocalBlockTree.FindBlock(terminalBlockWithLowerDifficulty.Hash!, BlockTreeLookupOptions.None).Should().NotBeNull(); - ctx.LocalBlockTree.BestSuggestedHeader!.Hash.Should().NotBe(terminalBlockWithLowerDifficulty.Hash!); - } + [TestCase(9000000, true)] + [TestCase(9000000, false)] + [TestCase(8000010, true)] + public void Can_reject_block_POW_block_after_TTD(long ttd, bool sendFakeTd) + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + Context ctx = CreateMergeContext(9, (UInt256)ttd); - [TestCase(9000010, true)] - [TestCase(9000010, false)] - public void Can_inject_terminal_block_with_higher_td_than_head(long ttd, bool sendFakeTd) + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + if (sendFakeTd) { - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - Block terminalBlockWithHigherTotalDifficulty = Build.A.Block - .WithDifficulty(1000010) - .WithParent(remoteBlockTree.Head!) - .WithTotalDifficulty(remoteBlockTree.Head!.TotalDifficulty + 1000010) - .TestObject; - remoteBlockTree.SuggestBlock(terminalBlockWithHigherTotalDifficulty); - Context ctx = CreateMergeContext(10, (UInt256)ttd); - Assert.True(terminalBlockWithHigherTotalDifficulty.IsTerminalBlock(ctx.SpecProvider)); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - if (sendFakeTd) - { - block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; - } - - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(9)); - ctx.LocalBlockTree.FindBlock(terminalBlockWithHigherTotalDifficulty.Hash!, BlockTreeLookupOptions.None).Should().NotBeNull(); - ctx.LocalBlockTree.BestSuggestedHeader!.Hash.Should().Be(terminalBlockWithHigherTotalDifficulty.Hash!); + block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; } + Assert.Throws(() => ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock)); + Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(8)); + } - [TestCase(9000010)] - public void PostMerge_block_from_gossip_should_not_override_main_chain(long ttd) + [TestCase(9000000, true)] + [TestCase(9000000, false)] + [TestCase(8000010, true)] + public void Post_merge_blocks_wont_be_accepted_by_gossip(long ttd, bool sendFakeTd) + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + Block postMergeBlock = Build.A.Block + .WithDifficulty(0) + .WithParent(remoteBlockTree.Head!) + .WithTotalDifficulty(remoteBlockTree.Head!.TotalDifficulty) + .WithNonce(0u) + .TestObject; + remoteBlockTree.SuggestBlock(postMergeBlock); + Context ctx = CreateMergeContext(9, (UInt256)ttd); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + if (sendFakeTd) { - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - Block poWBlockPostMerge = Build.A.Block - .WithDifficulty(1000010) - .WithParent(remoteBlockTree.Head!) - .WithTotalDifficulty(remoteBlockTree.Head!.TotalDifficulty + 1000010) - .TestObject; - remoteBlockTree.SuggestBlock(poWBlockPostMerge); - - Context ctx = CreateMergeContext(10, (UInt256)ttd); - Block newPostMergeBlock = Build.A.Block - .WithDifficulty(0) - .WithParent(ctx.LocalBlockTree.Head!) - .WithTotalDifficulty(ctx.LocalBlockTree.Head!.TotalDifficulty) - .TestObject; - ctx.LocalBlockTree.SuggestBlock(newPostMergeBlock); - ctx.LocalBlockTree.UpdateMainChain(new[] { newPostMergeBlock }, true, true); - - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(10)); - ctx.LocalBlockTree.FindBlock(poWBlockPostMerge.Hash!, BlockTreeLookupOptions.None).Should().NotBeNull(); - ctx.LocalBlockTree.BestSuggestedHeader!.Hash.Should().Be(newPostMergeBlock.Hash!); - ctx.LocalBlockTree.FindCanonicalBlockInfo(poWBlockPostMerge.Number).BlockHash.Should().NotBe(poWBlockPostMerge.Hash!); + block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; } + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(8)); + ctx.LocalBlockTree.FindBlock(postMergeBlock.Hash!, BlockTreeLookupOptions.None).Should().BeNull(); + } - private Context CreateMergeContext(int blockTreeChainLength, UInt256 ttd) + [TestCase(9000010, true, 100)] + [TestCase(9000010, false, 100)] + [TestCase(9000010, false, 1000000)] + [TestCase(9000010, true, 1000000)] + public void Can_inject_terminal_block_with_not_higher_td_than_head(long ttd, bool sendFakeTd, long difficulty) + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + Block terminalBlockWithLowerDifficulty = Build.A.Block + .WithDifficulty((UInt256)difficulty) + .WithParent(remoteBlockTree.Head!) + .WithGasLimit(remoteBlockTree.Head!.GasLimit + 1) + .WithTotalDifficulty(remoteBlockTree.Head.TotalDifficulty + (UInt256)difficulty) + .TestObject; + remoteBlockTree.SuggestBlock(terminalBlockWithLowerDifficulty); + Context ctx = CreateMergeContext(10, (UInt256)ttd); + Assert.That(terminalBlockWithLowerDifficulty.IsTerminalBlock(ctx.SpecProvider), Is.True); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + if (sendFakeTd) { - Context ctx = new(); - TestSpecProvider testSpecProvider = new(London.Instance) - { - TerminalTotalDifficulty = ttd, - }; - Block genesis = Build.A.Block.Genesis.TestObject; - BlockTree localBlockTree = Build.A.BlockTree(genesis, testSpecProvider).OfChainLength(blockTreeChainLength).TestObject; - - PoSSwitcher poSSwitcher = new( - new MergeConfig - { - TerminalTotalDifficulty = $"{ttd}" - }, - new SyncConfig(), - new MemDb(), - localBlockTree, - testSpecProvider, - new ChainSpec(), - LimboLogs.Instance); - MergeSealEngine sealEngine = new( - new SealEngine(new NethDevSealEngine(), Always.Valid), - poSSwitcher, - new MergeSealValidator(poSSwitcher, Always.Valid), - LimboLogs.Instance); - HeaderValidator headerValidator = new( - localBlockTree, - sealEngine, - testSpecProvider, - LimboLogs.Instance); - MergeHeaderValidator mergeHeaderValidator = new( - poSSwitcher, - headerValidator, - localBlockTree, - testSpecProvider, - Always.Valid, - LimboLogs.Instance); - - InvalidChainTracker invalidChainTracker = new( - poSSwitcher, - localBlockTree, - new BlockCacheService(), - LimboLogs.Instance); - InvalidHeaderInterceptor headerValidatorWithInterceptor = new( - mergeHeaderValidator, - invalidChainTracker, - LimboLogs.Instance); - BlockValidator blockValidator = new( - Always.Valid, - headerValidatorWithInterceptor, - Always.Valid, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - blockValidator, - sealEngine, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - testSpecProvider, - LimboLogs.Instance); - ctx.SpecProvider = testSpecProvider; - ctx.LocalBlockTree = localBlockTree; - - return ctx; + block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; } + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(9)); + ctx.LocalBlockTree.FindBlock(terminalBlockWithLowerDifficulty.Hash!, BlockTreeLookupOptions.None).Should().NotBeNull(); + ctx.LocalBlockTree.BestSuggestedHeader!.Hash.Should().NotBe(terminalBlockWithLowerDifficulty.Hash!); + } - [Test] - public void Will_not_reject_block_with_bad_total_diff_but_will_reset_diff_to_null() + [TestCase(9000010, true)] + [TestCase(9000010, false)] + public void Can_inject_terminal_block_with_higher_td_than_head(long ttd, bool sendFakeTd) + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + Block terminalBlockWithHigherTotalDifficulty = Build.A.Block + .WithDifficulty(1000010) + .WithParent(remoteBlockTree.Head!) + .WithTotalDifficulty(remoteBlockTree.Head!.TotalDifficulty + 1000010) + .TestObject; + remoteBlockTree.SuggestBlock(terminalBlockWithHigherTotalDifficulty); + Context ctx = CreateMergeContext(10, (UInt256)ttd); + Assert.That(terminalBlockWithHigherTotalDifficulty.IsTerminalBlock(ctx.SpecProvider), Is.True); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + if (sendFakeTd) { - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - - HeaderValidator headerValidator = new( - localBlockTree, - Always.Valid, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - - BlockValidator blockValidator = new( - Always.Valid, - headerValidator, - Always.Valid, - MainnetSpecProvider.Instance, - LimboLogs.Instance); + block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; + } - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - blockValidator, - Always.Valid, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(9)); + ctx.LocalBlockTree.FindBlock(terminalBlockWithHigherTotalDifficulty.Hash!, BlockTreeLookupOptions.None).Should().NotBeNull(); + ctx.LocalBlockTree.BestSuggestedHeader!.Hash.Should().Be(terminalBlockWithHigherTotalDifficulty.Hash!); + } - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); - Assert.That(block.Header.Hash, Is.EqualTo(localBlockTree.BestSuggestedHeader!.Hash)); + [TestCase(9000010)] + public void PostMerge_block_from_gossip_should_not_override_main_chain(long ttd) + { + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + Block poWBlockPostMerge = Build.A.Block + .WithDifficulty(1000010) + .WithParent(remoteBlockTree.Head!) + .WithTotalDifficulty(remoteBlockTree.Head!.TotalDifficulty + 1000010) + .TestObject; + remoteBlockTree.SuggestBlock(poWBlockPostMerge); + + Context ctx = CreateMergeContext(10, (UInt256)ttd); + Block newPostMergeBlock = Build.A.Block + .WithDifficulty(0) + .WithParent(ctx.LocalBlockTree.Head!) + .WithTotalDifficulty(ctx.LocalBlockTree.Head!.TotalDifficulty) + .TestObject; + ctx.LocalBlockTree.SuggestBlock(newPostMergeBlock); + ctx.LocalBlockTree.UpdateMainChain(new[] { newPostMergeBlock }, true, true); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + Assert.That(ctx.LocalBlockTree.BestSuggestedHeader!.Number, Is.EqualTo(10)); + ctx.LocalBlockTree.FindBlock(poWBlockPostMerge.Hash!, BlockTreeLookupOptions.None).Should().NotBeNull(); + ctx.LocalBlockTree.BestSuggestedHeader!.Hash.Should().Be(newPostMergeBlock.Hash!); + ctx.LocalBlockTree.FindCanonicalBlockInfo(poWBlockPostMerge.Number).BlockHash.Should().NotBe(poWBlockPostMerge.Hash!); + } - Block? parentBlock = remoteBlockTree.FindBlock(8, BlockTreeLookupOptions.None); - Assert.That(localBlockTree.BestSuggestedHeader.TotalDifficulty, Is.EqualTo(parentBlock!.TotalDifficulty + block.Difficulty)); - } - [Test] - public void Rejects_new_old_blocks() + private Context CreateMergeContext(int blockTreeChainLength, UInt256 ttd) + { + Context ctx = new(); + TestSpecProvider testSpecProvider = new(London.Instance) { - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(600).TestObject; + TerminalTotalDifficulty = ttd, + }; + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree localBlockTree = Build.A.BlockTree(genesis, testSpecProvider).OfChainLength(blockTreeChainLength).TestObject; - ISealValidator sealValidator = Substitute.For(); - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - Always.Valid, - sealValidator, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); + PoSSwitcher poSSwitcher = new( + new MergeConfig + { + TerminalTotalDifficulty = $"{ttd}" + }, + new SyncConfig(), + new MemDb(), + localBlockTree, + testSpecProvider, + new ChainSpec(), + LimboLogs.Instance); + MergeSealEngine sealEngine = new( + new SealEngine(new NethDevSealEngine(), Always.Valid), + poSSwitcher, + new MergeSealValidator(poSSwitcher, Always.Valid), + LimboLogs.Instance); + HeaderValidator headerValidator = new( + localBlockTree, + sealEngine, + testSpecProvider, + LimboLogs.Instance); + MergeHeaderValidator mergeHeaderValidator = new( + poSSwitcher, + headerValidator, + localBlockTree, + testSpecProvider, + Always.Valid, + LimboLogs.Instance); + + InvalidChainTracker invalidChainTracker = new( + poSSwitcher, + localBlockTree, + new BlockCacheService(), + LimboLogs.Instance); + InvalidHeaderInterceptor headerValidatorWithInterceptor = new( + mergeHeaderValidator, + invalidChainTracker, + LimboLogs.Instance); + BlockValidator blockValidator = new( + Always.Valid, + headerValidatorWithInterceptor, + Always.Valid, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + blockValidator, + sealEngine, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + testSpecProvider, + LimboLogs.Instance); + ctx.SpecProvider = testSpecProvider; + ctx.LocalBlockTree = localBlockTree; + + return ctx; + } - Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; - ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + [Test] + public void Will_not_reject_block_with_bad_total_diff_but_will_reset_diff_to_null() + { + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + + HeaderValidator headerValidator = new( + localBlockTree, + Always.Valid, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + BlockValidator blockValidator = new( + Always.Valid, + headerValidator, + Always.Valid, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + blockValidator, + Always.Valid, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + block.Header.TotalDifficulty = block.Header.TotalDifficulty * 2; + + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + Assert.That(block.Header.Hash, Is.EqualTo(localBlockTree.BestSuggestedHeader!.Hash)); + + Block? parentBlock = remoteBlockTree.FindBlock(8, BlockTreeLookupOptions.None); + Assert.That(localBlockTree.BestSuggestedHeader.TotalDifficulty, Is.EqualTo(parentBlock!.TotalDifficulty + block.Difficulty)); + } - sealValidator.DidNotReceive().ValidateSeal(Arg.Any(), Arg.Any()); - } + [Test] + public void Rejects_new_old_blocks() + { + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(600).TestObject; + + ISealValidator sealValidator = Substitute.For(); + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + Always.Valid, + sealValidator, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + Block block = remoteBlockTree.FindBlock(9, BlockTreeLookupOptions.None)!; + + ctx.SyncServer.AddNewBlock(block, ctx.NodeWhoSentTheBlock); + + sealValidator.DidNotReceive().ValidateSeal(Arg.Any(), Arg.Any()); + } - [Test] - public async Task Broadcast_NewBlock_on_arrival() - { - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - Always.Valid, - Always.Valid, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); + [Test] + public async Task Broadcast_NewBlock_on_arrival() + { + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + Always.Valid, + Always.Valid, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + ISyncServer remoteServer1 = Substitute.For(); + SyncPeerMock syncPeerMock1 = new(remoteBlockTree, TestItem.PublicKeyA, remoteSyncServer: remoteServer1); + PeerInfo peer1 = new(syncPeerMock1); + ISyncServer remoteServer2 = Substitute.For(); + SyncPeerMock syncPeerMock2 = new(remoteBlockTree, TestItem.PublicKeyB, remoteSyncServer: remoteServer2); + PeerInfo peer2 = new(syncPeerMock2); + PeerInfo[] peers = { peer1, peer2 }; + ctx.PeerPool.AllPeers.Returns(peers); + ctx.PeerPool.PeerCount.Returns(peers.Length); + ctx.SyncServer.AddNewBlock(remoteBlockTree.Head!, peer1.SyncPeer); + ctx.SyncServer.AddNewBlock(remoteBlockTree.Head!, peer2.SyncPeer); + await Task.Delay(100); // notifications fire on separate task + await Task.WhenAll(syncPeerMock1.Close(), syncPeerMock2.Close()); + remoteServer1.DidNotReceive().AddNewBlock(remoteBlockTree.Head!, Arg.Any()); + remoteServer2.Received().AddNewBlock(Arg.Is(b => b.Hash == remoteBlockTree.Head!.Hash), Arg.Any()); + } - ISyncServer remoteServer1 = Substitute.For(); - SyncPeerMock syncPeerMock1 = new(remoteBlockTree, TestItem.PublicKeyA, remoteSyncServer: remoteServer1); - PeerInfo peer1 = new(syncPeerMock1); - ISyncServer remoteServer2 = Substitute.For(); - SyncPeerMock syncPeerMock2 = new(remoteBlockTree, TestItem.PublicKeyB, remoteSyncServer: remoteServer2); - PeerInfo peer2 = new(syncPeerMock2); - PeerInfo[] peers = { peer1, peer2 }; - ctx.PeerPool.AllPeers.Returns(peers); - ctx.PeerPool.PeerCount.Returns(peers.Length); - ctx.SyncServer.AddNewBlock(remoteBlockTree.Head!, peer1.SyncPeer); - ctx.SyncServer.AddNewBlock(remoteBlockTree.Head!, peer2.SyncPeer); - await Task.Delay(100); // notifications fire on separate task - await Task.WhenAll(syncPeerMock1.Close(), syncPeerMock2.Close()); - remoteServer1.DidNotReceive().AddNewBlock(remoteBlockTree.Head!, Arg.Any()); - remoteServer2.Received().AddNewBlock(Arg.Is(b => b.Hash == remoteBlockTree.Head!.Hash), Arg.Any()); - } + [Test] + public async Task Skip_known_block() + { + Context ctx = new(); + BlockTree blockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + blockTree, + NullReceiptStorage.Instance, + Always.Valid, + Always.Valid, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + ISyncServer remoteServer1 = Substitute.For(); + SyncPeerMock syncPeerMock1 = new(blockTree, TestItem.PublicKeyA, remoteSyncServer: remoteServer1); + PeerInfo peer1 = new(syncPeerMock1); + ISyncServer remoteServer2 = Substitute.For(); + SyncPeerMock syncPeerMock2 = new(blockTree, TestItem.PublicKeyB, remoteSyncServer: remoteServer2); + PeerInfo peer2 = new(syncPeerMock2); + PeerInfo[] peers = { peer1, peer2 }; + ctx.PeerPool.AllPeers.Returns(peers); + ctx.PeerPool.PeerCount.Returns(peers.Length); + Block head = blockTree.Head!; + ctx.SyncServer.AddNewBlock(head, peer1.SyncPeer); + await Task.Delay(100); // notifications fire on separate task + await Task.WhenAll(syncPeerMock1.Close(), syncPeerMock2.Close()); + remoteServer1.DidNotReceive().AddNewBlock(head, Arg.Any()); + remoteServer2.DidNotReceive().AddNewBlock(head, Arg.Any()); + blockTree.FindLevel(head.Number)!.BlockInfos.Length.Should().Be(1); + } - [Test] - public async Task Skip_known_block() - { - Context ctx = new(); - BlockTree blockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - ctx.SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - blockTree, - NullReceiptStorage.Instance, - Always.Valid, - Always.Valid, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); + [Test] + [Retry(3)] + public async Task Broadcast_NewBlock_on_arrival_to_sqrt_of_peers([Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 50, 100)] int peerCount) + { + int expectedPeers = (int)Math.Ceiling(Math.Sqrt(peerCount - 1)); // -1 because of ignoring sender + + Context ctx = new(); + BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; + ctx.SyncServer = new SyncServer( + new MemDb(), + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + Always.Valid, + Always.Valid, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + ISyncServer remoteServer = Substitute.For(); + int count = 0; + remoteServer + .When(r => r.AddNewBlock(Arg.Is(b => b.Hash == remoteBlockTree.Head!.Hash), Arg.Any())) + .Do(_ => count++); + PeerInfo[] peers = Enumerable.Range(0, peerCount).Take(peerCount) + .Select(_ => new PeerInfo(new SyncPeerMock(remoteBlockTree, remoteSyncServer: remoteServer))) + .ToArray(); + ctx.PeerPool.AllPeers.Returns(peers); + ctx.PeerPool.PeerCount.Returns(peers.Length); + ctx.SyncServer.AddNewBlock(remoteBlockTree.Head!, peers[0].SyncPeer); + + Assert.That(() => count, Is.EqualTo(expectedPeers).After(5000, 100)); + await Task.WhenAll(peers.Select(p => ((SyncPeerMock)p.SyncPeer).Close()).ToArray()); + } - ISyncServer remoteServer1 = Substitute.For(); - SyncPeerMock syncPeerMock1 = new(blockTree, TestItem.PublicKeyA, remoteSyncServer: remoteServer1); - PeerInfo peer1 = new(syncPeerMock1); - ISyncServer remoteServer2 = Substitute.For(); - SyncPeerMock syncPeerMock2 = new(blockTree, TestItem.PublicKeyB, remoteSyncServer: remoteServer2); - PeerInfo peer2 = new(syncPeerMock2); - PeerInfo[] peers = { peer1, peer2 }; - ctx.PeerPool.AllPeers.Returns(peers); - ctx.PeerPool.PeerCount.Returns(peers.Length); - Block head = blockTree.Head!; - ctx.SyncServer.AddNewBlock(head, peer1.SyncPeer); - await Task.Delay(100); // notifications fire on separate task - await Task.WhenAll(syncPeerMock1.Close(), syncPeerMock2.Close()); - remoteServer1.DidNotReceive().AddNewBlock(head, Arg.Any()); - remoteServer2.DidNotReceive().AddNewBlock(head, Arg.Any()); - blockTree.FindLevel(head.Number)!.BlockInfos.Length.Should().Be(1); - } + [Test] + public void GetNodeData_returns_cached_trie_nodes() + { + Context ctx = new(); + BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(600).TestObject; + ISealValidator sealValidator = Substitute.For(); + MemDb stateDb = new(); + TrieStore trieStore = new(stateDb, Prune.WhenCacheReaches(10.MB()), NoPersistence.Instance, LimboLogs.Instance); + ctx.SyncServer = new SyncServer( + trieStore.TrieNodeRlpStore, + new MemDb(), + localBlockTree, + NullReceiptStorage.Instance, + Always.Valid, + sealValidator, + ctx.PeerPool, + StaticSelector.Full, + new SyncConfig(), + Policy.FullGossip, + MainnetSpecProvider.Instance, + LimboLogs.Instance); + + Hash256 nodeKey = TestItem.KeccakA; + TrieNode node = new(NodeType.Leaf, nodeKey, TestItem.KeccakB.Bytes); + IScopedTrieStore scopedTrieStore = trieStore.GetTrieStore(null); + scopedTrieStore.CommitNode(1, new NodeCommitInfo(node, TreePath.Empty)); + scopedTrieStore.FinishBlockCommit(TrieType.State, 1, node); + + stateDb.KeyExists(nodeKey).Should().BeFalse(); + ctx.SyncServer.GetNodeData(new[] { nodeKey }, CancellationToken.None, NodeDataType.All).Should().BeEquivalentTo(new[] { TestItem.KeccakB.BytesToArray() }); + } - [Test] - [Retry(3)] - public async Task Broadcast_NewBlock_on_arrival_to_sqrt_of_peers([Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 50, 100)] int peerCount) + private class Context + { + public Context() { - int expectedPeers = (int)Math.Ceiling(Math.Sqrt(peerCount - 1)); // -1 because of ignoring sender + NodeWhoSentTheBlock = Substitute.For(); + NodeWhoSentTheBlock.Node.Returns(new Node(TestItem.PublicKeyA, "127.0.0.1", 30303)); + PeerPool = Substitute.For(); - Context ctx = new(); - BlockTree remoteBlockTree = Build.A.BlockTree().OfChainLength(10).TestObject; - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(9).TestObject; - ctx.SyncServer = new SyncServer( + BlockTree = Substitute.For(); + StaticSelector selector = StaticSelector.Full; + SyncServer = new SyncServer( new MemDb(), new MemDb(), - localBlockTree, + BlockTree, NullReceiptStorage.Instance, Always.Valid, Always.Valid, - ctx.PeerPool, - StaticSelector.Full, + PeerPool, + selector, new SyncConfig(), Policy.FullGossip, MainnetSpecProvider.Instance, LimboLogs.Instance); - - ISyncServer remoteServer = Substitute.For(); - int count = 0; - remoteServer - .When(r => r.AddNewBlock(Arg.Is(b => b.Hash == remoteBlockTree.Head!.Hash), Arg.Any())) - .Do(_ => count++); - PeerInfo[] peers = Enumerable.Range(0, peerCount).Take(peerCount) - .Select(_ => new PeerInfo(new SyncPeerMock(remoteBlockTree, remoteSyncServer: remoteServer))) - .ToArray(); - ctx.PeerPool.AllPeers.Returns(peers); - ctx.PeerPool.PeerCount.Returns(peers.Length); - ctx.SyncServer.AddNewBlock(remoteBlockTree.Head!, peers[0].SyncPeer); - - Assert.That(() => count, Is.EqualTo(expectedPeers).After(5000, 100)); - await Task.WhenAll(peers.Select(p => ((SyncPeerMock)p.SyncPeer).Close()).ToArray()); } - [Test] - public void GetNodeData_returns_cached_trie_nodes() - { - Context ctx = new(); - BlockTree localBlockTree = Build.A.BlockTree().OfChainLength(600).TestObject; - ISealValidator sealValidator = Substitute.For(); - MemDb stateDb = new(); - TrieStore trieStore = new(stateDb, Prune.WhenCacheReaches(10.MB()), NoPersistence.Instance, LimboLogs.Instance); - ctx.SyncServer = new SyncServer( - trieStore.TrieNodeRlpStore, - new MemDb(), - localBlockTree, - NullReceiptStorage.Instance, - Always.Valid, - sealValidator, - ctx.PeerPool, - StaticSelector.Full, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - - Hash256 nodeKey = TestItem.KeccakA; - TrieNode node = new(NodeType.Leaf, nodeKey, TestItem.KeccakB.Bytes); - IScopedTrieStore scopedTrieStore = trieStore.GetTrieStore(null); - scopedTrieStore.CommitNode(1, new NodeCommitInfo(node, TreePath.Empty)); - scopedTrieStore.FinishBlockCommit(TrieType.State, 1, node); - - stateDb.KeyExists(nodeKey).Should().BeFalse(); - ctx.SyncServer.GetNodeData(new[] { nodeKey }, CancellationToken.None, NodeDataType.All).Should().BeEquivalentTo(new[] { TestItem.KeccakB.BytesToArray() }); - } + public IBlockTree BlockTree { get; } + public ISyncPeerPool PeerPool { get; } + public SyncServer SyncServer { get; set; } + public ISpecProvider SpecProvider { get; set; } = null!; - private class Context - { - public Context() - { - NodeWhoSentTheBlock = Substitute.For(); - NodeWhoSentTheBlock.Node.Returns(new Node(TestItem.PublicKeyA, "127.0.0.1", 30303)); - PeerPool = Substitute.For(); - - BlockTree = Substitute.For(); - StaticSelector selector = StaticSelector.Full; - SyncServer = new SyncServer( - new MemDb(), - new MemDb(), - BlockTree, - NullReceiptStorage.Instance, - Always.Valid, - Always.Valid, - PeerPool, - selector, - new SyncConfig(), - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); - } - - public IBlockTree BlockTree { get; } - public ISyncPeerPool PeerPool { get; } - public SyncServer SyncServer { get; set; } - public ISpecProvider SpecProvider { get; set; } = null!; - - public IBlockTree LocalBlockTree { get; set; } = null!; - public ISyncPeer NodeWhoSentTheBlock { get; } - } + public IBlockTree LocalBlockTree { get; set; } = null!; + public ISyncPeer NodeWhoSentTheBlock { get; } } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index 6509942731e..872499cf73f 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -40,955 +40,954 @@ using NUnit.Framework; using Nethermind.Trie; -namespace Nethermind.Synchronization.Test +namespace Nethermind.Synchronization.Test; + +[TestFixture(SynchronizerType.Fast)] +[TestFixture(SynchronizerType.Full)] +[TestFixture(SynchronizerType.Eth2MergeFull)] +[TestFixture(SynchronizerType.Eth2MergeFast)] +[TestFixture(SynchronizerType.Eth2MergeFastWithoutTTD)] +[TestFixture(SynchronizerType.Eth2MergeFullWithoutTTD)] +[Parallelizable(ParallelScope.Self)] +public class SynchronizerTests { - [TestFixture(SynchronizerType.Fast)] - [TestFixture(SynchronizerType.Full)] - [TestFixture(SynchronizerType.Eth2MergeFull)] - [TestFixture(SynchronizerType.Eth2MergeFast)] - [TestFixture(SynchronizerType.Eth2MergeFastWithoutTTD)] - [TestFixture(SynchronizerType.Eth2MergeFullWithoutTTD)] - [Parallelizable(ParallelScope.Self)] - public class SynchronizerTests - { - private readonly SynchronizerType _synchronizerType; + private readonly SynchronizerType _synchronizerType; - public SynchronizerTests(SynchronizerType synchronizerType) - { - _synchronizerType = synchronizerType; - } + public SynchronizerTests(SynchronizerType synchronizerType) + { + _synchronizerType = synchronizerType; + } - private static readonly Block _genesisBlock = Build.A.Block - .Genesis - .WithDifficulty(100000) - .WithTotalDifficulty((UInt256)100000).TestObject; + private static readonly Block _genesisBlock = Build.A.Block + .Genesis + .WithDifficulty(100000) + .WithTotalDifficulty((UInt256)100000).TestObject; - private class SyncPeerMock : ISyncPeer - { - public string Name => "Mock"; + private class SyncPeerMock : ISyncPeer + { + public string Name => "Mock"; - private readonly bool _causeTimeoutOnInit; - private readonly bool _causeTimeoutOnBlocks; - private readonly bool _causeTimeoutOnHeaders; - private List Blocks { get; } = new(); + private readonly bool _causeTimeoutOnInit; + private readonly bool _causeTimeoutOnBlocks; + private readonly bool _causeTimeoutOnHeaders; + private List Blocks { get; } = new(); - public Block HeadBlock => Blocks.Last(); + public Block HeadBlock => Blocks.Last(); - public BlockHeader HeadHeader => HeadBlock.Header; + public BlockHeader HeadHeader => HeadBlock.Header; - public SyncPeerMock( - string peerName, - bool causeTimeoutOnInit = false, - bool causeTimeoutOnBlocks = false, - bool causeTimeoutOnHeaders = false) - { - _causeTimeoutOnInit = causeTimeoutOnInit; - _causeTimeoutOnBlocks = causeTimeoutOnBlocks; - _causeTimeoutOnHeaders = causeTimeoutOnHeaders; - Blocks.Add(_genesisBlock); - UpdateHead(); - ClientId = peerName; - } + public SyncPeerMock( + string peerName, + bool causeTimeoutOnInit = false, + bool causeTimeoutOnBlocks = false, + bool causeTimeoutOnHeaders = false) + { + _causeTimeoutOnInit = causeTimeoutOnInit; + _causeTimeoutOnBlocks = causeTimeoutOnBlocks; + _causeTimeoutOnHeaders = causeTimeoutOnHeaders; + Blocks.Add(_genesisBlock); + UpdateHead(); + ClientId = peerName; + } - private void UpdateHead() - { - HeadHash = HeadBlock.Hash!; - HeadNumber = HeadBlock.Number; - TotalDifficulty = HeadBlock.TotalDifficulty ?? 0; - } + private void UpdateHead() + { + HeadHash = HeadBlock.Hash!; + HeadNumber = HeadBlock.Number; + TotalDifficulty = HeadBlock.TotalDifficulty ?? 0; + } - public Node Node { get; } = new Node(Build.A.PrivateKey.TestObject.PublicKey, "127.0.0.1", 1234); + public Node Node { get; } = new Node(Build.A.PrivateKey.TestObject.PublicKey, "127.0.0.1", 1234); - public string ClientId { get; } - public Hash256 HeadHash { get; set; } = null!; - public byte ProtocolVersion { get; } = default; - public string ProtocolCode { get; } = null!; - public long HeadNumber { get; set; } - public UInt256 TotalDifficulty { get; set; } + public string ClientId { get; } + public Hash256 HeadHash { get; set; } = null!; + public byte ProtocolVersion { get; } = default; + public string ProtocolCode { get; } = null!; + public long HeadNumber { get; set; } + public UInt256 TotalDifficulty { get; set; } - public bool IsInitialized { get; set; } - public bool IsPriority { get; set; } + public bool IsInitialized { get; set; } + public bool IsPriority { get; set; } - public void Disconnect(DisconnectReason reason, string details) - { - Disconnected?.Invoke(this, EventArgs.Empty); - } + public void Disconnect(DisconnectReason reason, string details) + { + Disconnected?.Invoke(this, EventArgs.Empty); + } - public Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) + public Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) + { + if (_causeTimeoutOnBlocks) { - if (_causeTimeoutOnBlocks) - { - return Task.FromException(new TimeoutException()); - } - - BlockBody[] result = new BlockBody[blockHashes.Count]; - for (int i = 0; i < blockHashes.Count; i++) - { - foreach (Block block in Blocks) - { - if (block.Hash == blockHashes[i]) - { - result[i] = new BlockBody(block.Transactions, block.Uncles); - } - } - } - - return Task.FromResult(new OwnedBlockBodies(result)); + return Task.FromException(new TimeoutException()); } - public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + BlockBody[] result = new BlockBody[blockHashes.Count]; + for (int i = 0; i < blockHashes.Count; i++) { - if (_causeTimeoutOnHeaders) - { - return Task.FromException?>(new TimeoutException()); - } - - int filled = 0; - bool started = false; - ArrayPoolList result = new ArrayPoolList(maxBlocks, maxBlocks); foreach (Block block in Blocks) { - if (block.Number == number) - { - started = true; - } - - if (started) - { - result[filled++] = block.Header; - } - - if (filled >= maxBlocks) + if (block.Hash == blockHashes[i]) { - break; + result[i] = new BlockBody(block.Transactions, block.Uncles); } } - - return Task.FromResult?>(result); } - public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + return Task.FromResult(new OwnedBlockBodies(result)); + } + + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + { + if (_causeTimeoutOnHeaders) { - throw new NotImplementedException(); + return Task.FromException?>(new TimeoutException()); } - public async Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) + int filled = 0; + bool started = false; + ArrayPoolList result = new ArrayPoolList(maxBlocks, maxBlocks); + foreach (Block block in Blocks) { - if (_causeTimeoutOnInit) + if (block.Number == number) { - Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER WITH EXCEPTION"); - await Task.FromException(new TimeoutException()); + started = true; } - BlockHeader header; - try + if (started) { - header = Blocks.Last().Header; + result[filled++] = block.Header; } - catch (Exception) + + if (filled >= maxBlocks) { - Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER EXCEPTION"); - throw; + break; } - - Console.WriteLine($"RESPONDING TO GET HEAD BLOCK HEADER WITH RESULT {header.Number}"); - return header; } - public void NotifyOfNewBlock(Block block, SendBlockMode mode) - { - if (mode == SendBlockMode.FullBlock) - ReceivedBlocks.Push(block); - } - - public ConcurrentStack ReceivedBlocks { get; } = new(); - - public event EventHandler? Disconnected; - - public PublicKey Id => Node.Id; + return Task.FromResult?>(result); + } - public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { } + public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + { + throw new NotImplementedException(); + } - public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) + public async Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) + { + if (_causeTimeoutOnInit) { - throw new NotImplementedException(); + Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER WITH EXCEPTION"); + await Task.FromException(new TimeoutException()); } - public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) + BlockHeader header; + try { - throw new NotImplementedException(); + header = Blocks.Last().Header; } - - public void AddBlocksUpTo(int i, int branchStart = 0, byte branchIndex = 0) + catch (Exception) { - Block block = Blocks.Last(); - for (long j = block.Number; j < i; j++) - { - block = Build.A.Block.WithDifficulty(1000000).WithParent(block) - .WithTotalDifficulty(block.TotalDifficulty + 1000000) - .WithExtraData(j < branchStart ? Array.Empty() : new[] { branchIndex }).TestObject; - Blocks.Add(block); - } - - UpdateHead(); + Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER EXCEPTION"); + throw; } - public void AddHighDifficultyBlocksUpTo(int i, int branchStart = 0, byte branchIndex = 0) - { - Block block = Blocks.Last(); - for (long j = block.Number; j < i; j++) - { - block = Build.A.Block.WithParent(block).WithDifficulty(2000000) - .WithTotalDifficulty(block.TotalDifficulty + 2000000) - .WithExtraData(j < branchStart ? Array.Empty() : new[] { branchIndex }).TestObject; - Blocks.Add(block); - } + Console.WriteLine($"RESPONDING TO GET HEAD BLOCK HEADER WITH RESULT {header.Number}"); + return header; + } - UpdateHead(); - } + public void NotifyOfNewBlock(Block block, SendBlockMode mode) + { + if (mode == SendBlockMode.FullBlock) + ReceivedBlocks.Push(block); + } - public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class - { - throw new NotImplementedException(); - } + public ConcurrentStack ReceivedBlocks { get; } = new(); - public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class - { - throw new NotImplementedException(); - } + public event EventHandler? Disconnected; + + public PublicKey Id => Node.Id; + + public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { } + + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) + { + throw new NotImplementedException(); } - private WhenImplementation When => new(_synchronizerType); + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) + { + throw new NotImplementedException(); + } - private class WhenImplementation + public void AddBlocksUpTo(int i, int branchStart = 0, byte branchIndex = 0) { - private readonly SynchronizerType _synchronizerType; + Block block = Blocks.Last(); + for (long j = block.Number; j < i; j++) + { + block = Build.A.Block.WithDifficulty(1000000).WithParent(block) + .WithTotalDifficulty(block.TotalDifficulty + 1000000) + .WithExtraData(j < branchStart ? Array.Empty() : new[] { branchIndex }).TestObject; + Blocks.Add(block); + } + + UpdateHead(); + } - public WhenImplementation(SynchronizerType synchronizerType) + public void AddHighDifficultyBlocksUpTo(int i, int branchStart = 0, byte branchIndex = 0) + { + Block block = Blocks.Last(); + for (long j = block.Number; j < i; j++) { - _synchronizerType = synchronizerType; + block = Build.A.Block.WithParent(block).WithDifficulty(2000000) + .WithTotalDifficulty(block.TotalDifficulty + 2000000) + .WithExtraData(j < branchStart ? Array.Empty() : new[] { branchIndex }).TestObject; + Blocks.Add(block); } - public SyncingContext Syncing => new(_synchronizerType); + UpdateHead(); } - public class SyncingContext + public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class { - public static ConcurrentQueue AllInstances { get; } = new(); + throw new NotImplementedException(); + } - private readonly Dictionary _peers = new(); - private BlockTree BlockTree { get; } + public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class + { + throw new NotImplementedException(); + } + } - private ISyncServer SyncServer { get; } + private WhenImplementation When => new(_synchronizerType); - private ISynchronizer Synchronizer { get; } + private class WhenImplementation + { + private readonly SynchronizerType _synchronizerType; - private ISyncPeerPool SyncPeerPool { get; } + public WhenImplementation(SynchronizerType synchronizerType) + { + _synchronizerType = synchronizerType; + } - readonly ILogManager _logManager = LimboLogs.Instance; + public SyncingContext Syncing => new(_synchronizerType); + } - private readonly ILogger _logger; + public class SyncingContext + { + public static ConcurrentQueue AllInstances { get; } = new(); - public SyncingContext(SynchronizerType synchronizerType) - { - ISyncConfig GetSyncConfig() => - synchronizerType switch - { - SynchronizerType.Fast => SyncConfig.WithFastSync, - SynchronizerType.Full => SyncConfig.WithFullSyncOnly, - SynchronizerType.Eth2MergeFastWithoutTTD => SyncConfig.WithFastSync, - SynchronizerType.Eth2MergeFullWithoutTTD => SyncConfig.WithFullSyncOnly, - SynchronizerType.Eth2MergeFast => SyncConfig.WithFastSync, - SynchronizerType.Eth2MergeFull => SyncConfig.WithFullSyncOnly, - _ => throw new ArgumentOutOfRangeException(nameof(synchronizerType), synchronizerType, null) - }; - - _logger = _logManager.GetClassLogger(); - ISyncConfig syncConfig = GetSyncConfig(); - syncConfig.MultiSyncModeSelectorLoopTimerMs = 1; - - IDbProvider dbProvider = TestMemDbProvider.Init(); - IDb stateDb = new MemDb(); - IDb codeDb = dbProvider.CodeDb; - BlockTree = Build.A.BlockTree() - .WithSpecProvider(new TestSingleReleaseSpecProvider(Constantinople.Instance)) - .WithoutSettingHead - .TestObject; - - ITimerFactory timerFactory = Substitute.For(); - NodeStatsManager stats = new(timerFactory, _logManager); - - MergeConfig mergeConfig = new(); - if (WithTTD(synchronizerType)) - { - mergeConfig.TerminalTotalDifficulty = UInt256.MaxValue.ToString(CultureInfo.InvariantCulture); - } - PoSSwitcher poSSwitcher = new(mergeConfig, syncConfig, dbProvider.MetadataDb, BlockTree, new TestSingleReleaseSpecProvider(Constantinople.Instance), new ChainSpec(), _logManager); - IBeaconPivot beaconPivot = new BeaconPivot(syncConfig, dbProvider.MetadataDb, BlockTree, poSSwitcher, _logManager); + private readonly Dictionary _peers = new(); + private BlockTree BlockTree { get; } - TrieStore trieStore = new(stateDb, LimboLogs.Instance); - TotalDifficultyBetterPeerStrategy totalDifficultyBetterPeerStrategy = new(LimboLogs.Instance); - IBetterPeerStrategy bestPeerStrategy = IsMerge(synchronizerType) - ? new MergeBetterPeerStrategy(totalDifficultyBetterPeerStrategy, poSSwitcher, beaconPivot, LimboLogs.Instance) - : totalDifficultyBetterPeerStrategy; + private ISyncServer SyncServer { get; } - StateReader reader = new StateReader(trieStore, codeDb, LimboLogs.Instance); - FullStateFinder fullStateFinder = new FullStateFinder(BlockTree, reader); - INodeStorage nodeStorage = new NodeStorage(dbProvider.StateDb); + private ISynchronizer Synchronizer { get; } - SyncPeerPool = new SyncPeerPool(BlockTree, stats, bestPeerStrategy, _logManager, 25); - Pivot pivot = new(syncConfig); + private ISyncPeerPool SyncPeerPool { get; } - IInvalidChainTracker invalidChainTracker = new NoopInvalidChainTracker(); - if (IsMerge(synchronizerType)) - { - IBlockDownloaderFactory blockDownloaderFactory = new MergeBlockDownloaderFactory( - poSSwitcher, - beaconPivot, - MainnetSpecProvider.Instance, - Always.Valid, - Always.Valid, - syncConfig, - bestPeerStrategy, - fullStateFinder, - _logManager - ); - Synchronizer = new MergeSynchronizer( - dbProvider, - nodeStorage, - MainnetSpecProvider.Instance, - BlockTree, - NullReceiptStorage.Instance, - SyncPeerPool, - stats, - syncConfig, - blockDownloaderFactory, - pivot, - poSSwitcher, - mergeConfig, - invalidChainTracker, - Substitute.For(), - bestPeerStrategy, - new ChainSpec(), - No.BeaconSync, - reader, - _logManager); - } - else - { - IBlockDownloaderFactory blockDownloaderFactory = new BlockDownloaderFactory( - MainnetSpecProvider.Instance, - Always.Valid, - Always.Valid, - new TotalDifficultyBetterPeerStrategy(_logManager), - _logManager); - - Synchronizer = new Synchronizer( - dbProvider, - nodeStorage, - MainnetSpecProvider.Instance, - BlockTree, - NullReceiptStorage.Instance, - SyncPeerPool, - stats, - syncConfig, - blockDownloaderFactory, - pivot, - Substitute.For(), - bestPeerStrategy, - new ChainSpec(), - reader, - _logManager); - } + readonly ILogManager _logManager = LimboLogs.Instance; - SyncServer = new SyncServer( - trieStore.TrieNodeRlpStore, - codeDb, - BlockTree, - NullReceiptStorage.Instance, + private readonly ILogger _logger; + + public SyncingContext(SynchronizerType synchronizerType) + { + ISyncConfig GetSyncConfig() => + synchronizerType switch + { + SynchronizerType.Fast => SyncConfig.WithFastSync, + SynchronizerType.Full => SyncConfig.WithFullSyncOnly, + SynchronizerType.Eth2MergeFastWithoutTTD => SyncConfig.WithFastSync, + SynchronizerType.Eth2MergeFullWithoutTTD => SyncConfig.WithFullSyncOnly, + SynchronizerType.Eth2MergeFast => SyncConfig.WithFastSync, + SynchronizerType.Eth2MergeFull => SyncConfig.WithFullSyncOnly, + _ => throw new ArgumentOutOfRangeException(nameof(synchronizerType), synchronizerType, null) + }; + + _logger = _logManager.GetClassLogger(); + ISyncConfig syncConfig = GetSyncConfig(); + syncConfig.MultiSyncModeSelectorLoopTimerMs = 1; + + IDbProvider dbProvider = TestMemDbProvider.Init(); + IDb stateDb = new MemDb(); + IDb codeDb = dbProvider.CodeDb; + BlockTree = Build.A.BlockTree() + .WithSpecProvider(new TestSingleReleaseSpecProvider(Constantinople.Instance)) + .WithoutSettingHead + .TestObject; + + ITimerFactory timerFactory = Substitute.For(); + NodeStatsManager stats = new(timerFactory, _logManager); + + MergeConfig mergeConfig = new(); + if (WithTTD(synchronizerType)) + { + mergeConfig.TerminalTotalDifficulty = UInt256.MaxValue.ToString(CultureInfo.InvariantCulture); + } + PoSSwitcher poSSwitcher = new(mergeConfig, syncConfig, dbProvider.MetadataDb, BlockTree, new TestSingleReleaseSpecProvider(Constantinople.Instance), new ChainSpec(), _logManager); + IBeaconPivot beaconPivot = new BeaconPivot(syncConfig, dbProvider.MetadataDb, BlockTree, poSSwitcher, _logManager); + + TrieStore trieStore = new(stateDb, LimboLogs.Instance); + TotalDifficultyBetterPeerStrategy totalDifficultyBetterPeerStrategy = new(LimboLogs.Instance); + IBetterPeerStrategy bestPeerStrategy = IsMerge(synchronizerType) + ? new MergeBetterPeerStrategy(totalDifficultyBetterPeerStrategy, poSSwitcher, beaconPivot, LimboLogs.Instance) + : totalDifficultyBetterPeerStrategy; + + StateReader reader = new StateReader(trieStore, codeDb, LimboLogs.Instance); + FullStateFinder fullStateFinder = new FullStateFinder(BlockTree, reader); + INodeStorage nodeStorage = new NodeStorage(dbProvider.StateDb); + + SyncPeerPool = new SyncPeerPool(BlockTree, stats, bestPeerStrategy, _logManager, 25); + Pivot pivot = new(syncConfig); + + IInvalidChainTracker invalidChainTracker = new NoopInvalidChainTracker(); + if (IsMerge(synchronizerType)) + { + IBlockDownloaderFactory blockDownloaderFactory = new MergeBlockDownloaderFactory( + poSSwitcher, + beaconPivot, + MainnetSpecProvider.Instance, Always.Valid, Always.Valid, - SyncPeerPool, - Synchronizer.SyncModeSelector, syncConfig, - Policy.FullGossip, + bestPeerStrategy, + fullStateFinder, + _logManager + ); + Synchronizer = new MergeSynchronizer( + dbProvider, + nodeStorage, MainnetSpecProvider.Instance, + BlockTree, + NullReceiptStorage.Instance, + SyncPeerPool, + stats, + syncConfig, + blockDownloaderFactory, + pivot, + poSSwitcher, + mergeConfig, + invalidChainTracker, + Substitute.For(), + bestPeerStrategy, + new ChainSpec(), + No.BeaconSync, + reader, _logManager); - - SyncPeerPool.Start(); - - Synchronizer.Start(); - - AllInstances.Enqueue(this); - } - - public SyncingContext BestKnownNumberIs(long number) - { - Assert.That(BlockTree.BestKnownNumber, Is.EqualTo(number), "best known number"); - return this; - } - - public SyncingContext BlockIsKnown() - { - Assert.True(BlockTree.IsKnownBlock(_blockHeader.Number, _blockHeader.Hash!), "block is known"); - return this; } - - private const int DynamicTimeout = 10000; - - public SyncingContext BestSuggestedHeaderIs(BlockHeader header) + else { - Assert.That( - () => BlockTree.BestSuggestedHeader, - Is.EqualTo(header).After(DynamicTimeout, 2), "header"); + IBlockDownloaderFactory blockDownloaderFactory = new BlockDownloaderFactory( + MainnetSpecProvider.Instance, + Always.Valid, + Always.Valid, + new TotalDifficultyBetterPeerStrategy(_logManager), + _logManager); - _blockHeader = BlockTree.BestSuggestedHeader!; - return this; + Synchronizer = new Synchronizer( + dbProvider, + nodeStorage, + MainnetSpecProvider.Instance, + BlockTree, + NullReceiptStorage.Instance, + SyncPeerPool, + stats, + syncConfig, + blockDownloaderFactory, + pivot, + Substitute.For(), + bestPeerStrategy, + new ChainSpec(), + reader, + _logManager); } - public SyncingContext BestSuggestedBlockHasNumber(long number) - { - _logger.Info($"ASSERTING THAT NUMBER IS {number}"); - - Assert.That( - () => BlockTree.BestSuggestedHeader!.Number, - Is.EqualTo(number).After(DynamicTimeout, 2), "block number"); - - _blockHeader = BlockTree.BestSuggestedHeader!; - return this; - } + SyncServer = new SyncServer( + trieStore.TrieNodeRlpStore, + codeDb, + BlockTree, + NullReceiptStorage.Instance, + Always.Valid, + Always.Valid, + SyncPeerPool, + Synchronizer.SyncModeSelector, + syncConfig, + Policy.FullGossip, + MainnetSpecProvider.Instance, + _logManager); - public SyncingContext BlockIsSameAsGenesis() - { - Assert.That(_blockHeader, Is.SameAs(BlockTree.Genesis), "genesis"); - return this; - } + SyncPeerPool.Start(); - private BlockHeader _blockHeader = null!; + Synchronizer.Start(); - public SyncingContext Genesis - { - get - { - _blockHeader = BlockTree.Genesis!; - return this; - } - } + AllInstances.Enqueue(this); + } - public SyncingContext WaitUntilInitialized() - { - Assert.That(() => SyncPeerPool.AllPeers.All(p => p.IsInitialized), Is.True.After(DynamicTimeout, 1)); - return this; - } + public SyncingContext BestKnownNumberIs(long number) + { + Assert.That(BlockTree.BestKnownNumber, Is.EqualTo(number), "best known number"); + return this; + } - public SyncingContext After(Action action) - { - action(); - return this; - } + public SyncingContext BlockIsKnown() + { + Assert.That(BlockTree.IsKnownBlock(_blockHeader.Number, _blockHeader.Hash!), Is.True, "block is known"); + return this; + } - public SyncingContext BestSuggested - { - get - { - _blockHeader = BlockTree.BestSuggestedHeader!; - return this; - } - } + private const int DynamicTimeout = 10000; - public SyncingContext AfterProcessingGenesis() - { - Block genesis = _genesisBlock; - BlockTree.SuggestBlock(genesis); - BlockTree.UpdateMainChain(genesis); - return this; - } + public SyncingContext BestSuggestedHeaderIs(BlockHeader header) + { + Assert.That( + () => BlockTree.BestSuggestedHeader, + Is.EqualTo(header).After(DynamicTimeout, 2), "header"); - public SyncingContext AfterPeerIsAdded(ISyncPeer syncPeer) - { - ((SyncPeerMock)syncPeer).Disconnected += (_, _) => SyncPeerPool.RemovePeer(syncPeer); + _blockHeader = BlockTree.BestSuggestedHeader!; + return this; + } - _logger.Info($"PEER ADDED {syncPeer.ClientId}"); - _peers.TryAdd(syncPeer.ClientId, syncPeer); - SyncPeerPool.AddPeer(syncPeer); - return this; - } + public SyncingContext BestSuggestedBlockHasNumber(long number) + { + _logger.Info($"ASSERTING THAT NUMBER IS {number}"); - public SyncingContext AfterPeerIsRemoved(ISyncPeer syncPeer) - { - _peers.Remove(syncPeer.ClientId); - SyncPeerPool.RemovePeer(syncPeer); - return this; - } + Assert.That( + () => BlockTree.BestSuggestedHeader!.Number, + Is.EqualTo(number).After(DynamicTimeout, 2), "block number"); - public SyncingContext AfterNewBlockMessage(Block block, ISyncPeer peer) - { - _logger.Info($"NEW BLOCK MESSAGE {block.Number}"); - block.Header.TotalDifficulty = block.Difficulty * (ulong)(block.Number + 1); - SyncServer.AddNewBlock(block, peer); - return this; - } + _blockHeader = BlockTree.BestSuggestedHeader!; + return this; + } - public SyncingContext AfterHintBlockMessage(Block block, ISyncPeer peer) - { - _logger.Info($"HINT BLOCK MESSAGE {block.Number}"); - SyncServer.HintBlock(block.Hash!, block.Number, peer); - return this; - } + public SyncingContext BlockIsSameAsGenesis() + { + Assert.That(_blockHeader, Is.SameAs(BlockTree.Genesis), "genesis"); + return this; + } - public SyncingContext PeerCountIs(long i) - { - Assert.That(SyncPeerPool.AllPeers.Count(), Is.EqualTo(i), "peer count"); - return this; - } + private BlockHeader _blockHeader = null!; - public SyncingContext PeerCountEventuallyIs(long i) + public SyncingContext Genesis + { + get { - Assert.That(() => SyncPeerPool.AllPeers.Count(), Is.EqualTo(i).After(5000, 100), "peer count"); + _blockHeader = BlockTree.Genesis!; return this; } + } - public async Task StopAsync() - { - await Synchronizer.StopAsync(); - await SyncPeerPool.StopAsync(); - } + public SyncingContext WaitUntilInitialized() + { + Assert.That(() => SyncPeerPool.AllPeers.All(p => p.IsInitialized), Is.True.After(DynamicTimeout, 1)); + return this; } - [OneTimeSetUp] - public void Setup() + public SyncingContext After(Action action) { + action(); + return this; } - [OneTimeTearDown] - public async Task TearDown() + public SyncingContext BestSuggested { - foreach (SyncingContext syncingContext in SyncingContext.AllInstances) + get { - await syncingContext.StopAsync(); + _blockHeader = BlockTree.BestSuggestedHeader!; + return this; } } - [Test, Retry(3)] - public async Task Init_condition_are_as_expected() + public SyncingContext AfterProcessingGenesis() { - await When.Syncing - .AfterProcessingGenesis() - .BestKnownNumberIs(0) - .Genesis.BlockIsKnown() - .BestSuggested.BlockIsSameAsGenesis() - .StopAsync(); + Block genesis = _genesisBlock; + BlockTree.SuggestBlock(genesis); + BlockTree.UpdateMainChain(genesis); + return this; } - [Test, Retry(3)] - public async Task Can_sync_with_one_peer_straight() + public SyncingContext AfterPeerIsAdded(ISyncPeer syncPeer) { - SyncPeerMock peerA = new("A"); + ((SyncPeerMock)syncPeer).Disconnected += (_, _) => SyncPeerPool.RemovePeer(syncPeer); - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggested.BlockIsSameAsGenesis() - .StopAsync(); + _logger.Info($"PEER ADDED {syncPeer.ClientId}"); + _peers.TryAdd(syncPeer.ClientId, syncPeer); + SyncPeerPool.AddPeer(syncPeer); + return this; } - [Test, Retry(3)] - public async Task Can_sync_with_one_peer_straight_and_extend_chain() + public SyncingContext AfterPeerIsRemoved(ISyncPeer syncPeer) { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(3); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); + _peers.Remove(syncPeer.ClientId); + SyncPeerPool.RemovePeer(syncPeer); + return this; } - [Test, Retry(3)] - public async Task Can_extend_chain_by_one_on_new_block_message() + public SyncingContext AfterNewBlockMessage(Block block, ISyncPeer peer) { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(1); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .WaitUntilInitialized() - .After(() => peerA.AddBlocksUpTo(2)) - .AfterNewBlockMessage(peerA.HeadBlock, peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); + _logger.Info($"NEW BLOCK MESSAGE {block.Number}"); + block.Header.TotalDifficulty = block.Difficulty * (ulong)(block.Number + 1); + SyncServer.AddNewBlock(block, peer); + return this; } - [Test, Retry(3)] - public async Task Can_reorg_on_new_block_message() + public SyncingContext AfterHintBlockMessage(Block block, ISyncPeer peer) { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(3); - - SyncPeerMock peerB = new("B"); - peerB.AddBlocksUpTo(3); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .AfterPeerIsAdded(peerB) - .WaitUntilInitialized() - .After(() => peerB.AddBlocksUpTo(6)) - .AfterNewBlockMessage(peerB.HeadBlock, peerB) - .BestSuggestedHeaderIs(peerB.HeadHeader) - .StopAsync(); + _logger.Info($"HINT BLOCK MESSAGE {block.Number}"); + SyncServer.HintBlock(block.Hash!, block.Number, peer); + return this; } - [Test, Retry(3)] - [Ignore("Not supported for now - still analyzing this scenario")] - public async Task Can_reorg_on_hint_block_message() + public SyncingContext PeerCountIs(long i) { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(3); - - SyncPeerMock peerB = new("B"); - peerB.AddBlocksUpTo(3); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .AfterPeerIsAdded(peerB) - .After(() => peerB.AddBlocksUpTo(6)) - .AfterHintBlockMessage(peerB.HeadBlock, peerB) - .BestSuggestedHeaderIs(peerB.HeadHeader) - .StopAsync(); + Assert.That(SyncPeerPool.AllPeers.Count(), Is.EqualTo(i), "peer count"); + return this; } - [Test, Retry(3)] - public async Task Can_extend_chain_by_one_on_block_hint_message() + public SyncingContext PeerCountEventuallyIs(long i) { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(1); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .WaitUntilInitialized() - .After(() => peerA.AddBlocksUpTo(2)) - .AfterHintBlockMessage(peerA.HeadBlock, peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); + Assert.That(() => SyncPeerPool.AllPeers.Count(), Is.EqualTo(i).After(5000, 100), "peer count"); + return this; } - [Test, Retry(3)] - public async Task Can_extend_chain_by_more_than_one_on_new_block_message() + public async Task StopAsync() { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(1); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .WaitUntilInitialized() - .After(() => peerA.AddBlocksUpTo(8)) - .AfterNewBlockMessage(peerA.HeadBlock, peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); - - Console.WriteLine("why?"); + await Synchronizer.StopAsync(); + await SyncPeerPool.StopAsync(); } + } - [Test, Retry(3)] - public async Task Will_ignore_new_block_that_is_far_ahead() - { - // this test was designed for no sync-timer sync process - // now it checks something different - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(1); + [OneTimeSetUp] + public void Setup() + { + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .WaitUntilInitialized() - .After(() => peerA.AddBlocksUpTo(16)) - .AfterNewBlockMessage(peerA.HeadBlock, peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); + [OneTimeTearDown] + public async Task TearDown() + { + foreach (SyncingContext syncingContext in SyncingContext.AllInstances) + { + await syncingContext.StopAsync(); } + } - [Test, Retry(3)] - public async Task Can_sync_when_best_peer_is_timing_out() - { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(1); + [Test, Retry(3)] + public async Task Init_condition_are_as_expected() + { + await When.Syncing + .AfterProcessingGenesis() + .BestKnownNumberIs(0) + .Genesis.BlockIsKnown() + .BestSuggested.BlockIsSameAsGenesis() + .StopAsync(); + } - SyncPeerMock badPeer = new("B", false, false, true); - badPeer.AddBlocksUpTo(20); + [Test, Retry(3)] + public async Task Can_sync_with_one_peer_straight() + { + SyncPeerMock peerA = new("A"); - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(badPeer) - .WaitUntilInitialized() - .AfterPeerIsAdded(peerA) - .BestSuggestedBlockHasNumber(1) - .StopAsync(); - } + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggested.BlockIsSameAsGenesis() + .StopAsync(); + } - [Test] - [Parallelizable(ParallelScope.None)] - public async Task Will_inform_connecting_peer_about_the_alternative_branch_with_same_difficulty() - { + [Test, Retry(3)] + public async Task Can_sync_with_one_peer_straight_and_extend_chain() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(3); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - if (WithTTD(_synchronizerType)) { return; } - if (_synchronizerType == SynchronizerType.Fast) - { - return; - } + [Test, Retry(3)] + public async Task Can_extend_chain_by_one_on_new_block_message() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .WaitUntilInitialized() + .After(() => peerA.AddBlocksUpTo(2)) + .AfterNewBlockMessage(peerA.HeadBlock, peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(2); + [Test, Retry(3)] + public async Task Can_reorg_on_new_block_message() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(3); + + SyncPeerMock peerB = new("B"); + peerB.AddBlocksUpTo(3); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .AfterPeerIsAdded(peerB) + .WaitUntilInitialized() + .After(() => peerB.AddBlocksUpTo(6)) + .AfterNewBlockMessage(peerB.HeadBlock, peerB) + .BestSuggestedHeaderIs(peerB.HeadHeader) + .StopAsync(); + } - SyncPeerMock peerB = new("B"); - peerB.AddBlocksUpTo(2, 0, 1); + [Test, Retry(3)] + [Ignore("Not supported for now - still analyzing this scenario")] + public async Task Can_reorg_on_hint_block_message() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(3); + + SyncPeerMock peerB = new("B"); + peerB.AddBlocksUpTo(3); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .AfterPeerIsAdded(peerB) + .After(() => peerB.AddBlocksUpTo(6)) + .AfterHintBlockMessage(peerB.HeadBlock, peerB) + .BestSuggestedHeaderIs(peerB.HeadHeader) + .StopAsync(); + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedBlockHasNumber(2) - .AfterPeerIsAdded(peerB) - .WaitUntilInitialized() - .StopAsync(); + [Test, Retry(3)] + public async Task Can_extend_chain_by_one_on_block_hint_message() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .WaitUntilInitialized() + .After(() => peerA.AddBlocksUpTo(2)) + .AfterHintBlockMessage(peerA.HeadBlock, peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - Assert.That(peerA.HeadBlock.Hash, Is.Not.EqualTo(peerB.HeadBlock.Hash)); + [Test, Retry(3)] + public async Task Can_extend_chain_by_more_than_one_on_new_block_message() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .WaitUntilInitialized() + .After(() => peerA.AddBlocksUpTo(8)) + .AfterNewBlockMessage(peerA.HeadBlock, peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + + Console.WriteLine("why?"); + } - Block? peerBNewBlock = null; - Assert.That(() => - { - bool receivedBlock = peerB.ReceivedBlocks.TryPeek(out peerBNewBlock); - return receivedBlock && peerBNewBlock!.Hash == peerA.HeadBlock.Hash; - }, Is.True.After(WaitTime, 1)); + [Test, Retry(3)] + public async Task Will_ignore_new_block_that_is_far_ahead() + { + // this test was designed for no sync-timer sync process + // now it checks something different + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .WaitUntilInitialized() + .After(() => peerA.AddBlocksUpTo(16)) + .AfterNewBlockMessage(peerA.HeadBlock, peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - Assert.That(peerA.HeadBlock.Hash, Is.EqualTo(peerBNewBlock?.Header.Hash!)); + [Test, Retry(3)] + public async Task Can_sync_when_best_peer_is_timing_out() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(1); + + SyncPeerMock badPeer = new("B", false, false, true); + badPeer.AddBlocksUpTo(20); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(badPeer) + .WaitUntilInitialized() + .AfterPeerIsAdded(peerA) + .BestSuggestedBlockHasNumber(1) + .StopAsync(); + } - } + [Test] + [Parallelizable(ParallelScope.None)] + public async Task Will_inform_connecting_peer_about_the_alternative_branch_with_same_difficulty() + { - [Test] - public async Task Will_not_add_same_peer_twice() + if (WithTTD(_synchronizerType)) { return; } + if (_synchronizerType == SynchronizerType.Fast) { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(1); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .AfterPeerIsAdded(peerA) - .WaitUntilInitialized() - .PeerCountIs(1) - .BestSuggestedBlockHasNumber(1) - .StopAsync(); + return; } - [Test] - public async Task Will_remove_peer_when_init_fails() - { - SyncPeerMock peerA = new("A", true, true); - peerA.AddBlocksUpTo(1); + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(2); - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .PeerCountEventuallyIs(0) - .StopAsync(); - } + SyncPeerMock peerB = new("B"); + peerB.AddBlocksUpTo(2, 0, 1); + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedBlockHasNumber(2) + .AfterPeerIsAdded(peerB) + .WaitUntilInitialized() + .StopAsync(); - [Test] - public async Task Can_remove_peers() - { - SyncPeerMock peerA = new("A"); - SyncPeerMock peerB = new("B"); + Assert.That(peerA.HeadBlock.Hash, Is.Not.EqualTo(peerB.HeadBlock.Hash)); - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .AfterPeerIsAdded(peerB) - .PeerCountIs(2) - .AfterPeerIsRemoved(peerB) - .PeerCountIs(1) - .AfterPeerIsRemoved(peerA) - .PeerCountIs(0) - .StopAsync(); - } - - [Test, Retry(3)] - public async Task Can_reorg_on_add_peer() + Block? peerBNewBlock = null; + Assert.That(() => { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(SyncBatchSize.Max); + bool receivedBlock = peerB.ReceivedBlocks.TryPeek(out peerBNewBlock); + return receivedBlock && peerBNewBlock!.Hash == peerA.HeadBlock.Hash; + }, Is.True.After(WaitTime, 1)); - SyncPeerMock peerB = new("B"); - peerB.AddBlocksUpTo(SyncBatchSize.Max * 2, 0, 1); + Assert.That(peerA.HeadBlock.Hash, Is.EqualTo(peerBNewBlock?.Header.Hash!)); - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .AfterPeerIsAdded(peerB) - .BestSuggestedHeaderIs(peerB.HeadHeader) - .StopAsync(); - } - - [Test, Retry(3)] - public async Task Can_reorg_based_on_total_difficulty() - { - if (WithTTD(_synchronizerType)) { return; } - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(10); - - SyncPeerMock peerB = new("B"); - peerB.AddHighDifficultyBlocksUpTo(6, 0, 1); + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .AfterPeerIsAdded(peerB) - .BestSuggestedHeaderIs(peerB.HeadHeader) - .StopAsync(); - } + [Test] + public async Task Will_not_add_same_peer_twice() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .AfterPeerIsAdded(peerA) + .WaitUntilInitialized() + .PeerCountIs(1) + .BestSuggestedBlockHasNumber(1) + .StopAsync(); + } - [Test, Retry(3)] - [Ignore("Not supported for now - still analyzing this scenario")] - public async Task Can_extend_chain_on_hint_block_when_high_difficulty_low_number() - { + [Test] + public async Task Will_remove_peer_when_init_fails() + { + SyncPeerMock peerA = new("A", true, true); + peerA.AddBlocksUpTo(1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .PeerCountEventuallyIs(0) + .StopAsync(); + } - if (WithTTD(_synchronizerType)) { return; } - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(10); - SyncPeerMock peerB = new("B"); - peerB.AddHighDifficultyBlocksUpTo(5, 0, 1); + [Test] + public async Task Can_remove_peers() + { + SyncPeerMock peerA = new("A"); + SyncPeerMock peerB = new("B"); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .AfterPeerIsAdded(peerB) + .PeerCountIs(2) + .AfterPeerIsRemoved(peerB) + .PeerCountIs(1) + .AfterPeerIsRemoved(peerA) + .PeerCountIs(0) + .StopAsync(); + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .AfterPeerIsAdded(peerB) - .After(() => peerB.AddHighDifficultyBlocksUpTo(6, 0, 1)) - .AfterHintBlockMessage(peerB.HeadBlock, peerB) - .BestSuggestedHeaderIs(peerB.HeadHeader) - .StopAsync(); - } + [Test, Retry(3)] + public async Task Can_reorg_on_add_peer() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(SyncBatchSize.Max); + + SyncPeerMock peerB = new("B"); + peerB.AddBlocksUpTo(SyncBatchSize.Max * 2, 0, 1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .AfterPeerIsAdded(peerB) + .BestSuggestedHeaderIs(peerB.HeadHeader) + .StopAsync(); + } - [Test, Retry(3)] - public async Task Can_extend_chain_on_new_block_when_high_difficulty_low_number() - { + [Test, Retry(3)] + public async Task Can_reorg_based_on_total_difficulty() + { + if (WithTTD(_synchronizerType)) { return; } + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(10); + + SyncPeerMock peerB = new("B"); + peerB.AddHighDifficultyBlocksUpTo(6, 0, 1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .AfterPeerIsAdded(peerB) + .BestSuggestedHeaderIs(peerB.HeadHeader) + .StopAsync(); + } - if (WithTTD(_synchronizerType)) { return; } - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(10); + [Test, Retry(3)] + [Ignore("Not supported for now - still analyzing this scenario")] + public async Task Can_extend_chain_on_hint_block_when_high_difficulty_low_number() + { - SyncPeerMock peerB = new("B"); - peerB.AddHighDifficultyBlocksUpTo(6, 0, 1); + if (WithTTD(_synchronizerType)) { return; } + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(10); + + SyncPeerMock peerB = new("B"); + peerB.AddHighDifficultyBlocksUpTo(5, 0, 1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .AfterPeerIsAdded(peerB) + .After(() => peerB.AddHighDifficultyBlocksUpTo(6, 0, 1)) + .AfterHintBlockMessage(peerB.HeadBlock, peerB) + .BestSuggestedHeaderIs(peerB.HeadHeader) + .StopAsync(); + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .WaitUntilInitialized() - .AfterPeerIsAdded(peerB) - .WaitUntilInitialized() - .After(() => peerB.AddHighDifficultyBlocksUpTo(6, 0, 1)) - .AfterNewBlockMessage(peerB.HeadBlock, peerB) - .WaitUntilInitialized() - .BestSuggestedHeaderIs(peerB.HeadHeader) - .StopAsync(); - } + [Test, Retry(3)] + public async Task Can_extend_chain_on_new_block_when_high_difficulty_low_number() + { - [Test, Retry(3)] - public async Task Will_not_reorganize_on_same_chain_length() - { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(10); + if (WithTTD(_synchronizerType)) { return; } + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(10); + + SyncPeerMock peerB = new("B"); + peerB.AddHighDifficultyBlocksUpTo(6, 0, 1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .WaitUntilInitialized() + .AfterPeerIsAdded(peerB) + .WaitUntilInitialized() + .After(() => peerB.AddHighDifficultyBlocksUpTo(6, 0, 1)) + .AfterNewBlockMessage(peerB.HeadBlock, peerB) + .WaitUntilInitialized() + .BestSuggestedHeaderIs(peerB.HeadHeader) + .StopAsync(); + } - SyncPeerMock peerB = new("B"); - peerB.AddBlocksUpTo(10, 0, 1); + [Test, Retry(3)] + public async Task Will_not_reorganize_on_same_chain_length() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(10); + + SyncPeerMock peerB = new("B"); + peerB.AddBlocksUpTo(10, 0, 1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .AfterPeerIsAdded(peerB) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .AfterPeerIsAdded(peerB) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); - } + [Test, Retry(3)] + public async Task Will_not_reorganize_more_than_max_reorg_length() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(BlockDownloader.MaxReorganizationLength + 1); + + SyncPeerMock peerB = new("B"); + peerB.AddBlocksUpTo(BlockDownloader.MaxReorganizationLength + 2, 0, 1); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .AfterPeerIsAdded(peerB) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - [Test, Retry(3)] - public async Task Will_not_reorganize_more_than_max_reorg_length() - { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(BlockDownloader.MaxReorganizationLength + 1); + [Test, Ignore("travis")] + public async Task Can_sync_more_than_a_batch() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(SyncBatchSize.Max * 3); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - SyncPeerMock peerB = new("B"); - peerB.AddBlocksUpTo(BlockDownloader.MaxReorganizationLength + 2, 0, 1); + [Test, Retry(3)] + public async Task Can_sync_exactly_one_batch() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(SyncBatchSize.Max); + + await When.Syncing + .AfterProcessingGenesis() + .AfterPeerIsAdded(peerA) + .BestSuggestedHeaderIs(peerA.HeadHeader) + .StopAsync(); + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .AfterPeerIsAdded(peerB) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); - } + [Test, Retry(3)] + public async Task Can_stop() + { + SyncPeerMock peerA = new("A"); + peerA.AddBlocksUpTo(SyncBatchSize.Max); - [Test, Ignore("travis")] - public async Task Can_sync_more_than_a_batch() - { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(SyncBatchSize.Max * 3); + await When.Syncing + .StopAsync(); + } - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); - } + private const int WaitTime = 1500; - [Test, Retry(3)] - public async Task Can_sync_exactly_one_batch() + private static bool IsMerge(SynchronizerType synchronizerType) => + synchronizerType switch { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(SyncBatchSize.Max); - - await When.Syncing - .AfterProcessingGenesis() - .AfterPeerIsAdded(peerA) - .BestSuggestedHeaderIs(peerA.HeadHeader) - .StopAsync(); - } - - [Test, Retry(3)] - public async Task Can_stop() + SynchronizerType.Eth2MergeFast or SynchronizerType.Eth2MergeFull + or SynchronizerType.Eth2MergeFastWithoutTTD or SynchronizerType.Eth2MergeFullWithoutTTD + => true, + _ => false + }; + + private static bool WithTTD(SynchronizerType synchronizerType) => + synchronizerType switch { - SyncPeerMock peerA = new("A"); - peerA.AddBlocksUpTo(SyncBatchSize.Max); - - await When.Syncing - .StopAsync(); - } - - private const int WaitTime = 1500; + SynchronizerType.Eth2MergeFast or SynchronizerType.Eth2MergeFull => true, + _ => false + }; - private static bool IsMerge(SynchronizerType synchronizerType) => - synchronizerType switch - { - SynchronizerType.Eth2MergeFast or SynchronizerType.Eth2MergeFull - or SynchronizerType.Eth2MergeFastWithoutTTD or SynchronizerType.Eth2MergeFullWithoutTTD - => true, - _ => false - }; - - private static bool WithTTD(SynchronizerType synchronizerType) => - synchronizerType switch - { - SynchronizerType.Eth2MergeFast or SynchronizerType.Eth2MergeFull => true, - _ => false - }; - - } } diff --git a/src/Nethermind/Nethermind.Trie.Test/HexPrefixTests.cs b/src/Nethermind/Nethermind.Trie.Test/HexPrefixTests.cs index 4b44b16bd55..522e9776507 100644 --- a/src/Nethermind/Nethermind.Trie.Test/HexPrefixTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/HexPrefixTests.cs @@ -4,97 +4,95 @@ using System.Linq; using NUnit.Framework; -namespace Nethermind.Trie.Test +namespace Nethermind.Trie.Test; + +public class HexPrefixTests { - [TestFixture] - public class HexPrefixTests + [TestCase(false, (byte)3, (byte)19)] + [TestCase(true, (byte)3, (byte)51)] + public void Encode_gives_correct_output_when_one(bool flag, byte nibble1, byte byte1) { - [TestCase(false, (byte)3, (byte)19)] - [TestCase(true, (byte)3, (byte)51)] - public void Encode_gives_correct_output_when_one(bool flag, byte nibble1, byte byte1) - { - byte[] output = HexPrefix.ToBytes(new[] { nibble1 }, flag); - Assert.That(output.Length, Is.EqualTo(1)); - Assert.That(output[0], Is.EqualTo(byte1)); - } + byte[] output = HexPrefix.ToBytes(new[] { nibble1 }, flag); + Assert.That(output.Length, Is.EqualTo(1)); + Assert.That(output[0], Is.EqualTo(byte1)); + } - [TestCase(false, (byte)3, (byte)7, (byte)13, (byte)19, (byte)125)] - [TestCase(true, (byte)3, (byte)7, (byte)13, (byte)51, (byte)125)] - public void Encode_gives_correct_output_when_odd(bool flag, byte nibble1, byte nibble2, byte nibble3, - byte byte1, byte byte2) - { - byte[] output = HexPrefix.ToBytes(new[] { nibble1, nibble2, nibble3 }, flag); + [TestCase(false, (byte)3, (byte)7, (byte)13, (byte)19, (byte)125)] + [TestCase(true, (byte)3, (byte)7, (byte)13, (byte)51, (byte)125)] + public void Encode_gives_correct_output_when_odd(bool flag, byte nibble1, byte nibble2, byte nibble3, + byte byte1, byte byte2) + { + byte[] output = HexPrefix.ToBytes(new[] { nibble1, nibble2, nibble3 }, flag); - Assert.That(output.Length, Is.EqualTo(2)); - Assert.That(output[0], Is.EqualTo(byte1)); - Assert.That(output[1], Is.EqualTo(byte2)); - } + Assert.That(output.Length, Is.EqualTo(2)); + Assert.That(output[0], Is.EqualTo(byte1)); + Assert.That(output[1], Is.EqualTo(byte2)); + } - [TestCase(false, (byte)3, (byte)7, (byte)0, (byte)55)] - [TestCase(true, (byte)3, (byte)7, (byte)32, (byte)55)] - public void Encode_gives_correct_output_when_even(bool flag, byte nibble1, byte nibble2, byte byte1, byte byte2) - { - byte[] output = HexPrefix.ToBytes(new[] { nibble1, nibble2 }, flag); + [TestCase(false, (byte)3, (byte)7, (byte)0, (byte)55)] + [TestCase(true, (byte)3, (byte)7, (byte)32, (byte)55)] + public void Encode_gives_correct_output_when_even(bool flag, byte nibble1, byte nibble2, byte byte1, byte byte2) + { + byte[] output = HexPrefix.ToBytes(new[] { nibble1, nibble2 }, flag); - Assert.That(output.Length, Is.EqualTo(2)); - Assert.That(output[0], Is.EqualTo(byte1)); - Assert.That(output[1], Is.EqualTo(byte2)); - } + Assert.That(output.Length, Is.EqualTo(2)); + Assert.That(output[0], Is.EqualTo(byte1)); + Assert.That(output[1], Is.EqualTo(byte2)); + } - [TestCase(false, (byte)3, (byte)7, (byte)0, (byte)55)] - [TestCase(true, (byte)3, (byte)7, (byte)32, (byte)55)] - public void Decode_gives_correct_output_when_even(bool expectedFlag, byte nibble1, byte nibble2, byte byte1, - byte byte2) - { - (byte[] key, bool isLeaf) = HexPrefix.FromBytes(new[] { byte1, byte2 }); - Assert.That(isLeaf, Is.EqualTo(expectedFlag)); - Assert.That(key.Length, Is.EqualTo(2)); - Assert.That(key[0], Is.EqualTo(nibble1)); - Assert.That(key[1], Is.EqualTo(nibble2)); - } + [TestCase(false, (byte)3, (byte)7, (byte)0, (byte)55)] + [TestCase(true, (byte)3, (byte)7, (byte)32, (byte)55)] + public void Decode_gives_correct_output_when_even(bool expectedFlag, byte nibble1, byte nibble2, byte byte1, + byte byte2) + { + (byte[] key, bool isLeaf) = HexPrefix.FromBytes(new[] { byte1, byte2 }); + Assert.That(isLeaf, Is.EqualTo(expectedFlag)); + Assert.That(key.Length, Is.EqualTo(2)); + Assert.That(key[0], Is.EqualTo(nibble1)); + Assert.That(key[1], Is.EqualTo(nibble2)); + } - [TestCase(false, (byte)3, (byte)19)] - [TestCase(true, (byte)3, (byte)51)] - public void Decode_gives_correct_output_when_one(bool expectedFlag, byte nibble1, byte byte1) - { - (byte[] key, bool isLeaf) = HexPrefix.FromBytes(new[] { byte1 }); + [TestCase(false, (byte)3, (byte)19)] + [TestCase(true, (byte)3, (byte)51)] + public void Decode_gives_correct_output_when_one(bool expectedFlag, byte nibble1, byte byte1) + { + (byte[] key, bool isLeaf) = HexPrefix.FromBytes(new[] { byte1 }); - Assert.That(isLeaf, Is.EqualTo(expectedFlag)); - Assert.That(key.Length, Is.EqualTo(1)); - Assert.That(key[0], Is.EqualTo(nibble1)); - } + Assert.That(isLeaf, Is.EqualTo(expectedFlag)); + Assert.That(key.Length, Is.EqualTo(1)); + Assert.That(key[0], Is.EqualTo(nibble1)); + } - [TestCase(false, (byte)3, (byte)7, (byte)13, (byte)19, (byte)125)] - [TestCase(true, (byte)3, (byte)7, (byte)13, (byte)51, (byte)125)] - public void Decode_gives_correct_output_when_odd(bool expectedFlag, byte nibble1, byte nibble2, byte nibble3, - byte byte1, byte byte2) - { - (byte[] key, bool isLeaf) = HexPrefix.FromBytes(new[] { byte1, byte2 }); - Assert.That(isLeaf, Is.EqualTo(expectedFlag)); - Assert.That(key.Length, Is.EqualTo(3)); - Assert.That(key[0], Is.EqualTo(nibble1)); - Assert.That(key[1], Is.EqualTo(nibble2)); - Assert.That(key[2], Is.EqualTo(nibble3)); - } + [TestCase(false, (byte)3, (byte)7, (byte)13, (byte)19, (byte)125)] + [TestCase(true, (byte)3, (byte)7, (byte)13, (byte)51, (byte)125)] + public void Decode_gives_correct_output_when_odd(bool expectedFlag, byte nibble1, byte nibble2, byte nibble3, + byte byte1, byte byte2) + { + (byte[] key, bool isLeaf) = HexPrefix.FromBytes(new[] { byte1, byte2 }); + Assert.That(isLeaf, Is.EqualTo(expectedFlag)); + Assert.That(key.Length, Is.EqualTo(3)); + Assert.That(key[0], Is.EqualTo(nibble1)); + Assert.That(key[1], Is.EqualTo(nibble2)); + Assert.That(key[2], Is.EqualTo(nibble3)); + } - // According to: https://ethereum.github.io/yellowpaper/paper.pdf#appendix.C - // Leaf flag (t) is omitted - [TestCase(new byte[] { 1, 2, 3, 4 }, new byte[] { 0, 1 * 16 + 2, 3 * 16 + 4 })] - [TestCase(new byte[] { 1, 2, 3 }, new byte[] { 16 + 1, 2 * 16 + 3 })] - public void Compact_hex_encoding_correct_output(byte[] nibbles, byte[] bytes) - { - byte[] result = Nibbles.ToCompactHexEncoding(nibbles); - CollectionAssert.AreEqual(bytes, result); - } + // According to: https://ethereum.github.io/yellowpaper/paper.pdf#appendix.C + // Leaf flag (t) is omitted + [TestCase(new byte[] { 1, 2, 3, 4 }, new byte[] { 0, 1 * 16 + 2, 3 * 16 + 4 })] + [TestCase(new byte[] { 1, 2, 3 }, new byte[] { 16 + 1, 2 * 16 + 3 })] + public void Compact_hex_encoding_correct_output(byte[] nibbles, byte[] bytes) + { + byte[] result = Nibbles.ToCompactHexEncoding(nibbles); + Assert.That(bytes, Is.EqualTo(result).AsCollection); + } - // Just pack nibbles to bytes - [Test] - public void Nibbles_to_bytes_correct_output() - { - byte[] nibbles = Enumerable.Repeat((byte)1, 64).ToArray(); - byte[] bytes = Enumerable.Repeat((byte)17, 32).ToArray(); - byte[] result = Nibbles.ToBytes(nibbles); - CollectionAssert.AreEqual(bytes, result); - } + // Just pack nibbles to bytes + [Test] + public void Nibbles_to_bytes_correct_output() + { + byte[] nibbles = Enumerable.Repeat((byte)1, 64).ToArray(); + byte[] bytes = Enumerable.Repeat((byte)17, 32).ToArray(); + byte[] result = Nibbles.ToBytes(nibbles); + Assert.That(bytes, Is.EqualTo(result).AsCollection); } } diff --git a/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs b/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs index 88036b30135..6ee564db88a 100644 --- a/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs @@ -19,1038 +19,1037 @@ using NSubstitute.ExceptionExtensions; using NUnit.Framework; -namespace Nethermind.Trie.Test +namespace Nethermind.Trie.Test; + +[Parallelizable(ParallelScope.All)] +public class TrieNodeTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class TrieNodeTests - { - // private TrieNode _tiniestLeaf; - // private TrieNode _heavyLeaf; - // private TrieNode _accountLeaf; - // - // [SetUp] - // public void Setup() - // { - // _tiniestLeaf = new TrieNode(NodeType.Leaf); - // _tiniestLeaf.Key = new HexPrefix(true, 5); - // _tiniestLeaf.Value = new byte[] {10}; - // - // _heavyLeaf = new TrieNode(NodeType.Leaf); - // _heavyLeaf.Key = new HexPrefix(true, new byte[20]); - // _heavyLeaf.Value = Keccak.EmptyTreeHash.Bytes.Concat(Keccak.EmptyTreeHash.Bytes).ToArray(); - // - // Account account = new Account(100); - // AccountDecoder decoder = new AccountDecoder(); - // _accountLeaf = TrieNodeFactory.CreateLeaf( - // HexPrefix.Leaf("bbb"), - // decoder.Encode(account).Bytes); - // } - - [Test] - public void Throws_trie_exception_when_setting_value_on_branch() - { - TrieNode trieNode = new(NodeType.Branch); - Assert.Throws(() => trieNode.Value = new byte[] { 1, 2, 3 }); - } + // private TrieNode _tiniestLeaf; + // private TrieNode _heavyLeaf; + // private TrieNode _accountLeaf; + // + // [SetUp] + // public void Setup() + // { + // _tiniestLeaf = new TrieNode(NodeType.Leaf); + // _tiniestLeaf.Key = new HexPrefix(true, 5); + // _tiniestLeaf.Value = new byte[] {10}; + // + // _heavyLeaf = new TrieNode(NodeType.Leaf); + // _heavyLeaf.Key = new HexPrefix(true, new byte[20]); + // _heavyLeaf.Value = Keccak.EmptyTreeHash.Bytes.Concat(Keccak.EmptyTreeHash.Bytes).ToArray(); + // + // Account account = new Account(100); + // AccountDecoder decoder = new AccountDecoder(); + // _accountLeaf = TrieNodeFactory.CreateLeaf( + // HexPrefix.Leaf("bbb"), + // decoder.Encode(account).Bytes); + // } + + [Test] + public void Throws_trie_exception_when_setting_value_on_branch() + { + TrieNode trieNode = new(NodeType.Branch); + Assert.Throws(() => trieNode.Value = new byte[] { 1, 2, 3 }); + } - [Test] - public void Throws_trie_exception_on_missing_node() - { - TrieNode trieNode = new(NodeType.Unknown); - Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); - } + [Test] + public void Throws_trie_exception_on_missing_node() + { + TrieNode trieNode = new(NodeType.Unknown); + Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); + } - [Test] - public void Forward_read_flags_on_resolve() + [Test] + public void Forward_read_flags_on_resolve() + { + ITrieNodeResolver resolver = Substitute.For(); + resolver.LoadRlp(TreePath.Empty, TestItem.KeccakA, ReadFlags.HintReadAhead).Returns((byte[])null); + TrieNode trieNode = new(NodeType.Unknown, TestItem.KeccakA); + try { - ITrieNodeResolver resolver = Substitute.For(); - resolver.LoadRlp(TreePath.Empty, TestItem.KeccakA, ReadFlags.HintReadAhead).Returns((byte[])null); - TrieNode trieNode = new(NodeType.Unknown, TestItem.KeccakA); - try - { - Assert.Throws(() => trieNode.ResolveNode(resolver, TreePath.Empty, ReadFlags.HintReadAhead)); - } - catch (TrieException) - { - } - resolver.Received().LoadRlp(TreePath.Empty, TestItem.KeccakA, ReadFlags.HintReadAhead); + Assert.Throws(() => trieNode.ResolveNode(resolver, TreePath.Empty, ReadFlags.HintReadAhead)); } - - [Test] - public void Throws_trie_exception_on_unexpected_format() + catch (TrieException) { - TrieNode trieNode = new(NodeType.Unknown, new byte[42]); - Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); } + resolver.Received().LoadRlp(TreePath.Empty, TestItem.KeccakA, ReadFlags.HintReadAhead); + } - [Test] - public void When_resolving_an_unknown_node_without_keccak_and_rlp_trie_exception_should_be_thrown() - { - TrieNode trieNode = new(NodeType.Unknown); - Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); - } + [Test] + public void Throws_trie_exception_on_unexpected_format() + { + TrieNode trieNode = new(NodeType.Unknown, new byte[42]); + Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); + } - [Test] - public void When_resolving_an_unknown_node_without_rlp_trie_exception_should_be_thrown() - { - TrieNode trieNode = new(NodeType.Unknown, Keccak.Zero); - Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); - } + [Test] + public void When_resolving_an_unknown_node_without_keccak_and_rlp_trie_exception_should_be_thrown() + { + TrieNode trieNode = new(NodeType.Unknown); + Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); + } - [Test] - public void Encoding_leaf_without_key_throws_trie_exception() - { - TrieNode trieNode = new(NodeType.Leaf); - trieNode.Value = new byte[] { 1, 2, 3 }; - TreePath emptyPath = TreePath.Empty; - Assert.Throws(() => trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath)); - } + [Test] + public void When_resolving_an_unknown_node_without_rlp_trie_exception_should_be_thrown() + { + TrieNode trieNode = new(NodeType.Unknown, Keccak.Zero); + Assert.Throws(() => trieNode.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty)); + } - [Test] - public void Throws_trie_exception_when_resolving_key_on_missing_rlp() - { - TrieNode trieNode = new(NodeType.Unknown); - TreePath emptyPath = TreePath.Empty; - Assert.Throws(() => trieNode.ResolveKey(NullTrieNodeResolver.Instance, ref emptyPath, false)); - } + [Test] + public void Encoding_leaf_without_key_throws_trie_exception() + { + TrieNode trieNode = new(NodeType.Leaf); + trieNode.Value = new byte[] { 1, 2, 3 }; + TreePath emptyPath = TreePath.Empty; + Assert.Throws(() => trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath)); + } + + [Test] + public void Throws_trie_exception_when_resolving_key_on_missing_rlp() + { + TrieNode trieNode = new(NodeType.Unknown); + TreePath emptyPath = TreePath.Empty; + Assert.Throws(() => trieNode.ResolveKey(NullTrieNodeResolver.Instance, ref emptyPath, false)); + } + + [Test(Description = "This is controversial and only used in visitors. Can consider an exception instead.")] + public void Get_child_hash_is_null_when_rlp_is_null() + { + TrieNode trieNode = new(NodeType.Branch); + Assert.That(trieNode.GetChildHash(0), Is.Null); + } - [Test(Description = "This is controversial and only used in visitors. Can consider an exception instead.")] - public void Get_child_hash_is_null_when_rlp_is_null() + [Test] + public void Can_check_if_branch_is_valid_with_one_child_less() + { + Context ctx = new(); + for (int i = 0; i < 16; i++) { TrieNode trieNode = new(NodeType.Branch); - Assert.Null(trieNode.GetChildHash(0)); + for (int j = 0; j < i; j++) + { + trieNode.SetChild(j, ctx.TiniestLeaf); + } + + if (i > 2) + { + Assert.That(trieNode.IsValidWithOneNodeLess, Is.True); + } + else + { + Assert.That(trieNode.IsValidWithOneNodeLess, Is.False); + } } + } - [Test] - public void Can_check_if_branch_is_valid_with_one_child_less() + [Test] + public void Can_check_if_child_is_null_on_a_branch() + { + Context ctx = new(); + for (int nonNullChildrenCount = 0; nonNullChildrenCount < 16; nonNullChildrenCount++) { - Context ctx = new(); - for (int i = 0; i < 16; i++) + TrieNode trieNode = new(NodeType.Branch); + for (int j = 0; j < nonNullChildrenCount; j++) { - TrieNode trieNode = new(NodeType.Branch); - for (int j = 0; j < i; j++) - { - trieNode.SetChild(j, ctx.TiniestLeaf); - } + trieNode.SetChild(j, ctx.TiniestLeaf); + } - if (i > 2) + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + TrieNode restoredNode = new(NodeType.Branch, rlp); + + for (int childIndex = 0; childIndex < 16; childIndex++) + { + if (childIndex < nonNullChildrenCount) { - Assert.True(trieNode.IsValidWithOneNodeLess); + Assert.That(trieNode.IsChildNull(childIndex), Is.False, $"original {childIndex}"); + Assert.That(restoredNode.IsChildNull(childIndex), Is.False, $"restored {childIndex}"); } else { - Assert.False(trieNode.IsValidWithOneNodeLess); + Assert.That(trieNode.IsChildNull(childIndex), Is.True, $"original {childIndex}"); + Assert.That(restoredNode.IsChildNull(childIndex), Is.True, $"restored {childIndex}"); } } } + } - [Test] - public void Can_check_if_child_is_null_on_a_branch() - { - Context ctx = new(); - for (int nonNullChildrenCount = 0; nonNullChildrenCount < 16; nonNullChildrenCount++) - { - TrieNode trieNode = new(NodeType.Branch); - for (int j = 0; j < nonNullChildrenCount; j++) - { - trieNode.SetChild(j, ctx.TiniestLeaf); - } + [Test] + public void Can_encode_decode_tiny_branch() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Branch); + trieNode.SetChild(11, ctx.TiniestLeaf); - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - TrieNode restoredNode = new(NodeType.Branch, rlp); + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - for (int childIndex = 0; childIndex < 16; childIndex++) - { - if (childIndex < nonNullChildrenCount) - { - Assert.False(trieNode.IsChildNull(childIndex), $"original {childIndex}"); - Assert.False(restoredNode.IsChildNull(childIndex), $"restored {childIndex}"); - } - else - { - Assert.True(trieNode.IsChildNull(childIndex), $"original {childIndex}"); - Assert.True(restoredNode.IsChildNull(childIndex), $"restored {childIndex}"); - } - } - } - } + TrieNode decoded = new(NodeType.Unknown, rlp); + decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); + TrieNode decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 11); + decodedTiniest.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); - [Test] - public void Can_encode_decode_tiny_branch() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Branch); - trieNode.SetChild(11, ctx.TiniestLeaf); - - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + Assert.That(decodedTiniest.Value.ToArray(), Is.EqualTo(ctx.TiniestLeaf.Value.ToArray()), "value"); + Assert.That(HexPrefix.ToBytes(decodedTiniest.Key!, true), Is.EqualTo(HexPrefix.ToBytes(ctx.TiniestLeaf.Key!, true)), "key"); + } - TrieNode decoded = new(NodeType.Unknown, rlp); - decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); - TrieNode decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 11); - decodedTiniest.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); + [Test] + public void Can_encode_decode_heavy_branch() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Branch); + trieNode.SetChild(11, ctx.HeavyLeaf); - Assert.That(decodedTiniest.Value.ToArray(), Is.EqualTo(ctx.TiniestLeaf.Value.ToArray()), "value"); - Assert.That(HexPrefix.ToBytes(decodedTiniest.Key!, true), Is.EqualTo(HexPrefix.ToBytes(ctx.TiniestLeaf.Key!, true)), "key"); - } + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - [Test] - public void Can_encode_decode_heavy_branch() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Branch); - trieNode.SetChild(11, ctx.HeavyLeaf); + TrieNode decoded = new(NodeType.Unknown, rlp); + decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); + TrieNode decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 11); - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + Assert.That(decodedTiniest.Keccak, Is.EqualTo(decoded.GetChildHash(11)), "value"); + } - TrieNode decoded = new(NodeType.Unknown, rlp); - decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); - TrieNode decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 11); + [Test] + public void Can_encode_decode_tiny_extension() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Extension); + trieNode.Key = new byte[] { 5 }; + trieNode.SetChild(0, ctx.TiniestLeaf); + + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + + TrieNode decoded = new(NodeType.Unknown, rlp); + decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); + TrieNode? decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 0); + decodedTiniest?.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); + + Assert.That(decodedTiniest.Value.ToArray(), Is.EqualTo(ctx.TiniestLeaf.Value.ToArray()), "value"); + Assert.That(HexPrefix.ToBytes(decodedTiniest.Key!, true), Is.EqualTo(HexPrefix.ToBytes(ctx.TiniestLeaf.Key!, true)), + "key"); + } - Assert.That(decodedTiniest.Keccak, Is.EqualTo(decoded.GetChildHash(11)), "value"); - } + [Test] + public void Can_encode_decode_heavy_extension() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Extension); + trieNode.Key = new byte[] { 5 }; + trieNode.SetChild(0, ctx.HeavyLeaf); - [Test] - public void Can_encode_decode_tiny_extension() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Extension); - trieNode.Key = new byte[] { 5 }; - trieNode.SetChild(0, ctx.TiniestLeaf); + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + TrieNode decoded = new(NodeType.Unknown, rlp); + decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); + TrieNode decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 0); - TrieNode decoded = new(NodeType.Unknown, rlp); - decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); - TrieNode? decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 0); - decodedTiniest?.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); + Assert.That(decodedTiniest.Keccak, Is.EqualTo(decoded.GetChildHash(0)), "keccak"); + } - Assert.That(decodedTiniest.Value.ToArray(), Is.EqualTo(ctx.TiniestLeaf.Value.ToArray()), "value"); - Assert.That(HexPrefix.ToBytes(decodedTiniest.Key!, true), Is.EqualTo(HexPrefix.ToBytes(ctx.TiniestLeaf.Key!, true)), - "key"); - } + [Test] + public void Can_set_and_get_children_using_indexer() + { + TrieNode tiniest = new(NodeType.Leaf); + tiniest.Key = new byte[] { 5 }; + tiniest.Value = new byte[] { 10 }; + + TrieNode trieNode = new(NodeType.Branch); + trieNode[11] = tiniest; + TreePath emptyPath = TreePath.Empty; + TrieNode getResult = trieNode.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 11); + Assert.That(getResult, Is.SameAs(tiniest)); + } - [Test] - public void Can_encode_decode_heavy_extension() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Extension); - trieNode.Key = new byte[] { 5 }; - trieNode.SetChild(0, ctx.HeavyLeaf); + [Test] + public void Get_child_hash_works_on_hashed_child_of_a_branch() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Branch); + trieNode[11] = ctx.HeavyLeaf; + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + TrieNode decoded = new(NodeType.Branch, rlp); + + Hash256 getResult = decoded.GetChildHash(11); + Assert.That(getResult, Is.Not.Null); + } - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + [Test] + public void Get_child_hash_works_on_inlined_child_of_a_branch() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Branch); - TrieNode decoded = new(NodeType.Unknown, rlp); - decoded.ResolveNode(NullTrieNodeResolver.Instance, TreePath.Empty); - TrieNode decodedTiniest = decoded.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 0); + trieNode[11] = ctx.TiniestLeaf; + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + TrieNode decoded = new(NodeType.Branch, rlp); - Assert.That(decodedTiniest.Keccak, Is.EqualTo(decoded.GetChildHash(0)), "keccak"); - } + Hash256 getResult = decoded.GetChildHash(11); + Assert.That(getResult, Is.Null); + } - [Test] - public void Can_set_and_get_children_using_indexer() - { - TrieNode tiniest = new(NodeType.Leaf); - tiniest.Key = new byte[] { 5 }; - tiniest.Value = new byte[] { 10 }; + [Test] + public void Get_child_hash_works_on_hashed_child_of_an_extension() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Extension); + trieNode[0] = ctx.HeavyLeaf; + trieNode.Key = new byte[] { 5 }; + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + TrieNode decoded = new(NodeType.Extension, rlp); + + Hash256 getResult = decoded.GetChildHash(0); + Assert.That(getResult, Is.Not.Null); + } - TrieNode trieNode = new(NodeType.Branch); - trieNode[11] = tiniest; - TreePath emptyPath = TreePath.Empty; - TrieNode getResult = trieNode.GetChild(NullTrieNodeResolver.Instance, ref emptyPath, 11); - Assert.That(getResult, Is.SameAs(tiniest)); - } + [Test] + public void Get_child_hash_works_on_inlined_child_of_an_extension() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Extension); + trieNode[0] = ctx.TiniestLeaf; + trieNode.Key = new byte[] { 5 }; + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + TrieNode decoded = new(NodeType.Extension, rlp); + + Hash256 getResult = decoded.GetChildHash(0); + Assert.That(getResult, Is.Null); + } - [Test] - public void Get_child_hash_works_on_hashed_child_of_a_branch() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Branch); - trieNode[11] = ctx.HeavyLeaf; - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - TrieNode decoded = new(NodeType.Branch, rlp); + [Test] + public void Extension_can_accept_visitors() + { + ITreeVisitor visitor = Substitute.For(); + TrieVisitContext context = new(); + TrieNode ignore = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("ccc"), Array.Empty()); + TrieNode node = TrieNodeFactory.CreateExtension(Bytes.FromHexString("aa"), ignore); - Hash256 getResult = decoded.GetChildHash(11); - Assert.NotNull(getResult); - } + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, NullTrieNodeResolver.Instance, ref emptyPath, context); - [Test] - public void Get_child_hash_works_on_inlined_child_of_a_branch() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Branch); + visitor.Received().VisitExtension(node, context); + } - trieNode[11] = ctx.TiniestLeaf; - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - TrieNode decoded = new(NodeType.Branch, rlp); + [Test] + public void Unknown_node_with_missing_data_can_accept_visitor() + { + ITreeVisitor visitor = Substitute.For(); + TrieVisitContext context = new(); + TrieNode node = new(NodeType.Unknown); - Hash256 getResult = decoded.GetChildHash(11); - Assert.Null(getResult); - } + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, NullTrieNodeResolver.Instance, ref emptyPath, context); - [Test] - public void Get_child_hash_works_on_hashed_child_of_an_extension() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Extension); - trieNode[0] = ctx.HeavyLeaf; - trieNode.Key = new byte[] { 5 }; - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - TrieNode decoded = new(NodeType.Extension, rlp); + visitor.Received().VisitMissingNode(node.Keccak, context); + } - Hash256 getResult = decoded.GetChildHash(0); - Assert.NotNull(getResult); - } + [Test] + public void Leaf_with_simple_account_can_accept_visitors() + { + TreeVisitorMock visitor = new(); + TrieVisitContext context = new(); + Account account = new(100); + AccountDecoder decoder = new(); + TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); - [Test] - public void Get_child_hash_works_on_inlined_child_of_an_extension() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Extension); - trieNode[0] = ctx.TiniestLeaf; - trieNode.Key = new byte[] { 5 }; - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = trieNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - TrieNode decoded = new(NodeType.Extension, rlp); + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); - Hash256 getResult = decoded.GetChildHash(0); - Assert.Null(getResult); - } + visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); + } - [Test] - public void Extension_can_accept_visitors() - { - ITreeVisitor visitor = Substitute.For(); - TrieVisitContext context = new(); - TrieNode ignore = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("ccc"), Array.Empty()); - TrieNode node = TrieNodeFactory.CreateExtension(Bytes.FromHexString("aa"), ignore); + [Test] + public void Leaf_with_contract_without_storage_and_empty_code_can_accept_visitors() + { + TreeVisitorMock visitor = new(); + TrieVisitContext context = new(); + Account account = new(1, 100, Keccak.EmptyTreeHash, Keccak.OfAnEmptyString); + AccountDecoder decoder = new(); + TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, NullTrieNodeResolver.Instance, ref emptyPath, context); + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); - visitor.Received().VisitExtension(node, context); - } + visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); + } - [Test] - public void Unknown_node_with_missing_data_can_accept_visitor() - { - ITreeVisitor visitor = Substitute.For(); - TrieVisitContext context = new(); - TrieNode node = new(NodeType.Unknown); + [Test] + public void Leaf_with_contract_without_storage_and_with_code_can_accept_visitors() + { + TreeVisitorMock visitor = new(); + TrieVisitContext context = new(); + Account account = new(1, 100, Keccak.EmptyTreeHash, Keccak.Zero); + AccountDecoder decoder = new(); + TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, NullTrieNodeResolver.Instance, ref emptyPath, context); + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); - visitor.Received().VisitMissingNode(node.Keccak, context); - } + visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); + } - [Test] - public void Leaf_with_simple_account_can_accept_visitors() - { - TreeVisitorMock visitor = new(); - TrieVisitContext context = new(); - Account account = new(100); - AccountDecoder decoder = new(); - TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); + [Test] + public void Leaf_with_contract_with_storage_and_without_code_can_accept_visitors() + { + TreeVisitorMock visitor = new(); + TrieVisitContext context = new(); + Account account = new(1, 100, Keccak.Zero, Keccak.OfAnEmptyString); + AccountDecoder decoder = new(); + TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); - visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); - } + visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); + } - [Test] - public void Leaf_with_contract_without_storage_and_empty_code_can_accept_visitors() - { - TreeVisitorMock visitor = new(); - TrieVisitContext context = new(); - Account account = new(1, 100, Keccak.EmptyTreeHash, Keccak.OfAnEmptyString); - AccountDecoder decoder = new(); - TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); + [Test] + public void Extension_with_leaf_can_be_visited() + { + Context ctx = new(); + TreeVisitorMock visitor = new(); + TrieVisitContext context = new(); + TrieNode node = TrieNodeFactory.CreateExtension(Bytes.FromHexString("aa"), ctx.AccountLeaf); - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); - visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); - } + visitor.VisitExtensionReceived[(TreePath.Empty, node, context)].Should().Be(1); + visitor.VisitLeafReceived[(new(new(Bytes.FromHexString("0xa000000000000000000000000000000000000000000000000000000000000000")), 1), ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray())].Should().Be(1); + } - [Test] - public void Leaf_with_contract_without_storage_and_with_code_can_accept_visitors() + [Test] + public void Branch_with_children_can_be_visited() + { + Context ctx = new(); + TreeVisitorMock visitor = new(); + TrieVisitContext context = new(); + TrieNode node = new(NodeType.Branch); + for (int i = 0; i < 16; i++) { - TreeVisitorMock visitor = new(); - TrieVisitContext context = new(); - Account account = new(1, 100, Keccak.EmptyTreeHash, Keccak.Zero); - AccountDecoder decoder = new(); - TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); + node.SetChild(i, ctx.AccountLeaf); + } - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); + TreePath emptyPath = TreePath.Empty; + node.ResolveKey(NullTrieStore.Instance, ref emptyPath, true); + node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); - visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); + visitor.VisitBranchReceived[(TreePath.Empty, node, context)].Should().Be(1); + for (byte i = 0; i < 16; i++) + { + var hex = "0x" + i.ToString("x2")[1] + "000000000000000000000000000000000000000000000000000000000000000"; + visitor.VisitLeafReceived[(new(new(Bytes.FromHexString(hex)), 1), ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray())].Should().Be(1); } + } - [Test] - public void Leaf_with_contract_with_storage_and_without_code_can_accept_visitors() + [Test] + public void Branch_can_accept_visitors() + { + ITreeVisitor visitor = Substitute.For(); + TrieVisitContext context = new(); + TrieNode node = new(NodeType.Branch); + for (int i = 0; i < 16; i++) { - TreeVisitorMock visitor = new(); - TrieVisitContext context = new(); - Account account = new(1, 100, Keccak.Zero, Keccak.OfAnEmptyString); - AccountDecoder decoder = new(); - TrieNode node = TrieNodeFactory.CreateLeaf(Bytes.FromHexString("aa"), decoder.Encode(account).Bytes); - - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); - - visitor.VisitLeafReceived[(TreePath.Empty, node, context, node.Value.ToArray())].Should().Be(1); + node.SetChild(i, null); } - [Test] - public void Extension_with_leaf_can_be_visited() - { - Context ctx = new(); - TreeVisitorMock visitor = new(); - TrieVisitContext context = new(); - TrieNode node = TrieNodeFactory.CreateExtension(Bytes.FromHexString("aa"), ctx.AccountLeaf); + TreePath emptyPath = TreePath.Empty; + node.Accept(visitor, NullTrieNodeResolver.Instance, ref emptyPath, context); - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); + visitor.Received().VisitBranch(node, context); + } - visitor.VisitExtensionReceived[(TreePath.Empty, node, context)].Should().Be(1); - visitor.VisitLeafReceived[(new(new(Bytes.FromHexString("0xa000000000000000000000000000000000000000000000000000000000000000")), 1), ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray())].Should().Be(1); - } + [Test] + public void Can_encode_branch_with_nulls() + { + TrieNode node = new(NodeType.Branch); + TreePath emptyPath = TreePath.Empty; + node.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + } - [Test] - public void Branch_with_children_can_be_visited() - { - Context ctx = new(); - TreeVisitorMock visitor = new(); - TrieVisitContext context = new(); - TrieNode node = new(NodeType.Branch); - for (int i = 0; i < 16; i++) - { - node.SetChild(i, ctx.AccountLeaf); - } + [Test] + public void Is_child_dirty_on_extension_when_child_is_null_returns_false() + { + TrieNode node = new(NodeType.Extension); + Assert.That(node.IsChildDirty(0), Is.False); + } - TreePath emptyPath = TreePath.Empty; - node.ResolveKey(NullTrieStore.Instance, ref emptyPath, true); - node.Accept(visitor, default, NullTrieNodeResolver.Instance, ref emptyPath, context); + [Test] + public void Is_child_dirty_on_extension_when_child_is_null_node_returns_false() + { + TrieNode node = new(NodeType.Extension); + node.SetChild(0, null); + Assert.That(node.IsChildDirty(0), Is.False); + } - visitor.VisitBranchReceived[(TreePath.Empty, node, context)].Should().Be(1); - for (byte i = 0; i < 16; i++) - { - var hex = "0x" + i.ToString("x2")[1] + "000000000000000000000000000000000000000000000000000000000000000"; - visitor.VisitLeafReceived[(new(new(Bytes.FromHexString(hex)), 1), ctx.AccountLeaf, context, ctx.AccountLeaf.Value.ToArray())].Should().Be(1); - } - } + [Test] + public void Is_child_dirty_on_extension_when_child_is_not_dirty_returns_false() + { + TrieNode node = new(NodeType.Extension); + TrieNode cleanChild = new(NodeType.Leaf, Keccak.Zero); + node.SetChild(0, cleanChild); + Assert.That(node.IsChildDirty(0), Is.False); + } - [Test] - public void Branch_can_accept_visitors() - { - ITreeVisitor visitor = Substitute.For(); - TrieVisitContext context = new(); - TrieNode node = new(NodeType.Branch); - for (int i = 0; i < 16; i++) - { - node.SetChild(i, null); - } + [Test] + public void Is_child_dirty_on_extension_when_child_is_dirty_returns_true() + { + TrieNode node = new(NodeType.Extension); + TrieNode dirtyChild = new(NodeType.Leaf); + node.SetChild(0, dirtyChild); + Assert.That(node.IsChildDirty(0), Is.True); + } - TreePath emptyPath = TreePath.Empty; - node.Accept(visitor, NullTrieNodeResolver.Instance, ref emptyPath, context); + [Test] + public void Empty_branch_will_not_be_valid_with_one_child_less() + { + TrieNode node = new(NodeType.Branch); + Assert.That(node.IsValidWithOneNodeLess, Is.False); + } - visitor.Received().VisitBranch(node, context); - } + [Test] + public void Cannot_ask_about_validity_on_non_branch_nodes() + { + TrieNode leaf = new(NodeType.Leaf); + TrieNode extension = new(NodeType.Leaf); + Assert.Throws(() => _ = leaf.IsValidWithOneNodeLess, "leaf"); + Assert.Throws(() => _ = extension.IsValidWithOneNodeLess, "extension"); + } - [Test] - public void Can_encode_branch_with_nulls() + [Test] + public void Can_encode_branch_with_unresolved_children() + { + TrieNode node = new(NodeType.Branch); + TrieNode randomTrieNode = new(NodeType.Leaf); + randomTrieNode.Key = new byte[] { 1, 2, 3 }; + randomTrieNode.Value = new byte[] { 1, 2, 3 }; + for (int i = 0; i < 16; i++) { - TrieNode node = new(NodeType.Branch); - TreePath emptyPath = TreePath.Empty; - node.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + node.SetChild(i, randomTrieNode); } - [Test] - public void Is_child_dirty_on_extension_when_child_is_null_returns_false() - { - TrieNode node = new(NodeType.Extension); - Assert.False(node.IsChildDirty(0)); - } + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = node.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - [Test] - public void Is_child_dirty_on_extension_when_child_is_null_node_returns_false() - { - TrieNode node = new(NodeType.Extension); - node.SetChild(0, null); - Assert.False(node.IsChildDirty(0)); - } + TrieNode restoredNode = new(NodeType.Branch, rlp); - [Test] - public void Is_child_dirty_on_extension_when_child_is_not_dirty_returns_false() - { - TrieNode node = new(NodeType.Extension); - TrieNode cleanChild = new(NodeType.Leaf, Keccak.Zero); - node.SetChild(0, cleanChild); - Assert.False(node.IsChildDirty(0)); - } + restoredNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + } - [Test] - public void Is_child_dirty_on_extension_when_child_is_dirty_returns_true() - { - TrieNode node = new(NodeType.Extension); - TrieNode dirtyChild = new(NodeType.Leaf); - node.SetChild(0, dirtyChild); - Assert.True(node.IsChildDirty(0)); - } + [Test] + public void Size_of_a_heavy_leaf_is_correct() + { + Context ctx = new(); + Assert.That(ctx.HeavyLeaf.GetMemorySize(false), Is.EqualTo(248)); + } - [Test] - public void Empty_branch_will_not_be_valid_with_one_child_less() - { - TrieNode node = new(NodeType.Branch); - Assert.False(node.IsValidWithOneNodeLess); - } + [Test] + public void Size_of_a_tiny_leaf_is_correct() + { + Context ctx = new(); + Assert.That(ctx.TiniestLeaf.GetMemorySize(false), Is.EqualTo(168)); + } - [Test] - public void Cannot_ask_about_validity_on_non_branch_nodes() + [Test] + public void Size_of_a_branch_is_correct() + { + Context ctx = new(); + TrieNode node = new(NodeType.Branch); + node.Key = new byte[] { 1 }; + for (int i = 0; i < 16; i++) { - TrieNode leaf = new(NodeType.Leaf); - TrieNode extension = new(NodeType.Leaf); - Assert.Throws(() => _ = leaf.IsValidWithOneNodeLess, "leaf"); - Assert.Throws(() => _ = extension.IsValidWithOneNodeLess, "extension"); + node.SetChild(i, ctx.AccountLeaf); } - [Test] - public void Can_encode_branch_with_unresolved_children() - { - TrieNode node = new(NodeType.Branch); - TrieNode randomTrieNode = new(NodeType.Leaf); - randomTrieNode.Key = new byte[] { 1, 2, 3 }; - randomTrieNode.Value = new byte[] { 1, 2, 3 }; - for (int i = 0; i < 16; i++) - { - node.SetChild(i, randomTrieNode); - } - - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = node.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); + Assert.That(node.GetMemorySize(true), Is.EqualTo(4048)); + Assert.That(node.GetMemorySize(false), Is.EqualTo(208)); + } - TrieNode restoredNode = new(NodeType.Branch, rlp); + [Test] + public void Size_of_an_extension_is_correct() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Extension); + trieNode.Key = new byte[] { 1 }; + trieNode.SetChild(0, ctx.TiniestLeaf); - restoredNode.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - } + Assert.That(trieNode.GetMemorySize(false), Is.EqualTo(120)); + } - [Test] - public void Size_of_a_heavy_leaf_is_correct() - { - Context ctx = new(); - Assert.That(ctx.HeavyLeaf.GetMemorySize(false), Is.EqualTo(248)); - } + [Test] + public void Size_of_unknown_node_is_correct() + { + Context ctx = new(); + TrieNode trieNode = new(NodeType.Extension); + trieNode.Key = new byte[] { 1 }; + trieNode.SetChild(0, ctx.TiniestLeaf); - [Test] - public void Size_of_a_tiny_leaf_is_correct() - { - Context ctx = new(); - Assert.That(ctx.TiniestLeaf.GetMemorySize(false), Is.EqualTo(168)); - } + Assert.That(trieNode.GetMemorySize(true), Is.EqualTo(288)); + Assert.That(trieNode.GetMemorySize(false), Is.EqualTo(120)); + } - [Test] - public void Size_of_a_branch_is_correct() - { - Context ctx = new(); - TrieNode node = new(NodeType.Branch); - node.Key = new byte[] { 1 }; - for (int i = 0; i < 16; i++) - { - node.SetChild(i, ctx.AccountLeaf); - } + [Test] + public void Size_of_an_unknown_empty_node_is_correct() + { + TrieNode trieNode = new(NodeType.Unknown); + trieNode.GetMemorySize(false).Should().Be(56); + } - Assert.That(node.GetMemorySize(true), Is.EqualTo(4048)); - Assert.That(node.GetMemorySize(false), Is.EqualTo(208)); - } + [Test] + public void Size_of_an_unknown_node_with_keccak_is_correct() + { + TrieNode trieNode = new(NodeType.Unknown, Keccak.Zero); + trieNode.GetMemorySize(false).Should().Be(104); + } - [Test] - public void Size_of_an_extension_is_correct() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Extension); - trieNode.Key = new byte[] { 1 }; - trieNode.SetChild(0, ctx.TiniestLeaf); + [Test] + public void Size_of_extension_with_child() + { + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, null); + trieNode.GetMemorySize(false).Should().Be(96); + } - Assert.That(trieNode.GetMemorySize(false), Is.EqualTo(120)); - } + [Test] + public void Size_of_branch_with_data() + { + TrieNode trieNode = new(NodeType.Branch); + trieNode.SetChild(0, null); + trieNode.GetMemorySize(false).Should().Be(208); + } - [Test] - public void Size_of_unknown_node_is_correct() - { - Context ctx = new(); - TrieNode trieNode = new(NodeType.Extension); - trieNode.Key = new byte[] { 1 }; - trieNode.SetChild(0, ctx.TiniestLeaf); + [Test] + public void Size_of_leaf_with_value() + { + TrieNode trieNode = new(NodeType.Leaf); + trieNode.Value = new byte[7]; + trieNode.GetMemorySize(false).Should().Be(152); + } - Assert.That(trieNode.GetMemorySize(true), Is.EqualTo(288)); - Assert.That(trieNode.GetMemorySize(false), Is.EqualTo(120)); - } + [Test] + public void Size_of_an_unknown_node_with_full_rlp_is_correct() + { + TrieNode trieNode = new(NodeType.Unknown, new byte[7]); + trieNode.GetMemorySize(false).Should().Be(120); + } - [Test] - public void Size_of_an_unknown_empty_node_is_correct() - { - TrieNode trieNode = new(NodeType.Unknown); - trieNode.GetMemorySize(false).Should().Be(56); - } + [Test] + public void Size_of_keccak_is_correct() + { + Hash256.MemorySize.Should().Be(48); + } - [Test] - public void Size_of_an_unknown_node_with_keccak_is_correct() - { - TrieNode trieNode = new(NodeType.Unknown, Keccak.Zero); - trieNode.GetMemorySize(false).Should().Be(104); - } + [Test] + public void Size_of_rlp_stream_is_correct() + { + RlpStream rlpStream = new(100); + rlpStream.MemorySize.Should().Be(160); + } - [Test] - public void Size_of_extension_with_child() - { - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, null); - trieNode.GetMemorySize(false).Should().Be(96); - } + [Test] + public void Size_of_rlp_stream_7_is_correct() + { + RlpStream rlpStream = new(7); + rlpStream.MemorySize.Should().Be(64); + } - [Test] - public void Size_of_branch_with_data() - { - TrieNode trieNode = new(NodeType.Branch); - trieNode.SetChild(0, null); - trieNode.GetMemorySize(false).Should().Be(208); - } + [Test] + public void Size_of_rlp_unaligned_is_correct() + { + Rlp rlp = new(new byte[1]); + rlp.MemorySize.Should().Be(56); + } - [Test] - public void Size_of_leaf_with_value() - { - TrieNode trieNode = new(NodeType.Leaf); - trieNode.Value = new byte[7]; - trieNode.GetMemorySize(false).Should().Be(152); - } + [Test] + public void Size_of_rlp_aligned_is_correct() + { + Rlp rlp = new(new byte[8]); + rlp.MemorySize.Should().Be(56); + } - [Test] - public void Size_of_an_unknown_node_with_full_rlp_is_correct() - { - TrieNode trieNode = new(NodeType.Unknown, new byte[7]); - trieNode.GetMemorySize(false).Should().Be(120); - } + [Test] + public void Cannot_seal_already_sealed() + { + TrieNode trieNode = new(NodeType.Leaf, Keccak.Zero); + Assert.Throws(() => trieNode.Seal()); + } - [Test] - public void Size_of_keccak_is_correct() - { - Hash256.MemorySize.Should().Be(48); - } + [Test] + public void Cannot_change_value_on_sealed() + { + TrieNode trieNode = new(NodeType.Leaf, Keccak.Zero); + Assert.Throws(() => trieNode.Value = new byte[5]); + } - [Test] - public void Size_of_rlp_stream_is_correct() - { - RlpStream rlpStream = new(100); - rlpStream.MemorySize.Should().Be(160); - } + [Test] + public void Cannot_change_key_on_sealed() + { + TrieNode trieNode = new(NodeType.Leaf, Keccak.Zero); + Assert.Throws( + () => trieNode.Key = Bytes.FromHexString("aaa")); + } - [Test] - public void Size_of_rlp_stream_7_is_correct() - { - RlpStream rlpStream = new(7); - rlpStream.MemorySize.Should().Be(64); - } + [Test] + public void Cannot_set_child_on_sealed() + { + TrieNode child = new(NodeType.Leaf, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension, Keccak.Zero); + Assert.Throws(() => trieNode.SetChild(0, child)); + } - [Test] - public void Size_of_rlp_unaligned_is_correct() - { - Rlp rlp = new(new byte[1]); - rlp.MemorySize.Should().Be(56); - } + [Test] + public void Pruning_regression() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); + + trieNode.PrunePersistedRecursively(1); + trieNode.Key = Bytes.FromHexString("abcd"); + TreePath emptyPath = TreePath.Empty; + trieNode.RlpEncode(NullTrieStore.Instance, ref emptyPath); + } - [Test] - public void Size_of_rlp_aligned_is_correct() - { - Rlp rlp = new(new byte[8]); - rlp.MemorySize.Should().Be(56); - } + [Test] + public void Extension_child_as_keccak() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); - [Test] - public void Cannot_seal_already_sealed() - { - TrieNode trieNode = new(NodeType.Leaf, Keccak.Zero); - Assert.Throws(() => trieNode.Seal()); - } + trieNode.PrunePersistedRecursively(1); + TreePath emptyPath = TreePath.Empty; + trieNode.GetChild(NullTrieStore.Instance, ref emptyPath, 0).Should().BeOfType(); + } - [Test] - public void Cannot_change_value_on_sealed() - { - TrieNode trieNode = new(NodeType.Leaf, Keccak.Zero); - Assert.Throws(() => trieNode.Value = new byte[5]); - } + [Test] + public void Extension_child_as_keccak_memory_size() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); - [Test] - public void Cannot_change_key_on_sealed() - { - TrieNode trieNode = new(NodeType.Leaf, Keccak.Zero); - Assert.Throws( - () => trieNode.Key = Bytes.FromHexString("aaa")); - } + trieNode.PrunePersistedRecursively(1); + trieNode.GetMemorySize(false).Should().Be(144); + } - [Test] - public void Cannot_set_child_on_sealed() - { - TrieNode child = new(NodeType.Leaf, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension, Keccak.Zero); - Assert.Throws(() => trieNode.SetChild(0, child)); - } + [Test] + public void Extension_child_as_keccak_clone() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); - [Test] - public void Pruning_regression() - { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); + trieNode.PrunePersistedRecursively(1); + TrieNode cloned = trieNode.Clone(); - trieNode.PrunePersistedRecursively(1); - trieNode.Key = Bytes.FromHexString("abcd"); - TreePath emptyPath = TreePath.Empty; - trieNode.RlpEncode(NullTrieStore.Instance, ref emptyPath); - } + cloned.GetMemorySize(false).Should().Be(144); + } - [Test] - public void Extension_child_as_keccak() - { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); + [Test] + public void Unresolve_of_persisted() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); + trieNode.Key = Bytes.FromHexString("abcd"); + TreePath emptyPath = TreePath.Empty; + trieNode.ResolveKey(NullTrieStore.Instance, ref emptyPath, false); + + trieNode.PrunePersistedRecursively(1); + trieNode.PrunePersistedRecursively(1); + } - trieNode.PrunePersistedRecursively(1); - TreePath emptyPath = TreePath.Empty; - trieNode.GetChild(NullTrieStore.Instance, ref emptyPath, 0).Should().BeOfType(); - } + [Test] + public void Small_child_unresolve() + { + TrieNode child = new(NodeType.Leaf); + child.Value = Bytes.FromHexString("a"); + child.Key = Bytes.FromHexString("b"); + TreePath emptyPath = TreePath.Empty; + child.ResolveKey(NullTrieStore.Instance, ref emptyPath, false); + child.IsPersisted = true; + + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); + trieNode.Key = Bytes.FromHexString("abcd"); + trieNode.ResolveKey(NullTrieStore.Instance, ref emptyPath, false); + + trieNode.PrunePersistedRecursively(2); + trieNode.GetChild(NullTrieStore.Instance, ref emptyPath, 0).Should().Be(child); + } - [Test] - public void Extension_child_as_keccak_memory_size() - { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); + [Test] + public void Extension_child_as_keccak_not_dirty() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); - trieNode.PrunePersistedRecursively(1); - trieNode.GetMemorySize(false).Should().Be(144); - } + trieNode.PrunePersistedRecursively(1); + trieNode.IsChildDirty(0).Should().Be(false); + } - [Test] - public void Extension_child_as_keccak_clone() - { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); + [TestCase(true)] + [TestCase(false)] + public void Extension_child_as_keccak_call_recursively(bool skipPersisted) + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); + + trieNode.PrunePersistedRecursively(1); + int count = 0; + TreePath emptyPath = TreePath.Empty; + trieNode.CallRecursively((n, s, p) => count++, null, ref emptyPath, NullTrieStore.Instance, skipPersisted, LimboTraceLogger.Instance); + count.Should().Be(1); + } - trieNode.PrunePersistedRecursively(1); - TrieNode cloned = trieNode.Clone(); + [Test] + public void Branch_child_as_keccak_encode() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Branch); + trieNode.SetChild(0, child); + trieNode.SetChild(4, child); + + trieNode.PrunePersistedRecursively(1); + TreePath emptyPath = TreePath.Empty; + trieNode.RlpEncode(NullTrieStore.Instance, ref emptyPath); + } - cloned.GetMemorySize(false).Should().Be(144); - } + [Test] + public void Branch_child_as_keccak_resolved() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Branch); + trieNode.SetChild(0, child); + trieNode.SetChild(4, child); + + trieNode.PrunePersistedRecursively(1); + var trieStore = Substitute.For(); + trieStore.FindCachedOrUnknown(Arg.Any(), Arg.Any()).Returns(child); + TreePath emptyPath = TreePath.Empty; + trieNode.GetChild(trieStore, ref emptyPath, 0).Should().Be(child); + trieNode.GetChild(trieStore, ref emptyPath, 1).Should().BeNull(); + trieNode.GetChild(trieStore, ref emptyPath, 4).Should().Be(child); + } - [Test] - public void Unresolve_of_persisted() - { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); - trieNode.Key = Bytes.FromHexString("abcd"); - TreePath emptyPath = TreePath.Empty; - trieNode.ResolveKey(NullTrieStore.Instance, ref emptyPath, false); + [Test] + public void Child_as_keccak_cached() + { + TrieNode child = new(NodeType.Unknown, Keccak.Zero); + TrieNode trieNode = new(NodeType.Extension); + trieNode.SetChild(0, child); + + trieNode.PrunePersistedRecursively(1); + var trieStore = Substitute.For(); + trieStore.FindCachedOrUnknown(Arg.Any(), Arg.Any()).Returns(child); + TreePath emptyPath = TreePath.Empty; + trieNode.GetChild(trieStore, ref emptyPath, 0).Should().Be(child); + } - trieNode.PrunePersistedRecursively(1); - trieNode.PrunePersistedRecursively(1); - } + [Test] + public void Batch_not_db_regression() + { + TrieNode child = new(NodeType.Leaf); + child.Key = Bytes.FromHexString("abc"); + child.Value = new byte[200]; + child.Seal(); + + TrieNode trieNode = new(NodeType.Extension); + trieNode.Key = Bytes.FromHexString("000102030506"); + trieNode.SetChild(0, child); + trieNode.Seal(); + + ITrieNodeResolver trieStore = Substitute.For(); + trieStore.LoadRlp(Arg.Any(), Arg.Any()).Throws(new TrieException()); + TreePath emptyPath = TreePath.Empty; + child.ResolveKey(trieStore, ref emptyPath, false); + child.IsPersisted = true; + + trieStore.FindCachedOrUnknown(Arg.Any(), Arg.Any()).Returns(new TrieNode(NodeType.Unknown, child.Keccak!)); + trieNode.GetChild(trieStore, ref emptyPath, 0); + Assert.Throws(() => trieNode.GetChild(trieStore, ref emptyPath, 0).ResolveNode(trieStore, TreePath.Empty)); + } - [Test] - public void Small_child_unresolve() + [Ignore("This does not fail on the build server")] + [Test] + public async Task Trie_node_is_not_thread_safe() + { + TrieNode trieNode = new(NodeType.Branch); + for (int i = 0; i < 16; i++) { - TrieNode child = new(NodeType.Leaf); - child.Value = Bytes.FromHexString("a"); - child.Key = Bytes.FromHexString("b"); - TreePath emptyPath = TreePath.Empty; - child.ResolveKey(NullTrieStore.Instance, ref emptyPath, false); - child.IsPersisted = true; + trieNode.SetChild(i, new TrieNode(NodeType.Unknown, TestItem.Keccaks[i])); + } - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); - trieNode.Key = Bytes.FromHexString("abcd"); - trieNode.ResolveKey(NullTrieStore.Instance, ref emptyPath, false); + trieNode.Seal(); + TreePath emptyPath = TreePath.Empty; + trieNode.ResolveKey(Substitute.For(), ref emptyPath, false); - trieNode.PrunePersistedRecursively(2); - trieNode.GetChild(NullTrieStore.Instance, ref emptyPath, 0).Should().Be(child); + void CheckChildren() + { + for (int i = 0; i < 16 * 10; i++) + { + try + { + trieNode.GetChildHash(i % 16).Should().BeEquivalentTo(TestItem.Keccaks[i % 16], i.ToString()); + } + catch (Exception) + { + throw new AssertionException("Failed"); + } + } } - [Test] - public void Extension_child_as_keccak_not_dirty() + List tasks = new(); + for (int i = 0; i < 2; i++) { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); - - trieNode.PrunePersistedRecursively(1); - trieNode.IsChildDirty(0).Should().Be(false); + Task task = new(CheckChildren); + task.Start(); + tasks.Add(task); } - [TestCase(true)] - [TestCase(false)] - public void Extension_child_as_keccak_call_recursively(bool skipPersisted) - { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); + Assert.ThrowsAsync(() => Task.WhenAll(tasks)); + await Task.CompletedTask; + } - trieNode.PrunePersistedRecursively(1); - int count = 0; - TreePath emptyPath = TreePath.Empty; - trieNode.CallRecursively((n, s, p) => count++, null, ref emptyPath, NullTrieStore.Instance, skipPersisted, LimboTraceLogger.Instance); - count.Should().Be(1); - } + [Test] + public void Rlp_is_cloned_when_cloning() + { + IScopedTrieStore trieStore = new TrieStore(new MemDb(), NullLogManager.Instance).GetTrieStore(null); + + TrieNode leaf1 = new(NodeType.Leaf); + leaf1.Key = Bytes.FromHexString("abc"); + leaf1.Value = new byte[111]; + TreePath emptyPath = TreePath.Empty; + leaf1.ResolveKey(trieStore, ref emptyPath, false); + leaf1.Seal(); + trieStore.CommitNode(0, new NodeCommitInfo(leaf1, TreePath.Empty)); + + TrieNode leaf2 = new(NodeType.Leaf); + leaf2.Key = Bytes.FromHexString("abd"); + leaf2.Value = new byte[222]; + leaf2.ResolveKey(trieStore, ref emptyPath, false); + leaf2.Seal(); + trieStore.CommitNode(0, new NodeCommitInfo(leaf2, TreePath.Empty)); + trieStore.FinishBlockCommit(TrieType.State, 0, leaf2); + + TrieNode trieNode = new(NodeType.Branch); + trieNode.SetChild(1, leaf1); + trieNode.SetChild(2, leaf2); + trieNode.ResolveKey(trieStore, ref emptyPath, true); + CappedArray rlp = trieNode.FullRlp; + + TrieNode restoredBranch = new(NodeType.Branch, rlp); + + TrieNode clone = restoredBranch.Clone(); + var restoredLeaf1 = clone.GetChild(trieStore, ref emptyPath, 1); + restoredLeaf1.Should().NotBeNull(); + restoredLeaf1.ResolveNode(trieStore, TreePath.Empty); + restoredLeaf1.Value.ToArray().Should().BeEquivalentTo(leaf1.Value.ToArray()); + } - [Test] - public void Branch_child_as_keccak_encode() + [Test] + public void Can_parallel_read_unresolved_children() + { + TrieNode node = new(NodeType.Branch); + for (int i = 0; i < 16; i++) { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Branch); - trieNode.SetChild(0, child); - trieNode.SetChild(4, child); - - trieNode.PrunePersistedRecursively(1); - TreePath emptyPath = TreePath.Empty; - trieNode.RlpEncode(NullTrieStore.Instance, ref emptyPath); + TrieNode randomTrieNode = new(NodeType.Leaf); + randomTrieNode.Key = new byte[] { (byte)i, 2, 3 }; + randomTrieNode.Value = new byte[] { 1, 2, 3 }; + node.SetChild(i, randomTrieNode); } - [Test] - public void Branch_child_as_keccak_resolved() - { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Branch); - trieNode.SetChild(0, child); - trieNode.SetChild(4, child); + TreePath emptyPath = TreePath.Empty; + CappedArray rlp = node.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - trieNode.PrunePersistedRecursively(1); - var trieStore = Substitute.For(); - trieStore.FindCachedOrUnknown(Arg.Any(), Arg.Any()).Returns(child); - TreePath emptyPath = TreePath.Empty; - trieNode.GetChild(trieStore, ref emptyPath, 0).Should().Be(child); - trieNode.GetChild(trieStore, ref emptyPath, 1).Should().BeNull(); - trieNode.GetChild(trieStore, ref emptyPath, 4).Should().Be(child); - } + TrieNode restoredNode = new(NodeType.Branch, rlp); - [Test] - public void Child_as_keccak_cached() + Parallel.For(0, 32, (index, _) => { - TrieNode child = new(NodeType.Unknown, Keccak.Zero); - TrieNode trieNode = new(NodeType.Extension); - trieNode.SetChild(0, child); + TreePath emptyPathParallel = TreePath.Empty; + restoredNode.GetChild(NullTrieNodeResolver.Instance, ref emptyPathParallel, index % 3); + }); + } - trieNode.PrunePersistedRecursively(1); - var trieStore = Substitute.For(); - trieStore.FindCachedOrUnknown(Arg.Any(), Arg.Any()).Returns(child); - TreePath emptyPath = TreePath.Empty; - trieNode.GetChild(trieStore, ref emptyPath, 0).Should().Be(child); - } + private class Context + { + public TrieNode TiniestLeaf { get; } + public TrieNode HeavyLeaf { get; } + public TrieNode AccountLeaf { get; } - [Test] - public void Batch_not_db_regression() + public Context() { - TrieNode child = new(NodeType.Leaf); - child.Key = Bytes.FromHexString("abc"); - child.Value = new byte[200]; - child.Seal(); - - TrieNode trieNode = new(NodeType.Extension); - trieNode.Key = Bytes.FromHexString("000102030506"); - trieNode.SetChild(0, child); - trieNode.Seal(); - - ITrieNodeResolver trieStore = Substitute.For(); - trieStore.LoadRlp(Arg.Any(), Arg.Any()).Throws(new TrieException()); - TreePath emptyPath = TreePath.Empty; - child.ResolveKey(trieStore, ref emptyPath, false); - child.IsPersisted = true; + TiniestLeaf = new TrieNode(NodeType.Leaf); + TiniestLeaf.Key = new byte[] { 5 }; + TiniestLeaf.Value = new byte[] { 10 }; - trieStore.FindCachedOrUnknown(Arg.Any(), Arg.Any()).Returns(new TrieNode(NodeType.Unknown, child.Keccak!)); - trieNode.GetChild(trieStore, ref emptyPath, 0); - Assert.Throws(() => trieNode.GetChild(trieStore, ref emptyPath, 0).ResolveNode(trieStore, TreePath.Empty)); - } + HeavyLeaf = new TrieNode(NodeType.Leaf); + HeavyLeaf.Key = new byte[20]; + HeavyLeaf.Value = Bytes.Concat(Keccak.EmptyTreeHash.Bytes, Keccak.EmptyTreeHash.Bytes); - [Ignore("This does not fail on the build server")] - [Test] - public async Task Trie_node_is_not_thread_safe() - { - TrieNode trieNode = new(NodeType.Branch); - for (int i = 0; i < 16; i++) - { - trieNode.SetChild(i, new TrieNode(NodeType.Unknown, TestItem.Keccaks[i])); - } + Account account = new(100); + AccountDecoder decoder = new(); + AccountLeaf = TrieNodeFactory.CreateLeaf( + Bytes.FromHexString("bbb"), + decoder.Encode(account).Bytes); + } + } - trieNode.Seal(); - TreePath emptyPath = TreePath.Empty; - trieNode.ResolveKey(Substitute.For(), ref emptyPath, false); + private class TreeVisitorMock : ITreeVisitor + { + public readonly Dictionary<(TreePath path, TrieNode, TrieVisitContext), int> VisitExtensionReceived = new(); + public readonly Dictionary<(TreePath path, TrieNode, TrieVisitContext), int> VisitBranchReceived = new(); + public readonly Dictionary<(TreePath path, TrieNode, TrieVisitContext, byte[]), int> VisitLeafReceived = new(new LeafComparer()); - void CheckChildren() - { - for (int i = 0; i < 16 * 10; i++) - { - try - { - trieNode.GetChildHash(i % 16).Should().BeEquivalentTo(TestItem.Keccaks[i % 16], i.ToString()); - } - catch (Exception) - { - throw new AssertionException("Failed"); - } - } - } + public bool IsFullDbScan => false; - List tasks = new(); - for (int i = 0; i < 2; i++) - { - Task task = new(CheckChildren); - task.Start(); - tasks.Add(task); - } + public bool ShouldVisit(in TreePathContext nodeContext, Hash256 nextNode) => true; - Assert.ThrowsAsync(() => Task.WhenAll(tasks)); - await Task.CompletedTask; + public void VisitTree(in TreePathContext nodeContext, Hash256 rootHash, TrieVisitContext trieVisitContext) + { } - [Test] - public void Rlp_is_cloned_when_cloning() + public void VisitMissingNode(in TreePathContext ctx, Hash256 nodeHash, TrieVisitContext trieVisitContext) { - IScopedTrieStore trieStore = new TrieStore(new MemDb(), NullLogManager.Instance).GetTrieStore(null); - - TrieNode leaf1 = new(NodeType.Leaf); - leaf1.Key = Bytes.FromHexString("abc"); - leaf1.Value = new byte[111]; - TreePath emptyPath = TreePath.Empty; - leaf1.ResolveKey(trieStore, ref emptyPath, false); - leaf1.Seal(); - trieStore.CommitNode(0, new NodeCommitInfo(leaf1, TreePath.Empty)); - - TrieNode leaf2 = new(NodeType.Leaf); - leaf2.Key = Bytes.FromHexString("abd"); - leaf2.Value = new byte[222]; - leaf2.ResolveKey(trieStore, ref emptyPath, false); - leaf2.Seal(); - trieStore.CommitNode(0, new NodeCommitInfo(leaf2, TreePath.Empty)); - trieStore.FinishBlockCommit(TrieType.State, 0, leaf2); - - TrieNode trieNode = new(NodeType.Branch); - trieNode.SetChild(1, leaf1); - trieNode.SetChild(2, leaf2); - trieNode.ResolveKey(trieStore, ref emptyPath, true); - CappedArray rlp = trieNode.FullRlp; - - TrieNode restoredBranch = new(NodeType.Branch, rlp); - - TrieNode clone = restoredBranch.Clone(); - var restoredLeaf1 = clone.GetChild(trieStore, ref emptyPath, 1); - restoredLeaf1.Should().NotBeNull(); - restoredLeaf1.ResolveNode(trieStore, TreePath.Empty); - restoredLeaf1.Value.ToArray().Should().BeEquivalentTo(leaf1.Value.ToArray()); } - [Test] - public void Can_parallel_read_unresolved_children() + public void VisitBranch(in TreePathContext ctx, TrieNode node, TrieVisitContext trieVisitContext) { - TrieNode node = new(NodeType.Branch); - for (int i = 0; i < 16; i++) - { - TrieNode randomTrieNode = new(NodeType.Leaf); - randomTrieNode.Key = new byte[] { (byte)i, 2, 3 }; - randomTrieNode.Value = new byte[] { 1, 2, 3 }; - node.SetChild(i, randomTrieNode); - } - - TreePath emptyPath = TreePath.Empty; - CappedArray rlp = node.RlpEncode(NullTrieNodeResolver.Instance, ref emptyPath); - - TrieNode restoredNode = new(NodeType.Branch, rlp); - - Parallel.For(0, 32, (index, _) => - { - TreePath emptyPathParallel = TreePath.Empty; - restoredNode.GetChild(NullTrieNodeResolver.Instance, ref emptyPathParallel, index % 3); - }); + CollectionsMarshal.GetValueRefOrAddDefault(VisitBranchReceived, (ctx.Path, node, trieVisitContext), out _) += 1; } - private class Context + public void VisitExtension(in TreePathContext ctx, TrieNode node, TrieVisitContext trieVisitContext) { - public TrieNode TiniestLeaf { get; } - public TrieNode HeavyLeaf { get; } - public TrieNode AccountLeaf { get; } - - public Context() - { - TiniestLeaf = new TrieNode(NodeType.Leaf); - TiniestLeaf.Key = new byte[] { 5 }; - TiniestLeaf.Value = new byte[] { 10 }; - - HeavyLeaf = new TrieNode(NodeType.Leaf); - HeavyLeaf.Key = new byte[20]; - HeavyLeaf.Value = Bytes.Concat(Keccak.EmptyTreeHash.Bytes, Keccak.EmptyTreeHash.Bytes); - - Account account = new(100); - AccountDecoder decoder = new(); - AccountLeaf = TrieNodeFactory.CreateLeaf( - Bytes.FromHexString("bbb"), - decoder.Encode(account).Bytes); - } + CollectionsMarshal.GetValueRefOrAddDefault(VisitExtensionReceived, (ctx.Path, node, trieVisitContext), out _) += 1; } - private class TreeVisitorMock : ITreeVisitor + public void VisitLeaf(in TreePathContext ctx, TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) { - public readonly Dictionary<(TreePath path, TrieNode, TrieVisitContext), int> VisitExtensionReceived = new(); - public readonly Dictionary<(TreePath path, TrieNode, TrieVisitContext), int> VisitBranchReceived = new(); - public readonly Dictionary<(TreePath path, TrieNode, TrieVisitContext, byte[]), int> VisitLeafReceived = new(new LeafComparer()); - - public bool IsFullDbScan => false; - - public bool ShouldVisit(in TreePathContext nodeContext, Hash256 nextNode) => true; - - public void VisitTree(in TreePathContext nodeContext, Hash256 rootHash, TrieVisitContext trieVisitContext) - { - } - - public void VisitMissingNode(in TreePathContext ctx, Hash256 nodeHash, TrieVisitContext trieVisitContext) - { - } - - public void VisitBranch(in TreePathContext ctx, TrieNode node, TrieVisitContext trieVisitContext) - { - CollectionsMarshal.GetValueRefOrAddDefault(VisitBranchReceived, (ctx.Path, node, trieVisitContext), out _) += 1; - } - - public void VisitExtension(in TreePathContext ctx, TrieNode node, TrieVisitContext trieVisitContext) - { - CollectionsMarshal.GetValueRefOrAddDefault(VisitExtensionReceived, (ctx.Path, node, trieVisitContext), out _) += 1; - } - - public void VisitLeaf(in TreePathContext ctx, TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan value) - { - CollectionsMarshal.GetValueRefOrAddDefault(VisitLeafReceived, (ctx.Path, node, trieVisitContext, value.ToArray()), out _) += 1; - } + CollectionsMarshal.GetValueRefOrAddDefault(VisitLeafReceived, (ctx.Path, node, trieVisitContext, value.ToArray()), out _) += 1; + } - public void VisitCode(in TreePathContext ctx, Hash256 codeHash, TrieVisitContext trieVisitContext) - { - } + public void VisitCode(in TreePathContext ctx, Hash256 codeHash, TrieVisitContext trieVisitContext) + { + } - private class LeafComparer : IEqualityComparer<(TreePath, TrieNode, TrieVisitContext, byte[])> - { - public bool Equals((TreePath, TrieNode, TrieVisitContext, byte[]) x, (TreePath, TrieNode, TrieVisitContext, byte[]) y) => - Equals(x.Item1, y.Item1) && Equals(x.Item2, y.Item2) && Equals(x.Item3, y.Item3) && Bytes.EqualityComparer.Equals(x.Item4, y.Item4); + private class LeafComparer : IEqualityComparer<(TreePath, TrieNode, TrieVisitContext, byte[])> + { + public bool Equals((TreePath, TrieNode, TrieVisitContext, byte[]) x, (TreePath, TrieNode, TrieVisitContext, byte[]) y) => + Equals(x.Item1, y.Item1) && Equals(x.Item2, y.Item2) && Equals(x.Item3, y.Item3) && Bytes.EqualityComparer.Equals(x.Item4, y.Item4); - public int GetHashCode((TreePath, TrieNode, TrieVisitContext, byte[]) obj) => - HashCode.Combine(obj.Item1, obj.Item2, obj.Item3, Bytes.EqualityComparer.GetHashCode(obj.Item4)); - } + public int GetHashCode((TreePath, TrieNode, TrieVisitContext, byte[]) obj) => + HashCode.Combine(obj.Item1, obj.Item2, obj.Item3, Bytes.EqualityComparer.GetHashCode(obj.Item4)); } } } diff --git a/src/Nethermind/Nethermind.Wallet.Test/WalletTests.cs b/src/Nethermind/Nethermind.Wallet.Test/WalletTests.cs index a39be4e3011..bb2b54a5018 100644 --- a/src/Nethermind/Nethermind.Wallet.Test/WalletTests.cs +++ b/src/Nethermind/Nethermind.Wallet.Test/WalletTests.cs @@ -17,139 +17,138 @@ using Nethermind.Serialization.Json; using NUnit.Framework; -namespace Nethermind.Wallet.Test +namespace Nethermind.Wallet.Test; + +[Parallelizable(ParallelScope.All)] +public class WalletTests { - [TestFixture, Parallelizable(ParallelScope.All)] - public class WalletTests + private class Context : IDisposable { - private class Context : IDisposable - { - private readonly TempPath _keyStorePath = TempPath.GetTempDirectory(); - - public IWallet Wallet { get; } + private readonly TempPath _keyStorePath = TempPath.GetTempDirectory(); - public Context(WalletType walletType) - { - switch (walletType) - { - case WalletType.KeyStore: - { - IKeyStoreConfig config = new KeyStoreConfig(); - config.KeyStoreDirectory = _keyStorePath.Path; - ISymmetricEncrypter encrypter = new AesEncrypter(config, LimboLogs.Instance); - Wallet = new DevKeyStoreWallet( - new FileKeyStore(config, new EthereumJsonSerializer(), encrypter, new CryptoRandom(), - LimboLogs.Instance, new PrivateKeyStoreIOSettingsProvider(config)), - LimboLogs.Instance); - break; - } - case WalletType.Memory: - { - Wallet = new DevWallet(new WalletConfig(), LimboLogs.Instance); - break; - } - case WalletType.ProtectedKeyStore: - { - IKeyStoreConfig config = new KeyStoreConfig(); - config.KeyStoreDirectory = _keyStorePath.Path; - ISymmetricEncrypter encrypter = new AesEncrypter(config, LimboLogs.Instance); - ProtectedKeyStoreWallet wallet = new ProtectedKeyStoreWallet( - new FileKeyStore(config, new EthereumJsonSerializer(), encrypter, new CryptoRandom(), - LimboLogs.Instance, new PrivateKeyStoreIOSettingsProvider(config)), - new ProtectedPrivateKeyFactory(new CryptoRandom(), - Timestamper.Default, config.KeyStoreDirectory), - Timestamper.Default, - LimboLogs.Instance); - wallet.SetupTestAccounts(3); - - Wallet = wallet; - break; - } - default: - throw new ArgumentOutOfRangeException(nameof(walletType), walletType, null); - } - } + public IWallet Wallet { get; } - public void Dispose() + public Context(WalletType walletType) + { + switch (walletType) { - _keyStorePath?.Dispose(); + case WalletType.KeyStore: + { + IKeyStoreConfig config = new KeyStoreConfig(); + config.KeyStoreDirectory = _keyStorePath.Path; + ISymmetricEncrypter encrypter = new AesEncrypter(config, LimboLogs.Instance); + Wallet = new DevKeyStoreWallet( + new FileKeyStore(config, new EthereumJsonSerializer(), encrypter, new CryptoRandom(), + LimboLogs.Instance, new PrivateKeyStoreIOSettingsProvider(config)), + LimboLogs.Instance); + break; + } + case WalletType.Memory: + { + Wallet = new DevWallet(new WalletConfig(), LimboLogs.Instance); + break; + } + case WalletType.ProtectedKeyStore: + { + IKeyStoreConfig config = new KeyStoreConfig(); + config.KeyStoreDirectory = _keyStorePath.Path; + ISymmetricEncrypter encrypter = new AesEncrypter(config, LimboLogs.Instance); + ProtectedKeyStoreWallet wallet = new ProtectedKeyStoreWallet( + new FileKeyStore(config, new EthereumJsonSerializer(), encrypter, new CryptoRandom(), + LimboLogs.Instance, new PrivateKeyStoreIOSettingsProvider(config)), + new ProtectedPrivateKeyFactory(new CryptoRandom(), + Timestamper.Default, config.KeyStoreDirectory), + Timestamper.Default, + LimboLogs.Instance); + wallet.SetupTestAccounts(3); + + Wallet = wallet; + break; + } + default: + throw new ArgumentOutOfRangeException(nameof(walletType), walletType, null); } } - private readonly ConcurrentDictionary _cachedWallets = new ConcurrentDictionary(); - private readonly ConcurrentQueue _wallets = new(); - - [OneTimeSetUp] - public void Setup() + public void Dispose() { - // by pre-caching wallets we make the tests do lot less work - Parallel.ForEach(WalletTypes.Union(WalletTypes), walletType => - { - Context cachedWallet = new Context(walletType); - _cachedWallets.TryAdd(walletType, cachedWallet); - _wallets.Enqueue(cachedWallet); - }); + _keyStorePath?.Dispose(); } + } - [OneTimeTearDown] - public void TearDown() + private readonly ConcurrentDictionary _cachedWallets = new ConcurrentDictionary(); + private readonly ConcurrentQueue _wallets = new(); + + [OneTimeSetUp] + public void Setup() + { + // by pre-caching wallets we make the tests do lot less work + Parallel.ForEach(WalletTypes.Union(WalletTypes), walletType => { - Parallel.ForEach(_wallets, wallet => - { - wallet.Dispose(); - }); - } + Context cachedWallet = new Context(walletType); + _cachedWallets.TryAdd(walletType, cachedWallet); + _wallets.Enqueue(cachedWallet); + }); + } - public enum WalletType + [OneTimeTearDown] + public void TearDown() + { + Parallel.ForEach(_wallets, wallet => { - KeyStore, - Memory, - ProtectedKeyStore - } + wallet.Dispose(); + }); + } - public static IEnumerable WalletTypes => FastEnum.GetValues(); + public enum WalletType + { + KeyStore, + Memory, + ProtectedKeyStore + } - [Test] - public void Has_10_dev_accounts([ValueSource(nameof(WalletTypes))] WalletType walletType) - { - Context ctx = _cachedWallets[walletType]; - Assert.That(ctx.Wallet.GetAccounts().Length, Is.EqualTo((walletType == WalletType.Memory ? 10 : 3))); - } + public static IEnumerable WalletTypes => FastEnum.GetValues(); - [Test] - public void Each_account_can_sign_with_simple_key([ValueSource(nameof(WalletTypes))] WalletType walletType) - { - Context ctx = _cachedWallets[walletType]; - int count = walletType == WalletType.Memory ? 10 : 3; - for (int i = 1; i <= count; i++) - { - byte[] keyBytes = new byte[32]; - keyBytes[31] = (byte)i; - PrivateKey key = new PrivateKey(keyBytes); - TestContext.Write(key.Address.Bytes.ToHexString() + Environment.NewLine); - Assert.True(ctx.Wallet.GetAccounts().Any(a => a == key.Address), $"{i}"); - } + [Test] + public void Has_10_dev_accounts([ValueSource(nameof(WalletTypes))] WalletType walletType) + { + Context ctx = _cachedWallets[walletType]; + Assert.That(ctx.Wallet.GetAccounts().Length, Is.EqualTo((walletType == WalletType.Memory ? 10 : 3))); + } - Assert.That(ctx.Wallet.GetAccounts().Length, Is.EqualTo(count)); + [Test] + public void Each_account_can_sign_with_simple_key([ValueSource(nameof(WalletTypes))] WalletType walletType) + { + Context ctx = _cachedWallets[walletType]; + int count = walletType == WalletType.Memory ? 10 : 3; + for (int i = 1; i <= count; i++) + { + byte[] keyBytes = new byte[32]; + keyBytes[31] = (byte)i; + PrivateKey key = new PrivateKey(keyBytes); + TestContext.Out.Write(key.Address.Bytes.ToHexString() + Environment.NewLine); + Assert.That(ctx.Wallet.GetAccounts().Any(a => a == key.Address), Is.True, $"{i}"); } - [Test] - public void Can_sign_on_networks_with_chain_id([ValueSource(nameof(WalletTypes))] WalletType walletType, [Values(0ul, 1ul, 40000ul, ulong.MaxValue / 3)] ulong chainId) + Assert.That(ctx.Wallet.GetAccounts().Length, Is.EqualTo(count)); + } + + [Test] + public void Can_sign_on_networks_with_chain_id([ValueSource(nameof(WalletTypes))] WalletType walletType, [Values(0ul, 1ul, 40000ul, ulong.MaxValue / 3)] ulong chainId) + { + EthereumEcdsa ecdsa = new EthereumEcdsa(chainId); + Context ctx = _cachedWallets[walletType]; + for (int i = 1; i <= (walletType == WalletType.Memory ? 10 : 3); i++) { - EthereumEcdsa ecdsa = new EthereumEcdsa(chainId); - Context ctx = _cachedWallets[walletType]; - for (int i = 1; i <= (walletType == WalletType.Memory ? 10 : 3); i++) - { - Address signerAddress = ctx.Wallet.GetAccounts()[0]; - Transaction tx = new Transaction(); - tx.SenderAddress = signerAddress; - - WalletExtensions.Sign(ctx.Wallet, tx, chainId); - Address recovered = ecdsa.RecoverAddress(tx); - Assert.That(recovered, Is.EqualTo(signerAddress), $"{i}"); - Console.WriteLine(tx.Signature); - Assert.That(tx.Signature.ChainId, Is.EqualTo(chainId), "chainId"); - } + Address signerAddress = ctx.Wallet.GetAccounts()[0]; + Transaction tx = new Transaction(); + tx.SenderAddress = signerAddress; + + WalletExtensions.Sign(ctx.Wallet, tx, chainId); + Address recovered = ecdsa.RecoverAddress(tx); + Assert.That(recovered, Is.EqualTo(signerAddress), $"{i}"); + Console.WriteLine(tx.Signature); + Assert.That(tx.Signature.ChainId, Is.EqualTo(chainId), "chainId"); } } }