From 3dfcaf966ccb56ca08c9534597628bbe33cdc403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Chodo=C5=82a?= <43241881+kamilchodola@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:04:13 +0100 Subject: [PATCH 1/8] Refactoring (#6782) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marek Moraczyński Co-authored-by: smartprogrammer Co-authored-by: Marcin Sobczak Co-authored-by: Ben Adams Co-authored-by: Ruben Buniatyan Co-authored-by: Ahmad Bitar <33181301+smartprogrammer93@users.noreply.github.com> Co-authored-by: Lukasz Rozmej Co-authored-by: Kamil Chodoła --- .github/workflows/hive-consensus-tests.yml | 31 +- .../Ethereum.Test.Base/BlockchainTestBase.cs | 7 +- .../AuRaSealValidatorTests.cs | 2 +- .../Nethermind.AuRa.Test/AuRaSealerTests.cs | 4 +- .../Validators/ListValidatorTests.cs | 2 +- .../BlockchainProcessorTests.cs | 4 +- .../InvalidBlockException.cs | 9 +- .../AuRaBlockProcessor.cs | 10 +- .../AuRaSealValidator.cs | 4 +- .../Nethermind.Consensus.AuRa/AuRaSealer.cs | 4 +- .../Validators/AuRaValidatorBase.cs | 7 +- .../Validators/IValidSealerStrategy.cs | 3 +- .../Validators/ValidSealerStrategy.cs | 3 +- .../Processing/BlockExtensions.cs | 17 +- ...sor.BlockProductionTransactionsExecutor.cs | 17 +- ...sor.BlockValidationTransactionsExecutor.cs | 16 +- .../Processing/BlockProcessor.cs | 2 +- .../Processing/BlockchainProcessor.cs | 50 +-- .../TransactionProcessorAdapterExtensions.cs | 5 +- .../Builders/BlockTreeBuilder.cs | 15 +- .../Nethermind.Evm.Test/Eip3860Tests.cs | 18 +- .../Tracing/ParityLikeTxTracerTests.cs | 8 +- .../TransactionProcessorTests.cs | 122 +++----- .../TransactionSubstateTests.cs | 23 +- .../VirtualMachineTests.cs | 2 +- .../BuildUpTransactionProcessorAdapter.cs | 2 +- ...llAndRestoreTransactionProcessorAdapter.cs | 2 +- .../ChangeableTransactionProcessorAdapter.cs | 4 +- .../ExecuteTransactionProcessorAdapter.cs | 2 +- .../ITransactionProcessor.cs | 8 +- .../ITransactionProcessorAdapter.cs | 2 +- .../ReadOnlyTransactionProcessor.cs | 8 +- .../TraceTransactionProcessorAdapter.cs | 2 +- .../TransactionProcessor.cs | 289 +++++++++--------- .../Nethermind.Evm/TransactionSubstate.cs | 87 +++--- .../Nethermind.Evm/VirtualMachine.cs | 15 +- .../BlockchainBridgeTests.cs | 2 +- .../Nethermind.Facade/BlockchainBridge.cs | 17 +- .../Modules/Eth/EthRpcModuleTests.cs | 1 + .../Modules/Proof/ProofRpcModuleTests.cs | 38 ++- .../Nethermind.JsonRpc/JsonRpcUrl.cs | 4 +- .../JsonRpcUrlCollection.cs | 9 +- .../Modules/Proof/ProofModuleFactory.cs | 4 +- .../Modules/Trace/TraceModuleFactory.cs | 3 +- .../Withdrawals/AuraWithdrawalProcessor.cs | 2 +- .../OptimismTransactionProcessor.cs | 62 ++-- .../Nethermind.Runner/JsonRpc/Startup.cs | 4 + .../WebSocketExtensionsTests.cs | 15 +- .../Nethermind.Sockets/SocketClient.cs | 6 +- 49 files changed, 490 insertions(+), 483 deletions(-) diff --git a/.github/workflows/hive-consensus-tests.yml b/.github/workflows/hive-consensus-tests.yml index 4a9b81a7d7b..a8b0fe06fe6 100644 --- a/.github/workflows/hive-consensus-tests.yml +++ b/.github/workflows/hive-consensus-tests.yml @@ -1,11 +1,11 @@ -name: 'Hive consensus tests' +name: 'Hive consensus tests' on: workflow_run: workflows: ["Publish Docker image"] branches: ["release/*"] types: - - completed + - completed workflow_dispatch: inputs: parallelism: @@ -40,7 +40,7 @@ jobs: run: | echo "ORG_NAME=${{ github.repository_owner }}" >> $GITHUB_ENV echo "REPO_NAME=${{ github.event.repository.name }}" >> $GITHUB_ENV - + - name: Check if master or release branch id: check_conditions run: | @@ -71,7 +71,7 @@ jobs: "dockerfile": "Dockerfile", "build-config": "release" }' - + - name: Wait for Docker Build Action to complete if: steps.check_conditions.outputs.skip_docker_build != 'true' env: @@ -107,7 +107,7 @@ jobs: dotnet run cat matrix.json echo "matrix=$(jq -c . matrix.json)" >> $GITHUB_OUTPUT - + run_hive_tests: runs-on: ubuntu-latest needs: [generate_hive_consensus_tests, create_docker_image] @@ -124,7 +124,7 @@ jobs: uses: actions/checkout@v4 with: path: nethermind - + - name: Install Linux packages run: | sudo apt-get update @@ -164,13 +164,12 @@ jobs: run: | chmod +x nethermind/scripts/hive-results.sh nethermind/scripts/hive-results.sh "hive/workspace/logs/*.json" - - name: Send results to dashboard - continue-on-error: true - uses: appleboy/scp-action@master - with: - host: ${{ secrets.HIVE_HOST }} - username: ${{ secrets.HIVE_USERNAME }} - key: ${{ secrets.HIVE_KEY }} - port: ${{ secrets.HIVE_PORT }} - source: hive/workspace/logs/* - target: ${{ secrets.HIVE_DIR }}/ + # - name: Send results to dashboard + # uses: appleboy/scp-action@master + # with: + # host: ${{ secrets.HIVE_HOST }} + # username: ${{ secrets.HIVE_USERNAME }} + # key: ${{ secrets.HIVE_KEY }} + # port: ${{ secrets.HIVE_PORT }} + # source: hive/workspace/logs/* + # target: ${{ secrets.HIVE_DIR }}/ diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index fe7fd623b4c..d4c19528d36 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -181,15 +181,13 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? stopwatch?.Start(); List<(Block Block, string ExpectedException)> correctRlp = DecodeRlps(test, failOnInvalidRlp); - if (test.GenesisRlp == null) - { - test.GenesisRlp = Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader))); - } + 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) @@ -271,7 +269,6 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? { 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))); diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs index 1dda8bf9cee..c4395f5c961 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs @@ -144,7 +144,7 @@ TestCaseData GetTestCaseData( public (bool, object) validate_params(BlockHeader parentBlock, BlockHeader block, Action modifyParameters, Repeat repeat, bool parentIsHead, bool isValidSealer) { _blockTree.Head.Returns(parentIsHead ? new Block(parentBlock) : new Block(Build.A.BlockHeader.WithNumber(parentBlock.Number - 1).TestObject)); - _validSealerStrategy.IsValidSealer(Arg.Any>(), block.Beneficiary, block.AuRaStep.Value).Returns(isValidSealer); + _validSealerStrategy.IsValidSealer(Arg.Any>(), block.Beneficiary, block.AuRaStep.Value, out _).Returns(isValidSealer); object cause = null; diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuRaSealerTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuRaSealerTests.cs index 3386d8b8b32..156a0517116 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/AuRaSealerTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/AuRaSealerTests.cs @@ -60,7 +60,7 @@ public void Setup() public bool can_seal(long auRaStep, bool validSealer) { _auRaStepCalculator.CurrentStep.Returns(auRaStep); - _validSealerStrategy.IsValidSealer(Arg.Any>(), _address, auRaStep).Returns(validSealer); + _validSealerStrategy.IsValidSealer(Arg.Any>(), _address, auRaStep, out _).Returns(validSealer); return _auRaSealer.CanSeal(10, _blockTree.Head.Hash); } @@ -68,7 +68,7 @@ public bool can_seal(long auRaStep, bool validSealer) public async Task seal_can_recover_address() { _auRaStepCalculator.CurrentStep.Returns(11); - _validSealerStrategy.IsValidSealer(Arg.Any>(), _address, 11).Returns(true); + _validSealerStrategy.IsValidSealer(Arg.Any>(), _address, 11, out _).Returns(true); Block block = Build.A.Block.WithHeader(Build.A.BlockHeader.WithBeneficiary(_address).WithAura(11, null).TestObject).TestObject; block = await _auRaSealer.SealBlock(block, CancellationToken.None); diff --git a/src/Nethermind/Nethermind.AuRa.Test/Validators/ListValidatorTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Validators/ListValidatorTests.cs index 79d8dbde6b8..b24b0a06020 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Validators/ListValidatorTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Validators/ListValidatorTests.cs @@ -48,7 +48,7 @@ private static IEnumerable ValidateTestCases [TestCaseSource(nameof(ValidateTestCases))] public bool should_validate_correctly(Address address, long index) => - _validSealerStrategy.IsValidSealer(GetListValidator(TestItem.AddressA, TestItem.AddressB).Validators, address, index); + _validSealerStrategy.IsValidSealer(GetListValidator(TestItem.AddressA, TestItem.AddressB).Validators, address, index, out _); [TestCase(1)] [TestCase(2)] diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs index aa50d09e96d..a5dc4884c80 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs @@ -78,7 +78,7 @@ public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, if (blockTracer != NullBlockTracer.Instance) { // this is for block reruns on failure for diag tracing - throw new InvalidBlockException(suggestedBlocks[0]); + throw new InvalidBlockException(suggestedBlocks[0], "wrong tracer"); } _logger.Info($"Processing {suggestedBlocks.Last().ToString(Block.Format.Short)}"); @@ -96,7 +96,7 @@ public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, { _allowedToFail.Remove(hash); BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty())); - throw new InvalidBlockException(suggestedBlock); + throw new InvalidBlockException(suggestedBlock, "allowed to fail"); } notYet = true; diff --git a/src/Nethermind/Nethermind.Blockchain/InvalidBlockException.cs b/src/Nethermind/Nethermind.Blockchain/InvalidBlockException.cs index c31e8887318..e589cf8bae5 100644 --- a/src/Nethermind/Nethermind.Blockchain/InvalidBlockException.cs +++ b/src/Nethermind/Nethermind.Blockchain/InvalidBlockException.cs @@ -8,8 +8,11 @@ namespace Nethermind.Blockchain; public class InvalidBlockException : BlockchainException { - public InvalidBlockException(Block block, Exception? innerException = null) - : base($"Invalid block: {block}", innerException) => InvalidBlock = block; + public InvalidBlockException(Block block, string message, Exception? innerException = null) + : base($"Invalid block: {block} : {message}", innerException) => InvalidBlock = block.Header; - public Block InvalidBlock { get; } + public InvalidBlockException(BlockHeader block, string message, Exception? innerException = null) + : base($"Invalid block: {block} : {message}", innerException) => InvalidBlock = block; + + public BlockHeader InvalidBlock { get; } } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs index 1c4c5b44b22..5eff1e0fed9 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs @@ -108,8 +108,9 @@ private void ValidateGasLimit(Block block) BlockHeader parentHeader = GetParentHeader(block); if (_gasLimitOverride?.IsGasLimitValid(parentHeader, block.GasLimit, out long? expectedGasLimit) == false) { - if (_logger.IsWarn) _logger.Warn($"Invalid gas limit for block {block.Number}, hash {block.Hash}, expected value from contract {expectedGasLimit}, but found {block.GasLimit}."); - throw new InvalidBlockException(block); + string reason = $"Invalid gas limit, expected value from contract {expectedGasLimit}, but found {block.GasLimit}"; + if (_logger.IsWarn) _logger.Warn($"Proposed block is not valid {block.ToString(Block.Format.FullHashAndNumber)}. {reason}."); + throw new InvalidBlockException(block, reason); } } @@ -121,8 +122,9 @@ private void ValidateTxs(Block block) AddingTxEventArgs args = CheckTxPosdaoRules(new AddingTxEventArgs(i, tx, block, block.Transactions)); if (args.Action != TxAction.Add) { - if (_logger.IsWarn) _logger.Warn($"Proposed block is not valid {block.ToString(Block.Format.FullHashAndNumber)}. {tx.ToShortString()} doesn't have required permissions. Reason: {args.Reason}."); - throw new InvalidBlockException(block); + string reason = $"{tx.ToShortString()} doesn't have required permissions: {args.Reason}"; + if (_logger.IsWarn) _logger.Warn($"Proposed block is not valid {block.ToString(Block.Format.FullHashAndNumber)}. {reason}."); + throw new InvalidBlockException(block, reason); } } } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs index 47002f22975..641b822b8be 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs @@ -75,9 +75,9 @@ public bool ValidateParams(BlockHeader parent, BlockHeader header, bool isUncle // no worries we do this validation later before processing the block if (parent.Hash == _blockTree.Head?.Hash) { - if (!_validSealerStrategy.IsValidSealer(_validatorStore.GetValidators(), header.Beneficiary, step)) + if (!_validSealerStrategy.IsValidSealer(_validatorStore.GetValidators(), header.Beneficiary, step, out Address expectedAddress)) { - if (_logger.IsError) _logger.Error($"Block from incorrect proposer at block {header.ToString(BlockHeader.Format.FullHashAndNumber)}, step {step} from author {header.Beneficiary}."); + if (_logger.IsError) _logger.Error($"Proposed block is not valid {header.ToString(BlockHeader.Format.FullHashAndNumber)}. Incorrect proposer at step {step}, expected {expectedAddress}, but found {header.Beneficiary}."); return false; } } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealer.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealer.cs index cfe6f992706..52903ed3d79 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealer.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealer.cs @@ -74,8 +74,8 @@ bool StepNotYetProduced(long step) => !_blockTree.Head.Header.AuRaStep.HasValue bool IsThisNodeTurn(long step) { - var validators = _validatorStore.GetValidators(); - return _validSealerStrategy.IsValidSealer(validators, _signer.Address, step); + Address[] validators = _validatorStore.GetValidators(); + return _validSealerStrategy.IsValidSealer(validators, _signer.Address, step, out _); } long currentStep = _auRaStepCalculator.CurrentStep; diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaValidatorBase.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaValidatorBase.cs index d673c1c5f33..b0fe7e7c540 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaValidatorBase.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaValidatorBase.cs @@ -49,11 +49,12 @@ public virtual void OnBlockProcessingStart(Block block, ProcessingOptions option if (!options.ContainsFlag(ProcessingOptions.ProducingBlock) && !block.IsGenesis) { var auRaStep = block.Header.AuRaStep.Value; - if (!_validSealerStrategy.IsValidSealer(Validators, block.Beneficiary, auRaStep)) + if (!_validSealerStrategy.IsValidSealer(Validators, block.Beneficiary, auRaStep, out Address expectedAddress)) { - if (_logger.IsError) _logger.Error($"Block from incorrect proposer at block {block.ToString(Block.Format.FullHashAndNumber)}, step {auRaStep} from author {block.Beneficiary}."); + string reason = $"Incorrect proposer at step {auRaStep}, expected {expectedAddress}, but found {block.Beneficiary}"; + if (_logger.IsError) _logger.Error($"Proposed block is not valid {block.ToString(Block.Format.FullHashAndNumber)}. {reason}."); this.GetReportingValidator().ReportBenign(block.Beneficiary, block.Number, IReportingValidator.BenignCause.IncorrectProposer); - throw new InvalidBlockException(block); + throw new InvalidBlockException(block, reason); } } } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidSealerStrategy.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidSealerStrategy.cs index 37565cc748a..d09c0ada06a 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidSealerStrategy.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidSealerStrategy.cs @@ -14,7 +14,8 @@ public interface IValidSealerStrategy /// Validators at given step. /// Address to be checked if its a sealer at this step. /// Step to be checked. + /// Address which should create block in current step. /// 'true' if should seal a block at for supplied collection. Otherwise 'false'. - bool IsValidSealer(IList
validators, Address address, long step); + bool IsValidSealer(IList
validators, Address address, long step, out Address expectedAddress); } } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidSealerStrategy.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidSealerStrategy.cs index c5746fdbc9e..6bb19756386 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidSealerStrategy.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidSealerStrategy.cs @@ -9,6 +9,7 @@ namespace Nethermind.Consensus.AuRa.Validators { public class ValidSealerStrategy : IValidSealerStrategy { - public bool IsValidSealer(IList
validators, Address address, long step) => validators.GetItemRoundRobin(step) == address; + public bool IsValidSealer(IList
validators, Address address, long step, out Address expectedAddress) => + (expectedAddress = validators.GetItemRoundRobin(step)) == address; } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs index 695c9129dd9..ba82ee02eb8 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs @@ -39,16 +39,11 @@ public static bool TrySetTransactions(this Block block, Transaction[] transactio return false; } - public static bool IsByNethermindNode(this Block block) - { - try - { - return Encoding.ASCII.GetString(block.ExtraData).Contains(BlocksConfig.DefaultExtraData, StringComparison.InvariantCultureIgnoreCase); - } - catch (Exception) - { - return false; - } - } + public static bool IsByNethermindNode(this Block block) => block.Header.IsByNethermindNode(); + + public static bool IsByNethermindNode(this BlockHeader block) => + Ascii.IsValid(block.ExtraData) + && Encoding.ASCII.GetString(block.ExtraData ?? Array.Empty()) + .Contains(BlocksConfig.DefaultExtraData, StringComparison.InvariantCultureIgnoreCase); } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs index fdaab77ccdb..161dd665971 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs @@ -109,13 +109,20 @@ protected TxAction ProcessTransaction( } else { - _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); + TransactionResult result = _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); - if (addToBlock) + if (result) { - transactionsInBlock.Add(currentTx); - _transactionProcessed?.Invoke(this, - new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index])); + if (addToBlock) + { + transactionsInBlock.Add(currentTx); + _transactionProcessed?.Invoke(this, + new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index])); + } + } + else + { + args.Set(TxAction.Skip, result.Error!); } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs index e520562d4e2..e2e7eb42592 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs @@ -2,13 +2,17 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; +using Nethermind.Blockchain; using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; using Nethermind.State; +using Metrics = Nethermind.Evm.Metrics; namespace Nethermind.Consensus.Processing { @@ -34,7 +38,7 @@ public BlockValidationTransactionsExecutor(ITransactionProcessorAdapter transact public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer receiptsTracer, IReleaseSpec spec) { - Evm.Metrics.ResetBlockStats(); + Metrics.ResetBlockStats(); BlockExecutionContext blkCtx = new(block.Header); for (int i = 0; i < block.Transactions.Length; i++) { @@ -46,9 +50,17 @@ public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processing private void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions) { - _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); + TransactionResult result = _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); + if (!result) ThrowInvalidBlockException(result, blkCtx.Header, currentTx, index); TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index])); } + + [DoesNotReturn] + [StackTraceHidden] + private void ThrowInvalidBlockException(TransactionResult result, BlockHeader header, Transaction currentTx, int index) + { + throw new InvalidBlockException(header, $"Transaction {currentTx.Hash} at index {index} failed with error {result.Error}"); + } } } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs index f3ae94af802..ff23595e83a 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs @@ -217,7 +217,7 @@ private void ValidateProcessedBlock(Block suggestedBlock, ProcessingOptions opti { if (_logger.IsWarn) _logger.Warn($"Processed block is not valid {suggestedBlock.ToString(Block.Format.FullHashAndNumber)}"); if (_logger.IsWarn) _logger.Warn($"Suggested block TD: {suggestedBlock.TotalDifficulty}, Suggested block IsPostMerge {suggestedBlock.IsPostMerge}, Block TD: {block.TotalDifficulty}, Block IsPostMerge {block.IsPostMerge}"); - throw new InvalidBlockException(suggestedBlock); + throw new InvalidBlockException(suggestedBlock, "invalid hash after block processing"); } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs index 33a673bce4a..2f03052f065 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs @@ -5,6 +5,8 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Text; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; @@ -496,32 +498,38 @@ void DeleteInvalidBlocks(in ProcessingBranch processingBranch, Hash256 invalidBl } catch (InvalidBlockException ex) { - InvalidBlock?.Invoke(this, new IBlockchainProcessor.InvalidBlockEventArgs { InvalidBlock = ex.InvalidBlock, }); - invalidBlockHash = ex.InvalidBlock.Hash; + Block? invalidBlock = processingBranch.BlocksToProcess.FirstOrDefault(b => b.Hash == invalidBlockHash); + if (invalidBlock is not null) + { + InvalidBlock?.Invoke(this, new IBlockchainProcessor.InvalidBlockEventArgs { InvalidBlock = invalidBlock, }); + BlockTraceDumper.LogDiagnosticRlp(invalidBlock, _logger, + (_options.DumpOptions & DumpOptions.Rlp) != 0, + (_options.DumpOptions & DumpOptions.RlpLog) != 0); - BlockTraceDumper.LogDiagnosticRlp(ex.InvalidBlock, _logger, - (_options.DumpOptions & DumpOptions.Rlp) != 0, - (_options.DumpOptions & DumpOptions.RlpLog) != 0); - - TraceFailingBranch( - processingBranch, - options, - new BlockReceiptsTracer(), - DumpOptions.Receipts); + TraceFailingBranch( + processingBranch, + options, + new BlockReceiptsTracer(), + DumpOptions.Receipts); - TraceFailingBranch( - processingBranch, - options, - new ParityLikeBlockTracer(ParityTraceTypes.StateDiff | ParityTraceTypes.Trace), - DumpOptions.Parity); + TraceFailingBranch( + processingBranch, + options, + new ParityLikeBlockTracer(ParityTraceTypes.StateDiff | ParityTraceTypes.Trace), + DumpOptions.Parity); - TraceFailingBranch( - processingBranch, - options, - new GethLikeBlockMemoryTracer(GethTraceOptions.Default), - DumpOptions.Geth); + TraceFailingBranch( + processingBranch, + options, + new GethLikeBlockMemoryTracer(GethTraceOptions.Default), + DumpOptions.Geth); + } + else + { + if (_logger.IsError) _logger.Error($"Unexpected situation occurred during the handling of an invalid block {ex.InvalidBlock}", ex); + } processedBlocks = null; } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs b/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs index 9b57646922a..bd569caf479 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs @@ -11,7 +11,7 @@ namespace Nethermind.Consensus.Processing; internal static class TransactionProcessorAdapterExtensions { - public static void ProcessTransaction(this ITransactionProcessorAdapter transactionProcessor, + public static TransactionResult ProcessTransaction(this ITransactionProcessorAdapter transactionProcessor, in BlockExecutionContext blkCtx, Transaction currentTx, BlockReceiptsTracer receiptsTracer, @@ -24,7 +24,8 @@ public static void ProcessTransaction(this ITransactionProcessorAdapter transact } using ITxTracer tracer = receiptsTracer.StartNewTxTrace(currentTx); - transactionProcessor.Execute(currentTx, in blkCtx, receiptsTracer); + TransactionResult result = transactionProcessor.Execute(currentTx, in blkCtx, receiptsTracer); receiptsTracer.EndTxTrace(); + return result; } } diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs index ff8811b67ee..39cbca5aa2b 100644 --- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs +++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs @@ -19,6 +19,7 @@ using Nethermind.State.Proofs; using Nethermind.State.Repositories; using Nethermind.Db.Blooms; +using Nethermind.Evm; using NSubstitute; using NUnit.Framework; @@ -259,8 +260,18 @@ private Block CreateBlock(int splitVariant, int splitFrom, int blockIndex, Block { Transaction[] transactions = new[] { - Build.A.Transaction.WithValue(1).WithData(Rlp.Encode(blockIndex).Bytes).Signed(_ecdsa!, TestItem.PrivateKeyA, _specProvider!.GetSpec(blockIndex + 1, null).IsEip155Enabled).TestObject, - Build.A.Transaction.WithValue(2).WithData(Rlp.Encode(blockIndex + 1).Bytes).Signed(_ecdsa!, TestItem.PrivateKeyA, _specProvider!.GetSpec(blockIndex + 1, null).IsEip155Enabled).TestObject + Build.A.Transaction + .WithValue(1) + .WithData(Rlp.Encode(blockIndex).Bytes) + .WithGasLimit(GasCostOf.Transaction * 2) + .Signed(_ecdsa!, TestItem.PrivateKeyA, _specProvider.GetSpec(blockIndex + 1, null).IsEip155Enabled) + .TestObject, + Build.A.Transaction + .WithValue(2) + .WithData(Rlp.Encode(blockIndex + 1).Bytes) + .WithGasLimit(GasCostOf.Transaction * 2) + .Signed(_ecdsa!, TestItem.PrivateKeyA, _specProvider.GetSpec(blockIndex + 1, null).IsEip155Enabled) + .TestObject }; currentBlock = currentBlockBuilder diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs index 3a2dcefcb3d..98f298a2179 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs @@ -7,6 +7,7 @@ using Nethermind.Core.Test.Builders; using NUnit.Framework; using Nethermind.Core; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Test @@ -72,7 +73,7 @@ public void Test_EIP_3860_InitCode_Create_Exceeds_Limit(string createCode) [Test] public void Test_EIP_3860_Disabled_InitCode_TxCreation_Exceeds_Limit_Succeeds() { - var tracer = PrepExecuteCreateTransaction(MainnetSpecProvider.ShanghaiBlockTimestamp - 1, Spec.MaxInitCodeSize + 1); + (_, var tracer) = PrepExecuteCreateTransaction(MainnetSpecProvider.ShanghaiBlockTimestamp - 1, Spec.MaxInitCodeSize + 1); Assert.That(tracer.StatusCode, Is.EqualTo(StatusCode.Success)); } @@ -80,22 +81,22 @@ public void Test_EIP_3860_Disabled_InitCode_TxCreation_Exceeds_Limit_Succeeds() [Test] public void Test_EIP_3860_Enabled_InitCode_TxCreation_Exceeds_Limit_Fails() { - var tracer = PrepExecuteCreateTransaction(MainnetSpecProvider.ShanghaiBlockTimestamp, Spec.MaxInitCodeSize + 1); + (var result, _) = PrepExecuteCreateTransaction(MainnetSpecProvider.ShanghaiBlockTimestamp, Spec.MaxInitCodeSize + 1); - Assert.That(tracer.StatusCode, Is.EqualTo(StatusCode.Failure)); - Assert.That(tracer.Error, Is.EqualTo("EIP-3860 - transaction size over max init code size")); + Assert.That(result.Fail, Is.True); + Assert.That(result.Error, Is.EqualTo("EIP-3860 - transaction size over max init code size")); } [Test] public void Test_EIP_3860_Enabled_InitCode_TxCreation_Within_Limit_Succeeds() { //7680 is the size of create instructions - Prepare.EvmCode.Create - var tracer = PrepExecuteCreateTransaction(MainnetSpecProvider.ShanghaiBlockTimestamp, Spec.MaxInitCodeSize - 7680); + (_, var tracer) = PrepExecuteCreateTransaction(MainnetSpecProvider.ShanghaiBlockTimestamp, Spec.MaxInitCodeSize - 7680); Assert.That(tracer.StatusCode, Is.EqualTo(StatusCode.Success)); } - protected TestAllTracerWithOutput PrepExecuteCreateTransaction(ulong timestamp, long byteCodeSize) + protected (TransactionResult, TestAllTracerWithOutput tracer) PrepExecuteCreateTransaction(ulong timestamp, long byteCodeSize) { var byteCode = new byte[byteCodeSize]; @@ -109,9 +110,8 @@ protected TestAllTracerWithOutput PrepExecuteCreateTransaction(ulong timestamp, transaction.To = null; transaction.Data = createCode; TestAllTracerWithOutput tracer = CreateTracer(); - _processor.Execute(transaction, block.Header, tracer); - - return tracer; + TransactionResult result = _processor.Execute(transaction, block.Header, tracer); + return (result, tracer); } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs index dabc8b9ae63..a9a4e54b844 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs @@ -11,6 +11,7 @@ using Nethermind.Int256; using Nethermind.Evm.Precompiles; using Nethermind.Evm.Tracing.ParityStyle; +using Nethermind.Evm.TransactionProcessing; using Nethermind.State; using NUnit.Framework; @@ -526,9 +527,10 @@ public void Can_trace_failed_action() .PushData(push2Hex) .Done; - (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code, 1000000.Ether()); + UInt256 value = 2.Ether(); + (ParityLikeTxTrace trace, _, _) = ExecuteAndTraceParityCall(code, value); Assert.Null(trace.VmTrace); - Assert.That(trace.Action.Value, Is.EqualTo(1000000.Ether())); + Assert.That(trace.Action.Value, Is.EqualTo(value)); } [Test] @@ -841,7 +843,7 @@ public void Is_tracing_rewards_only_when_rewards_trace_type_selected() { (Block block, Transaction transaction) = PrepareTx(BlockNumber, 100000, code, input, value); ParityLikeTxTracer tracer = new(block, transaction, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); - _processor.Execute(transaction, block.Header, tracer); + TransactionResult result = _processor.Execute(transaction, block.Header, tracer); return (tracer.BuildResult(), block, transaction); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs index 03b75e052d5..35b3a578376 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs @@ -70,13 +70,9 @@ public void Setup() public void Can_process_simple_transaction(bool withStateDiff, bool withTrace) { Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithGasLimit(100000).TestObject; - Block block = Build.A.Block.WithNumber(1).WithTransactions(tx).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Success)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Success, Is.True); } [TestCase(true, true)] @@ -93,7 +89,7 @@ public void Sets_state_root_on_receipts_before_eip658(bool withStateDiff, bool w Block block = Build.A.Block.WithNumber(blockNumber).WithTransactions(tx).TestObject; BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); + TransactionResult result = Execute(tx, block, tracer); if (_isEip155Enabled) // we use eip155 check just as a proxy on 658 { @@ -112,13 +108,9 @@ public void Sets_state_root_on_receipts_before_eip658(bool withStateDiff, bool w public void Can_handle_quick_fail_on_intrinsic_gas(bool withStateDiff, bool withTrace) { Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithGasLimit(20000).TestObject; - Block block = Build.A.Block.WithNumber(1).WithTransactions(tx).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -128,13 +120,9 @@ public void Can_handle_quick_fail_on_intrinsic_gas(bool withStateDiff, bool with public void Can_handle_quick_fail_on_missing_sender(bool withStateDiff, bool withTrace) { Transaction tx = Build.A.Transaction.Signed(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithGasLimit(100000).TestObject; - Block block = Build.A.Block.WithNumber(1).WithTransactions(tx).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -144,13 +132,9 @@ public void Can_handle_quick_fail_on_missing_sender(bool withStateDiff, bool wit public void Can_handle_quick_fail_on_non_existing_sender_account(bool withStateDiff, bool withTrace) { Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyB, _isEip155Enabled).WithGasLimit(100000).TestObject; - Block block = Build.A.Block.WithNumber(1).WithTransactions(tx).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -160,13 +144,9 @@ public void Can_handle_quick_fail_on_non_existing_sender_account(bool withStateD public void Can_handle_quick_fail_on_invalid_nonce(bool withStateDiff, bool withTrace) { Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithGasLimit(100000).WithNonce(100).TestObject; - Block block = Build.A.Block.WithNumber(1).WithTransactions(tx).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -191,10 +171,8 @@ public void Can_handle_quick_fail_on_not_enough_balance_on_intrinsic_gas(bool wi Block block = Build.A.Block.WithNumber(MainnetSpecProvider.BerlinBlockNumber).WithTransactions(tx).TestObject; - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -211,11 +189,8 @@ public void Can_handle_quick_fail_on_not_enough_balance_on_reserved_gas_payment( tx.Value = AccountBalance - GasCostOf.Transaction; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.BerlinBlockNumber).WithTransactions(tx).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -231,11 +206,8 @@ public void Can_handle_quick_fail_when_balance_is_lower_than_fee_cap_times_gas(b .WithGasLimit(100000).TestObject; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.LondonBlockNumber).WithTransactions(tx).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withStateDiff, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -245,13 +217,9 @@ public void Can_handle_quick_fail_when_balance_is_lower_than_fee_cap_times_gas(b public void Can_handle_quick_fail_on_above_block_gas_limit(bool withStateDiff, bool withTrace) { Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithGasLimit(100000).TestObject; - Block block = Build.A.Block.WithNumber(1).WithTransactions(tx).WithGasLimit(20000).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withTrace, withTrace); - Execute(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Failure)); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase(true, true)] @@ -261,13 +229,9 @@ public void Can_handle_quick_fail_on_above_block_gas_limit(bool withStateDiff, b public void Will_not_cause_quick_fail_above_block_gas_limit_during_calls(bool withStateDiff, bool withTrace) { Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithGasLimit(100000).TestObject; - Block block = Build.A.Block.WithNumber(1).WithTransactions(tx).WithGasLimit(20000).TestObject; - - BlockReceiptsTracer tracer = BuildTracer(block, tx, withTrace, withTrace); - CallAndRestore(tracer, tx, block); - - Assert.That(tracer.TxReceipts[0].StatusCode, Is.EqualTo(StatusCode.Success)); + TransactionResult result = CallAndRestore(tx, block); + Assert.That(result.Success, Is.True); } [TestCase] @@ -376,6 +340,7 @@ public static IEnumerable EstimateWithHighTxValueTestCases } } + [TestCase(562949953421312ul)] [TestCase(562949953421311ul)] public void Should_reject_tx_with_high_max_fee_per_gas(ulong topDigit) @@ -387,11 +352,8 @@ public void Should_reject_tx_with_high_max_fee_per_gas(ulong topDigit) long blockNumber = MainnetSpecProvider.LondonBlockNumber; Block block = Build.A.Block.WithNumber(blockNumber).WithTransactions(tx).TestObject; - BlockReceiptsTracer tracer = BuildTracer(block, tx, true, true); - - Execute(tracer, tx, block); - - tracer.TxReceipts[0].StatusCode.Should().Be(StatusCode.Failure); + TransactionResult result = Execute(tx, block); + Assert.That(result.Fail, Is.True); } [TestCase] @@ -652,7 +614,7 @@ public void Disables_Eip158_for_system_transactions() Block block = Build.A.Block.WithNumber(blockNumber).WithTransactions(tx).TestObject; BlockReceiptsTracer tracer = BuildTracer(block, tx, false, false); - Execute(tracer, tx, block); + Execute(tx, block, tracer); _stateProvider.AccountExists(tx.SenderAddress).Should().BeTrue(); } @@ -754,21 +716,31 @@ private BlockReceiptsTracer BuildTracer(Block block, Transaction tx, bool stateD return tracer; } - private void Execute(BlockReceiptsTracer tracer, Transaction tx, Block block) + private TransactionResult Execute(Transaction tx, Block block, BlockReceiptsTracer? tracer = null) { - tracer.StartNewBlockTrace(block); - tracer.StartNewTxTrace(tx); - _transactionProcessor.Execute(tx, block.Header, tracer); - tracer.EndTxTrace(); - tracer.EndBlockTrace(); + tracer?.StartNewBlockTrace(block); + tracer?.StartNewTxTrace(tx); + TransactionResult result = _transactionProcessor.Execute(tx, block.Header, tracer ?? NullTxTracer.Instance); + if (result) + { + tracer?.EndTxTrace(); + tracer?.EndBlockTrace(); + } + + return result; } - private void CallAndRestore(BlockReceiptsTracer tracer, Transaction tx, Block block) + private TransactionResult CallAndRestore(Transaction tx, Block block, BlockReceiptsTracer? tracer = null) { - tracer.StartNewBlockTrace(block); - tracer.StartNewTxTrace(tx); - _transactionProcessor.CallAndRestore(tx, block.Header, tracer); - tracer.EndTxTrace(); - tracer.EndBlockTrace(); + tracer?.StartNewBlockTrace(block); + tracer?.StartNewTxTrace(tx); + TransactionResult result = _transactionProcessor.CallAndRestore(tx, block.Header, tracer ?? NullTxTracer.Instance); + if (result) + { + tracer?.EndTxTrace(); + tracer?.EndBlockTrace(); + } + + return result; } } diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionSubstateTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionSubstateTests.cs index 96d1ed8ac5d..3b44d847768 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TransactionSubstateTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionSubstateTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using FluentAssertions; using Nethermind.Core; using Nethermind.Core.Extensions; @@ -31,7 +32,7 @@ public void should_return_proper_revert_error_when_there_is_no_exception() new LogEntry[] { }, true, true); - transactionSubstate.Error.Should().Be("Reverted 0x0506070809"); + transactionSubstate.Error.Should().Be("Reverted \u0005\u0006\u0007\u0008\t"); } [Test] @@ -45,7 +46,21 @@ public void should_return_proper_revert_error_when_there_is_exception() new LogEntry[] { }, true, true); - transactionSubstate.Error.Should().Be("Reverted 0x0506070809"); + transactionSubstate.Error.Should().Be("Reverted \u0005\u0006\u0007\u0008\t"); + } + + [Test] + public void should_return_weird_revert_error_when_there_is_exception() + { + byte[] data = TransactionSubstate.ErrorFunctionSelector.Concat(Bytes.FromHexString("0x00000001000000000000000000000000000000000000000012a9d65e7d180cfcf3601b6d00000000000000000000000000000000000000000000000000000001000276a400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000006a000000000300000000000115859c410282f6600012efb47fcfcad4f96c83d4ca676842fb03ef20a4770000000015f762bdaa80f6d9dc5518ff64cb7ba5717a10dabc4be3a41acd2c2f95ee22000012a9d65e7d180cfcf3601b6df0000000000000185594dac7eb0828ff000000000000000000000000")).ToArray(); + ReadOnlyMemory readOnlyMemory = new(data); + TransactionSubstate transactionSubstate = new(readOnlyMemory, + 0, + new ArraySegment
(), + new LogEntry[] { }, + true, + true); + transactionSubstate.Error.Should().Be("Reverted 0x08c379a000000001000000000000000000000000000000000000000012a9d65e7d180cfcf3601b6d00000000000000000000000000000000000000000000000000000001000276a400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000006a000000000300000000000115859c410282f6600012efb47fcfcad4f96c83d4ca676842fb03ef20a4770000000015f762bdaa80f6d9dc5518ff64cb7ba5717a10dabc4be3a41acd2c2f95ee22000012a9d65e7d180cfcf3601b6df0000000000000185594dac7eb0828ff000000000000000000000000"); } [Test] @@ -65,7 +80,7 @@ public void should_return_proper_revert_error_when_revert_custom_error_badly_imp new LogEntry[] { }, true, true); - transactionSubstate.Error.Should().Be($"Reverted {hex}"); + transactionSubstate.Error.Should().Be("Reverted 0x220266b600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001741413231206469646e2774207061792070726566756e64000000000000000000"); } private static IEnumerable<(byte[], string)> ErrorFunctionTestCases() @@ -121,7 +136,7 @@ public void should_return_proper_revert_error_when_revert_custom_error_badly_imp "Reverted unknown panic code (0xff)"); // Invalid case - yield return (new byte[] { 0x4e, 0x48, 0x7b, 0x71 }, "Reverted 0x4e487b71"); + yield return (new byte[] { 0xf0, 0x28, 0x8c, 0x28 }, "Reverted 0xf0288c28"); } [Test] diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs index f65a0d5bfc4..c035ac8c08c 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs @@ -554,7 +554,7 @@ public void Revert() byte[] code = Bytes.FromHexString("0x6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd"); TestAllTracerWithOutput receipt = Execute(blockNumber: MainnetSpecProvider.ByzantiumBlockNumber, 100_000, code); - Assert.That(receipt.Error, Is.EqualTo("Reverted 0x726576657274206d657373616765")); + Assert.That(receipt.Error, Is.EqualTo("Reverted revert message")); Assert.That(receipt.GasSpent, Is.EqualTo(GasCostOf.Transaction + 20024)); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs index acfb1c7d295..d0215a41aa3 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public BuildUpTransactionProcessorAdapter(ITransactionProcessor transactionProce _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => _transactionProcessor.BuildUp(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs index d518b5ee279..31232e3b7c6 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public CallAndRestoreTransactionProcessorAdapter(ITransactionProcessor transacti _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => _transactionProcessor.CallAndRestore(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs index 661a6698820..38d9ccf67c9 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs @@ -22,9 +22,7 @@ public ChangeableTransactionProcessorAdapter(ITransactionProcessor transactionPr TransactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) - { + public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => CurrentAdapter.Execute(transaction, in blkCtx, txTracer); - } } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs index b0f51de953e..729db62505e 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public ExecuteTransactionProcessorAdapter(ITransactionProcessor transactionProce _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => _transactionProcessor.Execute(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs index 21973ee817a..96ac8e27948 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs @@ -11,21 +11,21 @@ public interface ITransactionProcessor /// /// Execute transaction, commit state /// - void Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); + TransactionResult Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); /// /// Call transaction, rollback state /// - void CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); + TransactionResult CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); /// /// Execute transaction, keep the state uncommitted /// - void BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); + TransactionResult BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); /// /// Call transaction, no validations, commit state /// Will NOT charge gas from sender account, so stateDiff will miss gas fee /// - void Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); + TransactionResult Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs index 4f09f301792..ba77066d81a 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs @@ -8,6 +8,6 @@ namespace Nethermind.Evm.TransactionProcessing { public interface ITransactionProcessorAdapter { - void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer); + TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs index f6999143fd9..026427b6413 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs @@ -23,16 +23,16 @@ public ReadOnlyTransactionProcessor(ITransactionProcessor transactionProcessor, _stateProvider.StateRoot = startState ?? throw new ArgumentNullException(nameof(startState)); } - public void Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => _transactionProcessor.Execute(transaction, in blCtx, txTracer); - public void CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + public TransactionResult CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => _transactionProcessor.CallAndRestore(transaction, in blCtx, txTracer); - public void BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + public TransactionResult BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => _transactionProcessor.BuildUp(transaction, in blCtx, txTracer); - public void Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + public TransactionResult Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => _transactionProcessor.Trace(transaction, in blCtx, txTracer); diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs index 6c75c5b5e19..f272308db25 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public TraceTransactionProcessorAdapter(ITransactionProcessor transactionProcess _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => _transactionProcessor.Trace(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 6b5199301e4..2ce85b1aa7d 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Runtime.CompilerServices; @@ -67,37 +69,36 @@ public TransactionProcessor( IVirtualMachine? virtualMachine, ILogManager? logManager) { - Logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - SpecProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - WorldState = worldState ?? throw new ArgumentNullException(nameof(worldState)); - VirtualMachine = virtualMachine ?? throw new ArgumentNullException(nameof(virtualMachine)); + ArgumentNullException.ThrowIfNull(logManager, nameof(logManager)); + ArgumentNullException.ThrowIfNull(specProvider, nameof(specProvider)); + ArgumentNullException.ThrowIfNull(worldState, nameof(worldState)); + ArgumentNullException.ThrowIfNull(virtualMachine, nameof(virtualMachine)); + + Logger = logManager.GetClassLogger(); + SpecProvider = specProvider; + WorldState = worldState; + VirtualMachine = virtualMachine; Ecdsa = new EthereumEcdsa(specProvider.ChainId, logManager); } - public void CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) - { + public TransactionResult CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => Execute(transaction, in blCtx, txTracer, ExecutionOptions.CommitAndRestore); - } - public void BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) + public TransactionResult BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) { // we need to treat the result of previous transaction as the original value of next transaction // when we do not commit WorldState.TakeSnapshot(true); - Execute(transaction, in blCtx, txTracer, ExecutionOptions.None); + return Execute(transaction, in blCtx, txTracer, ExecutionOptions.None); } - public void Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) - { + public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => Execute(transaction, in blCtx, txTracer, ExecutionOptions.Commit); - } - public void Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) - { + public TransactionResult Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => Execute(transaction, in blCtx, txTracer, ExecutionOptions.NoValidation); - } - protected virtual void Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) + protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { BlockHeader header = blCtx.Header; IReleaseSpec spec = SpecProvider.GetSpec(header); @@ -111,52 +112,26 @@ protected virtual void Execute(Transaction tx, in BlockExecutionContext blCtx, I // we commit only after all block is constructed bool commit = opts.HasFlag(ExecutionOptions.Commit) || !spec.IsEip658Enabled; - if (!ValidateStatic(tx, header, spec, tracer, opts, out long intrinsicGas)) - return; - - UInt256 effectiveGasPrice = - tx.CalculateEffectiveGasPrice(spec.IsEip1559Enabled, header.BaseFeePerGas); - - if (opts == ExecutionOptions.Commit || opts == ExecutionOptions.None) - { - float gasPrice = (float)((double)effectiveGasPrice / 1_000_000_000.0); - Metrics.MinGasPrice = Math.Min(gasPrice, Metrics.MinGasPrice); - Metrics.MaxGasPrice = Math.Max(gasPrice, Metrics.MaxGasPrice); + TransactionResult result; + if (!(result = ValidateStatic(tx, header, spec, tracer, opts, out long intrinsicGas))) return result; - Metrics.BlockMinGasPrice = Math.Min(gasPrice, Metrics.BlockMinGasPrice); - Metrics.BlockMaxGasPrice = Math.Max(gasPrice, Metrics.BlockMaxGasPrice); + UInt256 effectiveGasPrice = tx.CalculateEffectiveGasPrice(spec.IsEip1559Enabled, header.BaseFeePerGas); - Metrics.AveGasPrice = (Metrics.AveGasPrice * Metrics.Transactions + gasPrice) / (Metrics.Transactions + 1); - Metrics.EstMedianGasPrice += Metrics.AveGasPrice * 0.01f * float.Sign(gasPrice - Metrics.EstMedianGasPrice); - Metrics.Transactions++; - - Metrics.BlockAveGasPrice = (Metrics.BlockAveGasPrice * Metrics.BlockTransactions + gasPrice) / (Metrics.BlockTransactions + 1); - Metrics.BlockEstMedianGasPrice += Metrics.BlockAveGasPrice * 0.01f * float.Sign(gasPrice - Metrics.BlockEstMedianGasPrice); - Metrics.BlockTransactions++; - } + UpdateMetrics(opts, effectiveGasPrice); bool deleteCallerAccount = RecoverSenderIfNeeded(tx, spec, opts, effectiveGasPrice); - if (!ValidateSender(tx, header, spec, tracer, opts)) - return; + if (!(result = ValidateSender(tx, header, spec, tracer, opts))) return result; + if (!(result = BuyGas(tx, header, spec, tracer, opts, effectiveGasPrice, out UInt256 premiumPerGas, out UInt256 senderReservedGasPayment))) return result; + if (!(result = IncrementNonce(tx, header, spec, tracer, opts))) return result; - if (!BuyGas(tx, header, spec, tracer, opts, effectiveGasPrice, out UInt256 premiumPerGas, out UInt256 senderReservedGasPayment)) - return; + if (commit) WorldState.Commit(spec, tracer.IsTracingState ? tracer : NullTxTracer.Instance); - if (!IncrementNonce(tx, header, spec, tracer, opts)) - return; - - if (commit) - WorldState.Commit(spec, tracer.IsTracingState ? tracer : NullTxTracer.Instance); - - ExecutionEnvironment env = BuildExecutionEnvironment(tx, in blCtx, spec, tracer, opts, effectiveGasPrice); + ExecutionEnvironment env = BuildExecutionEnvironment(tx, blCtx, spec, effectiveGasPrice); long gasAvailable = tx.GasLimit - intrinsicGas; - if (!ExecuteEvmCall(tx, header, spec, tracer, opts, gasAvailable, env, out TransactionSubstate? substate, out long spentGas, out byte statusCode)) - return; - - if (!PayFees(tx, header, spec, tracer, substate, spentGas, premiumPerGas, statusCode)) - return; + ExecuteEvmCall(tx, header, spec, tracer, opts, gasAvailable, env, out TransactionSubstate? substate, out long spentGas, out byte statusCode); + PayFees(tx, header, spec, tracer, substate, spentGas, premiumPerGas, statusCode); // Finalize if (restore) @@ -201,30 +176,31 @@ protected virtual void Execute(Transaction tx, in BlockExecutionContext blCtx, I tracer.MarkAsSuccess(env.ExecutingAccount, spentGas, substate.Output.ToArray(), logs, stateRoot); } } + + return TransactionResult.Ok; } - protected void QuickFail(Transaction tx, BlockHeader block, IReleaseSpec spec, ITxTracer txTracer, string? reason) + private static void UpdateMetrics(ExecutionOptions opts, UInt256 effectiveGasPrice) { - block.GasUsed += tx.GasLimit; + if (opts == ExecutionOptions.Commit || opts == ExecutionOptions.None) + { + float gasPrice = (float)((double)effectiveGasPrice / 1_000_000_000.0); + Metrics.MinGasPrice = Math.Min(gasPrice, Metrics.MinGasPrice); + Metrics.MaxGasPrice = Math.Max(gasPrice, Metrics.MaxGasPrice); - Address recipient = tx.To ?? ContractAddress.From( - tx.SenderAddress ?? Address.Zero, - WorldState.GetNonce(tx.SenderAddress ?? Address.Zero)); + Metrics.BlockMinGasPrice = Math.Min(gasPrice, Metrics.BlockMinGasPrice); + Metrics.BlockMaxGasPrice = Math.Max(gasPrice, Metrics.BlockMaxGasPrice); - if (txTracer.IsTracingReceipt) - { - Hash256? stateRoot = null; - if (!spec.IsEip658Enabled) - { - WorldState.RecalculateStateRoot(); - stateRoot = WorldState.StateRoot; - } + Metrics.AveGasPrice = (Metrics.AveGasPrice * Metrics.Transactions + gasPrice) / (Metrics.Transactions + 1); + Metrics.EstMedianGasPrice += Metrics.AveGasPrice * 0.01f * float.Sign(gasPrice - Metrics.EstMedianGasPrice); + Metrics.Transactions++; - txTracer.MarkAsFailed(recipient, tx.GasLimit, Array.Empty(), reason ?? "invalid", stateRoot); + Metrics.BlockAveGasPrice = (Metrics.BlockAveGasPrice * Metrics.BlockTransactions + gasPrice) / (Metrics.BlockTransactions + 1); + Metrics.BlockEstMedianGasPrice += Metrics.BlockAveGasPrice * 0.01f * float.Sign(gasPrice - Metrics.BlockEstMedianGasPrice); + Metrics.BlockTransactions++; } } - /// /// Validates the transaction, in a static manner (i.e. without accesing state/storage). /// It basically ensures the transaction is well formed (i.e. no null values where not allowed, no overflows, etc). @@ -238,7 +214,7 @@ protected void QuickFail(Transaction tx, BlockHeader block, IReleaseSpec spec, I /// Options (Flags) to use for execution /// Computed premium per gas /// - protected virtual bool ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, out long intrinsicGas) + protected virtual TransactionResult ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, out long intrinsicGas) { intrinsicGas = IntrinsicGasCalculator.Calculate(tx, spec); @@ -247,8 +223,7 @@ protected virtual bool ValidateStatic(Transaction tx, BlockHeader header, IRelea if (tx.SenderAddress is null) { TraceLogInvalidTx(tx, "SENDER_NOT_SPECIFIED"); - QuickFail(tx, header, spec, tracer, "sender not specified"); - return false; + return "sender not specified"; } if (validate && tx.Nonce >= ulong.MaxValue - 1) @@ -258,16 +233,14 @@ protected virtual bool ValidateStatic(Transaction tx, BlockHeader header, IRelea if (tx.IsContractCreation || tx.Nonce == ulong.MaxValue) { TraceLogInvalidTx(tx, "NONCE_OVERFLOW"); - QuickFail(tx, header, spec, tracer, "nonce overflow"); - return false; + return "nonce overflow"; } } if (tx.IsAboveInitCode(spec)) { TraceLogInvalidTx(tx, $"CREATE_TRANSACTION_SIZE_EXCEEDS_MAX_INIT_CODE_SIZE {tx.DataLength} > {spec.MaxInitCodeSize}"); - QuickFail(tx, header, spec, tracer, "EIP-3860 - transaction size over max init code size"); - return false; + return "EIP-3860 - transaction size over max init code size"; } if (!tx.IsSystem()) @@ -275,19 +248,17 @@ protected virtual bool ValidateStatic(Transaction tx, BlockHeader header, IRelea if (tx.GasLimit < intrinsicGas) { TraceLogInvalidTx(tx, $"GAS_LIMIT_BELOW_INTRINSIC_GAS {tx.GasLimit} < {intrinsicGas}"); - QuickFail(tx, header, spec, tracer, "gas limit below intrinsic gas"); - return false; + return "gas limit below intrinsic gas"; } if (validate && tx.GasLimit > header.GasLimit - header.GasUsed) { TraceLogInvalidTx(tx, $"BLOCK_GAS_LIMIT_EXCEEDED {tx.GasLimit} > {header.GasLimit} - {header.GasUsed}"); - QuickFail(tx, header, spec, tracer, "block gas limit exceeded"); - return false; + return "block gas limit exceeded"; } } - return true; + return TransactionResult.Ok; } // TODO Should we remove this already @@ -326,7 +297,7 @@ protected bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, Executio if (sender is null) { - throw new InvalidDataException($"Failed to recover sender address on tx {tx.Hash} when previously recovered sender account did not exist."); + ThrowInvalidDataException($"Failed to recover sender address on tx {tx.Hash} when previously recovered sender account did not exist."); } } @@ -334,21 +305,20 @@ protected bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, Executio } - protected virtual bool ValidateSender(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) + protected virtual TransactionResult ValidateSender(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) { bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); if (validate && WorldState.IsInvalidContractSender(spec, tx.SenderAddress)) { TraceLogInvalidTx(tx, "SENDER_IS_CONTRACT"); - QuickFail(tx, header, spec, tracer, "sender has deployed code"); - return false; + return "sender has deployed code"; } - return true; + return TransactionResult.Ok; } - protected virtual bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, + protected virtual TransactionResult BuyGas(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, in UInt256 effectiveGasPrice, out UInt256 premiumPerGas, out UInt256 senderReservedGasPayment) { premiumPerGas = UInt256.Zero; @@ -360,19 +330,16 @@ protected virtual bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec s if (!tx.TryCalculatePremiumPerGas(header.BaseFeePerGas, out premiumPerGas)) { TraceLogInvalidTx(tx, "MINER_PREMIUM_IS_NEGATIVE"); - QuickFail(tx, header, spec, tracer, "miner premium is negative"); - return false; + return "miner premium is negative"; } UInt256 senderBalance = WorldState.GetBalance(tx.SenderAddress); if (UInt256.SubtractUnderflow(senderBalance, tx.Value, out UInt256 balanceLeft)) { TraceLogInvalidTx(tx, $"INSUFFICIENT_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); - QuickFail(tx, header, spec, tracer, "insufficient sender balance"); - return false; + return "insufficient sender balance"; } - bool overflows; if (spec.IsEip1559Enabled && !tx.IsFree()) { @@ -380,8 +347,7 @@ protected virtual bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec s if (overflows || balanceLeft < maxGasFee) { TraceLogInvalidTx(tx, $"INSUFFICIENT_MAX_FEE_PER_GAS_FOR_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}, MAX_FEE_PER_GAS: {tx.MaxFeePerGas}"); - QuickFail(tx, header, spec, tracer, "insufficient MaxFeePerGas for sender balance"); - return false; + return "insufficient MaxFeePerGas for sender balance"; } if (tx.SupportsBlobs) { @@ -389,8 +355,7 @@ protected virtual bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec s if (overflows || UInt256.AddOverflow(maxGasFee, maxBlobGasFee, out UInt256 multidimGasFee) || multidimGasFee > balanceLeft) { TraceLogInvalidTx(tx, $"INSUFFICIENT_MAX_FEE_PER_BLOB_GAS_FOR_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); - QuickFail(tx, header, spec, tracer, "insufficient sender balance"); - return false; + return "insufficient sender balance"; } } } @@ -408,46 +373,42 @@ protected virtual bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec s if (overflows || senderReservedGasPayment > balanceLeft) { TraceLogInvalidTx(tx, $"INSUFFICIENT_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); - QuickFail(tx, header, spec, tracer, "insufficient sender balance"); - return false; + return "insufficient sender balance"; } } - if (validate) - WorldState.SubtractFromBalance(tx.SenderAddress, senderReservedGasPayment, spec); + if (validate) WorldState.SubtractFromBalance(tx.SenderAddress, senderReservedGasPayment, spec); - return true; + return TransactionResult.Ok; } - protected virtual bool IncrementNonce(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) + protected virtual TransactionResult IncrementNonce(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) { - if (tx.IsSystem()) - return true; + if (tx.IsSystem()) return TransactionResult.Ok; if (tx.Nonce != WorldState.GetNonce(tx.SenderAddress)) { TraceLogInvalidTx(tx, $"WRONG_TRANSACTION_NONCE: {tx.Nonce} (expected {WorldState.GetNonce(tx.SenderAddress)})"); - QuickFail(tx, header, spec, tracer, "wrong transaction nonce"); - return false; + return "wrong transaction nonce"; } WorldState.IncrementNonce(tx.SenderAddress); - return true; + return TransactionResult.Ok; } protected virtual ExecutionEnvironment BuildExecutionEnvironment( - Transaction tx, in BlockExecutionContext blCtx, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, + Transaction tx, + in BlockExecutionContext blCtx, + IReleaseSpec spec, in UInt256 effectiveGasPrice) { - Address recipient = tx.GetRecipient(tx.IsContractCreation ? WorldState.GetNonce(tx.SenderAddress) : 0) ?? - // this transaction is not a contract creation so it should have the recipient known and not null - throw new InvalidDataException("Recipient has not been resolved properly before tx execution"); + Address recipient = tx.GetRecipient(tx.IsContractCreation ? WorldState.GetNonce(tx.SenderAddress) : 0); + if (recipient is null) ThrowInvalidDataException("Recipient has not been resolved properly before tx execution"); - TxExecutionContext executionContext = - new(in blCtx, tx.SenderAddress, effectiveGasPrice, tx.BlobVersionedHashes); + TxExecutionContext executionContext = new(in blCtx, tx.SenderAddress, effectiveGasPrice, tx.BlobVersionedHashes); - CodeInfo codeInfo = tx.IsContractCreation ? new(tx.Data.AsArray()) - : VirtualMachine.GetCachedCodeInfo(WorldState, recipient, spec); + CodeInfo codeInfo = tx.IsContractCreation ? new(tx.Data?.AsArray() ?? Array.Empty()) + : VirtualMachine.GetCachedCodeInfo(WorldState, recipient, spec); byte[] inputData = tx.IsMessageCall ? tx.Data.AsArray() ?? Array.Empty() : Array.Empty(); @@ -464,10 +425,17 @@ protected virtual ExecutionEnvironment BuildExecutionEnvironment( ); } - protected virtual bool ExecuteEvmCall( - Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, - in long gasAvailable, in ExecutionEnvironment env, - out TransactionSubstate? substate, out long spentGas, out byte statusCode) + protected void ExecuteEvmCall( + Transaction tx, + BlockHeader header, + IReleaseSpec spec, + ITxTracer tracer, + ExecutionOptions opts, + in long gasAvailable, + in ExecutionEnvironment env, + out TransactionSubstate? substate, + out long spentGas, + out byte statusCode) { bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); @@ -492,8 +460,7 @@ protected virtual bool ExecuteEvmCall( PrepareAccountForContractDeployment(env.ExecutingAccount, spec); } - ExecutionType executionType = - tx.IsContractCreation ? ExecutionType.CREATE : ExecutionType.TRANSACTION; + ExecutionType executionType = tx.IsContractCreation ? ExecutionType.CREATE : ExecutionType.TRANSACTION; using (EvmState state = new(unspentGas, env, executionType, true, snapshot, false)) { @@ -513,14 +480,9 @@ protected virtual bool ExecuteEvmCall( state.WarmUp(header.GasBeneficiary); } - if (!tracer.IsTracingActions) - { - substate = VirtualMachine.Run(state, WorldState, tracer); - } - else - { - substate = VirtualMachine.Run(state, WorldState, tracer); - } + substate = !tracer.IsTracingActions + ? VirtualMachine.Run(state, WorldState, tracer) + : VirtualMachine.Run(state, WorldState, tracer); unspentGas = state.GasAvailable; @@ -545,12 +507,12 @@ protected virtual bool ExecuteEvmCall( long codeDepositGasCost = CodeDepositHandler.CalculateCost(substate.Output.Length, spec); if (unspentGas < codeDepositGasCost && spec.ChargeForTopLevelCreate) { - throw new OutOfGasException(); + ThrowOutOfGasException(); } if (CodeDepositHandler.CodeIsInvalid(spec, substate.Output)) { - throw new InvalidCodeException(); + ThrowInvalidCodeException(); } if (unspentGas >= codeDepositGasCost) @@ -579,41 +541,35 @@ protected virtual bool ExecuteEvmCall( spentGas = Refund(tx, header, spec, opts, substate, unspentGas, env.TxExecutionContext.GasPrice); } - catch (Exception ex) when (ex is EvmException || ex is OverflowException) // TODO: OverflowException? still needed? hope not + catch (Exception ex) when (ex is EvmException or OverflowException) // TODO: OverflowException? still needed? hope not { - if (Logger.IsTrace) - Logger.Trace($"EVM EXCEPTION: {ex.GetType().Name}"); + if (Logger.IsTrace) Logger.Trace($"EVM EXCEPTION: {ex.GetType().Name}:{ex.Message}"); WorldState.Restore(snapshot); } if (validate && !tx.IsSystem()) header.GasUsed += spentGas; - - return true; } - protected virtual bool PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in byte statusCode) + protected virtual void PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in byte statusCode) { - if (tx.IsSystem()) - return true; - - bool gasBeneficiaryNotDestroyed = substate?.DestroyList.Contains(header.GasBeneficiary) != true; - if (statusCode == StatusCode.Failure || gasBeneficiaryNotDestroyed) + if (!tx.IsSystem()) { + bool gasBeneficiaryNotDestroyed = substate?.DestroyList.Contains(header.GasBeneficiary) != true; + if (statusCode == StatusCode.Failure || gasBeneficiaryNotDestroyed) + { + UInt256 fees = (UInt256)spentGas * premiumPerGas; + UInt256 burntFees = !tx.IsFree() ? (UInt256)spentGas * header.BaseFeePerGas : 0; - UInt256 fees = (UInt256)spentGas * premiumPerGas; - UInt256 burntFees = !tx.IsFree() ? (UInt256)spentGas * header.BaseFeePerGas : 0; - - WorldState.AddToBalanceAndCreateIfNotExists(header.GasBeneficiary, fees, spec); + WorldState.AddToBalanceAndCreateIfNotExists(header.GasBeneficiary, fees, spec); - if (spec.IsEip1559Enabled && spec.Eip1559FeeCollector is not null && !burntFees.IsZero) - WorldState.AddToBalanceAndCreateIfNotExists(spec.Eip1559FeeCollector, burntFees, spec); ; + if (spec.IsEip1559Enabled && spec.Eip1559FeeCollector is not null && !burntFees.IsZero) + WorldState.AddToBalanceAndCreateIfNotExists(spec.Eip1559FeeCollector, burntFees, spec); - if (tracer.IsTracingFees) - tracer.ReportFees(fees, burntFees); + if (tracer.IsTracingFees) + tracer.ReportFees(fees, burntFees); + } } - - return true; } protected void PrepareAccountForContractDeployment(Address contractAddress, IReleaseSpec spec) @@ -633,7 +589,7 @@ protected void PrepareAccountForContractDeployment(Address contractAddress, IRel Logger.Trace($"Contract collision at {contractAddress}"); } - throw new TransactionCollisionException(); + ThrowTransactionCollisionException(); } // we clean any existing storage (in case of a previously called self destruct) @@ -669,5 +625,34 @@ protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec s return spentGas; } + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowInvalidDataException(string message) => throw new InvalidDataException(message); + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowInvalidCodeException() => throw new InvalidCodeException(); + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowOutOfGasException() => throw new OutOfGasException(); + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowTransactionCollisionException() => throw new TransactionCollisionException(); + } + + public readonly struct TransactionResult(string? error) + { + public static readonly TransactionResult Ok = new(); + public static readonly TransactionResult MalformedTransaction = new("malformed"); + [MemberNotNullWhen(true, nameof(Fail))] + [MemberNotNullWhen(false, nameof(Success))] + public string? Error { get; } = error; + public bool Fail => Error is not null; + public bool Success => Error is null; + public static implicit operator TransactionResult(string? error) => new(error); + public static implicit operator bool(TransactionResult result) => result.Success; } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs b/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs index a5368120981..32e40f6a175 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionSubstate.cs @@ -2,16 +2,21 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Frozen; using System.Collections.Generic; +using System.Text; +using System.Text.Unicode; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Int256; +using Nethermind.Logging; namespace Nethermind.Evm; public class TransactionSubstate { + private readonly ILogger _logger; private static readonly List
_emptyDestroyList = new(0); private static readonly List _emptyLogs = new(0); @@ -22,10 +27,10 @@ public class TransactionSubstate private const int WordSize = EvmPooledMemory.WordSize; private const string RevertedErrorMessagePrefix = "Reverted "; - private readonly byte[] ErrorFunctionSelector = Keccak.Compute("Error(string)").BytesToArray()[..RevertPrefix]; - private readonly byte[] PanicFunctionSelector = Keccak.Compute("Panic(uint256)").BytesToArray()[..RevertPrefix]; + public static readonly byte[] ErrorFunctionSelector = Keccak.Compute("Error(string)").BytesToArray()[..RevertPrefix]; + public static readonly byte[] PanicFunctionSelector = Keccak.Compute("Panic(uint256)").BytesToArray()[..RevertPrefix]; - private readonly IDictionary PanicReasons = new Dictionary + private static readonly FrozenDictionary PanicReasons = new Dictionary { { 0x00, "generic panic" }, { 0x01, "assert(false)" }, @@ -37,7 +42,7 @@ public class TransactionSubstate { 0x32, "out-of-bounds access of an array or bytesN" }, { 0x41, "out of memory" }, { 0x51, "uninitialized function" }, - }; + }.ToFrozenDictionary(); public bool IsError => Error is not null && !ShouldRevert; public string? Error { get; } @@ -56,14 +61,15 @@ public TransactionSubstate(EvmExceptionType exceptionType, bool isTracerConnecte ShouldRevert = false; } - public TransactionSubstate( - ReadOnlyMemory output, + public TransactionSubstate(ReadOnlyMemory output, long refund, IReadOnlyCollection
destroyList, IReadOnlyCollection logs, bool shouldRevert, - bool isTracerConnected) + bool isTracerConnected, + ILogger logger = default) { + _logger = logger; Output = output; Refund = refund; DestroyList = destroyList; @@ -87,60 +93,61 @@ public TransactionSubstate( ReadOnlySpan span = Output.Span; Error = string.Concat( RevertedErrorMessagePrefix, - TryGetErrorMessage(span) ?? DefaultErrorMessage(span) + TryGetErrorMessage(span) ?? EncodeErrorMessage(span) ); } - private static string DefaultErrorMessage(ReadOnlySpan span) => span.ToHexString(true); + private static string EncodeErrorMessage(ReadOnlySpan span) => + Utf8.IsValid(span) ? Encoding.UTF8.GetString(span) : span.ToHexString(true); private string? TryGetErrorMessage(ReadOnlySpan span) { - if (span.Length < RevertPrefix) { return null; } - ReadOnlySpan prefix = span.TakeAndMove(RevertPrefix); - - if (prefix.SequenceEqual(PanicFunctionSelector)) + try { - if (span.Length < WordSize) { return null; } + if (span.Length < RevertPrefix) return null; + ReadOnlySpan prefix = span.TakeAndMove(RevertPrefix); + UInt256 start, length; - UInt256 panicCode = new(span.TakeAndMove(WordSize), isBigEndian: true); - if (!PanicReasons.TryGetValue(panicCode, out string panicReason)) + if (prefix.SequenceEqual(PanicFunctionSelector)) { - return $"unknown panic code ({panicCode.ToHexString(skipLeadingZeros: true)})"; - } + if (span.Length < WordSize) return null; - return panicReason; - } + UInt256 panicCode = new(span.TakeAndMove(WordSize), isBigEndian: true); + if (!PanicReasons.TryGetValue(panicCode, out string panicReason)) + { + return $"unknown panic code ({panicCode.ToHexString(skipLeadingZeros: true)})"; + } - if (prefix.SequenceEqual(ErrorFunctionSelector)) - { - if (span.Length < WordSize * 2) { return null; } + return panicReason; + } - int start = (int)new UInt256(span.TakeAndMove(WordSize), isBigEndian: true); - if (start != WordSize) { return null; } + if (span.Length < WordSize * 2) return null; - int length = (int)new UInt256(span.TakeAndMove(WordSize), isBigEndian: true); - if (length > span.Length) { return null; } + if (prefix.SequenceEqual(ErrorFunctionSelector)) + { + start = new UInt256(span.TakeAndMove(WordSize), isBigEndian: true); + if (start != WordSize) return null; - ReadOnlySpan binaryMessage = span.TakeAndMove(length); - string message = System.Text.Encoding.UTF8.GetString(binaryMessage); + length = new UInt256(span.TakeAndMove(WordSize), isBigEndian: true); + if (length > span.Length) return null; - return message; - } + ReadOnlySpan binaryMessage = span.TakeAndMove((int)length); + return EncodeErrorMessage(binaryMessage); - try - { - if (span.Length < WordSize * 2) { return null; } + } - int start = (int)new UInt256(span.Slice(0, WordSize), isBigEndian: true); - if (checked(start + WordSize) > span.Length) { return null; } + start = new UInt256(span.Slice(0, WordSize), isBigEndian: true); + if (UInt256.AddOverflow(start, WordSize, out UInt256 lengthOffset) || lengthOffset > span.Length) return null; - int length = (int)new UInt256(span.Slice(start, WordSize), isBigEndian: true); - if (checked(start + WordSize + length) != span.Length) { return null; } + length = new UInt256(span.Slice((int)start, WordSize), isBigEndian: true); + if (UInt256.AddOverflow(lengthOffset, length, out UInt256 endOffset) || endOffset != span.Length) return null; - return span.Slice(start + WordSize, length).ToHexString(true); + span = span.Slice((int)lengthOffset, (int)length); + return EncodeErrorMessage(span); } - catch (OverflowException) + catch (Exception e) // shouldn't happen, just for being safe { + if (_logger.IsError == true) _logger.Error("Couldn't parse revert message", e); return null; } } diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index cb98e5eb5f8..48cba44f74d 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -95,7 +95,7 @@ public void InsertCode(ReadOnlyMemory code, Address codeOwner, IReleaseSpe } public TransactionSubstate Run(EvmState state, IWorldState worldState, ITxTracer txTracer) - where TTracingActions : struct, IIsTracing + where TTracingActions : struct, VirtualMachine.IIsTracing => _evm.Run(state, worldState, txTracer); private static FrozenDictionary InitializePrecompiledContracts() @@ -135,18 +135,10 @@ internal readonly ref struct CallResult public static CallResult OutOfGasException => new(EvmExceptionType.OutOfGas); public static CallResult AccessViolationException => new(EvmExceptionType.AccessViolation); public static CallResult InvalidJumpDestination => new(EvmExceptionType.InvalidJumpDestination); - public static CallResult InvalidInstructionException - { - get - { - return new(EvmExceptionType.BadInstruction); - } - } - + public static CallResult InvalidInstructionException => new(EvmExceptionType.BadInstruction); public static CallResult StaticCallViolationException => new(EvmExceptionType.StaticCallViolation); public static CallResult StackOverflowException => new(EvmExceptionType.StackOverflow); // TODO: use these to avoid CALL POP attacks public static CallResult StackUnderflowException => new(EvmExceptionType.StackUnderflow); // TODO: use these to avoid CALL POP attacks - public static CallResult InvalidCodeException => new(EvmExceptionType.InvalidCode); public static CallResult Empty => new(Array.Empty(), null); @@ -368,7 +360,8 @@ public TransactionSubstate Run(EvmState state, IWorldState worl (IReadOnlyCollection
)currentState.DestroyList, (IReadOnlyCollection)currentState.Logs, callResult.ShouldRevert, - isTracerConnected: isTracing); + isTracerConnected: isTracing, + _logger); } Address callCodeOwner = currentState.Env.ExecutingAccount; diff --git a/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs b/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs index ec3713b966b..9abe5a44755 100644 --- a/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs +++ b/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs @@ -157,7 +157,7 @@ public void Call_uses_valid_post_merge_and_random_value() _transactionProcessor.Received().CallAndRestore( tx, Arg.Is(blkCtx => - blkCtx.Header.IsPostMerge && blkCtx.Header.Random == TestItem.KeccakA), + blkCtx.Header.IsPostMerge && blkCtx.Header.Random == TestItem.KeccakA), Arg.Any()); } diff --git a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs index 5a40fd961f1..6fd77d79d86 100644 --- a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs +++ b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs @@ -155,7 +155,7 @@ public CallOutput(byte[] outputData, long gasSpent, string error, bool inputErro public CallOutput Call(BlockHeader header, Transaction tx, CancellationToken cancellationToken) { CallOutputTracer callOutputTracer = new(); - (bool Success, string Error) tryCallResult = TryCallAndRestore(header, tx, false, + TransactionResult tryCallResult = TryCallAndRestore(header, tx, false, callOutputTracer.WithCancellation(cancellationToken)); return new CallOutput { @@ -171,7 +171,7 @@ public CallOutput EstimateGas(BlockHeader header, Transaction tx, CancellationTo using IReadOnlyTransactionProcessor? readOnlyTransactionProcessor = _processingEnv.Build(header.StateRoot!); EstimateGasTracer estimateGasTracer = new(); - (bool Success, string Error) tryCallResult = TryCallAndRestore( + TransactionResult tryCallResult = TryCallAndRestore( header, tx, true, @@ -197,7 +197,7 @@ public CallOutput CreateAccessList(BlockHeader header, Transaction tx, Cancellat tx.GetRecipient(tx.IsContractCreation ? _processingEnv.StateReader.GetNonce(header.StateRoot, tx.SenderAddress) : 0)) : new(); - (bool Success, string Error) tryCallResult = TryCallAndRestore(header, tx, false, + TransactionResult tryCallResult = TryCallAndRestore(header, tx, false, new CompositeTxTracer(callOutputTracer, accessTxTracer).WithCancellation(cancellationToken)); return new CallOutput @@ -210,7 +210,7 @@ public CallOutput CreateAccessList(BlockHeader header, Transaction tx, Cancellat }; } - private (bool Success, string Error) TryCallAndRestore( + private TransactionResult TryCallAndRestore( BlockHeader blockHeader, Transaction transaction, bool treatBlockHeaderAsParentBlock, @@ -218,16 +218,15 @@ public CallOutput CreateAccessList(BlockHeader header, Transaction tx, Cancellat { try { - CallAndRestore(blockHeader, transaction, treatBlockHeaderAsParentBlock, tracer); - return (true, string.Empty); + return CallAndRestore(blockHeader, transaction, treatBlockHeaderAsParentBlock, tracer); } catch (InsufficientBalanceException ex) { - return (false, ex.Message); + return new TransactionResult(ex.Message); } } - private void CallAndRestore( + private TransactionResult CallAndRestore( BlockHeader blockHeader, Transaction transaction, bool treatBlockHeaderAsParentBlock, @@ -278,7 +277,7 @@ private void CallAndRestore( callHeader.MixHash = blockHeader.MixHash; callHeader.IsPostMerge = blockHeader.Difficulty == 0; transaction.Hash = transaction.CalculateHash(); - transactionProcessor.CallAndRestore(transaction, new(callHeader), tracer); + return transactionProcessor.CallAndRestore(transaction, new(callHeader), tracer); } public ulong GetChainId() diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs index 9246ab6b3ba..bcacbd6c0a4 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs @@ -41,6 +41,7 @@ namespace Nethermind.JsonRpc.Test.Modules.Eth; [Parallelizable(ParallelScope.All)] [TestFixture] +[Culture("en-US")] public partial class EthRpcModuleTests { [TestCase("earliest", "0x3635c9adc5dea00000")] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs index bbd658cc2cd..31a16936028 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs @@ -26,6 +26,7 @@ using Nethermind.TxPool; using NUnit.Framework; using System.Threading.Tasks; +using FluentAssertions; using Nethermind.Consensus.Processing; using Nethermind.Core.Buffers; using Nethermind.State.Tracing; @@ -34,7 +35,7 @@ namespace Nethermind.JsonRpc.Test.Modules.Proof { [Parallelizable(ParallelScope.None)] - [TestFixture(true, true)] + // [TestFixture(true, true)] TODO fix or remove test? [TestFixture(true, false)] [TestFixture(false, false)] public class ProofRpcModuleTests @@ -45,7 +46,7 @@ public class ProofRpcModuleTests private IBlockTree _blockTree = null!; private IDbProvider _dbProvider = null!; private TestSpecProvider _specProvider = null!; - private ReadOnlyWorldStateManager _readOnlyWorldStateManager = null!; + private WorldStateManager _worldStateManager = null!; public ProofRpcModuleTests(bool createSystemAccount, bool useNonZeroGasPrice) { @@ -56,16 +57,23 @@ public ProofRpcModuleTests(bool createSystemAccount, bool useNonZeroGasPrice) [SetUp] public async Task Setup() { - InMemoryReceiptStorage receiptStorage = new(); - _specProvider = new TestSpecProvider(London.Instance); - _blockTree = Build.A.BlockTree(_specProvider).WithTransactions(receiptStorage).OfChainLength(10).TestObject; _dbProvider = await TestMemDbProvider.InitAsync(); - ITrieStore trieStore = new TrieStore(_dbProvider.StateDb, LimboLogs.Instance); - _readOnlyWorldStateManager = new ReadOnlyWorldStateManager(_dbProvider, trieStore.AsReadOnly(), 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( - _readOnlyWorldStateManager, + _worldStateManager, _blockTree, new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(TestBlockchainIds.ChainId, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), receiptStorage, @@ -140,8 +148,8 @@ public async Task On_incorrect_params_returns_correct_error_code() Assert.True(response.Contains($"{ErrorCodes.InvalidParams}"), "missing"); } - [TestCase(true, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x6db23e4d6e1f23a0f67ae8637cd675363ec59aea22acd86300ac1f1cb42c9011\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x0\",\"gasUsed\":\"0x0\",\"effectiveGasPrice\":\"0x1\",\"to\":null,\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0e244ea69b68d9f3fd5eff812a4a7e1e105a8c1143ff82206458ad45fe1801c9b80808080808080a08a1641bd871a8d574e81653362ae89e549a9ab0660bd5b180328d00f13e9c6bb8080808080808080\",\"0xf86530b862f860800182520894000000000000000000000000000000000000000001818025a0e7b18371f1b94890bd11e7f67ba7e7a3a6b263d68b2d18e258f6e063d6abd90ea00a015b31944dee0bde211cec1636a3f05bfea0678e240ae8dfe309b2aac22d93\"],\"receiptProof\":[\"0xf851a053e4a8d7d8438fa45d6b75bbd6fb699b08049c1caf1c21ada42a746ddfb61d0b80808080808080a04de834bd23b53a3d82923ae5f359239b326c66758f2ae636ab934844dba2b9658080808080808080\",\"0xf9010f30b9010bf9010880825208b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"],\"blockHeader\":\"0xf901f9a0b3157bcccab04639f6393042690a6c9862deebe88c781f911e8dfd265531e9ffa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a038b96dec209c13afedbb48916f68cb38a423d13c469f5f1e338ad7415c9cf5e3a0e1b1585a222beceb3887dc6701802facccf186c2d0f6aa69e26ae0c431fc2b5db9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424001833d090080830f424183010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8\"},\"id\":67}")] - [TestCase(false, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x6db23e4d6e1f23a0f67ae8637cd675363ec59aea22acd86300ac1f1cb42c9011\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x0\",\"gasUsed\":\"0x0\",\"effectiveGasPrice\":\"0x1\",\"to\":null,\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0e244ea69b68d9f3fd5eff812a4a7e1e105a8c1143ff82206458ad45fe1801c9b80808080808080a08a1641bd871a8d574e81653362ae89e549a9ab0660bd5b180328d00f13e9c6bb8080808080808080\",\"0xf86530b862f860800182520894000000000000000000000000000000000000000001818025a0e7b18371f1b94890bd11e7f67ba7e7a3a6b263d68b2d18e258f6e063d6abd90ea00a015b31944dee0bde211cec1636a3f05bfea0678e240ae8dfe309b2aac22d93\"],\"receiptProof\":[\"0xf851a053e4a8d7d8438fa45d6b75bbd6fb699b08049c1caf1c21ada42a746ddfb61d0b80808080808080a04de834bd23b53a3d82923ae5f359239b326c66758f2ae636ab934844dba2b9658080808080808080\",\"0xf9010f30b9010bf9010880825208b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"]},\"id\":67}")] + [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!; @@ -159,11 +167,11 @@ public async Task Can_get_receipt(bool withHeader, string expectedResult) } string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); - Assert.That(response, Is.EqualTo(expectedResult)); + response.Should().Be(expectedResult); } - [TestCase(true, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x1d4bacd3b4db06677ec7f43b6be43a6c1c4285ba7c8e2e63021b53701cf8189b\",\"transactionIndex\":\"0x1\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x7d0\",\"gasUsed\":\"0x3e8\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"to\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x2\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x1d4bacd3b4db06677ec7f43b6be43a6c1c4285ba7c8e2e63021b53701cf8189b\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x3\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x1d4bacd3b4db06677ec7f43b6be43a6c1c4285ba7c8e2e63021b53701cf8189b\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0e244ea69b68d9f3fd5eff812a4a7e1e105a8c1143ff82206458ad45fe1801c9b80808080808080a08a1641bd871a8d574e81653362ae89e549a9ab0660bd5b180328d00f13e9c6bb8080808080808080\",\"0xf86431b861f85f8001825208940000000000000000000000000000000000000000020125a00861eb73c37c3560fc40047523506de00ecfa6b96dff7d37e5ce75dc3986078da032e161403eae434b0f94a36fcc7e6ad46ccffc00fe90f0756118506e918eaef9\"],\"receiptProof\":[\"0xf851a053e4a8d7d8438fa45d6b75bbd6fb699b08049c1caf1c21ada42a746ddfb61d0b80808080808080a04de834bd23b53a3d82923ae5f359239b326c66758f2ae636ab934844dba2b9658080808080808080\",\"0xf9010f31b9010bf901088082a410b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"],\"blockHeader\":\"0xf901f9a0b3157bcccab04639f6393042690a6c9862deebe88c781f911e8dfd265531e9ffa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a038b96dec209c13afedbb48916f68cb38a423d13c469f5f1e338ad7415c9cf5e3a0e1b1585a222beceb3887dc6701802facccf186c2d0f6aa69e26ae0c431fc2b5db9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424001833d090080830f424183010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8\"},\"id\":67}")] - [TestCase(false, "{\"jsonrpc\":\"2.0\",\"result\":{\"receipt\":{\"transactionHash\":\"0x1d4bacd3b4db06677ec7f43b6be43a6c1c4285ba7c8e2e63021b53701cf8189b\",\"transactionIndex\":\"0x1\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"cumulativeGasUsed\":\"0x7d0\",\"gasUsed\":\"0x3e8\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"to\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x2\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x1d4bacd3b4db06677ec7f43b6be43a6c1c4285ba7c8e2e63021b53701cf8189b\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x3\",\"transactionIndex\":\"0x1\",\"transactionHash\":\"0x1d4bacd3b4db06677ec7f43b6be43a6c1c4285ba7c8e2e63021b53701cf8189b\",\"blockHash\":\"0x77f368c23226eee1583f671719f117df588fc5bf19c2a73e190e404a8be570f1\",\"blockNumber\":\"0x1\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x0\",\"type\":\"0x0\"},\"txProof\":[\"0xf851a0e244ea69b68d9f3fd5eff812a4a7e1e105a8c1143ff82206458ad45fe1801c9b80808080808080a08a1641bd871a8d574e81653362ae89e549a9ab0660bd5b180328d00f13e9c6bb8080808080808080\",\"0xf86431b861f85f8001825208940000000000000000000000000000000000000000020125a00861eb73c37c3560fc40047523506de00ecfa6b96dff7d37e5ce75dc3986078da032e161403eae434b0f94a36fcc7e6ad46ccffc00fe90f0756118506e918eaef9\"],\"receiptProof\":[\"0xf851a053e4a8d7d8438fa45d6b75bbd6fb699b08049c1caf1c21ada42a746ddfb61d0b80808080808080a04de834bd23b53a3d82923ae5f359239b326c66758f2ae636ab934844dba2b9658080808080808080\",\"0xf9010f31b9010bf901088082a410b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0\"]},\"id\":67}")] + [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(); @@ -209,7 +217,7 @@ public async Task Get_receipt_when_block_has_few_receipts(bool withHeader, strin _receiptFinder.FindBlockHash(Arg.Any()).Returns(_blockTree.FindBlock(1)!.Hash); ProofModuleFactory moduleFactory = new ProofModuleFactory( - _readOnlyWorldStateManager, + _worldStateManager, _blockTree, new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(TestBlockchainIds.ChainId, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), _receiptFinder, @@ -229,7 +237,7 @@ public async Task Get_receipt_when_block_has_few_receipts(bool withHeader, strin } string response = await RpcTest.TestSerializedRequest(_proofRpcModule, "proof_getTransactionReceipt", $"{txHash}", $"{withHeader}"); - Assert.That(response, Is.EqualTo(expectedResult)); + response.Should().Be(expectedResult); } [TestCase] diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrl.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrl.cs index 4221fb7b4e2..8d3fb8498bd 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrl.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrl.cs @@ -13,7 +13,7 @@ namespace Nethermind.JsonRpc { public class JsonRpcUrl : IEquatable, ICloneable { - public JsonRpcUrl(string scheme, string host, int port, RpcEndpoint rpcEndpoint, bool isAuthenticated, string[] enabledModules) + public JsonRpcUrl(string scheme, string host, int port, RpcEndpoint rpcEndpoint, bool isAuthenticated, string[] enabledModules, long? maxRequestBodySize = null) { Scheme = scheme; Host = host; @@ -21,6 +21,7 @@ public JsonRpcUrl(string scheme, string host, int port, RpcEndpoint rpcEndpoint, RpcEndpoint = rpcEndpoint; EnabledModules = new HashSet(enabledModules, StringComparer.InvariantCultureIgnoreCase); IsAuthenticated = isAuthenticated; + MaxRequestBodySize = maxRequestBodySize; } public static JsonRpcUrl Parse(string packedUrlValue) @@ -75,6 +76,7 @@ public static JsonRpcUrl Parse(string packedUrlValue) return result; } + public long? MaxRequestBodySize { get; } public bool IsAuthenticated { get; } public string Scheme { get; set; } public string Host { get; set; } diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrlCollection.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrlCollection.cs index 4f926288776..cb6c3bee5db 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrlCollection.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcUrlCollection.cs @@ -6,6 +6,8 @@ using System.Linq; using Nethermind.Logging; using Nethermind.JsonRpc.Modules; +using Nethermind.Sockets; +using System.IO; namespace Nethermind.JsonRpc { @@ -31,8 +33,8 @@ public JsonRpcUrlCollection(ILogManager logManager, IJsonRpcConfig jsonRpcConfig private void BuildUrls(bool includeWebSockets) { - bool isAuthenticated = _jsonRpcConfig.EnabledModules.Any(m => m.Equals(ModuleType.Engine, StringComparison.InvariantCultureIgnoreCase)); - JsonRpcUrl defaultUrl = new(Uri.UriSchemeHttp, _jsonRpcConfig.Host, _jsonRpcConfig.Port, RpcEndpoint.Http, isAuthenticated, _jsonRpcConfig.EnabledModules); + bool HasEngineApi = _jsonRpcConfig.EnabledModules.Any(m => m.Equals(ModuleType.Engine, StringComparison.InvariantCultureIgnoreCase)); + JsonRpcUrl defaultUrl = new(Uri.UriSchemeHttp, _jsonRpcConfig.Host, _jsonRpcConfig.Port, RpcEndpoint.Http, HasEngineApi, _jsonRpcConfig.EnabledModules, HasEngineApi ? SocketClient.MAX_REQUEST_BODY_SIZE_FOR_ENGINE_API : _jsonRpcConfig.MaxRequestBodySize); string environmentVariableUrl = Environment.GetEnvironmentVariable(NethermindUrlVariable); if (!string.IsNullOrWhiteSpace(environmentVariableUrl)) { @@ -85,7 +87,8 @@ private void BuildEngineUrls(bool includeWebSockets) return; } JsonRpcUrl url = new(Uri.UriSchemeHttp, _jsonRpcConfig.EngineHost, _jsonRpcConfig.EnginePort.Value, - RpcEndpoint.Http, true, _jsonRpcConfig.EngineEnabledModules.Append(ModuleType.Engine).ToArray()); + RpcEndpoint.Http, true, _jsonRpcConfig.EngineEnabledModules.Append(ModuleType.Engine).ToArray(), + SocketClient.MAX_REQUEST_BODY_SIZE_FOR_ENGINE_API); if (ContainsKey(url.Port)) { diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs index bca0e9a34b0..0aeaeb2e336 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs @@ -48,8 +48,10 @@ public override IProofRpcModule Create() ReadOnlyTxProcessingEnv txProcessingEnv = new( _worldStateManager, _blockTree, _specProvider, _logManager); + RpcBlockTransactionsExecutor traceExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider); + ReadOnlyChainProcessingEnv chainProcessingEnv = new( - txProcessingEnv, Always.Valid, _recoveryStep, NoBlockRewards.Instance, new InMemoryReceiptStorage(), _specProvider, _logManager); + txProcessingEnv, Always.Valid, _recoveryStep, NoBlockRewards.Instance, new InMemoryReceiptStorage(), _specProvider, _logManager, traceExecutor); Tracer tracer = new( txProcessingEnv.StateProvider, diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs index 3235754eba1..9d34f031e44 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs @@ -64,8 +64,7 @@ public override ITraceRpcModule Create() _poSSwitcher); RpcBlockTransactionsExecutor rpcBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider); - BlockProcessor.BlockValidationTransactionsExecutor executeBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, - txProcessingEnv.StateProvider); + BlockProcessor.BlockValidationTransactionsExecutor executeBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider); ReadOnlyChainProcessingEnv CreateChainProcessingEnv(IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor) => new( txProcessingEnv, diff --git a/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs b/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs index 99d11de6f5c..85776645e9a 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs @@ -56,7 +56,7 @@ public void ProcessWithdrawals(Block block, IReleaseSpec spec) } catch (Exception ex) when (ex is ArgumentNullException || ex is EvmException) { - throw new InvalidBlockException(block, ex); + throw new InvalidBlockException(block, "failed to execute withdrawals contract", ex); } if (_logger.IsTrace) _logger.Trace($"Withdrawals applied for block {block}"); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs index 1af53687a9e..069b18c2cb0 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs @@ -31,7 +31,7 @@ public OptimismTransactionProcessor( private UInt256? _currentTxL1Cost; - protected override void Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) + protected override TransactionResult Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { IReleaseSpec spec = SpecProvider.GetSpec(blCtx.Header); _currentTxL1Cost = null; @@ -43,13 +43,13 @@ protected override void Execute(Transaction tx, in BlockExecutionContext blCtx, WorldState.Commit(spec); } - base.Execute(tx, in blCtx, tracer, opts); + return base.Execute(tx, in blCtx, tracer, opts); } - protected override bool ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, + protected override TransactionResult ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, out long intrinsicGas) { - bool result = base.ValidateStatic(tx, header, spec, tracer, opts, out intrinsicGas); + TransactionResult result = base.ValidateStatic(tx, header, spec, tracer, opts, out intrinsicGas); if (tx.IsDeposit() && !tx.IsOPSystemTransaction && !result) { if (!WorldState.AccountExists(tx.SenderAddress!)) @@ -65,7 +65,7 @@ protected override bool ValidateStatic(Transaction tx, BlockHeader header, IRele return result; } - protected override bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, + protected override TransactionResult BuyGas(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, in UInt256 effectiveGasPrice, out UInt256 premiumPerGas, out UInt256 senderReservedGasPayment) { premiumPerGas = UInt256.Zero; @@ -85,8 +85,7 @@ protected override bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec { WorldState.IncrementNonce(tx.SenderAddress!); } - QuickFail(tx, header, spec, tracer, "insufficient sender balance"); - return false; + return "insufficient sender balance"; } if (validate && !tx.IsDeposit()) @@ -94,39 +93,34 @@ protected override bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec if (!tx.TryCalculatePremiumPerGas(header.BaseFeePerGas, out premiumPerGas)) { TraceLogInvalidTx(tx, "MINER_PREMIUM_IS_NEGATIVE"); - QuickFail(tx, header, spec, tracer, "miner premium is negative"); - return false; + return "miner premium is negative"; } if (UInt256.SubtractUnderflow(senderBalance, tx.Value, out UInt256 balanceLeft)) { TraceLogInvalidTx(tx, $"INSUFFICIENT_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); - QuickFail(tx, header, spec, tracer, "insufficient sender balance"); - return false; + return "insufficient sender balance"; } UInt256 l1Cost = _currentTxL1Cost ??= _l1CostHelper.ComputeL1Cost(tx, header, WorldState); if (UInt256.SubtractUnderflow(balanceLeft, l1Cost, out balanceLeft)) { TraceLogInvalidTx(tx, $"INSUFFICIENT_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); - QuickFail(tx, header, spec, tracer, "insufficient sender balance"); - return false; + return "insufficient sender balance"; } bool overflows = UInt256.MultiplyOverflow((UInt256)tx.GasLimit, tx.MaxFeePerGas, out UInt256 maxGasFee); if (spec.IsEip1559Enabled && !tx.IsFree() && (overflows || balanceLeft < maxGasFee)) { TraceLogInvalidTx(tx, $"INSUFFICIENT_MAX_FEE_PER_GAS_FOR_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}, MAX_FEE_PER_GAS: {tx.MaxFeePerGas}"); - QuickFail(tx, header, spec, tracer, "insufficient MaxFeePerGas for sender balance"); - return false; + return "insufficient MaxFeePerGas for sender balance"; } overflows = UInt256.MultiplyOverflow((UInt256)tx.GasLimit, effectiveGasPrice, out senderReservedGasPayment); if (overflows || senderReservedGasPayment > balanceLeft) { TraceLogInvalidTx(tx, $"INSUFFICIENT_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); - QuickFail(tx, header, spec, tracer, "insufficient sender balance"); - return false; + return "insufficient sender balance"; } senderReservedGasPayment += l1Cost; // no overflow here, otherwise previous check would fail @@ -135,43 +129,35 @@ protected override bool BuyGas(Transaction tx, BlockHeader header, IReleaseSpec if (validate) WorldState.SubtractFromBalance(tx.SenderAddress!, senderReservedGasPayment, spec); - return true; + return TransactionResult.Ok; } - protected override bool IncrementNonce(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) + protected override TransactionResult IncrementNonce(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) { if (!tx.IsDeposit()) return base.IncrementNonce(tx, header, spec, tracer, opts); WorldState.IncrementNonce(tx.SenderAddress!); - return true; + return TransactionResult.Ok; } - protected override bool ValidateSender(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) - { - return tx.IsDeposit() || base.ValidateSender(tx, header, spec, tracer, opts); - } + protected override TransactionResult ValidateSender(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) => + tx.IsDeposit() ? TransactionResult.Ok : base.ValidateSender(tx, header, spec, tracer, opts); - protected override bool PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, + protected override void PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in byte statusCode) { - if (tx.IsDeposit()) + if (!tx.IsDeposit()) { // Skip coinbase payments for deposit tx in Regolith - return true; - } - - if (!base.PayFees(tx, header, spec, tracer, substate, spentGas, premiumPerGas, statusCode)) - // this should never happen, but just to be consistent - return false; + base.PayFees(tx, header, spec, tracer, substate, spentGas, premiumPerGas, statusCode); - if (_opConfigHelper.IsBedrock(header)) - { - UInt256 l1Cost = _currentTxL1Cost ??= _l1CostHelper.ComputeL1Cost(tx, header, WorldState); - WorldState.AddToBalanceAndCreateIfNotExists(_opConfigHelper.L1FeeReceiver, l1Cost, spec); + if (_opConfigHelper.IsBedrock(header)) + { + UInt256 l1Cost = _currentTxL1Cost ??= _l1CostHelper.ComputeL1Cost(tx, header, WorldState); + WorldState.AddToBalanceAndCreateIfNotExists(_opConfigHelper.L1FeeReceiver, l1Cost, spec); + } } - - return true; } protected override long Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, diff --git a/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs b/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs index ec0a30e5f7f..51019f6b904 100644 --- a/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs +++ b/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs @@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.DependencyInjection; @@ -145,6 +146,9 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IJsonRpc jsonRpcUrlCollection.TryGetValue(ctx.Connection.LocalPort, out JsonRpcUrl jsonRpcUrl) && jsonRpcUrl.RpcEndpoint.HasFlag(RpcEndpoint.Http)) { + if (jsonRpcUrl.MaxRequestBodySize is not null) + ctx.Features.Get().MaxRequestBodySize = jsonRpcUrl.MaxRequestBodySize; + if (jsonRpcUrl.IsAuthenticated && !rpcAuthentication!.Authenticate(ctx.Request.Headers.Authorization)) { await PushErrorResponse(StatusCodes.Status403Forbidden, ErrorCodes.InvalidRequest, diff --git a/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs b/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs index 809f7935379..1d50e19123a 100644 --- a/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs +++ b/src/Nethermind/Nethermind.Sockets.Test/WebSocketExtensionsTests.cs @@ -50,17 +50,10 @@ public override void Dispose() throw new NotImplementedException(); } - private byte byteIndex = 0; - public override Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) { - for (int i = 0; i < buffer.Count; i++) - { - unchecked - { - buffer[i] = byteIndex++; - } - } + // Had to use Array.Fill as it is more performant + Array.Fill(buffer.Array, (byte)0, buffer.Offset, buffer.Count); if (_receiveResults.Count == 0 && ReturnTaskWithFaultOnEmptyQueue) { @@ -202,9 +195,9 @@ public async Task Can_receive_whole_message_non_buffer_sizes() public async Task Throws_on_too_long_message() { Queue receiveResult = new Queue(); - for (int i = 0; i < 1024; i++) + for (int i = 0; i < 128 * 1024; i++) { - receiveResult.Enqueue(new WebSocketReceiveResult(5 * 1024, WebSocketMessageType.Text, false)); + receiveResult.Enqueue(new WebSocketReceiveResult(1024, WebSocketMessageType.Text, false)); } receiveResult.Enqueue(new WebSocketReceiveResult(1, WebSocketMessageType.Text, true)); diff --git a/src/Nethermind/Nethermind.Sockets/SocketClient.cs b/src/Nethermind/Nethermind.Sockets/SocketClient.cs index 72e9f4f109b..adf1224787b 100644 --- a/src/Nethermind/Nethermind.Sockets/SocketClient.cs +++ b/src/Nethermind/Nethermind.Sockets/SocketClient.cs @@ -11,7 +11,7 @@ namespace Nethermind.Sockets; public class SocketClient : ISocketsClient where TStream : Stream, IMessageBorderPreservingStream { - public const int MAX_POOLED_SIZE = 5 * 1024 * 1024; + public const int MAX_REQUEST_BODY_SIZE_FOR_ENGINE_API = 128 * 1024 * 1024; protected readonly TStream _stream; protected readonly IJsonSerializer _jsonSerializer; @@ -55,7 +55,7 @@ public async Task ReceiveLoopAsync() { currentMessageLength += result.Read; - if (currentMessageLength >= MAX_POOLED_SIZE) + if (currentMessageLength >= MAX_REQUEST_BODY_SIZE_FOR_ENGINE_API) { throw new InvalidOperationException("Message too long"); } @@ -76,7 +76,7 @@ public async Task ReceiveLoopAsync() else if (buffer.Length - currentMessageLength < standardBufferLength) // there is little room in current buffer { // grow the buffer 4x, but not more than max - int newLength = Math.Min(buffer.Length * 4, MAX_POOLED_SIZE); + int newLength = Math.Min(buffer.Length * 4, MAX_REQUEST_BODY_SIZE_FOR_ENGINE_API); if (newLength > buffer.Length) { byte[] newBuffer = ArrayPool.Shared.Rent(newLength); From 26f5ffc6f3d496d050af8cfef9e3391f418ff3a6 Mon Sep 17 00:00:00 2001 From: Lukasz Rozmej Date: Tue, 27 Feb 2024 15:23:02 +0100 Subject: [PATCH 2/8] more account struct (#6775) Co-authored-by: Jorge Mederos Co-authored-by: Ben Adams --- .../GeneratedTxSourceSealerTests.cs | 7 ++- .../ChainHeadReadOnlyStateProvider.cs | 10 +-- .../SpecificBlockReadOnlyStateProvider.cs | 36 ++++------- src/Nethermind/Nethermind.Core/Account.cs | 54 +++++++++++++--- .../AccountStateProviderExtensions.cs | 2 +- .../Nethermind.Core/IAccountStateProvider.cs | 34 +++++++++- .../Nethermind.Evm.Test/Eip1014Tests.cs | 16 ++--- .../Nethermind.Evm.Test/Eip3860Tests.cs | 2 +- .../Tracing/GethStyle/JavaScript/Db.cs | 2 +- .../Modules/TraceRpcModuleTests.cs | 63 ++++++++++--------- .../Nethermind.JsonRpc/Data/AccountForRpc.cs | 2 +- .../Modules/Eth/EthRpcModule.cs | 36 +++++------ .../EngineModuleTests.HelperFunctions.cs | 2 +- .../Boost/BoostBlockImprovementContext.cs | 7 ++- .../Nethermind.Mev.Test/TestBundlePool.cs | 6 +- .../EthereumRunnerTests.cs | 16 +++-- .../AccountDecoder.cs | 8 ++- .../IReadOnlyStateProvider.cs | 8 --- .../Nethermind.State/IStateReader.cs | 5 +- .../Nethermind.State/IWorldStateExtensions.cs | 4 +- .../Nethermind.State/StateReader.cs | 53 +++++----------- .../Nethermind.State/StateReaderExtensions.cs | 12 ++-- src/Nethermind/Nethermind.State/StateTree.cs | 10 ++- src/Nethermind/Nethermind.State/WorldState.cs | 46 +++++--------- .../PruningScenariosTests.cs | 4 +- .../NonceManagerTests.cs | 10 +-- .../TransactionPoolInfoProviderTests.cs | 2 +- .../Collections/TxDistinctSortedPool.cs | 2 +- .../Nethermind.TxPool/NonceManager.cs | 2 +- .../Nethermind.TxPool/TxFilteringState.cs | 22 ++++--- src/Nethermind/Nethermind.TxPool/TxPool.cs | 2 +- .../Nethermind.TxPool/TxPoolInfoProvider.cs | 2 +- 32 files changed, 261 insertions(+), 226 deletions(-) diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs index ebb8669a677..83d5e7f7b20 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/GeneratedTxSourceSealerTests.cs @@ -32,7 +32,12 @@ public void transactions_are_addable_to_block_after_sealing() Address nodeAddress = TestItem.AddressA; UInt256 expectedNonce = 10; - stateReader.GetAccount(blockHeader.StateRoot, nodeAddress).Returns(new AccountStruct(expectedNonce, UInt256.Zero)); + stateReader.TryGetAccount(blockHeader.StateRoot, nodeAddress, out Arg.Any()) + .Returns(x => + { + x[2] = new AccountStruct(expectedNonce, UInt256.Zero); + return true; + }); ulong expectedTimeStamp = 100; timestamper.UnixTime.Returns(UnixTime.FromSeconds(expectedTimeStamp)); diff --git a/src/Nethermind/Nethermind.Blockchain/ChainHeadReadOnlyStateProvider.cs b/src/Nethermind/Nethermind.Blockchain/ChainHeadReadOnlyStateProvider.cs index 508dc4146b6..41ee3214362 100644 --- a/src/Nethermind/Nethermind.Blockchain/ChainHeadReadOnlyStateProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/ChainHeadReadOnlyStateProvider.cs @@ -8,14 +8,10 @@ namespace Nethermind.Blockchain { - public class ChainHeadReadOnlyStateProvider : SpecificBlockReadOnlyStateProvider + public class ChainHeadReadOnlyStateProvider(IBlockFinder blockFinder, IStateReader stateReader) + : SpecificBlockReadOnlyStateProvider(stateReader) { - private readonly IBlockFinder _blockFinder; - - public ChainHeadReadOnlyStateProvider(IBlockFinder blockFinder, IStateReader stateReader) : base(stateReader) - { - _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); - } + private readonly IBlockFinder _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); public override Hash256 StateRoot => _blockFinder.Head?.StateRoot ?? Keccak.EmptyTreeHash; } diff --git a/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs b/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs index 8d5284c5347..c28e2000d9a 100644 --- a/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/SpecificBlockReadOnlyStateProvider.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Runtime.CompilerServices; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -10,49 +11,38 @@ namespace Nethermind.Blockchain { - public class SpecificBlockReadOnlyStateProvider : IReadOnlyStateProvider + public class SpecificBlockReadOnlyStateProvider(IStateReader stateReader, Hash256? stateRoot = null) : IReadOnlyStateProvider { - private readonly IStateReader _stateReader; + private readonly IStateReader _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); - public SpecificBlockReadOnlyStateProvider(IStateReader stateReader, Hash256? stateRoot = null) - { - _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); - StateRoot = stateRoot ?? Keccak.EmptyTreeHash; - } - - public virtual Hash256 StateRoot { get; } - - public AccountStruct GetAccount(Address address) => _stateReader.GetAccount(StateRoot, address) ?? AccountStruct.TotallyEmpty; + public virtual Hash256 StateRoot { get; } = stateRoot ?? Keccak.EmptyTreeHash; - public bool IsContract(Address address) => GetAccount(address).IsContract; + public bool TryGetAccount(Address address, out AccountStruct account) => _stateReader.TryGetAccount(StateRoot, address, out account); - public UInt256 GetNonce(Address address) => GetAccount(address).Nonce; - - public UInt256 GetBalance(Address address) => GetAccount(address).Balance; - - public ValueHash256 GetStorageRoot(Address address) => GetAccount(address).StorageRoot; + public bool IsContract(Address address) => TryGetAccount(address, out AccountStruct account) && account.IsContract; + [SkipLocalsInit] public byte[]? GetCode(Address address) { - AccountStruct account = GetAccount(address); + TryGetAccount(address, out AccountStruct account); return !account.HasCode ? Array.Empty() : _stateReader.GetCode(account.CodeHash); } public byte[]? GetCode(Hash256 codeHash) => _stateReader.GetCode(codeHash); public byte[]? GetCode(ValueHash256 codeHash) => _stateReader.GetCode(codeHash); - public ValueHash256 GetCodeHash(Address address) => GetAccount(address).CodeHash; - public void Accept(ITreeVisitor visitor, Hash256 stateRoot, VisitingOptions? visitingOptions) { _stateReader.RunTreeVisitor(visitor, stateRoot, visitingOptions); } - public bool AccountExists(Address address) => _stateReader.GetAccount(StateRoot, address) is not null; + public bool AccountExists(Address address) => _stateReader.TryGetAccount(StateRoot, address, out _); - public bool IsEmptyAccount(Address address) => GetAccount(address).IsEmpty; + [SkipLocalsInit] + public bool IsEmptyAccount(Address address) => TryGetAccount(address, out AccountStruct account) && account.IsEmpty; public bool HasStateForRoot(Hash256 stateRoot) => _stateReader.HasStateForRoot(stateRoot); - public bool IsDeadAccount(Address address) => GetAccount(address).IsEmpty; + [SkipLocalsInit] + public bool IsDeadAccount(Address address) => !TryGetAccount(address, out AccountStruct account) || account.IsEmpty; } } diff --git a/src/Nethermind/Nethermind.Core/Account.cs b/src/Nethermind/Nethermind.Core/Account.cs index 0f827fc9bcd..41279ec2b7b 100644 --- a/src/Nethermind/Nethermind.Core/Account.cs +++ b/src/Nethermind/Nethermind.Core/Account.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -106,41 +108,73 @@ public Account WithChangedCodeHash(Hash256 newCodeHash) public readonly struct AccountStruct { - private readonly static AccountStruct _totallyEmpty = Account.TotallyEmpty.ToStruct(); + private static readonly AccountStruct _totallyEmpty = Account.TotallyEmpty.ToStruct(); public static ref readonly AccountStruct TotallyEmpty => ref _totallyEmpty; + private readonly UInt256 _balance; + private readonly UInt256 _nonce = default; private readonly ValueHash256 _codeHash = Keccak.OfAnEmptyString.ValueHash256; private readonly ValueHash256 _storageRoot = Keccak.EmptyTreeHash.ValueHash256; public AccountStruct(in UInt256 nonce, in UInt256 balance, in ValueHash256 storageRoot, in ValueHash256 codeHash) { + _balance = balance; + _nonce = nonce; _codeHash = codeHash; _storageRoot = storageRoot; - Nonce = nonce; - Balance = balance; } public AccountStruct(in UInt256 nonce, in UInt256 balance) { - Nonce = nonce; - Balance = balance; + _balance = balance; + _nonce = nonce; } public AccountStruct(in UInt256 balance) { - Balance = balance; + _balance = balance; } public bool HasCode => _codeHash != Keccak.OfAnEmptyString.ValueHash256; public bool HasStorage => _storageRoot != Keccak.EmptyTreeHash.ValueHash256; - public UInt256 Nonce { get; } - public UInt256 Balance { get; } + public UInt256 Nonce => _nonce; + public UInt256 Balance => _balance; public ValueHash256 StorageRoot => _storageRoot; public ValueHash256 CodeHash => _codeHash; - public bool IsTotallyEmpty => _storageRoot == Keccak.EmptyTreeHash.ValueHash256 && IsEmpty; - public bool IsEmpty => _codeHash == Keccak.OfAnEmptyString.ValueHash256 && Balance.IsZero && Nonce.IsZero; + public bool IsTotallyEmpty => IsEmpty && _storageRoot == Keccak.EmptyTreeHash.ValueHash256; + public bool IsEmpty => Balance.IsZero && Nonce.IsZero && _codeHash == Keccak.OfAnEmptyString.ValueHash256; public bool IsContract => _codeHash != Keccak.OfAnEmptyString.ValueHash256; + public bool IsNull + { + get + { + // The following branchless code is generated by the JIT compiler for the IsNull property on x64 + // + // Method Nethermind.Core.AccountStruct:get_IsNull():bool:this (FullOpts) + // G_M000_IG01: + // vzeroupper + // + // G_M000_IG02: + // vmovups ymm0, ymmword ptr [rcx] + // vpor ymm0, ymm0, ymmword ptr [rcx+0x20] + // vpor ymm0, ymm0, ymmword ptr [rcx+0x40] + // vpor ymm0, ymm0, ymmword ptr [rcx+0x60] + // vptest ymm0, ymm0 + // sete al + // movzx rax, al + // + // G_M000_IG03: ;; offset=0x0021 + // vzeroupper + // ret + // ; Total bytes of code: 37 + + return (Unsafe.As>(ref Unsafe.AsRef(in _balance)) | + Unsafe.As>(ref Unsafe.AsRef(in _nonce)) | + Unsafe.As>(ref Unsafe.AsRef(in _codeHash)) | + Unsafe.As>(ref Unsafe.AsRef(in _storageRoot))) == default; + } + } } } diff --git a/src/Nethermind/Nethermind.Core/AccountStateProviderExtensions.cs b/src/Nethermind/Nethermind.Core/AccountStateProviderExtensions.cs index ca0df131ec1..45a8c09be5f 100644 --- a/src/Nethermind/Nethermind.Core/AccountStateProviderExtensions.cs +++ b/src/Nethermind/Nethermind.Core/AccountStateProviderExtensions.cs @@ -8,7 +8,7 @@ namespace Nethermind.Core public static class AccountStateProviderExtensions { public static bool HasCode(this IAccountStateProvider stateProvider, Address address) => - stateProvider.GetAccount(address).HasCode; + stateProvider.TryGetAccount(address, out AccountStruct account) && account.HasCode; public static bool IsInvalidContractSender(this IAccountStateProvider stateProvider, IReleaseSpec spec, Address address) => spec.IsEip3607Enabled && stateProvider.HasCode(address); diff --git a/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs b/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs index d43b0527f4b..116a6205d19 100644 --- a/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs +++ b/src/Nethermind/Nethermind.Core/IAccountStateProvider.cs @@ -1,10 +1,42 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Runtime.CompilerServices; +using Nethermind.Core.Crypto; +using Nethermind.Int256; + namespace Nethermind.Core { public interface IAccountStateProvider { - AccountStruct GetAccount(Address address); + bool TryGetAccount(Address address, out AccountStruct account); + + [SkipLocalsInit] + UInt256 GetNonce(Address address) + { + TryGetAccount(address, out AccountStruct account); + return account.Nonce; + } + + [SkipLocalsInit] + UInt256 GetBalance(Address address) + { + TryGetAccount(address, out AccountStruct account); + return account.Balance; + } + + [SkipLocalsInit] + ValueHash256 GetStorageRoot(Address address) + { + TryGetAccount(address, out AccountStruct account); + return account.StorageRoot; + } + + [SkipLocalsInit] + ValueHash256 GetCodeHash(Address address) + { + TryGetAccount(address, out AccountStruct account); + return account.CodeHash; + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs index 3a7a31de376..54f7641fb27 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs @@ -86,8 +86,8 @@ public void Test_out_of_gas_existing_account() Execute(code); - TestState.GetAccount(expectedAddress).Should().NotBeNull(); - TestState.GetAccount(expectedAddress).Balance.Should().Be(1.Ether()); + TestState.TryGetAccount(expectedAddress, out AccountStruct account).Should().BeTrue(); + account.Balance.Should().Be(1.Ether()); AssertEip1014(expectedAddress, Array.Empty()); } @@ -110,7 +110,7 @@ public void Test_out_of_gas_existing_account_with_storage() TestState.Commit(Spec); TestState.CommitTree(0); - ValueHash256 storageRoot = TestState.GetAccount(expectedAddress).StorageRoot; + ValueHash256 storageRoot = TestState.GetStorageRoot(expectedAddress); storageRoot.Should().NotBe(PatriciaTree.EmptyTreeHash); TestState.CreateAccount(TestItem.AddressC, 1.Ether()); @@ -123,17 +123,17 @@ public void Test_out_of_gas_existing_account_with_storage() Execute(code); - TestState.GetAccount(expectedAddress).Should().NotBeNull(); - TestState.GetAccount(expectedAddress).Balance.Should().Be(1.Ether()); - TestState.GetAccount(expectedAddress).StorageRoot.Should().Be(storageRoot); + TestState.TryGetAccount(expectedAddress, out AccountStruct account).Should().BeTrue(); + account.Balance.Should().Be(1.Ether()); + account.StorageRoot.Should().Be(storageRoot); AssertEip1014(expectedAddress, Array.Empty()); } [Test] public void Test_out_of_gas_non_existing_account() { - byte[] salt = { 4, 5, 6 }; - byte[] deployedCode = { 1, 2, 3 }; + byte[] salt = [4, 5, 6]; + byte[] deployedCode = [1, 2, 3]; byte[] initCode = Prepare.EvmCode .ForInitOf(deployedCode).Done; diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs index 98f298a2179..0e4029bffa2 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs @@ -66,7 +66,7 @@ public void Test_EIP_3860_InitCode_Create_Exceeds_Limit(string createCode) Assert.That(tracer.StatusCode, Is.EqualTo(StatusCode.Success)); Assert.That(tracer.ReportedActionErrors.Count, Is.EqualTo(1)); Assert.That(tracer.ReportedActionErrors[0], Is.EqualTo(EvmExceptionType.OutOfGas)); - Assert.That(TestState.GetAccount(TestItem.AddressC).Nonce, Is.EqualTo((UInt256)0)); + Assert.That(TestState.GetNonce(TestItem.AddressC), Is.EqualTo((UInt256)0)); Assert.That(tracer.GasSpent, Is.EqualTo(_transactionCallCost + contractCreationGasLimit)); } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs index c38c2d5cd56..c4ea242a0fa 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/JavaScript/Db.cs @@ -47,5 +47,5 @@ public ITypedArray getState(object address, object hash) } } - public bool exists(object address) => !WorldState.GetAccount(address.ToAddress()).IsTotallyEmpty; + public bool exists(object address) => WorldState.TryGetAccount(address.ToAddress(), out AccountStruct account) && !account.IsTotallyEmpty; } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index fba39b23c05..0e499183eb8 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -79,7 +79,8 @@ public async Task Build(ISpecProvider? specProvider = null, bool isAura = false) List transactions = new(); for (int j = 0; j < i; j++) { - transactions.Add(Core.Test.Builders.Build.A.Transaction.WithNonce(Blockchain.State.GetAccount(TestItem.AddressB).Nonce + (UInt256)j).SignedAndResolved(Blockchain.EthereumEcdsa, TestItem.PrivateKeyB).TestObject); + transactions.Add(Core.Test.Builders.Build.A.Transaction.WithNonce(Blockchain.State.GetNonce(TestItem.AddressB) + (UInt256)j) + .SignedAndResolved(Blockchain.EthereumEcdsa, TestItem.PrivateKeyB).TestObject); } await Blockchain.AddBlock(transactions.ToArray()); } @@ -191,7 +192,7 @@ public async Task Trace_filter_with_filtering_by_receiver_address() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); Transaction transaction = Build.A.Transaction.WithNonce(currentNonceAddressA) .WithTo(TestItem.AddressA) .SignedAndResolved(blockchain.EthereumEcdsa, TestItem.PrivateKeyA).TestObject; @@ -211,7 +212,7 @@ public async Task Trace_filter_with_filtering_by_sender() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); Transaction transaction = Build.A.Transaction.WithNonce(currentNonceAddressA) .WithTo(TestItem.AddressA) .SignedAndResolved(blockchain.EthereumEcdsa, TestItem.PrivateKeyA).TestObject; @@ -233,8 +234,8 @@ public async Task Trace_filter_with_filtering_by_internal_transaction_receiver() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; - UInt256 currentNonceAddressB = blockchain.State.GetAccount(TestItem.AddressB).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); + UInt256 currentNonceAddressB = blockchain.State.GetNonce(TestItem.AddressB); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode @@ -279,13 +280,13 @@ public async Task Trace_filter_with_filtering_by_sender_and_receiver() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); await context.Blockchain.AddBlock( new[] { Build.A.Transaction.WithNonce(currentNonceAddressA + 1).WithTo(TestItem.AddressD) .SignedAndResolved(TestItem.PrivateKeyA).TestObject, - Build.A.Transaction.WithNonce(blockchain.State.GetAccount(TestItem.AddressB).Nonce + 1).WithTo(TestItem.AddressC) + Build.A.Transaction.WithNonce(blockchain.State.GetNonce(TestItem.AddressB) + 1).WithTo(TestItem.AddressC) .SignedAndResolved(TestItem.PrivateKeyB).TestObject, Build.A.Transaction.WithNonce(currentNonceAddressA).WithTo(TestItem.AddressC) .SignedAndResolved(TestItem.PrivateKeyA).TestObject @@ -315,9 +316,9 @@ public async Task Trace_filter_complex_scenario() traceFilterRequest.ToBlock = BlockParameter.Latest; traceFilterRequest.FromAddress = new[] { TestItem.PrivateKeyA.Address, TestItem.PrivateKeyD.Address }; traceFilterRequest.ToAddress = new[] { TestItem.AddressC, TestItem.AddressA, TestItem.AddressB }; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; - UInt256 currentNonceAddressC = blockchain.State.GetAccount(TestItem.AddressC).Nonce; - UInt256 currentNonceAddressD = blockchain.State.GetAccount(TestItem.AddressD).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); + UInt256 currentNonceAddressC = blockchain.State.GetNonce(TestItem.AddressC); + UInt256 currentNonceAddressD = blockchain.State.GetNonce(TestItem.AddressD); // first block skipped: After 3 -> 1 await blockchain.AddBlock( new[] @@ -397,7 +398,7 @@ public async Task Trace_filter_complex_scenario_openethereum() traceFilterRequest.ToBlock = BlockParameter.Latest; // traceFilterRequest.FromAddress = new[] {TestItem.PrivateKeyA.Address, TestItem.PrivateKeyD.Address}; // traceFilterRequest.ToAddress = new[] {TestItem.AddressC, TestItem.AddressA, TestItem.AddressB}; - UInt256 currentNonceAddressC = blockchain.State.GetAccount(TestItem.AddressC).Nonce; + UInt256 currentNonceAddressC = blockchain.State.GetNonce(TestItem.AddressC); await blockchain.AddBlock(); await blockchain.AddBlock(); await blockchain.AddBlock( @@ -417,7 +418,7 @@ public async Task trace_transaction_and_get_simple_tx() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); Transaction transaction = Build.A.Transaction.WithNonce(currentNonceAddressA++).WithTo(TestItem.AddressC) .SignedAndResolved(TestItem.PrivateKeyA).TestObject; await blockchain.AddBlock(transaction); @@ -435,7 +436,7 @@ public async Task Trace_get_can_trace_simple_tx() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); Transaction transaction = Build.A.Transaction.WithNonce(currentNonceAddressA++).WithTo(TestItem.AddressC) .SignedAndResolved(TestItem.PrivateKeyA).TestObject; @@ -452,8 +453,8 @@ public async Task trace_transaction_and_get_internal_tx() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; - UInt256 currentNonceAddressB = blockchain.State.GetAccount(TestItem.AddressB).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); + UInt256 currentNonceAddressB = blockchain.State.GetNonce(TestItem.AddressB); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode @@ -498,8 +499,8 @@ public async Task Trace_transaction_with_error_reverted() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; - UInt256 currentNonceAddressB = blockchain.State.GetAccount(TestItem.AddressB).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); + UInt256 currentNonceAddressB = blockchain.State.GetNonce(TestItem.AddressB); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode @@ -554,8 +555,8 @@ public async Task Trace_replayTransaction_test() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; - UInt256 currentNonceAddressB = blockchain.State.GetAccount(TestItem.AddressB).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); + UInt256 currentNonceAddressB = blockchain.State.GetNonce(TestItem.AddressB); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); byte[] deployedCode = new byte[3]; byte[] initCode = Prepare.EvmCode @@ -588,8 +589,8 @@ public async Task Trace_replayTransaction_reward_test() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; - UInt256 currentNonceAddressB = blockchain.State.GetAccount(TestItem.AddressB).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); + UInt256 currentNonceAddressB = blockchain.State.GetNonce(TestItem.AddressB); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); Address? contractAddress = ContractAddress.From(TestItem.AddressA, currentNonceAddressA); byte[] code = Prepare.EvmCode @@ -619,7 +620,7 @@ public async Task trace_replayBlockTransactions_zeroGasUsed_test() TestSpecProvider specProvider = new(releaseSpec); await context.Build(specProvider, isAura: true); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressC = blockchain.State.GetAccount(TestItem.AddressC).Nonce; + UInt256 currentNonceAddressC = blockchain.State.GetNonce(TestItem.AddressC); Transaction serviceTransaction = Build.A.Transaction.WithNonce(currentNonceAddressC++) .WithTo(TestItem.AddressE) @@ -638,8 +639,8 @@ public async Task Trace_call_without_blockParameter_provided_test() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; - UInt256 currentNonceAddressB = blockchain.State.GetAccount(TestItem.AddressB).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); + UInt256 currentNonceAddressB = blockchain.State.GetNonce(TestItem.AddressB); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); Address? contractAddress = ContractAddress.From(TestItem.AddressA, currentNonceAddressA); @@ -709,7 +710,7 @@ public async Task Trace_callMany_internal_transactions_test() await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); Transaction transaction1 = Build.A.Transaction.WithNonce(currentNonceAddressA++).WithTo(TestItem.AddressC) .SignedAndResolved(TestItem.PrivateKeyA).TestObject; @@ -777,7 +778,7 @@ public async Task Trace_replayBlockTransactions_transactions_deploying_contract( Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); Address? contractAddress = ContractAddress.From(TestItem.AddressA, currentNonceAddressA); @@ -814,7 +815,7 @@ public async Task Trace_replayBlockTransactions_stateDiff() Context context = new(); await context.Build(); TestRpcBlockchain blockchain = context.Blockchain; - UInt256 currentNonceAddressA = blockchain.State.GetAccount(TestItem.AddressA).Nonce; + UInt256 currentNonceAddressA = blockchain.State.GetNonce(TestItem.AddressA); await blockchain.AddFunds(TestItem.AddressA, 10000.Ether()); Transaction tx = Build.A.Transaction.WithNonce(currentNonceAddressA++) @@ -823,11 +824,11 @@ public async Task Trace_replayBlockTransactions_stateDiff() .WithGasLimit(50000) .WithGasPrice(10).SignedAndResolved(TestItem.PrivateKeyA).TestObject; - AccountStruct accountA = blockchain.State.GetAccount(TestItem.AddressA); - AccountStruct accountD = blockchain.State.GetAccount(TestItem.AddressD); - AccountStruct accountF = blockchain.State.GetAccount(TestItem.AddressF); + blockchain.State.TryGetAccount(TestItem.AddressA, out AccountStruct accountA); + blockchain.State.TryGetAccount(TestItem.AddressD, out AccountStruct accountD); + blockchain.State.TryGetAccount(TestItem.AddressF, out AccountStruct accountF); - string[] traceTypes = { "stateDiff" }; + string[] traceTypes = ["stateDiff"]; await blockchain.AddBlock(tx); diff --git a/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs b/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs index 0fa2a73e40b..fd16a9fccc8 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Data/AccountForRpc.cs @@ -16,7 +16,7 @@ public AccountForRpc(Account account) _account = account; } - public AccountForRpc(in AccountStruct? account) + public AccountForRpc(in AccountStruct account) { _accountStruct = account; } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index 817d513cd21..3e01c2f6c9a 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -175,8 +175,8 @@ public ResultWrapper> eth_accounts() return Task.FromResult(GetStateFailureResult(header)); } - AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, address); - return Task.FromResult(ResultWrapper.Success(account?.Balance ?? UInt256.Zero)); + _stateReader.TryGetAccount(header!.StateRoot!, address, out AccountStruct account); + return Task.FromResult(ResultWrapper.Success(account.Balance)); } public ResultWrapper eth_getStorageAt(Address address, UInt256 positionIndex, @@ -213,10 +213,8 @@ public Task> eth_getTransactionCount(Address address, Blo return Task.FromResult(GetStateFailureResult(header)); } - AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, address); - UInt256 nonce = account?.Nonce ?? 0; - - return Task.FromResult(ResultWrapper.Success(nonce)); + _stateReader.TryGetAccount(header!.StateRoot!, address, out AccountStruct account); + return Task.FromResult(ResultWrapper.Success(account.Nonce)); } public ResultWrapper eth_getBlockTransactionCountByHash(Hash256 blockHash) @@ -265,13 +263,12 @@ public ResultWrapper eth_getCode(Address address, BlockParameter? blockP } BlockHeader header = searchResult.Object; - if (!HasStateForBlock(_blockchainBridge, header!)) - { - return GetStateFailureResult(header); - } - - AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, address); - return ResultWrapper.Success(account is null ? Array.Empty() : _stateReader.GetCode(account.Value.CodeHash)); + return !HasStateForBlock(_blockchainBridge, header!) + ? GetStateFailureResult(header) + : ResultWrapper.Success( + _stateReader.TryGetAccount(header!.StateRoot!, address, out AccountStruct account) + ? _stateReader.GetCode(account.CodeHash) + : Array.Empty()); } public ResultWrapper eth_sign(Address addressData, byte[] message) @@ -717,13 +714,12 @@ private static IEnumerable GetLogs(IEnumerable logs, Cance } BlockHeader header = searchResult.Object; - if (!HasStateForBlock(_blockchainBridge, header!)) - { - return GetStateFailureResult(header); - } - - AccountStruct? account = _stateReader.GetAccount(header!.StateRoot!, accountAddress); - return ResultWrapper.Success(account is null ? null : new AccountForRpc(account.Value)); + return !HasStateForBlock(_blockchainBridge, header!) + ? GetStateFailureResult(header) + : ResultWrapper.Success( + _stateReader.TryGetAccount(header!.StateRoot!, accountAddress, out AccountStruct account) + ? new AccountForRpc(account) + : null); } private static ResultWrapper GetFailureResult(SearchResult searchResult, bool isTemporary) where TSearch : class => diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs index ef3f4add6b1..42df50543de 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs @@ -66,7 +66,7 @@ Transaction BuildTransaction(uint index, AccountStruct senderAccount) => .SignedAndResolved(from).TestObject; parentHeader = chain.BlockTree.FindHeader(parentHash, BlockTreeLookupOptions.None)!; - AccountStruct account = chain.StateReader.GetAccount(parentHeader.StateRoot!, from.Address)!.Value; + chain.StateReader.TryGetAccount(parentHeader.StateRoot!, from.Address, out AccountStruct account); accountFrom = account; return Enumerable.Range(0, (int)count).Select(i => BuildTransaction((uint)i, account)).ToArray(); diff --git a/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/Boost/BoostBlockImprovementContext.cs b/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/Boost/BoostBlockImprovementContext.cs index ed8d78b6067..3d2f18e42bc 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/Boost/BoostBlockImprovementContext.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/Boost/BoostBlockImprovementContext.cs @@ -46,14 +46,15 @@ public BoostBlockImprovementContext(Block currentBestBlock, { payloadAttributes = await _boostRelay.GetPayloadAttributes(payloadAttributes, cancellationToken); - UInt256 balanceBefore = _stateReader.GetAccount(parentHeader.StateRoot!, payloadAttributes.SuggestedFeeRecipient)?.Balance ?? UInt256.Zero; + _stateReader.TryGetAccount(parentHeader.StateRoot!, payloadAttributes.SuggestedFeeRecipient, out AccountStruct account); + UInt256 balanceBefore = account.Balance; Block? block = await blockProductionTrigger.BuildBlock(parentHeader, cancellationToken, _feesTracer, payloadAttributes); if (block is not null) { CurrentBestBlock = block; BlockFees = _feesTracer.Fees; - UInt256 balanceAfter = _stateReader.GetAccount(block.StateRoot!, payloadAttributes.SuggestedFeeRecipient)?.Balance ?? UInt256.Zero; - await _boostRelay.SendPayload(new BoostExecutionPayloadV1 { Block = new ExecutionPayload(block), Profit = balanceAfter - balanceBefore }, cancellationToken); + _stateReader.TryGetAccount(parentHeader.StateRoot!, payloadAttributes.SuggestedFeeRecipient, out account); + await _boostRelay.SendPayload(new BoostExecutionPayloadV1 { Block = new ExecutionPayload(block), Profit = account.Balance - balanceBefore }, cancellationToken); } return CurrentBestBlock; diff --git a/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs b/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs index 577c2b61338..9e6ca0f4ed0 100644 --- a/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs +++ b/src/Nethermind/Nethermind.Mev.Test/TestBundlePool.cs @@ -74,6 +74,10 @@ public TestBundlePool(IBlockTree blockTree, public class MockProvider : IAccountStateProvider { - public AccountStruct GetAccount(Address address) => new(0); + public bool TryGetAccount(Address address, out AccountStruct account) + { + account = AccountStruct.TotallyEmpty; + return false; + } } } diff --git a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs index 651a582d7ad..680ca5d4de9 100644 --- a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs @@ -7,6 +7,7 @@ using System.Collections.Concurrent; using System.IO; using System.IO.Abstractions; +using System.Runtime.Loader; using System.Threading; using System.Threading.Tasks; using Nethermind.Api; @@ -33,9 +34,17 @@ namespace Nethermind.Runner.Test [TestFixture, Parallelizable(ParallelScope.All)] public class EthereumRunnerTests { - private static readonly Lazy _cachedProviders = new(InitOnce); + static EthereumRunnerTests() + { + AssemblyLoadContext.Default.Resolving += (context, name) => + { + return null; + }; + } - public static ICollection InitOnce() + private static readonly Lazy? _cachedProviders = new(InitOnce); + + private static ICollection InitOnce() { // by pre-caching configs providers we make the tests do lot less work ConcurrentQueue<(string, ConfigProvider)> result = new(); @@ -55,9 +64,8 @@ public static IEnumerable ChainSpecRunnerTests get { int index = 0; - foreach (var cachedProvider in _cachedProviders.Value) + foreach (var cachedProvider in _cachedProviders!.Value) { - yield return new TestCaseData(cachedProvider, index); index++; } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs index 982b36239d6..48279b9f049 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs @@ -307,19 +307,21 @@ private ValueHash256 DecodeCodeHashStruct(ref Rlp.ValueDecoderContext rlpStream) return codeHash; } - public AccountStruct? DecodeStruct(ref Rlp.ValueDecoderContext decoderContext) + public bool TryDecodeStruct(ref Rlp.ValueDecoderContext decoderContext, out AccountStruct account) { int length = decoderContext.ReadSequenceLength(); if (length == 1) { - return null; + account = AccountStruct.TotallyEmpty; + return false; } UInt256 nonce = decoderContext.DecodeUInt256(); UInt256 balance = decoderContext.DecodeUInt256(); ValueHash256 storageRoot = DecodeStorageRootStruct(ref decoderContext); ValueHash256 codeHash = DecodeCodeHashStruct(ref decoderContext); - return new AccountStruct(nonce, balance, storageRoot, codeHash); + account = new AccountStruct(nonce, balance, storageRoot, codeHash); + return true; } } } diff --git a/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs b/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs index d13754211a9..28760632939 100644 --- a/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs +++ b/src/Nethermind/Nethermind.State/IReadOnlyStateProvider.cs @@ -12,20 +12,12 @@ public interface IReadOnlyStateProvider : IAccountStateProvider { Hash256 StateRoot { get; } - UInt256 GetNonce(Address address); - - UInt256 GetBalance(Address address); - - ValueHash256 GetStorageRoot(Address address); - byte[]? GetCode(Address address); byte[]? GetCode(Hash256 codeHash); byte[]? GetCode(ValueHash256 codeHash); - ValueHash256 GetCodeHash(Address address); - public bool IsContract(Address address); /// diff --git a/src/Nethermind/Nethermind.State/IStateReader.cs b/src/Nethermind/Nethermind.State/IStateReader.cs index 4dc0af84ab5..d098c33881f 100644 --- a/src/Nethermind/Nethermind.State/IStateReader.cs +++ b/src/Nethermind/Nethermind.State/IStateReader.cs @@ -11,13 +11,10 @@ namespace Nethermind.State { public interface IStateReader { - AccountStruct? GetAccount(Hash256 stateRoot, Address address); - + bool TryGetAccount(Hash256 stateRoot, Address address, out AccountStruct account); ReadOnlySpan GetStorage(Hash256 stateRoot, Address address, in UInt256 index); - byte[]? GetCode(Hash256 codeHash); byte[]? GetCode(in ValueHash256 codeHash); - void RunTreeVisitor(ITreeVisitor treeVisitor, Hash256 stateRoot, VisitingOptions? visitingOptions = null); bool HasStateForRoot(Hash256 stateRoot); } diff --git a/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs b/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs index cfc096af46e..f6ffa4250d1 100644 --- a/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs +++ b/src/Nethermind/Nethermind.State/IWorldStateExtensions.cs @@ -15,8 +15,8 @@ public static class WorldStateExtensions { public static byte[] GetCode(this IWorldState stateProvider, Address address) { - AccountStruct account = stateProvider.GetAccount(address); - return !account.HasCode ? Array.Empty() : stateProvider.GetCode(account.CodeHash); + stateProvider.TryGetAccount(address, out AccountStruct account); + return !account.HasCode ? Array.Empty() : stateProvider.GetCode(account.CodeHash) ?? Array.Empty(); } public static void InsertCode(this IWorldState worldState, Address address, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false) diff --git a/src/Nethermind/Nethermind.State/StateReader.cs b/src/Nethermind/Nethermind.State/StateReader.cs index 5927a321927..ee29d3e7845 100644 --- a/src/Nethermind/Nethermind.State/StateReader.cs +++ b/src/Nethermind/Nethermind.State/StateReader.cs @@ -14,34 +14,19 @@ namespace Nethermind.State { - public class StateReader : IStateReader + public class StateReader(ITrieStore trieStore, IKeyValueStore? codeDb, ILogManager? logManager) : IStateReader { - private readonly IKeyValueStore _codeDb; - private readonly ILogger _logger; - private readonly StateTree _state; - private readonly StorageTree _storage; - private readonly ITrieStore _trieStore; + private readonly IKeyValueStore _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); + private readonly StateTree _state = new(trieStore, logManager); + private readonly StorageTree _storage = new(trieStore, Keccak.EmptyTreeHash, logManager); - public StateReader(ITrieStore? trieStore, IKeyValueStore? codeDb, ILogManager? logManager) - { - _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); - _trieStore = trieStore; - _state = new StateTree(trieStore, logManager); - _storage = new StorageTree(trieStore, Keccak.EmptyTreeHash, logManager); - } - - public AccountStruct? GetAccount(Hash256 stateRoot, Address address) - { - return GetState(stateRoot, address); - } + public bool TryGetAccount(Hash256 stateRoot, Address address, out AccountStruct account) => TryGetState(stateRoot, address, out account); public ReadOnlySpan GetStorage(Hash256 stateRoot, Address address, in UInt256 index) { - AccountStruct? account = GetAccount(stateRoot, address); - if (account is null) return null; + if (!TryGetAccount(stateRoot, address, out AccountStruct account)) return ReadOnlySpan.Empty; - ValueHash256 storageRoot = account.Value.StorageRoot; + ValueHash256 storageRoot = account.StorageRoot; if (storageRoot == Keccak.EmptyTreeHash) { return Bytes.ZeroByte.Span; @@ -50,11 +35,13 @@ public ReadOnlySpan GetStorage(Hash256 stateRoot, Address address, in UInt Metrics.StorageTreeReads++; return _storage.Get(index, new Hash256(storageRoot)); + } public UInt256 GetBalance(Hash256 stateRoot, Address address) { - return GetState(stateRoot, address)?.Balance ?? UInt256.Zero; + TryGetState(stateRoot, address, out AccountStruct account); + return account.Balance; } public byte[]? GetCode(Hash256 codeHash) => codeHash == Keccak.OfAnEmptyString ? Array.Empty() : _codeDb[codeHash.Bytes]; @@ -64,29 +51,23 @@ public void RunTreeVisitor(ITreeVisitor treeVisitor, Hash256 rootHash, VisitingO _state.Accept(treeVisitor, rootHash, visitingOptions); } - public bool HasStateForRoot(Hash256 stateRoot) - { - return _trieStore.HasRoot(stateRoot); - } + public bool HasStateForRoot(Hash256 stateRoot) => trieStore.HasRoot(stateRoot); - public byte[]? GetCode(Hash256 stateRoot, Address address) - { - AccountStruct? account = GetState(stateRoot, address); - return account is null ? Array.Empty() : GetCode(account.Value.CodeHash); - } + public byte[]? GetCode(Hash256 stateRoot, Address address) => + TryGetState(stateRoot, address, out AccountStruct account) ? GetCode(account.CodeHash) : Array.Empty(); public byte[]? GetCode(in ValueHash256 codeHash) => codeHash == Keccak.OfAnEmptyString ? Array.Empty() : _codeDb[codeHash.Bytes]; - private AccountStruct? GetState(Hash256 stateRoot, Address address) + private bool TryGetState(Hash256 stateRoot, Address address, out AccountStruct account) { if (stateRoot == Keccak.EmptyTreeHash) { - return null; + account = AccountStruct.TotallyEmpty; + return false; } Metrics.StateTreeReads++; - AccountStruct? account = _state.GetStruct(address, stateRoot); - return account; + return _state.TryGetStruct(address, out account, stateRoot); } } } diff --git a/src/Nethermind/Nethermind.State/StateReaderExtensions.cs b/src/Nethermind/Nethermind.State/StateReaderExtensions.cs index 58ccad3b672..ac63366349c 100644 --- a/src/Nethermind/Nethermind.State/StateReaderExtensions.cs +++ b/src/Nethermind/Nethermind.State/StateReaderExtensions.cs @@ -15,17 +15,20 @@ public static class StateReaderExtensions { public static UInt256 GetNonce(this IStateReader stateReader, Hash256 stateRoot, Address address) { - return stateReader.GetAccount(stateRoot, address)?.Nonce ?? UInt256.Zero; + stateReader.TryGetAccount(stateRoot, address, out AccountStruct account); + return account.Nonce; } public static UInt256 GetBalance(this IStateReader stateReader, Hash256 stateRoot, Address address) { - return stateReader.GetAccount(stateRoot, address)?.Balance ?? UInt256.Zero; + stateReader.TryGetAccount(stateRoot, address, out AccountStruct account); + return account.Balance; } public static ValueHash256 GetStorageRoot(this IStateReader stateReader, Hash256 stateRoot, Address address) { - return stateReader.GetAccount(stateRoot, address)?.StorageRoot ?? Keccak.EmptyTreeHash; + stateReader.TryGetAccount(stateRoot, address, out AccountStruct account); + return account.StorageRoot; } public static byte[] GetCode(this IStateReader stateReader, Hash256 stateRoot, Address address) @@ -35,7 +38,8 @@ public static byte[] GetCode(this IStateReader stateReader, Hash256 stateRoot, A public static ValueHash256 GetCodeHash(this IStateReader stateReader, Hash256 stateRoot, Address address) { - return stateReader.GetAccount(stateRoot, address)?.CodeHash ?? Keccak.OfAnEmptyString; + stateReader.TryGetAccount(stateRoot, address, out AccountStruct account); + return account.CodeHash; } public static bool HasStateForBlock(this IStateReader stateReader, BlockHeader header) diff --git a/src/Nethermind/Nethermind.State/StateTree.cs b/src/Nethermind/Nethermind.State/StateTree.cs index f81e58c4e92..0ebbb966ca7 100644 --- a/src/Nethermind/Nethermind.State/StateTree.cs +++ b/src/Nethermind/Nethermind.State/StateTree.cs @@ -42,11 +42,17 @@ public StateTree(ITrieStore? store, ILogManager? logManager) } [DebuggerStepThrough] - public AccountStruct? GetStruct(Address address, Hash256? rootHash = null) + public bool TryGetStruct(Address address, out AccountStruct account, Hash256? rootHash = null) { ReadOnlySpan bytes = Get(ValueKeccak.Compute(address.Bytes).BytesAsSpan, rootHash); Rlp.ValueDecoderContext valueDecoderContext = new Rlp.ValueDecoderContext(bytes); - return bytes.IsEmpty ? null : _decoder.DecodeStruct(ref valueDecoderContext); + if (bytes.IsEmpty) + { + account = AccountStruct.TotallyEmpty; + return false; + } + + return _decoder.TryDecodeStruct(ref valueDecoderContext, out account); } [DebuggerStepThrough] diff --git a/src/Nethermind/Nethermind.State/WorldState.cs b/src/Nethermind/Nethermind.State/WorldState.cs index 7497b1bde15..1066fb0dbf2 100644 --- a/src/Nethermind/Nethermind.State/WorldState.cs +++ b/src/Nethermind/Nethermind.State/WorldState.cs @@ -59,9 +59,10 @@ public Account GetAccount(Address address) return _stateProvider.GetAccount(address); } - AccountStruct IAccountStateProvider.GetAccount(Address address) + bool IAccountStateProvider.TryGetAccount(Address address, out AccountStruct account) { - return _stateProvider.GetAccount(address).ToStruct(); + account = _stateProvider.GetAccount(address).ToStruct(); + return !account.IsTotallyEmpty; } public bool IsContract(Address address) @@ -156,38 +157,21 @@ public void TouchCode(in ValueHash256 codeHash) _stateProvider.TouchCode(codeHash); } - public UInt256 GetNonce(Address address) - { - return _stateProvider.GetNonce(address); - } - public UInt256 GetBalance(Address address) - { - return _stateProvider.GetBalance(address); - } - public ValueHash256 GetStorageRoot(Address address) - { - return _stateProvider.GetStorageRoot(address); - } - public byte[] GetCode(Address address) - { - return _stateProvider.GetCode(address); - } - public byte[] GetCode(Hash256 codeHash) - { - return _stateProvider.GetCode(codeHash); - } + public UInt256 GetNonce(Address address) => _stateProvider.GetNonce(address); - public byte[] GetCode(ValueHash256 codeHash) - { - return _stateProvider.GetCode(codeHash); - } + public UInt256 GetBalance(Address address) => _stateProvider.GetBalance(address); - public Hash256 GetCodeHash(Address address) - { - return _stateProvider.GetCodeHash(address); - } + public ValueHash256 GetStorageRoot(Address address) => _stateProvider.GetStorageRoot(address); + + public byte[] GetCode(Address address) => _stateProvider.GetCode(address); + + public byte[] GetCode(Hash256 codeHash) => _stateProvider.GetCode(codeHash); + + public byte[] GetCode(ValueHash256 codeHash) => _stateProvider.GetCode(codeHash); + + public Hash256 GetCodeHash(Address address) => _stateProvider.GetCodeHash(address); - ValueHash256 IReadOnlyStateProvider.GetCodeHash(Address address) + ValueHash256 IAccountStateProvider.GetCodeHash(Address address) { return _stateProvider.GetCodeHash(address); } diff --git a/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs b/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs index 7b69f8c3856..0ab43cfa6a3 100644 --- a/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/PruningScenariosTests.cs @@ -151,14 +151,14 @@ public PruningContext ReadStorage(int accountIndex, int storageKey) public PruningContext ReadAccount(int accountIndex) { _logger.Info($"READ ACCOUNT {accountIndex}"); - _stateProvider.GetAccount(Address.FromNumber((UInt256)accountIndex)); + _stateProvider.TryGetAccount(Address.FromNumber((UInt256)accountIndex), out _); return this; } public PruningContext ReadAccountViaStateReader(int accountIndex) { _logger.Info($"READ ACCOUNT {accountIndex}"); - _stateReader.GetAccount(_stateProvider.StateRoot, Address.FromNumber((UInt256)accountIndex)); + _stateReader.TryGetAccount(_stateProvider.StateRoot, Address.FromNumber((UInt256)accountIndex), out _); return this; } diff --git a/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs b/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs index bbd7b4186df..574d7b7e0c0 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/NonceManagerTests.cs @@ -116,16 +116,16 @@ public void should_increment_own_transaction_nonces_locally_when_requesting_rese public void should_pick_account_nonce_as_initial_value() { IAccountStateProvider accountStateProvider = Substitute.For(); - AccountStruct account = new(0); - accountStateProvider.GetAccount(TestItem.AddressA).Returns(account); + accountStateProvider.GetNonce(TestItem.AddressA).Returns(UInt256.Zero); _nonceManager = new NonceManager(accountStateProvider); - using (NonceLocker locker = _nonceManager.ReserveNonce(TestItem.AddressA, out UInt256 nonce)) + + using (_nonceManager.ReserveNonce(TestItem.AddressA, out UInt256 nonce)) { nonce.Should().Be(0); } - accountStateProvider.GetAccount(TestItem.AddressA).Returns(new AccountStruct(10, account.Balance)); - using (NonceLocker locker = _nonceManager.ReserveNonce(TestItem.AddressA, out UInt256 nonce)) + accountStateProvider.GetNonce(TestItem.AddressA).Returns((UInt256)10); + using (_nonceManager.ReserveNonce(TestItem.AddressA, out UInt256 nonce)) { nonce.Should().Be(10); } diff --git a/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs index d12c6744e77..f9486f29e11 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TransactionPoolInfoProviderTests.cs @@ -33,7 +33,7 @@ public void Setup() public void should_return_valid_pending_and_queued_transactions() { uint nonce = 3; - _stateReader.GetAccount(_address).Returns(new AccountStruct(nonce, UInt256.Zero)); + _stateReader.GetNonce(_address).Returns(nonce); var transactions = GetTransactions(); _txPool.GetPendingTransactionsBySender() diff --git a/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs index 95a885c2741..d3b949168eb 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs @@ -80,7 +80,7 @@ public void UpdatePool(IAccountStateProvider accounts, Func 0); - AccountStruct account = accounts.GetAccount(address); + accounts.TryGetAccount(address, out AccountStruct account); UpdateGroupNonLocked(address, account, bucket, changingElements); } } diff --git a/src/Nethermind/Nethermind.TxPool/NonceManager.cs b/src/Nethermind/Nethermind.TxPool/NonceManager.cs index 11abe3802b6..111ca6d9dcd 100644 --- a/src/Nethermind/Nethermind.TxPool/NonceManager.cs +++ b/src/Nethermind/Nethermind.TxPool/NonceManager.cs @@ -23,7 +23,7 @@ public NonceLocker ReserveNonce(Address address, out UInt256 reservedNonce) { AddressNonceManager addressNonceManager = _addressNonceManagers.GetOrAdd(address, _ => new AddressNonceManager()); - return addressNonceManager.ReserveNonce(_accounts.GetAccount(address).Nonce, out reservedNonce); + return addressNonceManager.ReserveNonce(_accounts.GetNonce(address), out reservedNonce); } public NonceLocker TxWithNonceReceived(Address address, UInt256 nonce) diff --git a/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs b/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs index 38dff33f54b..1240f4203e6 100644 --- a/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs +++ b/src/Nethermind/Nethermind.TxPool/TxFilteringState.cs @@ -5,18 +5,20 @@ namespace Nethermind.TxPool; -public class TxFilteringState +public class TxFilteringState(Transaction tx, IAccountStateProvider accounts) { + private AccountStruct _senderAccount; - private readonly IAccountStateProvider _accounts; - private readonly Transaction _tx; - - public TxFilteringState(Transaction tx, IAccountStateProvider accounts) + public AccountStruct SenderAccount { - _accounts = accounts; - _tx = tx; - } + get + { + if (_senderAccount.IsNull) + { + accounts.TryGetAccount(tx.SenderAddress!, out _senderAccount); + } - private AccountStruct? _senderAccount = null; - public AccountStruct SenderAccount { get { return _senderAccount ??= _accounts.GetAccount(_tx.SenderAddress!); } } + return _senderAccount; + } + } } diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index f9596408c1c..ee34c3bd0c6 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -661,7 +661,7 @@ internal void TryGetBlobTxSortingEquivalent(Hash256 hash, out Transaction? trans // maybe it should use NonceManager, as it already has info about local txs? public UInt256 GetLatestPendingNonce(Address address) { - UInt256 maxPendingNonce = _accounts.GetAccount(address).Nonce; + UInt256 maxPendingNonce = _accounts.GetNonce(address); bool hasPendingTxs = _transactions.GetBucketCount(address) > 0; if (!hasPendingTxs && !(_blobTransactions.GetBucketCount(address) > 0)) diff --git a/src/Nethermind/Nethermind.TxPool/TxPoolInfoProvider.cs b/src/Nethermind/Nethermind.TxPool/TxPoolInfoProvider.cs index e6db9f35da7..1caa8ddca44 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPoolInfoProvider.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPoolInfoProvider.cs @@ -29,7 +29,7 @@ public TxPoolInfo GetInfo() foreach (KeyValuePair group in groupedTransactions) { Address address = group.Key; - var accountNonce = _stateReader.GetAccount(address).Nonce; + var accountNonce = _stateReader.GetNonce(address); var expectedNonce = accountNonce; var pending = new Dictionary(); var queued = new Dictionary(); From 263f66c647aa4e39a311c79c7b59482279c664e6 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 28 Feb 2024 11:47:21 +0000 Subject: [PATCH 3/8] Update KnownChainSizesTests.cs (#6788) --- .../Nethermind.Blockchain.Test/KnownChainSizesTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs index 132702166f5..c2e9053db0a 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs @@ -15,7 +15,7 @@ public void Update_known_chain_sizes() { // Pruning size have to be updated frequently ChainSizes.CreateChainSizeInfo(BlockchainIds.Mainnet).PruningSize.Should().BeLessThan(210.GB()); - ChainSizes.CreateChainSizeInfo(BlockchainIds.Goerli).PruningSize.Should().BeLessThan(95.GB()); + ChainSizes.CreateChainSizeInfo(BlockchainIds.Goerli).PruningSize.Should().BeLessThan(100.GB()); ChainSizes.CreateChainSizeInfo(BlockchainIds.Sepolia).PruningSize.Should().BeLessThan(18.GB()); ChainSizes.CreateChainSizeInfo(BlockchainIds.Chiado).PruningSize.Should().Be(null); From 84ff7e8fecfa902ba1f6b922f6fa6e3795940bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Moraczy=C5=84ski?= Date: Wed, 28 Feb 2024 14:37:54 +0100 Subject: [PATCH 4/8] TxPool autorecover (#6789) --- .../ConfigFilesTests.cs | 3 +- .../DistinctValueSortedPoolTests.cs | 94 +++++++++++-------- .../Collections/BlobTxDistinctSortedPool.cs | 6 +- .../Collections/DistinctValueSortedPool.cs | 2 +- .../PersistentBlobTxDistinctSortedPool.cs | 8 -- .../Collections/SortedPool.cs | 49 +++++++++- .../Collections/TxDistinctSortedPool.cs | 8 +- 7 files changed, 108 insertions(+), 62 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs b/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs index a2ae556a89a..cb1c6093e05 100644 --- a/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs @@ -171,10 +171,9 @@ public void Metrics_disabled_by_default(string configWildcard) Test(configWildcard, c => c.PushGatewayUrl, ""); } - [TestCase("^mainnet ^spaceneth ^volta", 50)] + [TestCase("^spaceneth ^volta", 50)] [TestCase("spaceneth", 4)] [TestCase("volta", 25)] - [TestCase("mainnet", 50)] public void Network_defaults_are_correct(string configWildcard, int activePeers = 50) { Test(configWildcard, c => c.DiscoveryPort, 30303); diff --git a/src/Nethermind/Nethermind.TxPool.Test/Collections/DistinctValueSortedPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/Collections/DistinctValueSortedPoolTests.cs index ae23f1e4469..6cb226795ca 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/Collections/DistinctValueSortedPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/Collections/DistinctValueSortedPoolTests.cs @@ -140,6 +140,19 @@ public int GetHashCode(WithFinalizer obj) } } + private class ShrinkableDistinctPool : WithFinalizerDistinctPool + { + public ShrinkableDistinctPool(int capacity, IComparer comparer, IEqualityComparer distinctComparer, ILogManager logManager) + : base(capacity, comparer, distinctComparer, logManager) + { + } + + public void Shrink(int capacity) + { + EnsureCapacity(capacity); + } + } + private class WithFinalizerDistinctPool : DistinctValueSortedPool { public WithFinalizerDistinctPool(int capacity, IComparer comparer, IEqualityComparer distinctComparer, ILogManager logManager) @@ -155,23 +168,23 @@ public WithFinalizerDistinctPool(int capacity, IComparer comparer protected override int GetKey(WithFinalizer value) => value.Index; } - [Test] - public void Capacity_is_never_exceeded() + IComparer _comparer = Comparer.Create((t1, t2) => { - IComparer comparer = Comparer.Create((t1, t2) => - { - int t1Oddity = t1.Index % 2; - int t2Oddity = t2.Index % 2; + int t1Oddity = t1.Index % 2; + int t2Oddity = t2.Index % 2; - if (t1Oddity.CompareTo(t2Oddity) != 0) - { - return t1Oddity.CompareTo(t2Oddity); - } + if (t1Oddity.CompareTo(t2Oddity) != 0) + { + return t1Oddity.CompareTo(t2Oddity); + } - return t1.Index.CompareTo(t2.Index); - }); + return t1.Index.CompareTo(t2.Index); + }); - var pool = new WithFinalizerDistinctPool(Capacity, comparer, new WithFinalizerComparer(), LimboLogs.Instance); + [Test] + public void Capacity_is_never_exceeded() + { + var pool = new WithFinalizerDistinctPool(Capacity, _comparer, new WithFinalizerComparer(), LimboLogs.Instance); int capacityMultiplier = 10; int expectedAllCount = Capacity * capacityMultiplier; @@ -192,23 +205,39 @@ public void Capacity_is_never_exceeded() pool.Count.Should().Be(Capacity); } - [Test] - public void Capacity_is_never_exceeded_when_there_are_duplicates() + [TestCase(0, 16)] + [TestCase(1, 15)] + [TestCase(2, 14)] + [TestCase(6, 10)] + [TestCase(10, 6)] + [TestCase(11, 6)] + [TestCase(13, 6)] + public void Capacity_can_shrink_to_given_value(int shrinkValue, int expectedCapacity) { - Comparer comparer = Comparer.Create((t1, t2) => + var pool = new ShrinkableDistinctPool(Capacity, _comparer, new WithFinalizerComparer(), LimboLogs.Instance); + + int capacityMultiplier = 10; + int expectedAllCount = Capacity * capacityMultiplier; + + WithFinalizer newOne; + for (int i = 0; i < expectedAllCount; i++) { - int t1Oddity = t1.Index % 2; - int t2Oddity = t2.Index % 2; + newOne = new WithFinalizer(); + pool.TryInsert(newOne.Index, newOne); + } - if (t1Oddity.CompareTo(t2Oddity) != 0) - { - return t1Oddity.CompareTo(t2Oddity); - } + newOne = null; + + CollectAndFinalize(); - return t1.Index.CompareTo(t2.Index); - }); + pool.Shrink(Capacity - shrinkValue); + pool.Count.Should().Be(expectedCapacity); + } - var pool = new WithFinalizerDistinctPool(Capacity, comparer, new WithFinalizerComparer(), LimboLogs.Instance); + [Test] + public void Capacity_is_never_exceeded_when_there_are_duplicates() + { + var pool = new WithFinalizerDistinctPool(Capacity, _comparer, new WithFinalizerComparer(), LimboLogs.Instance); int capacityMultiplier = 10; @@ -232,20 +261,7 @@ public async Task Capacity_is_never_exceeded_with_multiple_threads() _finalizedCount.Should().Be(0); _allCount.Should().Be(0); - IComparer comparer = Comparer.Create((t1, t2) => - { - int t1Oddity = t1.Index % 2; - int t2Oddity = t2.Index % 2; - - if (t1Oddity.CompareTo(t2Oddity) != 0) - { - return t1Oddity.CompareTo(t2Oddity); - } - - return t1.Index.CompareTo(t2.Index); - }); - - var pool = new WithFinalizerDistinctPool(Capacity, comparer, new WithFinalizerComparer(), LimboLogs.Instance); + var pool = new WithFinalizerDistinctPool(Capacity, _comparer, new WithFinalizerComparer(), LimboLogs.Instance); void KeepGoing(int iterations) { diff --git a/src/Nethermind/Nethermind.TxPool/Collections/BlobTxDistinctSortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/BlobTxDistinctSortedPool.cs index 96332932782..196b0b1262c 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/BlobTxDistinctSortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/BlobTxDistinctSortedPool.cs @@ -22,11 +22,7 @@ public BlobTxDistinctSortedPool(int capacity, IComparer comparer, I protected override IComparer GetReplacementComparer(IComparer comparer) => comparer.GetBlobReplacementComparer(); - public override void VerifyCapacity() - { - if (_logger.IsWarn && Count > _poolCapacity) - _logger.Warn($"Blob pool exceeds the config size {Count}/{_poolCapacity}"); - } + protected override string ShortPoolName => "BlobPool"; /// /// For tests only - to test sorting diff --git a/src/Nethermind/Nethermind.TxPool/Collections/DistinctValueSortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/DistinctValueSortedPool.cs index 948871ada72..301004f370f 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/DistinctValueSortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/DistinctValueSortedPool.cs @@ -35,7 +35,7 @@ protected DistinctValueSortedPool( IComparer comparer, IEqualityComparer distinctComparer, ILogManager logManager) - : base(capacity, comparer) + : base(capacity, comparer, logManager) { // ReSharper disable once VirtualMemberCallInConstructor _comparer = GetReplacementComparer(comparer ?? throw new ArgumentNullException(nameof(comparer))); diff --git a/src/Nethermind/Nethermind.TxPool/Collections/PersistentBlobTxDistinctSortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/PersistentBlobTxDistinctSortedPool.cs index 3b3542f35da..89aea5b28ac 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/PersistentBlobTxDistinctSortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/PersistentBlobTxDistinctSortedPool.cs @@ -94,12 +94,4 @@ protected override bool Remove(ValueHash256 hash, Transaction tx) _blobTxStorage.Delete(hash, tx.Timestamp); return base.Remove(hash, tx); } - - public override void VerifyCapacity() - { - base.VerifyCapacity(); - - if (_logger.IsDebug && Count == _poolCapacity) - _logger.Debug($"Blob persistent storage has reached max size of {_poolCapacity}, blob txs can be evicted now"); - } } diff --git a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs index af4f5748089..89162014496 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs @@ -9,6 +9,7 @@ using System.Runtime.CompilerServices; using Nethermind.Core.Collections; using Nethermind.Core.Threading; +using Nethermind.Logging; namespace Nethermind.TxPool.Collections { @@ -25,6 +26,7 @@ public abstract partial class SortedPool protected McsPriorityLock Lock { get; } = new(); private readonly int _capacity; + private readonly ILogger _logger; // comparer for a bucket private readonly IComparer _groupComparer; @@ -48,7 +50,7 @@ public abstract partial class SortedPool /// /// Max capacity, after surpassing it elements will be removed based on last by . /// Comparer to sort items. - protected SortedPool(int capacity, IComparer comparer) + protected SortedPool(int capacity, IComparer comparer, ILogManager logManager) { _capacity = capacity; // ReSharper disable VirtualMemberCallInConstructor @@ -57,6 +59,7 @@ protected SortedPool(int capacity, IComparer comparer) _cacheMap = new Dictionary(); // do not initialize it at the full capacity _buckets = new Dictionary>(); _worstSortedValues = new DictionarySortedSet(_sortedComparer); + _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); } /// @@ -312,6 +315,8 @@ public virtual bool TryInsert(TKey key, TValue value, out TValue? removed) { if (!RemoveLast(out removed) || _cacheMap.Count > _capacity) { + if (_cacheMap.Count > _capacity && _logger.IsWarn) + _logger.Warn($"Capacity exceeded or failed to remove the last item from the pool, the current state is {Count}/{_capacity}. {GetInfoAboutWorstValues}"); UpdateWorstValue(); RemoveLast(out removed); } @@ -453,6 +458,46 @@ public bool TryGetBucketsWorstValue(TGroupKey groupKey, out TValue? item) return false; } + protected void EnsureCapacity(int? expectedCapacity = null) + { + expectedCapacity ??= _capacity; // expectedCapacity is added for testing purpose. null should be used in production code + if (Count <= expectedCapacity) + return; + + if (_logger.IsWarn) + _logger.Warn($"{ShortPoolName} exceeds the config size {Count}/{expectedCapacity}. Trying to repair the pool"); + + // Trying to auto-recover TxPool. If this code is executed, it means that something is wrong with our TxPool logic. + // However, auto-recover mitigates bad consequences of such bugs. + int maxIterations = 10; // We don't want to add an infinite loop, so we can break after a few iterations. + int iterations = 0; + while (Count > expectedCapacity) + { + ++iterations; + if (RemoveLast(out TValue? removed)) + { + if (_logger.IsInfo) + _logger.Info($"Removed the last item {removed} from the pool, the current state is {Count}/{expectedCapacity}. {GetInfoAboutWorstValues}"); + } + else + { + if (_logger.IsWarn) + _logger.Warn($"Failed to remove the last item from the pool, the current state is {Count}/{expectedCapacity}. {GetInfoAboutWorstValues}"); + UpdateWorstValue(); + } + + if (iterations >= maxIterations) break; + } + } + + private string GetInfoAboutWorstValues() + { + TKey? key = _worstValue.GetValueOrDefault().Value; + var isWorstValueInPool = _cacheMap.TryGetValue(key, out TValue? value) && value != null; + return + $"Worst value {_worstValue}, items in worstSortedValues {_worstSortedValues.Count}, GetVakye: {_worstValue.GetValueOrDefault()} current max in worst values {_worstSortedValues.Max}, IsWorstValueInPool {isWorstValueInPool}"; + } + public void UpdatePool(Func, IEnumerable<(TValue Tx, Action? Change)>> changingElements) { using var lockRelease = Lock.Acquire(); @@ -485,5 +530,7 @@ protected virtual void UpdateGroup(TGroupKey groupKey, EnhancedSortedSet change?.Invoke(value); } } + + protected virtual string ShortPoolName => "SortedPool"; } } diff --git a/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs index d3b949168eb..07223685f5b 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/TxDistinctSortedPool.cs @@ -75,7 +75,7 @@ public void UpdatePool(IAccountStateProvider accounts, Func bucket) in _buckets) { Debug.Assert(bucket.Count > 0); @@ -133,10 +133,6 @@ public void UpdateGroup(Address groupKey, AccountStruct groupValue, Func
_poolCapacity) - _logger.Warn($"TxPool exceeds the config size {Count}/{_poolCapacity}"); - } + protected override string ShortPoolName => "TxPool"; } } From f6616966b07fe7b7df71ff273e2cc989599b8ae3 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Thu, 29 Feb 2024 12:07:48 +0800 Subject: [PATCH 5/8] Cleanup/double check p2p message disposability (#6779) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Chodoła <43241881+kamilchodola@users.noreply.github.com> Co-authored-by: Ben Adams Co-authored-by: Lukasz Rozmej --- .../Network/AaProtocolHandlerTests.cs | 11 +- .../UserOperationsMessageSerializerTests.cs | 13 +- .../Network/AaProtocolHandler.cs | 27 ++-- .../Network/UserOperationsMessage.cs | 23 ++-- .../UserOperationsMessageSerializer.cs | 7 +- .../BlockTreeTests.cs | 61 ++++----- .../Nethermind.Blockchain/BlockTree.cs | 19 +-- .../Nethermind.Blockchain/IBlockTree.cs | 3 +- .../ReadOnlyBlockTree.cs | 3 +- .../Synchronization/INodeDataPeer.cs | 3 +- .../Synchronization/ISnapSyncPeer.cs | 7 +- .../Synchronization/ISyncPeer.cs | 9 +- .../Scheduler/BackgroundTaskScheduler.cs | 7 +- .../Collections/ArrayPoolListTests.cs | 90 +++++++++---- .../Collections/ArrayPoolList.cs | 72 ++++++++-- .../Collections/IOwnedReadOnlyList.cs | 22 ++++ .../Extensions/EnumerableExtensions.cs | 6 +- .../Extensions/SpanExtensions.cs | 9 +- .../Steps/Migrations/ReceiptFixMigration.cs | 3 +- .../EngineModuleTests.Synchronization.cs | 3 +- .../Synchronization/BeaconHeadersSyncTests.cs | 26 ++-- .../Synchronization/PeerRefresherTests.cs | 3 +- .../Synchronization/MergeBlockDownloader.cs | 14 +- .../Synchronization/PeerRefresher.cs | 16 ++- .../Eth62ProtocolHandlerBenchmarks.cs | 3 +- .../Model/P2PNodeDetails.cs | 4 +- .../P2P/DisconnectMessageSerializerTests.cs | 8 +- .../P2P/HelloMessageSerializerTests.cs | 14 +- .../P2P/P2PProtocolHandlerTests.cs | 15 +-- .../P2P/PacketSenderTests.cs | 2 +- .../P2P/PingMessageSerializerTests.cs | 2 +- .../P2P/PongMessageSerializerTests.cs | 2 +- .../P2P/SerializerTester.cs | 2 +- .../V62/BlockBodiesMessageSerializerTests.cs | 2 +- .../Eth/V62/BlockBodiesMessageTests.cs | 4 +- .../V62/BlockHeadersMessageSerializerTests.cs | 24 ++-- .../Eth/V62/Eth62ProtocolHandlerTests.cs | 49 +++---- .../GetBlockBodiesMessageSerializerTests.cs | 6 +- .../GetBlockHeadersMessageSerializerTests.cs | 14 +- .../NewBlockHashesMessageSerializerTests.cs | 4 +- .../Eth/V62/NewBlockMessageSerializerTests.cs | 6 +- .../Eth/V62/StatusMessageSerializerTests.cs | 18 +-- .../V62/TransactionsMessageSerializerTests.cs | 75 ++++++----- .../V62/ZeroNewBlockMessageSerializerTests.cs | 4 +- .../Eth/V63/Eth63ProtocolHandlerTests.cs | 31 +++-- .../V63/GetNodeDataMessageSerializerTests.cs | 3 +- .../Eth/V63/GetNodeDataMessageTests.cs | 8 +- .../V63/GetReceiptsMessageSerializerTests.cs | 8 +- .../Eth/V63/GetReceiptsMessageTests.cs | 8 +- .../Eth/V63/NodeDataMessageSeralizerTests.cs | 11 +- .../Eth/V63/NodeDataMessageTests.cs | 15 ++- .../Eth/V63/ReceiptsMessageSerializerTests.cs | 37 +++--- .../Eth/V63/ReceiptsMessageTests.cs | 15 ++- .../Eth/V65/Eth65ProtocolHandlerTests.cs | 8 +- ...ooledTransactionsMessageSerializerTests.cs | 5 +- ...TransactionHashesMessageSerializerTests.cs | 11 +- ...ooledTransactionsMessageSerializerTests.cs | 74 ++++++----- .../V66/BlockBodiesMessageSerializerTests.cs | 4 +- .../V66/BlockHeadersMessageSerializerTests.cs | 7 +- .../Eth/V66/Eth66ProtocolHandlerTests.cs | 33 +++-- .../V66/GetNodeDataMessageSerializerTests.cs | 3 +- .../GetPooledTransactionsSerializerTests.cs | 3 +- .../V66/GetReceiptsMessageSerializerTests.cs | 3 +- .../Eth/V66/NodeDataMessageSerializerTests.cs | 3 +- ...ooledTransactionsMessageSerializerTests.cs | 3 +- .../Eth/V66/ReceiptsMessageSerializerTests.cs | 4 +- .../Eth/V67/Eth67ProtocolHandlerTests.cs | 6 +- .../Eth/V68/Eth68ProtocolHandlerTests.cs | 25 ++-- ...TransactionHashesMessageSerializerTests.cs | 3 +- .../Les/AnnounceMessageSerializerTests.cs | 2 +- .../Les/BlockBodiesSerializerTests.cs | 2 +- .../Les/BlockHeadersMessageSerializerTests.cs | 6 +- .../ContractCodesMessageSerializerTests.cs | 5 +- .../GetContractCodesMessageSerializerTests.cs | 2 +- ...tHelperTrieProofsMessageSerializerTests.cs | 2 +- .../Les/GetReceiptsMessageSerializerTests.cs | 5 +- .../Les/ReceiptsMessageSerializerTests.cs | 7 +- .../Les/StatusMessageSerializerTests.cs | 2 +- .../GetNodeDataMessageSerializerTests.cs | 3 +- .../NodeData/GetNodeDataMessageTests.cs | 8 +- .../NodeDataMessageSerializerTests.cs | 11 +- .../NodeData/NodeDataMessageTests.cs | 19 +-- .../NodeData/NodeDataProtocolHandlerTests.cs | 13 +- .../AccountRangeMessageSerializerTests.cs | 21 +-- .../ByteCodesMessageSerializerTests.cs | 3 +- .../GetByteCodesMessageSerializerTests.cs | 6 +- .../GetStorageRangesMessageSerializerTests.cs | 6 +- .../GetTrieNodesMessageSerializerTests.cs | 21 +-- .../StorageRangesMessageSerializerTests.cs | 17 +-- .../TrieNodesMessageSerializerTests.cs | 5 +- ...lockWitnessHashesMessageSerializerTests.cs | 9 +- ...lockWitnessHashesMessageSerializerTests.cs | 6 +- .../Wit/WitProtocolHandlerTests.cs | 6 +- .../ProtocolsManagerTests.cs | 21 +-- .../Rlpx/HobbitTests.cs | 14 +- .../Rlpx/ZeroNettyFrameMergerTests.cs | 2 +- .../Rlpx/ZeroNettyPacketSplitterTests.cs | 6 +- .../SnapProtocolHandlerTests.cs | 23 ++-- .../P2PProtocolInitializedEventArgs.cs | 2 +- .../P2P/Messages/HelloMessage.cs | 3 +- .../P2P/Messages/HelloMessageSerializer.cs | 4 +- .../ProtocolHandlers/P2PProtocolHandler.cs | 85 +++++------- .../SyncPeerProtocolHandlerBase.cs | 91 +++++++------ .../ZeroProtocolHandlerBase.cs | 8 +- .../P2P/Subprotocols/Eth/HashesMessage.cs | 7 +- .../Eth/HashesMessageSerializer.cs | 12 ++ .../Subprotocols/Eth/PooledTxsRequestor.cs | 26 ++-- .../Eth/V62/Eth62ProtocolHandler.cs | 55 ++++---- .../Eth/V62/MessageSizeEstimator.cs | 2 +- .../Eth/V62/Messages/BlockBodiesMessage.cs | 7 +- .../Eth/V62/Messages/BlockHeadersMessage.cs | 14 +- .../Messages/BlockHeadersMessageSerializer.cs | 6 +- .../Eth/V62/Messages/TransactionsMessage.cs | 7 +- .../Messages/TransactionsMessageSerializer.cs | 7 +- .../Eth/V63/Eth63ProtocolHandler.cs | 38 +++--- .../Eth/V63/Messages/GetNodeDataMessage.cs | 8 +- .../Messages/GetNodeDataMessageSerializer.cs | 3 +- .../Eth/V63/Messages/GetReceiptsMessage.cs | 8 +- .../Messages/GetReceiptsMessageSerializer.cs | 5 +- .../Eth/V63/Messages/NodeDataMessage.cs | 15 ++- .../V63/Messages/NodeDataMessageSerializer.cs | 7 +- .../Eth/V63/Messages/ReceiptsMessage.cs | 14 +- .../V63/Messages/ReceiptsMessageSerializer.cs | 5 +- .../Eth/V65/Eth65ProtocolHandler.cs | 20 ++- .../Messages/GetPooledTransactionsMessage.cs | 8 +- .../GetPooledTransactionsMessageSerializer.cs | 3 +- .../NewPooledTransactionHashesMessage.cs | 8 +- ...ooledTransactionHashesMessageSerializer.cs | 3 +- .../V65/Messages/PooledTransactionsMessage.cs | 3 +- .../PooledTransactionsMessageSerializer.cs | 3 +- .../Eth/V66/Eth66ProtocolHandler.cs | 51 +++---- .../Eth/V68/Eth68ProtocolHandler.cs | 11 +- .../NewPooledTransactionHashesMessage68.cs | 25 ++-- ...ledTransactionHashesMessageSerializer68.cs | 7 +- .../Subprotocols/Les/LesProtocolHandler.cs | 42 +++--- .../Les/Messages/ContractCodesMessage.cs | 11 +- .../ContractCodesMessageSerializer.cs | 6 +- .../Les/Messages/GetBlockHeadersMessage.cs | 6 + .../NodeData/Messages/GetNodeDataMessage.cs | 3 +- .../Messages/GetNodeDataMessageSerializer.cs | 3 +- .../NodeData/Messages/NodeDataMessage.cs | 4 +- .../Messages/NodeDataMessageSerializer.cs | 7 +- .../NodeData/NodeDataProtocolHandler.cs | 55 +++++--- .../Snap/Messages/AccountRangeMessage.cs | 12 +- .../Messages/AccountRangeMessageSerializer.cs | 20 +-- .../Snap/Messages/ByteCodesMessage.cs | 16 ++- .../Messages/ByteCodesMessageSerializer.cs | 7 +- .../Snap/Messages/GetByteCodesMessage.cs | 9 +- .../Messages/GetByteCodesMessageSerializer.cs | 2 +- .../GetStorageRangesMessageSerializer.cs | 2 +- .../Snap/Messages/GetTrieNodesMessage.cs | 10 +- .../Messages/GetTrieNodesMessageSerializer.cs | 12 +- .../Snap/Messages/StorageRangeMessage.cs | 12 +- .../StorageRangesMessageSerializer.cs | 22 ++-- .../Snap/Messages/TrieNodesMessage.cs | 16 ++- .../Messages/TrieNodesMessageSerializer.cs | 7 +- .../Subprotocols/Snap/SnapProtocolHandler.cs | 80 +++++------ .../Wit/Messages/BlockWitnessHashesMessage.cs | 12 +- .../Subprotocols/Wit/WitProtocolHandler.cs | 20 +-- .../Utils/BackgroundTaskSchedulerWrapper.cs | 10 +- .../Nethermind.Network/ProtocolsManager.cs | 13 +- .../Nethermind.Serialization.Rlp/Rlp.cs | 45 +++++++ .../Nethermind.Serialization.Rlp/RlpStream.cs | 28 ++++ .../Snap/AccountsAndProofs.cs | 15 ++- .../Snap/AccountsToRefreshRequest.cs | 13 +- .../Snap/GetTrieNodesRequest.cs | 3 +- .../Nethermind.State/Snap/SlotsAndProofs.cs | 15 ++- .../Nethermind.State/Snap/StorageRange.cs | 25 +++- .../BlockDownloaderTests.cs | 51 +++---- .../FastBlocks/BodiesSyncFeedTests.cs | 10 +- .../FastBlocks/FastHeadersSyncTests.cs | 41 +++--- .../FastBlocks/ReceiptsSyncFeedTests.cs | 29 ++-- .../StateSyncDispatcherTests.cs | 4 +- .../FastSync/StateSyncFeedTests.cs | 4 +- .../FastSync/StateSyncFeedTestsBase.cs | 15 ++- .../OldStyleFullSynchronizerTests.cs | 5 +- .../ReceiptSyncFeedTests.cs | 10 +- .../SnapSync/ProgressTrackerTests.cs | 56 ++++---- .../SnapSync/SnapServerTest.cs | 51 +++---- .../SnapSync/SnapSyncBatchTests.cs | 18 ++- .../SnapSyncFeed/SnapSyncFeedTests.cs | 4 +- .../SyncPeerMock.cs | 24 ++-- .../SyncPeerPoolTests.cs | 17 +-- .../SynchronizerTests.cs | 15 ++- .../Trie/HealingTreeTests.cs | 2 +- .../Trie/RecoveryTests.cs | 11 +- .../Blocks/BlockDownloadContext.cs | 6 +- .../Blocks/BlockDownloader.cs | 39 +++--- .../FastBlocks/BodiesSyncBatch.cs | 13 +- .../FastBlocks/BodiesSyncFeed.cs | 2 +- .../FastBlocks/FastBlocksBatch.cs | 4 +- .../FastBlocks/FastHeadersSyncFeed.cs | 23 ++-- .../FastBlocks/HeadersSyncBatch.cs | 9 +- .../FastBlocks/ReceiptsSyncBatch.cs | 12 +- .../FastBlocks/ReceiptsSyncFeed.cs | 3 +- .../FastSync/StateSyncBatch.cs | 26 ++-- .../FastSync/StateSyncFeed.cs | 5 +- .../FastSync/TreeSync.cs | 13 +- .../Nethermind.Synchronization/ISyncServer.cs | 5 +- .../Nethermind.Synchronization.csproj | 1 + .../ParallelSync/SyncDispatcher.cs | 3 +- .../Peers/ISyncPeerPool.cs | 8 +- .../SnapSync/ISnapProvider.cs | 8 +- .../SnapSync/ISnapServer.cs | 11 +- .../SnapSync/ProgressTracker.cs | 124 ++++++++---------- .../SnapSync/SnapProvider.cs | 56 ++++---- .../SnapSync/SnapProviderHelper.cs | 20 +-- .../SnapSync/SnapServer.cs | 61 ++++----- .../SnapSync/SnapSyncBatch.cs | 23 +++- .../SnapSync/SnapSyncDownloader.cs | 4 +- .../SnapSync/SnapSyncFeed.cs | 55 ++++---- .../StateSync/StateSyncDownloader.cs | 12 +- .../Nethermind.Synchronization/SyncServer.cs | 13 +- .../Trie/GetNodeDataTrieNodeRecovery.cs | 6 +- .../Trie/HealingStateTree.cs | 7 +- .../Trie/HealingStorageTree.cs | 7 +- .../Trie/SnapTrieNodeRecovery.cs | 5 +- .../Nethermind.Trie/RangeQueryVisitor.cs | 8 +- src/Nethermind/Nethermind.TxPool/ITxPool.cs | 2 +- .../Nethermind.TxPool/NullTxPool.cs | 2 +- src/Nethermind/Nethermind.TxPool/TxPool.cs | 16 +-- 221 files changed, 1985 insertions(+), 1437 deletions(-) create mode 100644 src/Nethermind/Nethermind.Core/Collections/IOwnedReadOnlyList.cs diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/AaProtocolHandlerTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/AaProtocolHandlerTests.cs index 9ff180456e0..2151309b67f 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/AaProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/AaProtocolHandlerTests.cs @@ -9,6 +9,7 @@ using Nethermind.AccountAbstraction.Network; using Nethermind.AccountAbstraction.Source; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Logging; @@ -83,10 +84,12 @@ public void Can_handle_user_operations_message() parsed = Address.TryParse("0x90f3e1105e63c877bf9587de5388c23cdb702c6b", out Address? _ep2); Address ep1 = _ep1 ?? throw new ArgumentNullException(nameof(_ep1)); Address ep2 = _ep2 ?? throw new ArgumentNullException(nameof(_ep2)); - IList uOps = new List(); - uOps.Add(new UserOperationWithEntryPoint(Build.A.UserOperation.SignedAndResolved().TestObject, ep1)); - uOps.Add(new UserOperationWithEntryPoint(Build.A.UserOperation.SignedAndResolved().TestObject, ep2)); - UserOperationsMessage msg = new UserOperationsMessage(uOps); + ArrayPoolList uOps = new(2) + { + new UserOperationWithEntryPoint(Build.A.UserOperation.SignedAndResolved().TestObject, ep1), + new UserOperationWithEntryPoint(Build.A.UserOperation.SignedAndResolved().TestObject, ep2) + }; + using UserOperationsMessage msg = new UserOperationsMessage(uOps); HandleZeroMessage(msg, AaMessageCode.UserOperations); } diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs index 0efdf1434c6..26ffda723f3 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs @@ -6,6 +6,7 @@ using Nethermind.AccountAbstraction.Data; using Nethermind.AccountAbstraction.Network; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.Test.P2P; using Nethermind.Serialization.Rlp; using NUnit.Framework; @@ -42,7 +43,7 @@ public void Roundtrip() Signature = new byte[] { 1, 2, 3 } }); - UserOperationsMessage message = new(new[] { new UserOperationWithEntryPoint(userOperation, new Address("0x90f3e1105e63c877bf9587de5388c23cdb702c6b")) }); + using UserOperationsMessage message = new(new ArrayPoolList(1) { new(userOperation, new Address("0x90f3e1105e63c877bf9587de5388c23cdb702c6b")) }); TestZero(serializer, message, "f856f8549400000000000000000000000000000000000000018203e88203048201020506070801940000000000000000000000000000000000000002820506830102039490f3e1105e63c877bf9587de5388c23cdb702c6b"); // Meaning of RLP above: @@ -70,8 +71,8 @@ public void Roundtrip() // 83 = 131 = 128 + 3 (length of Signature) // 010203 (Signature) - message = new(new[] { new UserOperationWithEntryPoint(userOperation, new Address("0x90f3e1105e63c877bf9587de5388c23cdb702c6b")), new UserOperationWithEntryPoint(userOperation, new Address("0xdb8b5f6080a8e466b64a8d7458326cb650b3353f")) }); - TestZero(serializer, message, "f8acf8549400000000000000000000000000000000000000018203e88203048201020506070801940000000000000000000000000000000000000002820506830102039490f3e1105e63c877bf9587de5388c23cdb702c6bf8549400000000000000000000000000000000000000018203e882030482010205060708019400000000000000000000000000000000000000028205068301020394db8b5f6080a8e466b64a8d7458326cb650b3353f"); + using UserOperationsMessage message2 = new(new ArrayPoolList(2) { new(userOperation, new Address("0x90f3e1105e63c877bf9587de5388c23cdb702c6b")), new(userOperation, new Address("0xdb8b5f6080a8e466b64a8d7458326cb650b3353f")) }); + TestZero(serializer, message2, "f8acf8549400000000000000000000000000000000000000018203e88203048201020506070801940000000000000000000000000000000000000002820506830102039490f3e1105e63c877bf9587de5388c23cdb702c6bf8549400000000000000000000000000000000000000018203e882030482010205060708019400000000000000000000000000000000000000028205068301020394db8b5f6080a8e466b64a8d7458326cb650b3353f"); // Meaning of RLP above: // f8 @@ -88,7 +89,7 @@ public void Roundtrip() public void Can_handle_empty() { UserOperationsMessageSerializer serializer = new(); - UserOperationsMessage message = new(new UserOperationWithEntryPoint[] { }); + using UserOperationsMessage message = new(ArrayPoolList.Empty()); SerializerTester.TestZero(serializer, message); } @@ -96,7 +97,7 @@ public void Can_handle_empty() [Test] public void To_string_empty() { - UserOperationsMessage message = new(new UserOperationWithEntryPoint[] { }); + using UserOperationsMessage message = new(ArrayPoolList.Empty()); _ = message.ToString(); } @@ -107,7 +108,7 @@ private static void TestZero(UserOperationsMessageSerializer serializer, UserOpe try { serializer.Serialize(buffer, message); - UserOperationsMessage deserialized = serializer.Deserialize(buffer); + using UserOperationsMessage deserialized = serializer.Deserialize(buffer); // Abi is similar in deserialized and message, but for assertion there is some difference and an error. Line below excludes Abi from assertion deserialized.Should().BeEquivalentTo(message, options => options.Excluding(o => o.Path.EndsWith("Abi"))); diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Network/AaProtocolHandler.cs b/src/Nethermind/Nethermind.AccountAbstraction/Network/AaProtocolHandler.cs index ea6832c043a..621e4d6c033 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction/Network/AaProtocolHandler.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction/Network/AaProtocolHandler.cs @@ -97,17 +97,20 @@ public void HandleMessage(ZeroPacket message) switch (message.PacketType) { case AaMessageCode.UserOperations: - Metrics.UserOperationsMessagesReceived++; - UserOperationsMessage uopMsg = Deserialize(message.Content); - ReportIn(uopMsg, size); - Handle(uopMsg); - break; + { + Metrics.UserOperationsMessagesReceived++; + using UserOperationsMessage uopMsg = Deserialize(message.Content); + ReportIn(uopMsg, size); + Handle(uopMsg); + + break; + } } } private void Handle(UserOperationsMessage uopMsg) { - IList userOperations = uopMsg.UserOperationsWithEntryPoint; + IOwnedReadOnlyList userOperations = uopMsg.UserOperationsWithEntryPoint; for (int i = 0; i < userOperations.Count; i++) { UserOperationWithEntryPoint uop = userOperations[i]; @@ -125,20 +128,20 @@ private void Handle(UserOperationsMessage uopMsg) public void SendNewUserOperation(UserOperationWithEntryPoint uop) { - SendMessage(new[] { uop }); + SendMessage(new ArrayPoolList(1) { uop }); } public void SendNewUserOperations(IEnumerable uops) { const int maxCapacity = 256; - using ArrayPoolList uopsToSend = new(maxCapacity); + ArrayPoolList uopsToSend = new(maxCapacity); foreach (UserOperationWithEntryPoint uop in uops) { if (uopsToSend.Count == maxCapacity) { SendMessage(uopsToSend); - uopsToSend.Clear(); + uopsToSend = new(maxCapacity); } // TODO: Why this check @@ -153,9 +156,13 @@ public void SendNewUserOperations(IEnumerable uops) { SendMessage(uopsToSend); } + else + { + uopsToSend.Dispose(); + } } - private void SendMessage(IList uopsToSend) + private void SendMessage(IOwnedReadOnlyList uopsToSend) { UserOperationsMessage msg = new(uopsToSend); Send(msg); diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessage.cs b/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessage.cs index a4dcd8008ef..1ac9857ff9a 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessage.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessage.cs @@ -1,37 +1,34 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Collections.Generic; using Nethermind.AccountAbstraction.Data; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Messages; namespace Nethermind.AccountAbstraction.Network { - public class UserOperationsMessage : P2PMessage + public class UserOperationsMessage(IOwnedReadOnlyList userOperations) : P2PMessage { public override int PacketType { get; } = AaMessageCode.UserOperations; public override string Protocol { get; } = "aa"; - public IList UserOperationsWithEntryPoint { get; } + public IOwnedReadOnlyList UserOperationsWithEntryPoint { get; } = userOperations; - public UserOperationsMessage(IList userOperations) + public override void Dispose() { - UserOperationsWithEntryPoint = userOperations; + base.Dispose(); + UserOperationsWithEntryPoint.Dispose(); } public override string ToString() => $"{nameof(UserOperationsMessage)}({UserOperationsWithEntryPoint?.Count})"; } - public class UserOperationWithEntryPoint + public class UserOperationWithEntryPoint(UserOperation userOperation, Address entryPoint) { - public UserOperation UserOperation { get; } - public Address EntryPoint { get; } - - public UserOperationWithEntryPoint(UserOperation userOperation, Address entryPoint) - { - UserOperation = userOperation; - EntryPoint = entryPoint; - } + public UserOperation UserOperation { get; } = userOperation; + public Address EntryPoint { get; } = entryPoint; } } diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessageSerializer.cs b/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessageSerializer.cs index d9a71523f48..beb7cf614ea 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction/Network/UserOperationsMessageSerializer.cs @@ -3,6 +3,7 @@ using DotNetty.Buffers; using Nethermind.AccountAbstraction.Data; +using Nethermind.Core.Collections; using Nethermind.Network; using Nethermind.Serialization.Rlp; @@ -28,7 +29,7 @@ public void Serialize(IByteBuffer byteBuffer, UserOperationsMessage message) public UserOperationsMessage Deserialize(IByteBuffer byteBuffer) { NettyRlpStream rlpStream = new(byteBuffer); - UserOperationWithEntryPoint[] uOps = DeserializeUOps(rlpStream); + ArrayPoolList uOps = DeserializeUOps(rlpStream); return new UserOperationsMessage(uOps); } @@ -43,9 +44,9 @@ public int GetLength(UserOperationsMessage message, out int contentLength) return Rlp.LengthOfSequence(contentLength); } - private static UserOperationWithEntryPoint[] DeserializeUOps(NettyRlpStream rlpStream) + private static ArrayPoolList DeserializeUOps(NettyRlpStream rlpStream) { - return Rlp.DecodeArray(rlpStream); + return Rlp.DecodeArrayPool(rlpStream); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs index 17da8cffc11..ffe0db3564a 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs @@ -13,6 +13,7 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Blockchain.Visitors; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Test; @@ -445,8 +446,8 @@ public void Find_headers_basic() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] headers = blockTree.FindHeaders(block0.Hash, 2, 0, false); - Assert.That(headers.Length, Is.EqualTo(2)); + 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)); } @@ -462,8 +463,8 @@ public void Find_headers_skip() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] headers = blockTree.FindHeaders(block0.Hash, 2, 1, false); - Assert.That(headers.Length, Is.EqualTo(2)); + 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)); } @@ -483,8 +484,8 @@ public void Find_headers_reverse() AddToMain(blockTree, block3); AddToMain(blockTree, block4); - BlockHeader[] headers = blockTree.FindHeaders(block2.Hash, 2, 0, true); - Assert.That(headers.Length, Is.EqualTo(2)); + 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)); } @@ -500,8 +501,8 @@ public void Find_headers_reverse_skip() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] headers = blockTree.FindHeaders(block2.Hash, 2, 1, true); - Assert.That(headers.Length, Is.EqualTo(2)); + 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)); } @@ -517,8 +518,8 @@ public void Find_headers_reverse_below_zero() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] headers = blockTree.FindHeaders(block0.Hash, 2, 1, true); - Assert.That(headers.Length, Is.EqualTo(2)); + 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]); } @@ -534,8 +535,8 @@ public void When_finding_headers_does_not_find_a_header_it_breaks_the_loop() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] headers = blockTree.FindHeaders(block0.Hash, 100, 0, false); - Assert.That(headers.Length, Is.EqualTo(100)); + 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]); @@ -553,8 +554,8 @@ public void When_finding_blocks_does_not_find_a_block_it_breaks_the_loop() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] headers = blockTree.FindHeaders(block0.Hash, 100, 0, false); - Assert.That(headers.Length, Is.EqualTo(100)); + 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]); @@ -573,8 +574,8 @@ public void Find_sequence_basic_longer() AddToMain(blockTree, block2); int length = 256; - BlockHeader[] blocks = blockTree.FindHeaders(block0.Hash, length, 0, false); - Assert.That(blocks.Length, Is.EqualTo(length)); + 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)); @@ -592,8 +593,8 @@ public void Find_sequence_basic_shorter() AddToMain(blockTree, block2); int length = 2; - BlockHeader[] blocks = blockTree.FindHeaders(block1.Hash, length, 0, false); - Assert.That(blocks.Length, Is.EqualTo(length)); + 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)); } @@ -610,8 +611,8 @@ public void Find_sequence_basic() AddToMain(blockTree, block2); int length = 3; - BlockHeader[] blocks = blockTree.FindHeaders(block0.Hash, length, 0, false); - Assert.That(blocks.Length, Is.EqualTo(length)); + 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)); @@ -628,8 +629,8 @@ public void Find_sequence_reverse() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] blocks = blockTree.FindHeaders(block2.Hash, 3, 0, true); - Assert.That(blocks.Length, Is.EqualTo(3)); + 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)); @@ -647,8 +648,8 @@ public void Find_sequence_zero_blocks() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] blocks = blockTree.FindHeaders(block0.Hash, 0, 0, false); - Assert.That(blocks.Length, Is.EqualTo(0)); + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 0, 0, false); + Assert.That(blocks.Count, Is.EqualTo(0)); } [Test, Timeout(Timeout.MaxTestTime)] @@ -662,8 +663,8 @@ public void Find_sequence_one_block() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] blocks = blockTree.FindHeaders(block2.Hash, 1, 0, false); - Assert.That(blocks.Length, Is.EqualTo(1)); + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block2.Hash, 1, 0, false); + Assert.That(blocks.Count, Is.EqualTo(1)); } [Test, Timeout(Timeout.MaxTestTime)] @@ -677,8 +678,8 @@ public void Find_sequence_basic_skip() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] blocks = blockTree.FindHeaders(block0.Hash, 2, 1, false); - Assert.That(blocks.Length, Is.EqualTo(2), "length"); + 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)); } @@ -694,8 +695,8 @@ public void Find_sequence_some_empty() AddToMain(blockTree, block1); AddToMain(blockTree, block2); - BlockHeader[] blocks = blockTree.FindHeaders(block0.Hash, 4, 0, false); - Assert.That(blocks.Length, Is.EqualTo(4)); + using IOwnedReadOnlyList blocks = blockTree.FindHeaders(block0.Hash, 4, 0, false); + Assert.That(blocks.Count, Is.EqualTo(4)); Assert.IsNull(blocks[3]); } diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs index 89779c3b157..19b69fed50c 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs @@ -15,6 +15,7 @@ using Nethermind.Core; using Nethermind.Core.Attributes; using Nethermind.Core.Caching; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -536,40 +537,40 @@ public AddBlockResult SuggestBlock(Block block, BlockTreeSuggestOptions options return GetBlockHashOnMainOrBestDifficultyHash(number); } - public BlockHeader[] FindHeaders(Hash256? blockHash, int numberOfBlocks, int skip, bool reverse) + public IOwnedReadOnlyList FindHeaders(Hash256? blockHash, int numberOfBlocks, int skip, bool reverse) { if (numberOfBlocks == 0) { - return Array.Empty(); + return ArrayPoolList.Empty(); } if (blockHash is null) { - return new BlockHeader[numberOfBlocks]; + return new ArrayPoolList(numberOfBlocks, numberOfBlocks); } BlockHeader startHeader = FindHeader(blockHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (startHeader is null) { - return new BlockHeader[numberOfBlocks]; + return new ArrayPoolList(numberOfBlocks, numberOfBlocks); } if (numberOfBlocks == 1) { - return new[] { startHeader }; + return new ArrayPoolList(1) { startHeader }; } if (skip == 0) { - static BlockHeader[] FindHeadersReversedFast(BlockTree tree, BlockHeader startHeader, int numberOfBlocks, bool reverse = false) + static ArrayPoolList FindHeadersReversedFast(BlockTree tree, BlockHeader startHeader, int numberOfBlocks, bool reverse = false) { ArgumentNullException.ThrowIfNull(startHeader); if (numberOfBlocks == 1) { - return new[] { startHeader }; + return new ArrayPoolList(1) { startHeader }; } - BlockHeader[] result = new BlockHeader[numberOfBlocks]; + ArrayPoolList result = new ArrayPoolList(numberOfBlocks, numberOfBlocks); BlockHeader current = startHeader; int responseIndex = reverse ? 0 : numberOfBlocks - 1; @@ -606,7 +607,7 @@ as it does not require the step of resolving number -> hash */ } } - BlockHeader[] result = new BlockHeader[numberOfBlocks]; + ArrayPoolList result = new ArrayPoolList(numberOfBlocks, numberOfBlocks); BlockHeader current = startHeader; int directionMultiplier = reverse ? -1 : 1; int responseIndex = 0; diff --git a/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs b/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs index cadb3f87451..1bfbfaa6f87 100644 --- a/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs @@ -8,6 +8,7 @@ using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Visitors; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Blockchain @@ -150,7 +151,7 @@ AddBlockResult Insert(Block block, BlockTreeInsertBlockOptions insertBlockOption Hash256 FindHash(long blockNumber); - BlockHeader[] FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse); + IOwnedReadOnlyList FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse); BlockHeader FindLowestCommonAncestor(BlockHeader firstDescendant, BlockHeader secondDescendant, long maxSearchDepth); diff --git a/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs b/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs index 8fdeb68242a..5ceaacf2495 100644 --- a/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Nethermind.Blockchain.Visitors; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -103,7 +104,7 @@ public void UpdateHeadBlock(Hash256 blockHash) public Hash256 FindHash(long blockNumber) => _wrapped.FindHash(blockNumber); - public BlockHeader[] FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse) => _wrapped.FindHeaders(hash, numberOfBlocks, skip, reverse); + public IOwnedReadOnlyList FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse) => _wrapped.FindHeaders(hash, numberOfBlocks, skip, reverse); public BlockHeader FindLowestCommonAncestor(BlockHeader firstDescendant, BlockHeader secondDescendant, long maxSearchDepth) => _wrapped.FindLowestCommonAncestor(firstDescendant, secondDescendant, maxSearchDepth); diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/INodeDataPeer.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/INodeDataPeer.cs index 8f8cebd564d..f87888dcf1f 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/INodeDataPeer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/INodeDataPeer.cs @@ -4,11 +4,12 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Blockchain.Synchronization; public interface INodeDataPeer { - Task GetNodeData(IReadOnlyList hashes, CancellationToken token); + Task> GetNodeData(IReadOnlyList hashes, CancellationToken token); } diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISnapSyncPeer.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISnapSyncPeer.cs index ba0e1dc6b85..2e59c03b0f1 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISnapSyncPeer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISnapSyncPeer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.State.Snap; @@ -13,8 +14,8 @@ public interface ISnapSyncPeer { Task GetAccountRange(AccountRange range, CancellationToken token); Task GetStorageRange(StorageRange range, CancellationToken token); - Task GetByteCodes(IReadOnlyList codeHashes, CancellationToken token); - Task GetTrieNodes(AccountsToRefreshRequest request, CancellationToken token); - Task GetTrieNodes(GetTrieNodesRequest request, CancellationToken token); + Task> GetByteCodes(IReadOnlyList codeHashes, CancellationToken token); + Task> GetTrieNodes(AccountsToRefreshRequest request, CancellationToken token); + Task> GetTrieNodes(GetTrieNodesRequest request, CancellationToken token); } } diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs index 980e247b6c0..a51275ff58c 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Int256; using Nethermind.Stats.Model; @@ -32,11 +33,11 @@ public interface ISyncPeer : ITxPoolPeer, IPeerWithSatelliteProtocol string ProtocolCode { get; } void Disconnect(DisconnectReason reason, string details); Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token); - Task GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token); - Task GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token); + Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token); + Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token); Task GetHeadBlockHeader(Hash256? hash, CancellationToken token); void NotifyOfNewBlock(Block block, SendBlockMode mode); - Task GetReceipts(IReadOnlyList blockHash, CancellationToken token); - Task GetNodeData(IReadOnlyList hashes, CancellationToken token); + Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token); + Task> GetNodeData(IReadOnlyList hashes, CancellationToken token); } } diff --git a/src/Nethermind/Nethermind.Consensus/Scheduler/BackgroundTaskScheduler.cs b/src/Nethermind/Nethermind.Consensus/Scheduler/BackgroundTaskScheduler.cs index d45733b483d..cf4b7744b8d 100644 --- a/src/Nethermind/Nethermind.Consensus/Scheduler/BackgroundTaskScheduler.cs +++ b/src/Nethermind/Nethermind.Consensus/Scheduler/BackgroundTaskScheduler.cs @@ -117,7 +117,7 @@ public void ScheduleTask(TReq request, Func timeout ??= DefaultTimeout; DateTimeOffset deadline = DateTimeOffset.UtcNow + timeout.Value; - IActivity activity = new Activity() + IActivity activity = new Activity { Deadline = deadline, Request = request, @@ -126,6 +126,11 @@ public void ScheduleTask(TReq request, Func if (!_taskQueue.Writer.TryWrite(activity)) { + if (request is IDisposable disposable) + { + disposable.Dispose(); + } + // This should never happen unless something goes very wrong. throw new InvalidOperationException("Unable to write to background task queue."); } diff --git a/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs b/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs index 0dc50207560..db99f4a314c 100644 --- a/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs @@ -17,7 +17,7 @@ public class ArrayPoolListTests [Test] public void Empty_list() { - ArrayPoolList list = new(1024); + using ArrayPoolList list = new(1024); list.Should().BeEquivalentTo(Array.Empty()); list.Count.Should().Be(0); list.Capacity.Should().Be(1024); @@ -26,7 +26,7 @@ public void Empty_list() [Test] public void Should_not_hang_when_capacity_is_zero() { - ArrayPoolList list = new(0); + using ArrayPoolList list = new(0); list.Should().BeEquivalentTo(Array.Empty()); list.Add(1); list.Count.Should().Be(1); @@ -39,7 +39,7 @@ public void Should_not_hang_when_capacity_is_zero() [Test] public void Add_should_work() { - ArrayPoolList list = new(1024); + using ArrayPoolList list = new(1024); list.AddRange(Enumerable.Range(0, 4)); list.Should().BeEquivalentTo(Enumerable.Range(0, 4)); } @@ -47,7 +47,7 @@ public void Add_should_work() [Test] public void Add_should_expand() { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 50)); list.Should().BeEquivalentTo(Enumerable.Range(0, 50)); list.Count.Should().Be(50); @@ -57,7 +57,7 @@ public void Add_should_expand() [Test] public void Clear_should_clear() { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 50)); list.Clear(); list.Should().BeEquivalentTo(Array.Empty()); @@ -71,7 +71,7 @@ public void Clear_should_clear() [TestCase(-1, ExpectedResult = false)] public bool Contains_should_check_ok(int item) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 50)); return list.Contains(item); } @@ -81,7 +81,7 @@ public bool Contains_should_check_ok(int item) [TestCase(16, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1 })] public void Insert_should_expand(int index, int[] expected) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 16)); list.Insert(index, -1); list.Should().BeEquivalentTo(expected); @@ -91,7 +91,7 @@ public void Insert_should_expand(int index, int[] expected) [TestCase(-1)] public void Insert_should_throw(int index) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); Action action = () => list.Insert(index, -1); action.Should().Throw(); @@ -103,7 +103,7 @@ public void Insert_should_throw(int index) [TestCase(-1, ExpectedResult = -1)] public int IndexOf_should_return_index(int item) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 50)); return list.IndexOf(item); } @@ -115,7 +115,7 @@ public int IndexOf_should_return_index(int item) [TestCase(-1, false, new[] { 0, 1, 2, 3, 4, 5, 6, 7 })] public void Remove_should_remove(int item, bool removed, int[] expected) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); list.Remove(item).Should().Be(removed); list.Should().BeEquivalentTo(expected); @@ -125,7 +125,7 @@ public void Remove_should_remove(int item, bool removed, int[] expected) [TestCase(7, new[] { 0, 1, 2, 3, 4, 5, 6 })] public void RemoveAt_should_remove(int item, int[] expected) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); list.RemoveAt(item); list.Should().BeEquivalentTo(expected); @@ -135,7 +135,7 @@ public void RemoveAt_should_remove(int item, int[] expected) [TestCase(-1, new[] { 0, 1, 2, 3, 4, 5, 6, 7 })] public void RemoveAt_should_throw(int item, int[] expected) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); Action action = () => list.RemoveAt(item); action.Should().Throw(); @@ -144,7 +144,7 @@ public void RemoveAt_should_throw(int item, int[] expected) [Test] public void CopyTo_should_copy() { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 50)); int[] array = new int[51]; list.CopyTo(array, 1); @@ -155,7 +155,7 @@ public void CopyTo_should_copy() [TestCase(7, ExpectedResult = 7)] public int Get_should_return(int item) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); return list[item]; } @@ -164,7 +164,7 @@ public int Get_should_return(int item) [TestCase(-1)] public void Get_should_throw(int item) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); Func action = () => list[item]; action.Should().Throw(); @@ -174,7 +174,7 @@ public void Get_should_throw(int item) [TestCase(7, ExpectedResult = -1)] public int Set_should_set(int item) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); list[item] = -1; return list[item]; @@ -184,7 +184,7 @@ public int Set_should_set(int item) [TestCase(-1)] public void Set_should_throw(int item) { - ArrayPoolList list = new(4); + using ArrayPoolList list = new(4); list.AddRange(Enumerable.Range(0, 8)); Action action = () => list[item] = 1; action.Should().Throw(); @@ -197,7 +197,7 @@ public void Set_should_throw(int item) [TestCase(100, 128)] public void AddRange_should_expand(int items, int expectedCapacity) { - ArrayPoolList list = new(16) { 0, 1 }; + using ArrayPoolList list = new(16) { 0, 1 }; list.AddRange(Enumerable.Range(2, items)); list.Should().BeEquivalentTo(Enumerable.Range(0, items + 2)); list.Capacity.Should().Be(expectedCapacity); @@ -206,7 +206,7 @@ public void AddRange_should_expand(int items, int expectedCapacity) [Test] public void Should_implement_IList_the_same_as_IListT() { - var listT = new ArrayPoolList(1024); + using var listT = new ArrayPoolList(1024); var list = (IList)listT; list.Add(1); @@ -240,7 +240,8 @@ public void Should_implement_IList_the_same_as_IListT() [Test] public void Should_throw_on_null_insertion_if_null_illegal() { - var list = (IList)new ArrayPoolList(1024); + using var arrayPoolList = new ArrayPoolList(1024); + var list = (IList)arrayPoolList; Action action = () => list.Add(null); action.Should().Throw(); @@ -255,7 +256,8 @@ public void Should_throw_on_null_insertion_if_null_illegal() [Test] public void Should_throw_on_invalid_type_insertion() { - var list = (IList)new ArrayPoolList(1024); + using var arrayPoolList = new ArrayPoolList(1024); + var list = (IList)arrayPoolList; Action action = () => list.Add(string.Empty); action.Should().Throw(); @@ -271,7 +273,8 @@ public void Should_throw_on_invalid_type_insertion() [TestCase(null)] public void Should_not_throw_on_invalid_type_lookup(object? value) { - var list = (IList)new ArrayPoolList(1024); + using var arrayPoolList = new ArrayPoolList(1024); + var list = (IList)arrayPoolList; list.Add(1); list.Contains(value).Should().BeFalse(); @@ -284,7 +287,7 @@ public void Should_not_throw_on_invalid_type_lookup(object? value) [Test] public void Should_implement_basic_properties_as_expected() { - var list = new ArrayPoolList(1024); + using var list = new ArrayPoolList(1024); ((ICollection)list).IsReadOnly.Should().BeFalse(); ((IList)list).IsReadOnly.Should().BeFalse(); @@ -292,4 +295,45 @@ public void Should_implement_basic_properties_as_expected() ((IList)list).IsSynchronized.Should().BeFalse(); ((IList)list).SyncRoot.Should().Be(list); } + + [Test] + public void Dispose_ShouldNotHaveAnEffect_OnEmptyPool() + { + var list = new ArrayPoolList(0); + list.Dispose(); + + Action act = () => _ = list.Count; + act.Should().NotThrow(); + } + + [Test] + public void Can_resize_totally_empty_list() + { + using ArrayPoolList list = new(0); + list.Add(1); + list.Count.Should().Be(1); + } + +#if DEBUG + [Test] + [Explicit("Crashes the test runner")] + public void Finalizer_throws_if_not_disposed() + { + static void CreateAndDrop() + { + ArrayPoolList list = new(1); + } + + bool exception = false; + AppDomain.CurrentDomain.UnhandledException += (_, e) => + { + exception = true; + }; + CreateAndDrop(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + exception.Should().BeTrue(); + } +#endif } diff --git a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs index b6633758716..f94f8342984 100644 --- a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs +++ b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs @@ -5,13 +5,14 @@ using System.Buffers; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Threading; namespace Nethermind.Core.Collections; -public sealed class ArrayPoolList : IList, IList, IReadOnlyList, IDisposable +public sealed class ArrayPoolList : IList, IList, IOwnedReadOnlyList { private readonly ArrayPool _arrayPool; private T[] _array; @@ -21,14 +22,31 @@ public sealed class ArrayPoolList : IList, IList, IReadOnlyList, IDispo public ArrayPoolList(int capacity) : this(ArrayPool.Shared, capacity) { } + public ArrayPoolList(int capacity, int count) : this(ArrayPool.Shared, capacity, count) { } + public ArrayPoolList(int capacity, IEnumerable enumerable) : this(capacity) => this.AddRange(enumerable); - public ArrayPoolList(ArrayPool arrayPool, int capacity) + public ArrayPoolList(ArrayPool arrayPool, int capacity, int startingCount = 0) { _arrayPool = arrayPool; - if (capacity == 0) capacity = 16; // minimum with arraypool is 16 anyway... - _array = arrayPool.Rent(capacity); + + if (capacity != 0) + { + _array = arrayPool.Rent(capacity); + _array.AsSpan(0, startingCount).Clear(); + } + else + { + _array = Array.Empty(); + } _capacity = _array.Length; + + _count = startingCount; + } + + ReadOnlySpan IOwnedReadOnlyList.AsSpan() + { + return AsSpan(); } public IEnumerator GetEnumerator() @@ -69,7 +87,7 @@ int IList.Add(object? value) return Count - 1; } - public void AddRange(Span items) + public void AddRange(ReadOnlySpan items) { GuardResize(items.Length); items.CopyTo(_array.AsSpan(_count, items.Length)); @@ -153,9 +171,15 @@ private void GuardResize(int itemsToAdd = 1) { GuardDispose(); int newCount = _count + itemsToAdd; - if (newCount > _capacity) + if (_capacity == 0) + { + _array = _arrayPool.Rent(newCount); + _capacity = _array.Length; + } + else if (newCount > _capacity) { int newCapacity = _capacity * 2; + if (newCapacity == 0) newCapacity = 1; while (newCount > newCapacity) { newCapacity *= 2; @@ -195,6 +219,13 @@ private bool RemoveAtInternal(int index, bool shouldThrow) return isValid; } + public void Truncate(int newLength) + { + GuardDispose(); + GuardIndex(newLength, allowEqualToCount: true); + _count = newLength; + } + public T this[int index] { get @@ -244,6 +275,8 @@ static void ThrowArgumentOutOfRangeException() private static bool IsCompatibleObject(object? value) => value is T || value is null && default(T) is null; + public static ArrayPoolList Empty() => new(0); + private struct ArrayPoolListEnumerator : IEnumerator { private readonly T[] _array; @@ -270,13 +303,36 @@ public readonly void Dispose() { } public void Dispose() { + // Noop for empty array as sometimes this is used as part of an empty shared response. + if (_capacity == 0) return; + if (!_disposed) { - _arrayPool.Return(_array); - _array = null!; _disposed = true; + T[]? array = _array; + if (array is not null) + { + _arrayPool.Return(_array); + _array = null!; + } + } + +#if DEBUG + GC.SuppressFinalize(this); +#endif + } + +#if DEBUG + private readonly StackTrace _creationStackTrace = new(); + + ~ArrayPoolList() + { + if (!_disposed) + { + throw new InvalidOperationException($"{nameof(ArrayPoolList)} hasn't been disposed. Created at: {_creationStackTrace}"); } } +#endif public Span AsSpan() => _array.AsSpan(0, _count); } diff --git a/src/Nethermind/Nethermind.Core/Collections/IOwnedReadOnlyList.cs b/src/Nethermind/Nethermind.Core/Collections/IOwnedReadOnlyList.cs new file mode 100644 index 00000000000..6890daa1b34 --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Collections/IOwnedReadOnlyList.cs @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; + +namespace Nethermind.Core.Collections; + +/// +/// Mark a list that is owned by the containing class/struct and should be disposed together with the class. +/// Conventionally: +/// - If this is returned from a method, the method caller should dispose it. +/// - If this is passed to a method, the receiving object for the method should dispose it. +/// You give it to me, I own it. I give it to you, you now own it. You own it, you clean it up la... +/// +/// TODO: One day, check if https://github.com/dotnet/roslyn-analyzers/issues/1617 has progressed. +/// +/// +public interface IOwnedReadOnlyList : IReadOnlyList, IDisposable +{ + ReadOnlySpan AsSpan(); +} diff --git a/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs index f994b0bf00b..19eff3af5c4 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs @@ -3,12 +3,16 @@ using System.Collections.Generic; using System.Linq; +using Nethermind.Core.Collections; namespace Nethermind.Core.Extensions { public static class EnumerableExtensions { public static ISet AsSet(this IEnumerable enumerable) => - enumerable is ISet set ? set : enumerable.ToHashSet(); + enumerable as ISet ?? enumerable.ToHashSet(); + + public static ArrayPoolList ToPooledList(this IEnumerable enumerable, int count) => new(count, enumerable); + public static ArrayPoolList ToPooledList(this IReadOnlyCollection collection) => new(collection.Count, collection); } } diff --git a/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs index a95f462a358..9898d72366d 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs @@ -6,7 +6,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Core.Extensions @@ -159,5 +159,12 @@ public static ReadOnlySpan TakeAndMove(this ref ReadOnlySpan span, i public static bool IsNull(this in Span span) => Unsafe.IsNullRef(ref MemoryMarshal.GetReference(span)); public static bool IsNullOrEmpty(this in ReadOnlySpan span) => span.Length == 0; public static bool IsNull(this in ReadOnlySpan span) => Unsafe.IsNullRef(ref MemoryMarshal.GetReference(span)); + + public static ArrayPoolList ToPooledList(this in ReadOnlySpan span) + { + ArrayPoolList newList = new ArrayPoolList(span.Length); + newList.AddRange(span); + return newList; + } } } diff --git a/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs b/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs index cc634c9bc22..6a841cf2bb1 100644 --- a/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs +++ b/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs @@ -12,6 +12,7 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Blockchain.Visitors; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Logging; using Nethermind.Stats; @@ -122,7 +123,7 @@ private async Task DownloadReceiptsForBlock(Block block) { try { - TxReceipt[]?[] receipts = await currentSyncPeer.GetReceipts(new List { block.Hash }, _cancellationToken); + IOwnedReadOnlyList receipts = await currentSyncPeer.GetReceipts(new List { block.Hash }, _cancellationToken); TxReceipt[]? txReceipts = receipts.FirstOrDefault(); if (txReceipts is not null) { diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs index 69046fa9df2..99e202690b6 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs @@ -10,6 +10,7 @@ using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; @@ -117,7 +118,7 @@ public async Task forkChoiceUpdatedV1_unknown_block_without_newpayload_initiates ISyncPeer syncPeer = Substitute.For(); syncPeer .GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(Task.FromResult(new BlockHeader[1] { block.Header })); + .Returns(Task.FromResult?>(new ArrayPoolList(1) { block.Header })); SyncPeerAllocation alloc = new SyncPeerAllocation(new PeerInfo(syncPeer), AllocationContexts.All); alloc.AllocateBestPeer(new[] { new PeerInfo(syncPeer) }, Substitute.For(), Substitute.For()); chain.SyncPeerPool diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs index 3e7d4dadbee..02009b52d73 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs @@ -8,7 +8,9 @@ using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; using Nethermind.Db; @@ -168,7 +170,7 @@ public async Task Can_keep_returning_nulls_after_all_batches_were_prepared() await feed.PrepareRequest(); } - HeadersSyncBatch? result = await feed.PrepareRequest(); + using HeadersSyncBatch? result = await feed.PrepareRequest(); result.Should().BeNull(); } @@ -205,7 +207,7 @@ public async Task Finishes_when_all_downloaded() await feed.PrepareRequest(); } blockTree.LowestInsertedBeaconHeader.Returns(Build.A.BlockHeader.WithNumber(1001).TestObject); - HeadersSyncBatch? result = await feed.PrepareRequest(); + using HeadersSyncBatch? result = await feed.PrepareRequest(); result.Should().BeNull(); feed.CurrentState.Should().Be(SyncFeedState.Dormant); measuredProgress.CurrentValue.Should().Be(999); @@ -271,7 +273,7 @@ public async Task Feed_able_to_connect_to_existing_chain_through_block_hash() ctx.BeaconSync.ShouldBeInBeaconHeaders().Should().BeTrue(); blockTree.BestKnownNumber.Should().Be(6); BuildHeadersSyncBatches(ctx, blockTree, syncedBlockTree, pivot, 2); - HeadersSyncBatch? result = await ctx.Feed.PrepareRequest(); + using HeadersSyncBatch? result = await ctx.Feed.PrepareRequest(); result.Should().BeNull(); blockTree.BestKnownNumber.Should().Be(6); ctx.Feed.CurrentState.Should().Be(SyncFeedState.Dormant); @@ -290,8 +292,8 @@ public void Feed_connect_invalid_chain() ctx.BeaconPivot = PreparePivot(99, new SyncConfig(), ctx.BlockTree, syncedBlockTree.FindHeader(99, BlockTreeLookupOptions.None)); ctx.Feed.InitializeFeed(); - HeadersSyncBatch? batch = ctx.Feed.PrepareRequest().Result; - batch!.Response = syncedBlockTree.FindHeaders(syncedBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, false); + using HeadersSyncBatch batch = ctx.Feed.PrepareRequest().Result!; + batch.Response = syncedBlockTree.FindHeaders(syncedBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, false)!; ctx.Feed.HandleResponse(batch); Hash256 lastHeader = syncedBlockTree.FindHeader(batch.EndNumber, BlockTreeLookupOptions.None)!.GetOrCalculateHash(); @@ -331,14 +333,15 @@ public async Task When_pivot_changed_during_header_sync_after_chain_merged__do_n HeadersSyncBatch? request = await ctx.Feed.PrepareRequest(); request!.Should().NotBeNull(); request!.Response = Enumerable.Range((int)request.StartNumber, request.RequestSize) - .Select((blockNumber) => ctx.RemoteBlockTree.FindHeader(blockNumber)) - .ToArray(); + .Select(blockNumber => ctx.RemoteBlockTree.FindHeader(blockNumber)) + .ToPooledList(request.RequestSize); ctx.Feed.HandleResponse(request); // Ensure pivot happens which reset lowest inserted beacon header further ahead. ctx.BeaconPivot.EnsurePivot(ctx.RemoteBlockTree.FindHeader(pivotNumber + 10)); ctx.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeFalse(); + request.Dispose(); // The sync feed must adapt to this request = await ctx.Feed.PrepareRequest(); @@ -347,8 +350,9 @@ public async Task When_pivot_changed_during_header_sync_after_chain_merged__do_n // We respond it again request!.Response = Enumerable.Range((int)request.StartNumber, request.RequestSize) .Select((blockNumber) => ctx.RemoteBlockTree.FindHeader(blockNumber)) - .ToArray(); + .ToPooledList(request.RequestSize); ctx.Feed.HandleResponse(request); + request.Dispose(); // It should complete successfully ctx.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeTrue(); @@ -394,7 +398,7 @@ private async void BuildHeadersSyncBatches( long lowestHeaderNumber = pivot.PivotNumber; while (lowestHeaderNumber > endLowestBeaconHeader) { - HeadersSyncBatch? batch = await ctx.Feed.PrepareRequest(); + using HeadersSyncBatch? batch = await ctx.Feed.PrepareRequest(); batch.Should().NotBeNull(); BuildHeadersSyncBatchResponse(batch, syncedBlockTree); ctx.Feed.HandleResponse(batch); @@ -416,8 +420,8 @@ private void BuildHeadersSyncBatchResponse(HeadersSyncBatch? batch, IBlockTree b return; } - BlockHeader[] headers = blockTree.FindHeaders(startHeader.Hash!, batch.RequestSize, 0, false); - batch.Response = headers; + using IOwnedReadOnlyList headers = blockTree.FindHeaders(startHeader.Hash!, batch.RequestSize, 0, false); + batch.Response = new ArrayPoolList(headers.Count, headers); } private IBeaconPivot PreparePivot(long blockNumber, ISyncConfig syncConfig, IBlockTree blockTree, BlockHeader? pivotHeader = null) diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/PeerRefresherTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/PeerRefresherTests.cs index fe599c77842..7e2b4f403a9 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/PeerRefresherTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/PeerRefresherTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Logging; @@ -90,7 +91,7 @@ private Task WhenCalledWithCorrectHash() private void GivenAllHeaderAvailable() { _syncPeer.GetBlockHeaders(_headParentBlockHeader.Hash!, 2, 0, Arg.Any()) - .Returns(Task.FromResult(new[] { _headParentBlockHeader, _headBlockHeader })); + .Returns(Task.FromResult?>(new ArrayPoolList(2) { _headParentBlockHeader, _headBlockHeader })); GivenFinalizedHeaderAvailable(); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeBlockDownloader.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeBlockDownloader.cs index 05d48d91c8a..be9884fa11b 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeBlockDownloader.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeBlockDownloader.cs @@ -11,6 +11,8 @@ using Nethermind.Consensus; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Collections; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Crypto; using Nethermind.Logging; @@ -322,21 +324,21 @@ bool HasMoreToSync(out BlockHeader[]? headers, out int headersToRequest) return blocksSynced; } - protected override async Task RequestHeaders(PeerInfo peer, CancellationToken cancellation, long currentNumber, int headersToRequest) + protected override async Task> RequestHeaders(PeerInfo peer, CancellationToken cancellation, long currentNumber, int headersToRequest) { // Override PoW's RequestHeaders so that it won't request beyond PoW. // This fixes `Incremental Sync` hive test. - BlockHeader[] response = await base.RequestHeaders(peer, cancellation, currentNumber, headersToRequest); - if (response.Length > 0) + IOwnedReadOnlyList response = await base.RequestHeaders(peer, cancellation, currentNumber, headersToRequest); + if (response.Count > 0) { BlockHeader lastBlockHeader = response[^1]; bool lastBlockIsPostMerge = _poSSwitcher.GetBlockConsensusInfo(response[^1]).IsPostMerge; if (lastBlockIsPostMerge) // Initial check to prevent creating new array every time { response = response - .TakeWhile((header) => !_poSSwitcher.GetBlockConsensusInfo(header).IsPostMerge) - .ToArray(); - if (_logger.IsInfo) _logger.Info($"Last block is post merge. {lastBlockHeader.Hash}. Trimming to {response.Length} sized batch."); + .TakeWhile(header => !_poSSwitcher.GetBlockConsensusInfo(header).IsPostMerge) + .ToPooledList(response.Count); + if (_logger.IsInfo) _logger.Info($"Last block is post merge. {lastBlockHeader.Hash}. Trimming to {response.Count} sized batch."); } } return response; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs index e6181e20622..529960e4f96 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs @@ -2,12 +2,14 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Timers; using Nethermind.Logging; @@ -91,7 +93,7 @@ internal async Task RefreshPeerForFcu( CancellationToken token) { // headBlockhash is obtained together with headParentBlockhash - Task getHeadParentHeaderTask = syncPeer.GetBlockHeaders(headParentBlockhash, 2, 0, token); + Task?> getHeadParentHeaderTask = syncPeer.GetBlockHeaders(headParentBlockhash, 2, 0, token); Task getFinalizedHeaderTask = finalizedBlockhash == Keccak.Zero ? Task.FromResult(null) : syncPeer.GetHeadBlockHeader(finalizedBlockhash, token); @@ -100,8 +102,8 @@ internal async Task RefreshPeerForFcu( try { - BlockHeader[] headAndParentHeaders = await getHeadParentHeaderTask; - if (!TryGetHeadAndParent(headBlockhash, headParentBlockhash, headAndParentHeaders, out headBlockHeader, out headParentBlockHeader)) + IOwnedReadOnlyList? headAndParentHeaders = await getHeadParentHeaderTask; + if (!TryGetHeadAndParent(headBlockhash, headParentBlockhash, headAndParentHeaders!, out headBlockHeader, out headParentBlockHeader)) { _syncPeerPool.ReportRefreshFailed(syncPeer, "ForkChoiceUpdate: unexpected response length"); return; @@ -167,21 +169,21 @@ private bool CheckHeader(ISyncPeer syncPeer, BlockHeader? header) return true; } - private static bool TryGetHeadAndParent(Hash256 headBlockhash, Hash256 headParentBlockhash, BlockHeader[] headers, out BlockHeader? headBlockHeader, out BlockHeader? headParentBlockHeader) + private static bool TryGetHeadAndParent(Hash256 headBlockhash, Hash256 headParentBlockhash, IReadOnlyList headers, out BlockHeader? headBlockHeader, out BlockHeader? headParentBlockHeader) { headBlockHeader = null; headParentBlockHeader = null; - if (headers.Length > 2) + if (headers.Count > 2) { return false; } - if (headers.Length == 1 && headers[0].Hash == headParentBlockhash) + if (headers.Count == 1 && headers[0].Hash == headParentBlockhash) { headParentBlockHeader = headers[0]; } - else if (headers.Length == 2) + else if (headers.Count == 2) { // Maybe the head is not the same as we expected. In that case, leave it as null if (headBlockhash == headers[1].Hash) diff --git a/src/Nethermind/Nethermind.Network.Benchmark/Eth62ProtocolHandlerBenchmarks.cs b/src/Nethermind/Nethermind.Network.Benchmark/Eth62ProtocolHandlerBenchmarks.cs index c860d112ae7..0f8bae8edc8 100644 --- a/src/Nethermind/Nethermind.Network.Benchmark/Eth62ProtocolHandlerBenchmarks.cs +++ b/src/Nethermind/Nethermind.Network.Benchmark/Eth62ProtocolHandlerBenchmarks.cs @@ -10,6 +10,7 @@ using Nethermind.Consensus.Validators; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; @@ -81,7 +82,7 @@ public void SetUp() _handler.HandleMessage(_zeroPacket); Transaction tx = Build.A.Transaction.SignedAndResolved(ecdsa, TestItem.PrivateKeyA).TestObject; - _txMsg = new TransactionsMessage(new[] { tx }); + _txMsg = new TransactionsMessage(new[] { tx }.ToPooledList()); } [GlobalCleanup] diff --git a/src/Nethermind/Nethermind.Network.Stats/Model/P2PNodeDetails.cs b/src/Nethermind/Nethermind.Network.Stats/Model/P2PNodeDetails.cs index d88d8b65c97..16cdff970f3 100644 --- a/src/Nethermind/Nethermind.Network.Stats/Model/P2PNodeDetails.cs +++ b/src/Nethermind/Nethermind.Network.Stats/Model/P2PNodeDetails.cs @@ -1,13 +1,15 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Collections.Generic; + namespace Nethermind.Stats.Model { public class P2PNodeDetails { public byte P2PVersion { get; set; } public string ClientId { get; set; } - public Capability[] Capabilities { get; set; } + public IReadOnlyList Capabilities { get; set; } public int ListenPort { get; set; } } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/DisconnectMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/DisconnectMessageSerializerTests.cs index 6314dfc3403..fae42bfbd05 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/DisconnectMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/DisconnectMessageSerializerTests.cs @@ -16,11 +16,11 @@ public class DisconnectMessageSerializerTests [Test] public void Can_do_roundtrip() { - DisconnectMessage msg = new(EthDisconnectReason.AlreadyConnected); + using DisconnectMessage msg = new(EthDisconnectReason.AlreadyConnected); DisconnectMessageSerializer serializer = new(); byte[] serialized = serializer.Serialize(msg); Assert.That(serialized.ToHexString(true), Is.EqualTo("0xc105"), "bytes"); - DisconnectMessage deserialized = serializer.Deserialize(serialized); + using DisconnectMessage deserialized = serializer.Deserialize(serialized); Assert.That(deserialized.Reason, Is.EqualTo(msg.Reason), "reason"); } @@ -29,7 +29,7 @@ public void Can_read_single_byte_message() { DisconnectMessageSerializer serializer = new(); byte[] serialized = new byte[] { 16 }; - DisconnectMessage deserialized = serializer.Deserialize(serialized); + using DisconnectMessage deserialized = serializer.Deserialize(serialized); Assert.That((EthDisconnectReason)deserialized.Reason, Is.EqualTo(EthDisconnectReason.Other), "reason"); } @@ -41,7 +41,7 @@ public void Can_read_other_format_message(string hex, EthDisconnectReason expect { DisconnectMessageSerializer serializer = new DisconnectMessageSerializer(); byte[] serialized = Bytes.FromHexString(hex); - DisconnectMessage deserialized = serializer.Deserialize(serialized); + using DisconnectMessage deserialized = serializer.Deserialize(serialized); deserialized.Reason.Should().Be((int)expectedReason); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs index e9180323380..9f9803fa5db 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/HelloMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Network.Contract.P2P; @@ -18,10 +19,9 @@ public class HelloMessageSerializerTests [Test] public void Can_do_roundtrip() { - HelloMessage helloMessage = new(); + using HelloMessage helloMessage = new(); helloMessage.P2PVersion = 1; - helloMessage.Capabilities = new List(); - helloMessage.Capabilities.Add(new Capability(Protocol.Eth, 1)); + helloMessage.Capabilities = new ArrayPoolList(1) { new(Protocol.Eth, 1) }; helloMessage.ClientId = "Nethermind/alpha"; helloMessage.ListenPort = 8002; helloMessage.NodeId = NetTestVectors.StaticKeyA.PublicKey; @@ -32,7 +32,7 @@ public void Can_do_roundtrip() Assert.True(Bytes.AreEqual(serialized, expectedBytes), "bytes"); - 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)); @@ -48,7 +48,7 @@ public void Can_deserialize_sample_from_ethereumJ() { byte[] helloMessageRaw = Bytes.FromHexString("f87902a5457468657265756d282b2b292f76302e372e392f52656c656173652f4c696e75782f672b2bccc58365746827c583736868018203e0b8401fbf1e41f08078918c9f7b6734594ee56d7f538614f602c71194db0a1af5a77f9b86eb14669fe7a8a46a2dd1b7d070b94e463f4ecd5b337c8b4d31bbf8dd5646"); HelloMessageSerializer serializer = new(); - HelloMessage helloMessage = serializer.Deserialize(helloMessageRaw); + 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)}"); @@ -64,7 +64,7 @@ public void Can_deserialize_sample_from_eip8_ethereumJ() "fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569" + "bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877c883666f6f836261720304"); HelloMessageSerializer serializer = new(); - HelloMessage helloMessage = serializer.Deserialize(helloMessageRaw); + 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)}"); @@ -82,7 +82,7 @@ public void Can_deserialize_ethereumJ_eip8_sample() "bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877c883666f6f836261720304"); HelloMessageSerializer serializer = new(); - HelloMessage helloMessage = serializer.Deserialize(bytes); + using HelloMessage helloMessage = serializer.Deserialize(bytes); Assert.That(helloMessage.P2PVersion, Is.EqualTo(55)); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs index 305d92937c2..26ce82f8973 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using DotNetty.Buffers; using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Logging; @@ -98,12 +99,9 @@ public void On_hello_with_no_matching_capability() P2PProtocolHandler p2PProtocolHandler = CreateSession(); p2PProtocolHandler.AddSupportedCapability(new Capability(Protocol.Wit, 66)); - HelloMessage message = new HelloMessage() + using HelloMessage message = new() { - Capabilities = new List() - { - new Capability(Protocol.Eth, 63) - }, + Capabilities = new ArrayPoolList(1) { new(Protocol.Eth, 63) }, NodeId = TestItem.PublicKeyA, }; @@ -132,12 +130,9 @@ public void On_hello_with_not_matching_client_id(string pattern, string clientId _clientIdPattern = new Regex(pattern); P2PProtocolHandler p2PProtocolHandler = CreateSession(); - HelloMessage message = new HelloMessage() + using HelloMessage message = new() { - Capabilities = new List() - { - new Capability(Protocol.Eth, 63) - }, + Capabilities = new ArrayPoolList(1) { new Capability(Protocol.Eth, 63) }, NodeId = TestItem.PublicKeyA, ClientId = clientId, }; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs index db01f8de0e2..475a6fe9e7d 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs @@ -25,7 +25,7 @@ public void Does_send_on_active_channel() IByteBuffer serialized = UnpooledByteBufferAllocator.Default.Buffer(2); var serializer = Substitute.For(); - TestMessage testMessage = new TestMessage(); + using TestMessage testMessage = new(); serializer.ZeroSerialize(testMessage).Returns(serialized); serialized.SafeRelease(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs index 0fb454ac4f1..b42677ed229 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/PingMessageSerializerTests.cs @@ -17,7 +17,7 @@ public void Can_do_roundtrip() PingMessageSerializer serializer = new(); byte[] serialized = serializer.Serialize(msg); Assert.That(serialized[0], Is.EqualTo(0xc0)); - PingMessage deserialized = serializer.Deserialize(serialized); + using PingMessage deserialized = serializer.Deserialize(serialized); Assert.NotNull(deserialized); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs index 8d702e869e3..61bd7028c07 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/PongMessageSerializerTests.cs @@ -17,7 +17,7 @@ public void Can_do_roundtrip() PongMessageSerializer serializer = new(); byte[] serialized = serializer.Serialize(msg); Assert.That(serialized[0], Is.EqualTo(0xc0)); - PongMessage deserialized = serializer.Deserialize(serialized); + using PongMessage deserialized = serializer.Deserialize(serialized); Assert.NotNull(deserialized); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs b/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs index 2df8513aae4..ecb452577cc 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs @@ -22,7 +22,7 @@ public static void TestZero(IZeroMessageSerializer serializer, T message, try { serializer.Serialize(buffer, message); - T deserialized = serializer.Deserialize(buffer); + using T deserialized = serializer.Deserialize(buffer); // RlpLength is calculated explicitly when serializing an object by Calculate method. It's null after deserialization. deserialized.Should().BeEquivalentTo(message, options => diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageSerializerTests.cs index 1cbe93036c8..c011f42da5f 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageSerializerTests.cs @@ -31,7 +31,7 @@ public void Should_not_contain_network_form_tx_wrapper(BlockBody[] bodies) IByteBuffer buffer = PooledByteBufferAllocator.Default.Buffer(1024 * 16); BlockBodiesMessageSerializer serializer = new(); serializer.Serialize(buffer, new BlockBodiesMessage(bodies)); - BlockBodiesMessage deserializedMessage = serializer.Deserialize(buffer); + using BlockBodiesMessage deserializedMessage = serializer.Deserialize(buffer); foreach (BlockBody? body in deserializedMessage.Bodies.Bodies) { if (body is null) continue; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageTests.cs index a5fb020fe45..d07fd9e9bf1 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/BlockBodiesMessageTests.cs @@ -13,14 +13,14 @@ public class BlockBodiesMessageTests [Test] public void Ctor_with_nulls() { - var message = new BlockBodiesMessage(new[] { Build.A.Block.TestObject, null, Build.A.Block.TestObject }); + using BlockBodiesMessage message = new([Build.A.Block.TestObject, null, Build.A.Block.TestObject]); Assert.That(message.Bodies.Bodies.Length, Is.EqualTo(3)); } [Test] public void To_string() { - BlockBodiesMessage newBlockMessage = new(); + using BlockBodiesMessage newBlockMessage = new(); _ = newBlockMessage.ToString(); } } 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 be06db030b0..d16bf1020df 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 @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages; @@ -15,8 +17,8 @@ public class BlockHeadersMessageSerializerTests [Test] public void Roundtrip() { - BlockHeadersMessage message = new(); - message.BlockHeaders = new[] { 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); @@ -24,8 +26,8 @@ public void Roundtrip() Assert.That(expectedBytes.ToHexString(), Is.EqualTo(bytes.ToHexString()), "bytes"); - BlockHeadersMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.BlockHeaders.Length, Is.EqualTo(message.BlockHeaders.Length), "length"); + 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); @@ -34,14 +36,14 @@ public void Roundtrip() [Test] public void Roundtrip_nulls() { - BlockHeadersMessage message = new(); - message.BlockHeaders = new[] { Build.A.BlockHeader.TestObject, null }; + using BlockHeadersMessage message = new(); + message.BlockHeaders = new ArrayPoolList(2) { Build.A.BlockHeader.TestObject, null }; BlockHeadersMessageSerializer serializer = new(); byte[] bytes = serializer.Serialize(message); - BlockHeadersMessage deserialized = serializer.Deserialize(bytes); - Assert.That(deserialized.BlockHeaders.Length, Is.EqualTo(message.BlockHeaders.Length), "length"); + 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]); @@ -55,8 +57,8 @@ public void Can_decode_249_bloom() // f9 01 02 81 7f 0 0 0 ... 0 // 249 -> 258 -> 129 127 0 0 0 ... 0 (strange?) BlockHeadersMessageSerializer serializer = new(); - BlockHeadersMessage message = serializer.Deserialize(rlp.Bytes); - Assert.That(message.BlockHeaders.Length, Is.EqualTo(8)); + using BlockHeadersMessage message = serializer.Deserialize(rlp.Bytes); + Assert.That(message.BlockHeaders.Count, Is.EqualTo(8)); } [Test] @@ -74,7 +76,7 @@ public void Throws_on_invalid_goerli_headers() [Test] public void To_string() { - BlockHeadersMessage newBlockMessage = new(); + using BlockHeadersMessage newBlockMessage = new(); _ = newBlockMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs index e53a05b514b..f1874f6e0b4 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs @@ -14,6 +14,7 @@ using Nethermind.Consensus; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; @@ -180,7 +181,7 @@ public void Cannot_broadcast_a_block_without_total_difficulty_but_can_hint() [Test] public void Get_headers_from_genesis() { - var msg = new GetBlockHeadersMessage(); + using GetBlockHeadersMessage msg = new(); msg.StartBlockHash = TestItem.KeccakA; msg.MaxHeaders = 3; msg.Skip = 1; @@ -217,11 +218,11 @@ public void Get_headers_when_blocks_are_missing_at_the_end() headers[2] = Build.A.BlockHeader.TestObject; _syncManager.FindHash(100).Returns(TestItem.KeccakA); - _syncManager.FindHeaders(TestItem.KeccakA, 5, 1, true).Returns(headers); + _syncManager.FindHeaders(TestItem.KeccakA, 5, 1, true).Returns(headers.ToPooledList()); _syncManager.Head.Returns(_genesisBlock.Header); _syncManager.Genesis.Returns(_genesisBlock.Header); - var msg = new GetBlockHeadersMessage(); + using GetBlockHeadersMessage msg = new(); msg.StartBlockNumber = 100; msg.MaxHeaders = 5; msg.Skip = 1; @@ -230,7 +231,7 @@ public void Get_headers_when_blocks_are_missing_at_the_end() HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth62MessageCode.GetBlockHeaders); - _session.Received().DeliverMessage(Arg.Is(bhm => bhm.BlockHeaders.Length == 3)); + _session.Received().DeliverMessage(Arg.Is(bhm => bhm.BlockHeaders.Count == 3)); _syncManager.Received().FindHash(100); } @@ -253,12 +254,12 @@ public void Get_headers_when_blocks_are_missing_in_the_middle() _syncManager.FindHash(100).Returns(TestItem.KeccakA); _syncManager.FindHeaders(TestItem.KeccakA, 5, 1, true) - .Returns(headers); + .Returns(headers.ToPooledList()); _syncManager.Head.Returns(_genesisBlock.Header); _syncManager.Genesis.Returns(_genesisBlock.Header); - var msg = new GetBlockHeadersMessage(); + using GetBlockHeadersMessage msg = new(); msg.StartBlockNumber = 100; msg.MaxHeaders = 5; msg.Skip = 1; @@ -267,14 +268,14 @@ public void Get_headers_when_blocks_are_missing_in_the_middle() HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth62MessageCode.GetBlockHeaders); - _session.Received().DeliverMessage(Arg.Is(bhm => bhm.BlockHeaders.Length == 5)); + _session.Received().DeliverMessage(Arg.Is(bhm => bhm.BlockHeaders.Count == 5)); _syncManager.Received().FindHash(100); } [Test] public void Can_handle_new_block_message() { - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = Build.A.Block.WithParent(_genesisBlock).TestObject; newBlockMessage.TotalDifficulty = _genesisBlock.Difficulty + newBlockMessage.Block.Difficulty; @@ -289,7 +290,7 @@ public void Can_handle_new_block_message() [Test] public void Should_disconnect_peer_sending_new_block_message_in_PoS() { - NewBlockMessage newBlockMessage = new NewBlockMessage(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = Build.A.Block.WithParent(_genesisBlock).TestObject; newBlockMessage.TotalDifficulty = _genesisBlock.Difficulty + newBlockMessage.Block.Difficulty; @@ -304,7 +305,7 @@ public void Should_disconnect_peer_sending_new_block_message_in_PoS() [Test] public void Throws_if_adding_new_block_fails() { - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = Build.A.Block.WithParent(_genesisBlock).TestObject; newBlockMessage.TotalDifficulty = _genesisBlock.Difficulty + newBlockMessage.Block.Difficulty; @@ -322,7 +323,7 @@ public void Throws_if_adding_new_block_fails() [Test] public void Can_handle_new_block_hashes() { - NewBlockHashesMessage msg = new((Keccak.Zero, 1), (Keccak.Zero, 2)); + using NewBlockHashesMessage msg = new((Keccak.Zero, 1), (Keccak.Zero, 2)); HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth62MessageCode.NewBlockHashes); } @@ -330,7 +331,7 @@ public void Can_handle_new_block_hashes() [Test] public void Should_disconnect_peer_sending_new_block_hashes_in_PoS() { - NewBlockHashesMessage msg = new NewBlockHashesMessage((Keccak.Zero, 1), (Keccak.Zero, 2)); + using NewBlockHashesMessage msg = new((Keccak.Zero, 1), (Keccak.Zero, 2)); _gossipPolicy.ShouldDisconnectGossipingNodes.Returns(true); @@ -343,7 +344,7 @@ public void Should_disconnect_peer_sending_new_block_hashes_in_PoS() [Test] public void Can_handle_get_block_bodies() { - GetBlockBodiesMessage msg = new(new[] { Keccak.Zero, TestItem.KeccakA }); + using GetBlockBodiesMessage msg = new(new[] { Keccak.Zero, TestItem.KeccakA }); HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth62MessageCode.GetBlockBodies); @@ -369,7 +370,7 @@ public void Should_truncate_array_when_too_many_body(int availableBody, int expe _syncManager.Find(blocks[^1].Hash).Returns(blocks[^1]); } - GetBlockBodiesMessage msg = new(blocks.Select(block => block.Hash).ToArray()); + using GetBlockBodiesMessage msg = new(blocks.Select(block => block.Hash).ToArray()); BlockBodiesMessage response = null; _session.When(session => session.DeliverMessage(Arg.Any())).Do((call) => response = (BlockBodiesMessage)call[0]); @@ -384,13 +385,14 @@ public void Should_truncate_array_when_too_many_body(int availableBody, int expe { responseBody.Should().NotBeNull(); } + response.Dispose(); } [Test] public void Can_handle_transactions([Values(true, false)] bool canGossipTransactions) { _txGossipPolicy.ShouldListenToGossipedTransactions.Returns(canGossipTransactions); - TransactionsMessage msg = new(new List(Build.A.Transaction.SignedAndResolved().TestObjectNTimes(3))); + using TransactionsMessage msg = new(Build.A.Transaction.SignedAndResolved().TestObjectNTimes(3).ToPooledList()); HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth62MessageCode.Transactions); @@ -400,7 +402,7 @@ public void Can_handle_transactions([Values(true, false)] bool canGossipTransact [Test] public void Can_handle_transactions_without_filtering() { - TransactionsMessage msg = new(new List(Build.A.Transaction.SignedAndResolved().TestObjectNTimes(3))); + using TransactionsMessage msg = new(Build.A.Transaction.SignedAndResolved().TestObjectNTimes(3).ToPooledList()); _handler.DisableTxFiltering(); HandleIncomingStatusMessage(); @@ -410,11 +412,11 @@ public void Can_handle_transactions_without_filtering() [Test] public async Task Can_LimitGetBlockBodiesRequestSize() { - BlockBodiesMessage msg = new(Build.A.Block.TestObjectNTimes(3)); + using BlockBodiesMessage msg = new(Build.A.Block.TestObjectNTimes(3)); Transaction signedTransaction = Build.A.Transaction.SignedAndResolved().TestObject; Block largerBlock = Build.A.Block.WithTransactions(Enumerable.Repeat(signedTransaction, 1000).ToArray()).TestObject; - BlockBodiesMessage largeMsg = new(Enumerable.Repeat(largerBlock, 100).ToArray()); + using BlockBodiesMessage largeMsg = new(Enumerable.Repeat(largerBlock, 100).ToArray()); List requests = Enumerable.Repeat(Keccak.Zero, 1000).ToList(); GetBlockBodiesMessage? getMsg = null; @@ -441,12 +443,13 @@ public async Task Can_LimitGetBlockBodiesRequestSize() await getTask; Assert.That(getMsg.BlockHashes.Count, Is.EqualTo(4)); + getMsg.Dispose(); } [Test] public void Can_handle_block_bodies() { - BlockBodiesMessage msg = new(Build.A.Block.TestObjectNTimes(3)); + using BlockBodiesMessage msg = new(Build.A.Block.TestObjectNTimes(3)); HandleIncomingStatusMessage(); ((ISyncPeer)_handler).GetBlockBodies(new List(new[] { Keccak.Zero }), CancellationToken.None); @@ -465,7 +468,7 @@ public async Task Get_block_bodies_returns_immediately_when_empty_hash_list() [Test] public void Throws_when_receiving_a_bodies_message_that_has_not_been_requested() { - BlockBodiesMessage msg = new(Build.A.Block.TestObjectNTimes(3)); + using BlockBodiesMessage msg = new(Build.A.Block.TestObjectNTimes(3)); HandleIncomingStatusMessage(); Assert.Throws(() => HandleZeroMessage(msg, Eth62MessageCode.BlockBodies)); @@ -474,7 +477,7 @@ public void Throws_when_receiving_a_bodies_message_that_has_not_been_requested() [Test] public void Can_handle_headers() { - BlockHeadersMessage msg = new(Build.A.BlockHeader.TestObjectNTimes(3)); + using BlockHeadersMessage msg = new(Build.A.BlockHeader.TestObjectNTimes(3).ToPooledList()); ((ISyncPeer)_handler).GetBlockHeaders(1, 1, 1, CancellationToken.None); HandleIncomingStatusMessage(); @@ -484,7 +487,7 @@ public void Can_handle_headers() [Test] public void Throws_when_receiving_a_headers_message_that_has_not_been_requested() { - BlockHeadersMessage msg = new(Build.A.BlockHeader.TestObjectNTimes(3)); + using BlockHeadersMessage msg = new(Build.A.BlockHeader.TestObjectNTimes(3).ToPooledList()); HandleIncomingStatusMessage(); Assert.Throws(() => HandleZeroMessage(msg, Eth62MessageCode.BlockHeaders)); @@ -587,7 +590,7 @@ private void HandleZeroMessage(T msg, int messageCode) where T : MessageBase [Test] public void Throws_if_new_block_message_received_before_status() { - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = Build.A.Block.WithParent(_genesisBlock).TestObject; newBlockMessage.TotalDifficulty = _genesisBlock.Difficulty + newBlockMessage.Block.Difficulty; 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 a5892085a6c..c292b37c091 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 @@ -15,13 +15,13 @@ public class GetBlockBodiesMessageSerializerTests public void Roundtrip() { GetBlockBodiesMessageSerializer serializer = new(); - GetBlockBodiesMessage message = new(Keccak.OfAnEmptySequenceRlp, Keccak.Zero, Keccak.EmptyTreeHash); + 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"); - GetBlockBodiesMessage deserialized = serializer.Deserialize(bytes); + 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++) { @@ -34,7 +34,7 @@ public void Roundtrip() [Test] public void To_string() { - GetBlockBodiesMessage newBlockMessage = new(); + 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 b4eead1014b..42279051591 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 @@ -14,7 +14,7 @@ public class GetBlockHeadersMessageSerializerTests [Test] public void Roundtrip_hash() { - GetBlockHeadersMessage message = new(); + using GetBlockHeadersMessage message = new(); message.MaxHeaders = 1; message.Skip = 2; message.Reverse = 1; @@ -25,7 +25,7 @@ public void Roundtrip_hash() Assert.True(Bytes.AreEqual(bytes, expectedBytes), "bytes"); - GetBlockHeadersMessage deserialized = serializer.Deserialize(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)}"); @@ -37,7 +37,7 @@ public void Roundtrip_hash() [Test] public void Roundtrip_number() { - GetBlockHeadersMessage message = new(); + using GetBlockHeadersMessage message = new(); message.MaxHeaders = 1; message.Skip = 2; message.Reverse = 1; @@ -48,7 +48,7 @@ public void Roundtrip_number() Assert.True(Bytes.AreEqual(bytes, expectedBytes), "bytes"); - GetBlockHeadersMessage deserialized = serializer.Deserialize(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)}"); @@ -60,7 +60,7 @@ public void Roundtrip_number() [Test] public void Roundtrip_zero() { - GetBlockHeadersMessage message = new(); + using GetBlockHeadersMessage message = new(); message.MaxHeaders = 1; message.Skip = 2; message.Reverse = 0; @@ -72,7 +72,7 @@ public void Roundtrip_zero() Assert.That(bytes, Is.EqualTo(expectedBytes), "bytes"); - GetBlockHeadersMessage deserialized = serializer.Deserialize(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)}"); @@ -84,7 +84,7 @@ public void Roundtrip_zero() [Test] public void To_string() { - GetBlockHeadersMessage newBlockMessage = new(); + using GetBlockHeadersMessage newBlockMessage = new(); _ = newBlockMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockHashesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockHashesMessageSerializerTests.cs index 4967fafbc6f..46ba11b35f3 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockHashesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockHashesMessageSerializerTests.cs @@ -13,7 +13,7 @@ public class NewBlockHashesMessageSerializerTests [Test] public void Roundtrip() { - NewBlockHashesMessage message = new((Keccak.Compute("1"), 1), (Keccak.Compute("2"), 2)); + using NewBlockHashesMessage message = new((Keccak.Compute("1"), 1), (Keccak.Compute("2"), 2)); var serializer = new NewBlockHashesMessageSerializer(); SerializerTester.TestZero(serializer, message); } @@ -21,7 +21,7 @@ public void Roundtrip() [Test] public void To_string() { - NewBlockHashesMessage statusMessage = new(); + using NewBlockHashesMessage statusMessage = new(); _ = statusMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockMessageSerializerTests.cs index 8fb5b925060..5984cce3f4f 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/NewBlockMessageSerializerTests.cs @@ -14,7 +14,7 @@ public class NewBlockMessageSerializerTests [Test] public void Roundtrip() { - NewBlockMessage message = new(); + using NewBlockMessage message = new(); message.TotalDifficulty = 131200; message.Block = Build.A.Block.Genesis.TestObject; NewBlockMessageSerializer serializer = new(); @@ -37,7 +37,7 @@ public void Roundtrip2() transaction.SenderAddress = null; } - NewBlockMessage message = new(); + using NewBlockMessage message = new(); message.Block = block; NewBlockMessageSerializer serializer = new(); @@ -47,7 +47,7 @@ public void Roundtrip2() [Test] public void To_string() { - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); _ = newBlockMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/StatusMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/StatusMessageSerializerTests.cs index e37c3cded2f..5923a6d94d1 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/StatusMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/StatusMessageSerializerTests.cs @@ -16,7 +16,7 @@ public class StatusMessageSerializerTests [Test] public void Roundtrip() { - StatusMessage statusMessage = new(); + using StatusMessage statusMessage = new(); statusMessage.ProtocolVersion = 63; statusMessage.BestHash = Keccak.Compute("1"); statusMessage.GenesisHash = Keccak.Compute("0"); @@ -30,7 +30,7 @@ public void Roundtrip() [Test] public void Roundtrip_empty_status() { - StatusMessage statusMessage = new(); + using StatusMessage statusMessage = new(); StatusMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, statusMessage); } @@ -38,7 +38,7 @@ public void Roundtrip_empty_status() [Test] public void Roundtrip_with_fork_id_next_is_zero() { - StatusMessage statusMessage = new(); + using StatusMessage statusMessage = new(); statusMessage.ProtocolVersion = 63; statusMessage.BestHash = Keccak.Compute("1"); statusMessage.GenesisHash = Keccak.Compute("0"); @@ -53,7 +53,7 @@ public void Roundtrip_with_fork_id_next_is_zero() [Test] public void Roundtrip_with_fork_id_next_is_max() { - StatusMessage statusMessage = new(); + using StatusMessage statusMessage = new(); statusMessage.ProtocolVersion = 63; statusMessage.BestHash = Keccak.Compute("1"); statusMessage.GenesisHash = Keccak.Compute("0"); @@ -72,7 +72,7 @@ public void Can_serialize_fork_id_properly(string forkHash, ulong? next, string { next ??= BinaryPrimitives.ReadUInt32BigEndian(Bytes.FromHexString("baddcafe")); StatusMessageSerializer serializer = new(); - StatusMessage message = new(); + using StatusMessage message = new(); message.ForkId = new ForkId(Bytes.ReadEthUInt32(Bytes.FromHexString(forkHash)), next.Value); serializer.Serialize(message).ToHexString().Should().EndWith(expected); } @@ -91,7 +91,7 @@ public void Can_deserialize_eth_64(string msgHex) { byte[] bytes = Bytes.FromHexString(msgHex); StatusMessageSerializer serializer = new(); - StatusMessage message = serializer.Deserialize(bytes); + using StatusMessage message = serializer.Deserialize(bytes); byte[] serialized = serializer.Serialize(message); serialized.Should().BeEquivalentTo(bytes); Assert.That(message.ProtocolVersion, Is.EqualTo(64), "ProtocolVersion"); @@ -112,7 +112,7 @@ public void Can_deserialize_own_eth_64(string msgHex) { byte[] bytes = Bytes.FromHexString(msgHex.Replace(" ", string.Empty)); StatusMessageSerializer serializer = new(); - StatusMessage message = serializer.Deserialize(bytes); + using StatusMessage message = serializer.Deserialize(bytes); byte[] serialized = serializer.Serialize(message); serialized.Should().BeEquivalentTo(bytes); Assert.That(message.ProtocolVersion, Is.EqualTo(64), "ProtocolVersion"); @@ -123,7 +123,7 @@ public void Can_deserialize_example_from_ethereumJ() { byte[] bytes = Bytes.FromHexString("f84927808425c60144a0832056d3c93ff2739ace7199952e5365aa29f18805be05634c4db125c5340216a0955f36d073ccb026b78ab3424c15cf966a7563aa270413859f78702b9e8e22cb"); StatusMessageSerializer serializer = new(); - StatusMessage message = serializer.Deserialize(bytes); + using StatusMessage message = serializer.Deserialize(bytes); Assert.That(message.ProtocolVersion, Is.EqualTo(39), "ProtocolVersion"); Assert.That((int)message.TotalDifficulty, Is.EqualTo(0x25c60144), "Difficulty"); @@ -137,7 +137,7 @@ public void Can_deserialize_example_from_ethereumJ() [Test] public void To_string() { - StatusMessage statusMessage = new(); + using StatusMessage statusMessage = new(); _ = statusMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/TransactionsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/TransactionsMessageSerializerTests.cs index 9c58c001545..1003b9d29e3 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/TransactionsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/TransactionsMessageSerializerTests.cs @@ -5,7 +5,9 @@ using System.Linq; using DotNetty.Buffers; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; using Nethermind.Logging; @@ -21,47 +23,49 @@ public class TransactionsMessageSerializerTests public void Roundtrip_init() { TransactionsMessageSerializer serializer = new(); - Transaction transaction = new(); - transaction.GasLimit = 10; - transaction.GasPrice = 100; - transaction.Data = new byte[] { 4, 5, 6 }; - transaction.Nonce = 1000; - transaction.Signature = new Signature(1, 2, 27); - transaction.To = null; - transaction.Value = 10000; + Transaction transaction = new() + { + GasLimit = 10, + GasPrice = 100, + Data = new byte[] { 4, 5, 6 }, + Nonce = 1000, + Signature = new Signature(1, 2, 27), + To = null, + Value = 10000 + }; transaction.Hash = transaction.CalculateHash(); transaction.SenderAddress = null; - TransactionsMessage message = new(new[] { transaction, transaction }); - SerializerTester.TestZero(serializer, message, - "e2d08203e8640a80822710830405061b0102d08203e8640a80822710830405061b0102"); + using TransactionsMessage message = new(new ArrayPoolList(2) { transaction, transaction }); + SerializerTester.TestZero(serializer, message, "e2d08203e8640a80822710830405061b0102d08203e8640a80822710830405061b0102"); } [Test] public void Roundtrip_call() { TransactionsMessageSerializer serializer = new(); - Transaction transaction = new(); - transaction.Data = new byte[] { 1, 2, 3 }; - transaction.GasLimit = 10; - transaction.GasPrice = 100; - transaction.Nonce = 1000; - transaction.Signature = new Signature(1, 2, 27); - transaction.To = TestItem.AddressA; - transaction.Value = 10000; + Transaction transaction = new() + { + Data = new byte[] { 1, 2, 3 }, + GasLimit = 10, + GasPrice = 100, + Nonce = 1000, + Signature = new Signature(1, 2, 27), + To = TestItem.AddressA, + Value = 10000 + }; transaction.Hash = transaction.CalculateHash(); transaction.SenderAddress = null; - TransactionsMessage message = new(new[] { transaction, transaction }); - SerializerTester.TestZero(serializer, message, - "f84ae48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102e48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102"); + using TransactionsMessage message = new(new ArrayPoolList(2) { transaction, transaction }); + SerializerTester.TestZero(serializer, message, "f84ae48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102e48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102"); } [Test] public void Can_handle_empty() { TransactionsMessageSerializer serializer = new(); - TransactionsMessage message = new(new Transaction[] { }); + using TransactionsMessage message = new(ArrayPoolList.Empty()); SerializerTester.TestZero(serializer, message); } @@ -69,20 +73,24 @@ public void Can_handle_empty() [Test] public void To_string_empty() { - TransactionsMessage message = new(new Transaction[] { }); - TransactionsMessage message2 = new(null); + using TransactionsMessage message = new(ArrayPoolList.Empty()); + using TransactionsMessage message2 = new(null); _ = message.ToString(); _ = message2.ToString(); } [TestCaseSource(nameof(GetTransactionMessages))] - public void Should_pass_roundtrip(TransactionsMessage transactionsMessage) => SerializerTester.TestZero( - new TransactionsMessageSerializer(), - transactionsMessage, - additionallyExcluding: (o) => - o.For(msg => msg.Transactions) - .Exclude(tx => tx.SenderAddress)); + public void Should_pass_roundtrip(TransactionsMessage transactionsMessage) + { + SerializerTester.TestZero( + new TransactionsMessageSerializer(), + transactionsMessage, + additionallyExcluding: (o) => + o.For(msg => msg.Transactions) + .Exclude(tx => tx.SenderAddress)); + transactionsMessage.Dispose(); + } [TestCaseSource(nameof(GetTransactionMessages))] public void Should_contain_network_form_tx_wrapper(TransactionsMessage transactionsMessage) @@ -90,7 +98,8 @@ public void Should_contain_network_form_tx_wrapper(TransactionsMessage transacti IByteBuffer buffer = PooledByteBufferAllocator.Default.Buffer(1024 * 130); TransactionsMessageSerializer serializer = new(); serializer.Serialize(buffer, transactionsMessage); - TransactionsMessage deserializedMessage = serializer.Deserialize(buffer); + transactionsMessage.Dispose(); + using TransactionsMessage deserializedMessage = serializer.Deserialize(buffer); foreach (Transaction? tx in deserializedMessage.Transactions.Where(tx => tx.SupportsBlobs)) { Assert.That(tx.NetworkWrapper, Is.Not.Null); @@ -103,7 +112,7 @@ public void Should_contain_network_form_tx_wrapper(TransactionsMessage transacti } private static IEnumerable GetTransactionMessages() => - GetTransactions().Select(txs => new TransactionsMessage(txs.ToList())); + GetTransactions().Select(txs => new TransactionsMessage(txs.ToPooledList(3))); public static IEnumerable> GetTransactions() { diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs index 1cb0699c428..d6e92efeaa8 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs @@ -23,7 +23,7 @@ public void Roundtrip() Transaction a = Build.A.Transaction.TestObject; Transaction b = Build.A.Transaction.TestObject; Block block = Build.A.Block.WithTransactions(a, b).TestObject; - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = block; NewBlockMessageSerializer serializer = new(); @@ -48,7 +48,7 @@ public void Roundtrip2() Transaction a = Build.A.Transaction.TestObject; Transaction b = Build.A.Transaction.TestObject; Block block = Build.A.Block.WithTransactions(a, b).TestObject; - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = block; NewBlockMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs index 8db07b66b65..4e8d247533d 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs @@ -7,7 +7,9 @@ using FluentAssertions; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; using Nethermind.Logging; @@ -38,11 +40,11 @@ public async Task Can_request_and_handle_receipts() Enumerable.Repeat(Build.A.Receipt.WithAllFieldsFilled.TestObject, 100).ToArray(), 1000).ToArray(); // TxReceipt[1000][100] - ReceiptsMessage receiptsMsg = new(receipts); + using ReceiptsMessage receiptsMsg = new(receipts.ToPooledList()); Packet receiptsPacket = new("eth", Eth63MessageCode.Receipts, ctx._receiptMessageSerializer.Serialize(receiptsMsg)); - Task task = ctx.ProtocolHandler.GetReceipts( + Task> task = ctx.ProtocolHandler.GetReceipts( Enumerable.Repeat(Keccak.Zero, 1000).ToArray(), CancellationToken.None); @@ -59,11 +61,11 @@ public async Task Limit_receipt_request() TxReceipt[] oneBlockReceipt = Enumerable.Repeat(Build.A.Receipt.WithAllFieldsFilled.TestObject, 100).ToArray(); Packet smallReceiptsPacket = new("eth", Eth63MessageCode.Receipts, ctx._receiptMessageSerializer.Serialize( - new(Enumerable.Repeat(oneBlockReceipt, 10).ToArray()) + new(RepeatPooled(oneBlockReceipt, 10)) )); Packet largeReceiptsPacket = new("eth", Eth63MessageCode.Receipts, ctx._receiptMessageSerializer.Serialize( - new(Enumerable.Repeat(oneBlockReceipt, 1000).ToArray()) + new(RepeatPooled(oneBlockReceipt, 1000)) )); GetReceiptsMessage? receiptsMessage = null; @@ -72,8 +74,8 @@ public async Task Limit_receipt_request() .When(session => session.DeliverMessage(Arg.Any())) .Do((info => receiptsMessage = (GetReceiptsMessage)info[0])); - Task receiptsTask = ctx.ProtocolHandler.GetReceipts( - Enumerable.Repeat(Keccak.Zero, 1000).ToArray(), + Task> receiptsTask = ctx.ProtocolHandler.GetReceipts( + RepeatPooled(Keccak.Zero, 1000), CancellationToken.None); ctx.ProtocolHandler.HandleMessage(smallReceiptsPacket); @@ -82,7 +84,7 @@ public async Task Limit_receipt_request() Assert.That(receiptsMessage?.Hashes?.Count, Is.EqualTo(8)); receiptsTask = ctx.ProtocolHandler.GetReceipts( - Enumerable.Repeat(Keccak.Zero, 1000).ToArray(), + RepeatPooled(Keccak.Zero, 1000), CancellationToken.None); ctx.ProtocolHandler.HandleMessage(largeReceiptsPacket); @@ -92,21 +94,24 @@ public async Task Limit_receipt_request() // Back to 10 receiptsTask = ctx.ProtocolHandler.GetReceipts( - Enumerable.Repeat(Keccak.Zero, 1000).ToArray(), + RepeatPooled(Keccak.Zero, 1000), CancellationToken.None); ctx.ProtocolHandler.HandleMessage(smallReceiptsPacket); await receiptsTask; Assert.That(receiptsMessage?.Hashes?.Count, Is.EqualTo(8)); + receiptsMessage.Dispose(); } + private ArrayPoolList RepeatPooled(T txReceipts, int count) => Enumerable.Repeat(txReceipts, count).ToPooledList(count); + [Test] public void Will_not_serve_receipts_requests_above_512() { Context ctx = new(); - GetReceiptsMessage getReceiptsMessage = new( - Enumerable.Repeat(Keccak.Zero, 513).ToArray()); + using GetReceiptsMessage getReceiptsMessage = new( + RepeatPooled(Keccak.Zero, 513)); Packet getReceiptsPacket = new("eth", Eth63MessageCode.GetReceipts, ctx._getReceiptMessageSerializer.Serialize(getReceiptsMessage)); @@ -121,13 +126,13 @@ public void Will_not_send_messages_larger_than_2MB() ctx.SyncServer.GetReceipts(Arg.Any()).Returns( Enumerable.Repeat(Build.A.Receipt.WithAllFieldsFilled.TestObject, 512).ToArray()); - GetReceiptsMessage getReceiptsMessage = new( - Enumerable.Repeat(Keccak.Zero, 512).ToArray()); + using GetReceiptsMessage getReceiptsMessage = new( + RepeatPooled(Keccak.Zero, 512)); Packet getReceiptsPacket = new("eth", Eth63MessageCode.GetReceipts, ctx._getReceiptMessageSerializer.Serialize(getReceiptsMessage)); ctx.ProtocolHandler.HandleMessage(getReceiptsPacket); - ctx.Session.Received().DeliverMessage(Arg.Is(r => r.TxReceipts.Length == 14)); + ctx.Session.Received().DeliverMessage(Arg.Is(r => r.TxReceipts.Count == 14)); } private class Context diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageSerializerTests.cs index 2f83e61f55c..dca2f73e1b2 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages; using NUnit.Framework; @@ -13,7 +14,7 @@ public class GetNodeDataMessageSerializerTests { private static void Test(Hash256[] keys) { - GetNodeDataMessage message = new(keys); + using GetNodeDataMessage message = new(keys.ToPooledList()); GetNodeDataMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, message); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageTests.cs index 1014057ddd7..694d2daba2f 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetNodeDataMessageTests.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages; using NUnit.Framework; @@ -16,8 +18,8 @@ public class GetNodeDataMessageTests [Test] public void Sets_values_from_constructor_argument() { - Hash256[] keys = { TestItem.KeccakA, TestItem.KeccakB }; - GetNodeDataMessage message = new(keys); + ArrayPoolList keys = new(2) { TestItem.KeccakA, TestItem.KeccakB }; + using GetNodeDataMessage message = new(keys); Assert.That(message.Hashes, Is.SameAs(keys)); } @@ -30,7 +32,7 @@ public void Throws_on_null_argument() [Test] public void To_string() { - GetNodeDataMessage statusMessage = new(new List()); + using GetNodeDataMessage statusMessage = new(ArrayPoolList.Empty()); _ = statusMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageSerializerTests.cs index 378ea5a07b3..d044c22e9f6 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageSerializerTests.cs @@ -14,10 +14,10 @@ public class GetReceiptsMessageSerializerTests { private static void Test(Hash256[] keys) { - GetReceiptsMessage message = new(keys); + using GetReceiptsMessage message = new(keys.ToPooledList()); GetReceiptsMessageSerializer serializer = new(); var serialized = serializer.Serialize(message); - GetReceiptsMessage deserialized = serializer.Deserialize(serialized); + using GetReceiptsMessage deserialized = serializer.Deserialize(serialized); Assert.That(deserialized.Hashes.Count, Is.EqualTo(keys.Length), "count"); for (int i = 0; i < keys.Length; i++) Assert.That(deserialized.Hashes[i], Is.EqualTo(keys[i]), $"blockHashes[{i}]"); @@ -45,11 +45,11 @@ public void Roundtrip_example_from_network() GetReceiptsMessageSerializer serializer = new(); - GetReceiptsMessage message = serializer.Deserialize(bytes1); + using GetReceiptsMessage message = serializer.Deserialize(bytes1); byte[] serialized = serializer.Serialize(message); Assert.That(serialized, Is.EqualTo(bytes1)); - GetReceiptsMessage message2 = serializer.Deserialize(bytes2); + using GetReceiptsMessage message2 = serializer.Deserialize(bytes2); byte[] serialized2 = serializer.Serialize(message2); Assert.That(serialized2, Is.EqualTo(bytes2)); } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageTests.cs index 051c8ce6087..f435e2cab15 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/GetReceiptsMessageTests.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages; using NUnit.Framework; @@ -16,8 +18,8 @@ public class GetReceiptsMessageTests [Test] public void Sets_values_from_contructor_argument() { - Hash256[] hashes = { TestItem.KeccakA, TestItem.KeccakB }; - GetReceiptsMessage message = new(hashes); + ArrayPoolList hashes = new(2) { TestItem.KeccakA, TestItem.KeccakB }; + using GetReceiptsMessage message = new(hashes); Assert.That(message.Hashes, Is.SameAs(hashes)); } @@ -30,7 +32,7 @@ public void Throws_on_null_argument() [Test] public void To_string() { - GetReceiptsMessage statusMessage = new(new List()); + using GetReceiptsMessage statusMessage = new(ArrayPoolList.Empty()); _ = statusMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageSeralizerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageSeralizerTests.cs index d0878927523..c8ac5fc56e7 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageSeralizerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageSeralizerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages; using NUnit.Framework; @@ -11,9 +12,9 @@ namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V63 [Parallelizable(ParallelScope.All)] public class NodeDataMessageSerializerTests { - private static void Test(byte[][] data) + private static void Test(IOwnedReadOnlyList data) { - NodeDataMessage message = new(data); + using NodeDataMessage message = new(data); NodeDataMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, message); @@ -22,14 +23,14 @@ private static void Test(byte[][] data) [Test] public void Roundtrip() { - byte[][] data = { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; + ArrayPoolList data = new(3) { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; Test(data); } [Test] public void Zero_roundtrip() { - byte[][] data = { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; + ArrayPoolList data = new(3) { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; Test(data); } @@ -42,7 +43,7 @@ public void Roundtrip_with_null_top_level() [Test] public void Roundtrip_with_nulls() { - byte[][] data = { TestItem.KeccakA.BytesToArray(), Array.Empty(), TestItem.KeccakC.BytesToArray() }; + ArrayPoolList data = new(3) { TestItem.KeccakA.BytesToArray(), Array.Empty(), TestItem.KeccakC.BytesToArray() }; Test(data); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageTests.cs index 5bbfa6e6ab0..800c052ebc1 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/NodeDataMessageTests.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages; using NUnit.Framework; @@ -12,30 +13,30 @@ public class NodeDataMessageTests [Test] public void Accepts_nulls_inside() { - byte[][] data = { new byte[] { 1, 2, 3 }, null }; - NodeDataMessage message = new(data); + ArrayPoolList data = new(2) { new byte[] { 1, 2, 3 }, null }; + using NodeDataMessage message = new(data); Assert.That(message.Data, Is.SameAs(data)); } [Test] public void Accepts_nulls_top_level() { - NodeDataMessage message = new(null); - Assert.That(message.Data.Length, Is.EqualTo(0)); + using NodeDataMessage message = new(null); + Assert.That(message.Data.Count, Is.EqualTo(0)); } [Test] public void Sets_values_from_constructor_argument() { - byte[][] data = { new byte[] { 1, 2, 3 }, new byte[] { 4, 5, 6 } }; - NodeDataMessage message = new(data); + ArrayPoolList data = new(2) { new byte[] { 1, 2, 3 }, new byte[] { 4, 5, 6 } }; + using NodeDataMessage message = new(data); Assert.That(message.Data, Is.SameAs(data)); } [Test] public void To_string() { - NodeDataMessage statusMessage = new(new byte[][] { }); + using NodeDataMessage statusMessage = new(ArrayPoolList.Empty()); _ = statusMessage.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 41265df8fc4..71628a407e2 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 @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Linq; using DotNetty.Buffers; using FluentAssertions; using Nethermind.Blockchain.Receipts; @@ -17,20 +19,20 @@ namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V63 [Parallelizable(ParallelScope.All)] public class ReceiptsMessageSerializerTests { - private static void Test(TxReceipt[][] txReceipts) + private static void Test(TxReceipt[][]? txReceipts) { - ReceiptsMessage message = new(txReceipts); + using ReceiptsMessage message = new(txReceipts?.ToPooledList()); ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); var serialized = serializer.Serialize(message); - ReceiptsMessage deserialized = serializer.Deserialize(serialized); + using ReceiptsMessage deserialized = serializer.Deserialize(serialized); if (txReceipts is null) { - Assert.That(deserialized.TxReceipts.Length, Is.EqualTo(0)); + Assert.That(deserialized.TxReceipts.Count, Is.EqualTo(0)); } else { - Assert.That(deserialized.TxReceipts.Length, Is.EqualTo(txReceipts.Length), "length"); + Assert.That(deserialized.TxReceipts.Count, Is.EqualTo(txReceipts.Length), "length"); for (int i = 0; i < txReceipts.Length; i++) { if (txReceipts[i] is null) @@ -74,14 +76,14 @@ private static void Test(TxReceipt[][] txReceipts) [Test] public void Roundtrip() { - TxReceipt[][] data = { new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject }, new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject } }; + 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() { - TxReceipt[][] data = { new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject }, new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject } }; + 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); @@ -92,7 +94,7 @@ public void Roundtrip_with_IgnoreOutputs() [Test] public void Roundtrip_with_eip658() { - TxReceipt[][] data = { new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject }, new[] { Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(MainnetSpecProvider.ConstantinopleFixBlockNumber).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject } }; + 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); } @@ -105,7 +107,7 @@ public void Roundtrip_with_null_top_level() [Test] public void Roundtrip_with_nulls() { - TxReceipt[][] data = { new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject }, null, new[] { null, Build.A.Receipt.WithAllFieldsFilled.TestObject } }; + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject], null, new[] { null, Build.A.Receipt.WithAllFieldsFilled.TestObject }]; Test(data); } @@ -113,14 +115,15 @@ public void Roundtrip_with_nulls() public void Deserialize_empty() { ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); - serializer.Deserialize(new byte[0]).TxReceipts.Should().HaveCount(0); + 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 = { new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject }, new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject } }; - ReceiptsMessage message = new(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]]; + using ReceiptsMessage message = new(data.ToPooledList()); ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); IByteBuffer buffer = Unpooled.Buffer(serializer.GetLength(message, out int _) + 1); @@ -128,9 +131,9 @@ public void Deserialize_non_empty_but_bytebuffer_starts_with_empty() buffer.ReadByte(); serializer.Serialize(buffer, message); - ReceiptsMessage deserialized = serializer.Deserialize(buffer); + using ReceiptsMessage deserialized = serializer.Deserialize(buffer); - deserialized.TxReceipts.Length.Should().Be(data.Length); + deserialized.TxReceipts.Count.Should().Be(data.Length); } [Test] @@ -138,7 +141,7 @@ public void Roundtrip_mainnet_sample() { byte[] bytes = Bytes.FromHexString("f9012ef9012bf90128a08ccc6709a5df7acef07f97c5681356b6c37cfac15b554aff68e986f57116df2e825208b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0"); ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); - ReceiptsMessage message = serializer.Deserialize(bytes); + using ReceiptsMessage message = serializer.Deserialize(bytes); byte[] serialized = serializer.Serialize(message); Assert.That(serialized, Is.EqualTo(bytes)); } @@ -146,14 +149,14 @@ public void Roundtrip_mainnet_sample() [Test] public void Roundtrip_one_receipt_with_accessList() { - TxReceipt[][] data = { new[] { Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject } }; + TxReceipt[][] data = [[Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject]]; Test(data); } [Test] public void Roundtrip_with_both_txTypes_of_receipt() { - TxReceipt[][] data = { new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).WithTxType(TxType.AccessList).TestObject }, new[] { Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject } }; + 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/P2P/Subprotocols/Eth/V63/ReceiptsMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageTests.cs index 22a7d7e7a58..e6df3adee97 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages; using NUnit.Framework; @@ -13,30 +14,30 @@ public class ReceiptsMessageTests [Test] public void Accepts_nulls_inside() { - TxReceipt[][] data = { new[] { new TxReceipt(), new TxReceipt() }, null }; - ReceiptsMessage message = new(data); + ArrayPoolList data = new(3) { new[] { new TxReceipt(), new TxReceipt() }, null }; + using ReceiptsMessage message = new(data); Assert.That(message.TxReceipts, Is.SameAs(data)); } [Test] public void Accepts_nulls_top_level() { - ReceiptsMessage message = new(null); - Assert.That(message.TxReceipts.Length, Is.EqualTo(0)); + using ReceiptsMessage message = new(null); + Assert.That(message.TxReceipts.Count, Is.EqualTo(0)); } [Test] public void Sets_values_from_constructor_argument() { - TxReceipt[][] data = { new[] { new TxReceipt(), new TxReceipt() }, new[] { new TxReceipt(), new TxReceipt() } }; - ReceiptsMessage message = new(data); + ArrayPoolList data = new(2) { new[] { new TxReceipt(), new TxReceipt() }, new[] { new TxReceipt(), new TxReceipt() } }; + using ReceiptsMessage message = new(data); Assert.That(message.TxReceipts, Is.SameAs(data)); } [Test] public void To_string() { - ReceiptsMessage statusMessage = new(null); + using ReceiptsMessage statusMessage = new(null); _ = statusMessage.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs index 925d105f1a3..869d245cd24 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs @@ -11,6 +11,7 @@ using Nethermind.Consensus; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; @@ -152,7 +153,7 @@ public async Task should_send_requested_PooledTransactions_up_to_MaxPacketSize() x[1] = tx; return true; }); - GetPooledTransactionsMessage request = new(TestItem.Keccaks); + using GetPooledTransactionsMessage request = new(TestItem.Keccaks.ToPooledList()); PooledTransactionsMessage response = await _handler.FulfillPooledTransactionsRequest(request, CancellationToken.None); response.Transactions.Count.Should().Be(numberOfTxsInOneMsg); } @@ -176,7 +177,7 @@ public async Task should_send_single_requested_PooledTransaction_even_if_exceed_ x[1] = tx; return true; }); - GetPooledTransactionsMessage request = new(new Hash256[2048]); + using GetPooledTransactionsMessage request = new(new Hash256[2048].ToPooledList()); PooledTransactionsMessage response = await _handler.FulfillPooledTransactionsRequest(request, CancellationToken.None); response.Transactions.Count.Should().Be(numberOfTxsInOneMsg); } @@ -185,8 +186,7 @@ public async Task should_send_single_requested_PooledTransaction_even_if_exceed_ public void should_handle_NewPooledTransactionHashesMessage([Values(true, false)] bool canGossipTransactions) { _txGossipPolicy.ShouldListenToGossipedTransactions.Returns(canGossipTransactions); - NewPooledTransactionHashesMessage msg = new(new[] { TestItem.KeccakA, TestItem.KeccakB }); - IMessageSerializationService serializationService = Build.A.SerializationService().WithEth65().TestObject; + using NewPooledTransactionHashesMessage msg = new(new[] { TestItem.KeccakA, TestItem.KeccakB }.ToPooledList()); HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth65MessageCode.NewPooledTransactionHashes); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/GetPooledTransactionsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/GetPooledTransactionsMessageSerializerTests.cs index ee8d3bd73f4..bb59494c82c 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/GetPooledTransactionsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/GetPooledTransactionsMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages; using NUnit.Framework; @@ -13,7 +14,7 @@ public class GetPooledTransactionsSerializerTests { private static void Test(Hash256[] keys) { - GetPooledTransactionsMessage message = new(keys); + using GetPooledTransactionsMessage message = new(keys.ToPooledList()); GetPooledTransactionsMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, message); @@ -36,7 +37,7 @@ public void Roundtrip_with_nulls() [Test] public void Empty_to_string() { - GetPooledTransactionsMessage message = new(new Hash256[] { }); + using GetPooledTransactionsMessage message = new(new Hash256[] { }.ToPooledList()); _ = message.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/NewPooledTransactionHashesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/NewPooledTransactionHashesMessageSerializerTests.cs index 3a53c9f1c6e..63eade4e00b 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/NewPooledTransactionHashesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/NewPooledTransactionHashesMessageSerializerTests.cs @@ -1,7 +1,9 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages; using NUnit.Framework; @@ -13,7 +15,7 @@ public class NewPooledTransactionHashesMessageSerializerTests { private static void Test(Hash256[] keys) { - NewPooledTransactionHashesMessage message = new(keys); + using NewPooledTransactionHashesMessage message = new(keys.ToPooledList()); NewPooledTransactionHashesMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, message); @@ -22,22 +24,21 @@ private static void Test(Hash256[] keys) [Test] public void Roundtrip() { - Hash256[] keys = { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; + Hash256[] keys = [TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC]; Test(keys); } [Test] public void Roundtrip_with_nulls() { - Hash256[] keys = { null, TestItem.KeccakA, null, TestItem.KeccakB, null, null }; + Hash256[] keys = [null, TestItem.KeccakA, null, TestItem.KeccakB, null, null]; Test(keys); } [Test] public void Empty_to_string() { - NewPooledTransactionHashesMessage message - = new(new Hash256[] { }); + using NewPooledTransactionHashesMessage message = new(ArrayPoolList.Empty()); _ = message.ToString(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTransactionsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTransactionsMessageSerializerTests.cs index 9c0f815f3a7..5e20a4128e7 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTransactionsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTransactionsMessageSerializerTests.cs @@ -5,7 +5,9 @@ using System.Linq; using DotNetty.Buffers; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; using Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages; @@ -21,47 +23,49 @@ public class PooledTransactionsMessageSerializerTests public void Roundtrip_init() { PooledTransactionsMessageSerializer serializer = new(); - Transaction transaction = new(); - transaction.GasLimit = 10; - transaction.GasPrice = 100; - transaction.Data = new byte[] { 4, 5, 6 }; - transaction.Nonce = 1000; - transaction.Signature = new Signature(1, 2, 27); - transaction.To = null; - transaction.Value = 10000; + Transaction transaction = new() + { + GasLimit = 10, + GasPrice = 100, + Data = new byte[] { 4, 5, 6 }, + Nonce = 1000, + Signature = new Signature(1, 2, 27), + To = null, + Value = 10000 + }; transaction.Hash = transaction.CalculateHash(); transaction.SenderAddress = null; - PooledTransactionsMessage message = new(new[] { transaction, transaction }); - SerializerTester.TestZero(serializer, message, - "e2d08203e8640a80822710830405061b0102d08203e8640a80822710830405061b0102"); + using PooledTransactionsMessage message = new(new ArrayPoolList(2) { transaction, transaction }); + SerializerTester.TestZero(serializer, message, "e2d08203e8640a80822710830405061b0102d08203e8640a80822710830405061b0102"); } [Test] public void Roundtrip_call() { PooledTransactionsMessageSerializer serializer = new(); - Transaction transaction = new(); - transaction.Data = new byte[] { 1, 2, 3 }; - transaction.GasLimit = 10; - transaction.GasPrice = 100; - transaction.Nonce = 1000; - transaction.Signature = new Signature(1, 2, 27); - transaction.To = TestItem.AddressA; - transaction.Value = 10000; + Transaction transaction = new() + { + Data = new byte[] { 1, 2, 3 }, + GasLimit = 10, + GasPrice = 100, + Nonce = 1000, + Signature = new Signature(1, 2, 27), + To = TestItem.AddressA, + Value = 10000 + }; transaction.Hash = transaction.CalculateHash(); transaction.SenderAddress = null; - PooledTransactionsMessage message = new(new[] { transaction, transaction }); - SerializerTester.TestZero(serializer, message, - "f84ae48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102e48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102"); + using PooledTransactionsMessage message = new(new ArrayPoolList(2) { transaction, transaction }); + SerializerTester.TestZero(serializer, message, "f84ae48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102e48203e8640a94b7705ae4c6f81b66cdb323c65f4e8133690fc099822710830102031b0102"); } [Test] public void Can_handle_empty() { PooledTransactionsMessageSerializer serializer = new(); - PooledTransactionsMessage message = new(new Transaction[] { }); + using PooledTransactionsMessage message = new(ArrayPoolList.Empty()); SerializerTester.TestZero(serializer, message); } @@ -69,20 +73,24 @@ public void Can_handle_empty() [Test] public void Empty_to_string() { - PooledTransactionsMessage message = new(new Transaction[] { }); - PooledTransactionsMessage message2 = new(null); + using PooledTransactionsMessage message = new(ArrayPoolList.Empty()); + using PooledTransactionsMessage message2 = new(null); _ = message.ToString(); _ = message2.ToString(); } [TestCaseSource(nameof(GetTransactionMessages))] - public void Should_pass_roundtrip(PooledTransactionsMessage transactionsMessage) => SerializerTester.TestZero( - new PooledTransactionsMessageSerializer(), - transactionsMessage, - additionallyExcluding: (o) => - o.For(msg => msg.Transactions) - .Exclude(tx => tx.SenderAddress)); + public void Should_pass_roundtrip(PooledTransactionsMessage transactionsMessage) + { + SerializerTester.TestZero( + new PooledTransactionsMessageSerializer(), + transactionsMessage, + additionallyExcluding: (o) => + o.For(msg => msg.Transactions) + .Exclude(tx => tx.SenderAddress)); + transactionsMessage.Dispose(); + } [TestCaseSource(nameof(GetTransactionMessages))] public void Should_contain_network_form_tx_wrapper(PooledTransactionsMessage transactionsMessage) @@ -90,7 +98,7 @@ public void Should_contain_network_form_tx_wrapper(PooledTransactionsMessage tra IByteBuffer buffer = PooledByteBufferAllocator.Default.Buffer(1024 * 130); PooledTransactionsMessageSerializer serializer = new(); serializer.Serialize(buffer, transactionsMessage); - PooledTransactionsMessage deserializedMessage = serializer.Deserialize(buffer); + using PooledTransactionsMessage deserializedMessage = serializer.Deserialize(buffer); foreach (Transaction? tx in deserializedMessage.Transactions.Where(tx => tx.Type == TxType.Blob)) { Assert.That(tx.NetworkWrapper, Is.Not.Null); @@ -104,5 +112,5 @@ public void Should_contain_network_form_tx_wrapper(PooledTransactionsMessage tra private static IEnumerable GetTransactionMessages() => TransactionsMessageSerializerTests.GetTransactions() - .Select(txs => new PooledTransactionsMessage(txs.ToList())); + .Select(txs => new PooledTransactionsMessage(txs.ToPooledList(3))); } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockBodiesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockBodiesMessageSerializerTests.cs index 2e657ad6bca..2af06da8986 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockBodiesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockBodiesMessageSerializerTests.cs @@ -63,12 +63,12 @@ public void RoundTrip() Hash = new Hash256("0xf39c7dac06a9f3abf09faf5e30439a349d3717611b3ed337cd52b0d192bc72da") }; - var ethMessage = new Network.P2P.Subprotocols.Eth.V62.Messages.BlockBodiesMessage + using var ethMessage = new Network.P2P.Subprotocols.Eth.V62.Messages.BlockBodiesMessage { Bodies = new(new[] { new BlockBody(new[] { tx1, tx2 }, new[] { header }) }) }; - BlockBodiesMessage message = new(1111, ethMessage); + using BlockBodiesMessage message = new(1111, ethMessage); BlockBodiesMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockHeadersMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockHeadersMessageSerializerTests.cs index cd3f5ac1bb5..ea3e8909805 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockHeadersMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/BlockHeadersMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V66.Messages; @@ -34,10 +35,10 @@ public void RoundTrip() header.Nonce = 0; header.Hash = new Hash256("0x8c2f2af15b7b563b6ab1e09bed0e9caade7ed730aec98b70a993597a797579a9"); - var ethMessage = new Network.P2P.Subprotocols.Eth.V62.Messages.BlockHeadersMessage(); - ethMessage.BlockHeaders = new[] { header }; + using var ethMessage = new Network.P2P.Subprotocols.Eth.V62.Messages.BlockHeadersMessage(); + ethMessage.BlockHeaders = new ArrayPoolList(1) { header }; - BlockHeadersMessage message = new(1111, ethMessage); + using BlockHeadersMessage message = new(1111, ethMessage); BlockHeadersMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandlerTests.cs index c9b58648444..d46fe53acef 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandlerTests.cs @@ -9,7 +9,9 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; @@ -127,7 +129,7 @@ public void Can_handle_get_block_headers() [Test] public void Can_handle_block_headers() { - var msg62 = new BlockHeadersMessage(Build.A.BlockHeader.TestObjectNTimes(3)); + var msg62 = new BlockHeadersMessage(Build.A.BlockHeader.TestObjectNTimes(3).ToPooledList()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.BlockHeadersMessage(1111, msg62); _session.When((session) => session.DeliverMessage(Arg.Any>())).Do(callInfo => @@ -144,7 +146,7 @@ public void Can_handle_block_headers() [Test] public void Should_throw_when_receiving_unrequested_block_headers() { - var msg62 = new BlockHeadersMessage(Build.A.BlockHeader.TestObjectNTimes(3)); + var msg62 = new BlockHeadersMessage(Build.A.BlockHeader.TestObjectNTimes(3).ToPooledList()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.BlockHeadersMessage(1111, msg62); HandleIncomingStatusMessage(); @@ -194,7 +196,7 @@ public void Should_throw_when_receiving_unrequested_block_bodies() [Test] public void Can_handle_get_pooled_transactions() { - var msg65 = new GetPooledTransactionsMessage(new[] { Keccak.Zero, TestItem.KeccakA }); + var msg65 = new GetPooledTransactionsMessage(new[] { Keccak.Zero, TestItem.KeccakA }.ToPooledList()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.GetPooledTransactionsMessage(1111, msg65); HandleIncomingStatusMessage(); @@ -206,7 +208,7 @@ public void Can_handle_get_pooled_transactions() public void Can_handle_pooled_transactions() { Transaction tx = Build.A.Transaction.Signed(new EthereumEcdsa(1, LimboLogs.Instance), TestItem.PrivateKeyA).TestObject; - var msg65 = new PooledTransactionsMessage(new[] { tx }); + var msg65 = new PooledTransactionsMessage(new ArrayPoolList(1) { tx }); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.PooledTransactionsMessage(1111, msg65); HandleIncomingStatusMessage(); @@ -216,7 +218,7 @@ public void Can_handle_pooled_transactions() [Test] public void Can_handle_get_node_data() { - var msg63 = new GetNodeDataMessage(new[] { Keccak.Zero, TestItem.KeccakA }); + var msg63 = new GetNodeDataMessage(new[] { Keccak.Zero, TestItem.KeccakA }.ToPooledList()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.GetNodeDataMessage(1111, msg63); HandleIncomingStatusMessage(); @@ -227,7 +229,7 @@ public void Can_handle_get_node_data() [Test] public void Can_handle_node_data() { - var msg63 = new NodeDataMessage(System.Array.Empty()); + var msg63 = new NodeDataMessage(ArrayPoolList.Empty()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.NodeDataMessage(1111, msg63); _session.When((session) => session.DeliverMessage(Arg.Any>())).Do(callInfo => @@ -244,7 +246,7 @@ public void Can_handle_node_data() [Test] public void Should_throw_when_receiving_unrequested_node_data() { - var msg63 = new NodeDataMessage(System.Array.Empty()); + var msg63 = new NodeDataMessage(ArrayPoolList.Empty()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.NodeDataMessage(1111, msg63); HandleIncomingStatusMessage(); @@ -255,7 +257,7 @@ public void Should_throw_when_receiving_unrequested_node_data() [Test] public void Can_handle_get_receipts() { - var msg63 = new GetReceiptsMessage(new[] { Keccak.Zero, TestItem.KeccakA }); + var msg63 = new GetReceiptsMessage(new[] { Keccak.Zero, TestItem.KeccakA }.ToPooledList()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.GetReceiptsMessage(1111, msg63); HandleIncomingStatusMessage(); @@ -266,7 +268,7 @@ public void Can_handle_get_receipts() [Test] public void Can_handle_receipts() { - var msg63 = new ReceiptsMessage(System.Array.Empty()); + var msg63 = new ReceiptsMessage(ArrayPoolList.Empty()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.ReceiptsMessage(1111, msg63); _session.When((session) => session.DeliverMessage(Arg.Any>())).Do(callInfo => @@ -283,7 +285,7 @@ public void Can_handle_receipts() [Test] public void Should_throw_when_receiving_unrequested_receipts() { - var msg63 = new ReceiptsMessage(System.Array.Empty()); + var msg63 = new ReceiptsMessage(ArrayPoolList.Empty()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.ReceiptsMessage(1111, msg63); HandleIncomingStatusMessage(); @@ -314,18 +316,23 @@ public void should_request_in_GetPooledTransactionsMessage_up_to_256_txs(int num new ForkInfo(_specProvider, _genesisBlock.Header.Hash!), LimboLogs.Instance); - List hashes = new(numberOfTransactions); + ArrayPoolList hashes = new(numberOfTransactions); for (int i = 0; i < numberOfTransactions; i++) { hashes.Add(new Hash256(i.ToString("X64"))); } - NewPooledTransactionHashesMessage hashesMsg = new(hashes); + using NewPooledTransactionHashesMessage hashesMsg = new(hashes); HandleIncomingStatusMessage(); + + bool callReceived = true; + _session.When((session) => session.DeliverMessage(Arg.Is(m => m.EthMessage.Hashes.Count == maxNumberOfTxsInOneMsg || m.EthMessage.Hashes.Count == numberOfTransactions % maxNumberOfTxsInOneMsg))) + .Do(_ => callReceived = true); + HandleZeroMessage(hashesMsg, Eth65MessageCode.NewPooledTransactionHashes); - _session.Received(expectedNumberOfMessages).DeliverMessage(Arg.Is(m => m.EthMessage.Hashes.Count == maxNumberOfTxsInOneMsg || m.EthMessage.Hashes.Count == numberOfTransactions % maxNumberOfTxsInOneMsg)); + callReceived.Should().BeTrue(); } private void HandleZeroMessage(T msg, int messageCode) where T : MessageBase diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetNodeDataMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetNodeDataMessageSerializerTests.cs index c897b058354..48821eea718 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetNodeDataMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetNodeDataMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Network.P2P.Subprotocols.Eth.V66.Messages; using NUnit.Framework; @@ -16,7 +17,7 @@ public void Roundtrip() { Hash256[] keys = { new("0x00000000000000000000000000000000000000000000000000000000deadc0de"), new("0x00000000000000000000000000000000000000000000000000000000feedbeef") }; - var ethMessage = new Network.P2P.Subprotocols.Eth.V63.Messages.GetNodeDataMessage(keys); + var ethMessage = new Network.P2P.Subprotocols.Eth.V63.Messages.GetNodeDataMessage(keys.ToPooledList()); GetNodeDataMessage message = new(1111, ethMessage); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetPooledTransactionsSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetPooledTransactionsSerializerTests.cs index 17400ea6fea..22a8f060447 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetPooledTransactionsSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetPooledTransactionsSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Network.P2P.Subprotocols.Eth.V66.Messages; using NUnit.Framework; @@ -17,7 +18,7 @@ public void Roundtrip() Hash256 a = new("0x00000000000000000000000000000000000000000000000000000000deadc0de"); Hash256 b = new("0x00000000000000000000000000000000000000000000000000000000feedbeef"); Hash256[] keys = { a, b }; - var ethMessage = new Network.P2P.Subprotocols.Eth.V65.Messages.GetPooledTransactionsMessage(keys); + var ethMessage = new Network.P2P.Subprotocols.Eth.V65.Messages.GetPooledTransactionsMessage(keys.ToPooledList()); GetPooledTransactionsMessage message = new(1111, ethMessage); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetReceiptsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetReceiptsMessageSerializerTests.cs index be38a11f073..2f9ea2e7fde 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetReceiptsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/GetReceiptsMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Network.P2P.Subprotocols.Eth.V66.Messages; using NUnit.Framework; @@ -18,7 +19,7 @@ public void RoundTrip() Hash256 b = new("0x00000000000000000000000000000000000000000000000000000000feedbeef"); Hash256[] hashes = { a, b }; - var ethMessage = new Network.P2P.Subprotocols.Eth.V63.Messages.GetReceiptsMessage(hashes); + var ethMessage = new Network.P2P.Subprotocols.Eth.V63.Messages.GetReceiptsMessage(hashes.ToPooledList()); GetReceiptsMessage message = new(1111, ethMessage); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/NodeDataMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/NodeDataMessageSerializerTests.cs index 09afa156608..9dfb0b4ddbd 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/NodeDataMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/NodeDataMessageSerializerTests.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Subprotocols.Eth.V66.Messages; using NUnit.Framework; @@ -13,7 +14,7 @@ public class NodeDataMessageSerializerTests [Test] public void Roundtrip() { - byte[][] data = { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed, 0xbe, 0xef } }; + ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed, 0xbe, 0xef } }; var ethMessage = new Network.P2P.Subprotocols.Eth.V63.Messages.NodeDataMessage(data); NodeDataMessage message = new(1111, ethMessage); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/PooledTransactionsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/PooledTransactionsMessageSerializerTests.cs index d6e7222543d..ee7a4a13625 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/PooledTransactionsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/PooledTransactionsMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Network.P2P.Subprotocols.Eth.V66.Messages; using NUnit.Framework; @@ -43,7 +44,7 @@ public void Roundtrip() Hash = new Hash256("0xf39c7dac06a9f3abf09faf5e30439a349d3717611b3ed337cd52b0d192bc72da") }; - var ethMessage = new Network.P2P.Subprotocols.Eth.V65.Messages.PooledTransactionsMessage(new[] { tx1, tx2 }); + var ethMessage = new Network.P2P.Subprotocols.Eth.V65.Messages.PooledTransactionsMessage(new ArrayPoolList(2) { tx1, tx2 }); PooledTransactionsMessage message = new(1111, ethMessage); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/ReceiptsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/ReceiptsMessageSerializerTests.cs index e7e585d8d3a..25b26f580bc 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/ReceiptsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V66/ReceiptsMessageSerializerTests.cs @@ -26,7 +26,7 @@ public void RoundTrip() byte[] serialized = serializer.Serialize(deserializedMessage); Assert.That(serialized, Is.EqualTo(bytes)); - Network.P2P.Subprotocols.Eth.V63.Messages.ReceiptsMessage ethMessage = deserializedMessage.EthMessage; + using Network.P2P.Subprotocols.Eth.V63.Messages.ReceiptsMessage ethMessage = deserializedMessage.EthMessage; TxReceipt txReceipt = ethMessage.TxReceipts[0][0]; @@ -43,7 +43,7 @@ public void RoundTrip() txReceipt.BlockHash.Should().BeNull(); txReceipt.Index.Should().Be(0x0); - ReceiptsMessage message = new(1111, ethMessage); + using ReceiptsMessage message = new(1111, ethMessage); SerializerTester.TestZero(serializer, message, rlp); } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V67/Eth67ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V67/Eth67ProtocolHandlerTests.cs index 98c838bb1b8..68ac4957707 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V67/Eth67ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V67/Eth67ProtocolHandlerTests.cs @@ -6,7 +6,9 @@ using FluentAssertions; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; @@ -100,7 +102,7 @@ public void Metadata_correct() [Test] public void Can_ignore_get_node_data() { - var msg63 = new GetNodeDataMessage(new[] { Keccak.Zero, TestItem.KeccakA }); + var msg63 = new GetNodeDataMessage(new[] { Keccak.Zero, TestItem.KeccakA }.ToPooledList()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.GetNodeDataMessage(1111, msg63); HandleIncomingStatusMessage(); @@ -111,7 +113,7 @@ public void Can_ignore_get_node_data() [Test] public void Can_ignore_node_data_and_not_throw_when_receiving_unrequested_node_data() { - var msg63 = new NodeDataMessage(System.Array.Empty()); + var msg63 = new NodeDataMessage(ArrayPoolList.Empty()); var msg66 = new Network.P2P.Subprotocols.Eth.V66.Messages.NodeDataMessage(1111, msg63); HandleIncomingStatusMessage(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs index 8ad638a8130..dbcd5b777f2 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs @@ -8,6 +8,7 @@ using FluentAssertions; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Core.Test; @@ -111,7 +112,7 @@ public void Can_handle_NewPooledTransactions_message([Values(0, 1, 2, 100)] int { _txGossipPolicy.ShouldListenToGossipedTransactions.Returns(canGossipTransactions); - GenerateLists(txCount, out List types, out List sizes, out List hashes); + GenerateLists(txCount, out ArrayPoolList types, out ArrayPoolList sizes, out ArrayPoolList hashes); var msg = new NewPooledTransactionHashesMessage68(types, sizes, hashes); @@ -126,7 +127,7 @@ public void Can_handle_NewPooledTransactions_message([Values(0, 1, 2, 100)] int [TestCase(false)] public void Should_throw_when_sizes_doesnt_match(bool removeSize) { - GenerateLists(4, out List types, out List sizes, out List hashes); + GenerateLists(4, out ArrayPoolList types, out ArrayPoolList sizes, out ArrayPoolList hashes); if (removeSize) { @@ -150,8 +151,8 @@ public void Should_process_huge_transaction() Transaction tx = Build.A.Transaction.WithType(TxType.EIP1559).WithData(new byte[2 * 1024 * 1024]) .WithHash(TestItem.KeccakA).TestObject; - var msg = new NewPooledTransactionHashesMessage68(new[] { (byte)tx.Type }, - new[] { tx.GetLength() }, new[] { tx.Hash }); + var msg = new NewPooledTransactionHashesMessage68(new ArrayPoolList(1) { (byte)tx.Type }, + new ArrayPoolList(1) { tx.GetLength() }, new ArrayPoolList(1) { tx.Hash }); HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes); @@ -216,9 +217,9 @@ public void should_divide_GetPooledTransactionsMessage_if_max_message_size_is_ex int maxNumberOfTxsInOneMsg = sizeOfOneTx < TransactionsMessage.MaxPacketSize ? TransactionsMessage.MaxPacketSize / sizeOfOneTx : 1; int messagesCount = numberOfTransactions / maxNumberOfTxsInOneMsg + (numberOfTransactions % maxNumberOfTxsInOneMsg == 0 ? 0 : 1); - List types = new(numberOfTransactions); - List sizes = new(numberOfTransactions); - List hashes = new(numberOfTransactions); + ArrayPoolList types = new(numberOfTransactions); + ArrayPoolList sizes = new(numberOfTransactions); + ArrayPoolList hashes = new(numberOfTransactions); for (int i = 0; i < numberOfTransactions; i++) { @@ -227,7 +228,7 @@ public void should_divide_GetPooledTransactionsMessage_if_max_message_size_is_ex hashes.Add(new Hash256(i.ToString("X64"))); } - NewPooledTransactionHashesMessage68 hashesMsg = new(types, sizes, hashes); + using NewPooledTransactionHashesMessage68 hashesMsg = new(types, sizes, hashes); HandleIncomingStatusMessage(); HandleZeroMessage(hashesMsg, Eth68MessageCode.NewPooledTransactionHashes); @@ -252,12 +253,12 @@ private void HandleZeroMessage(T msg, byte messageCode) where T : MessageBase _handler.HandleMessage(new ZeroPacket(getBlockHeadersPacket) { PacketType = messageCode }); } - private void GenerateLists(int txCount, out List types, out List sizes, out List hashes) + private void GenerateLists(int txCount, out ArrayPoolList types, out ArrayPoolList sizes, out ArrayPoolList hashes) { TxDecoder txDecoder = new(); - types = new(); - sizes = new(); - hashes = new(); + types = new(txCount); + sizes = new(txCount); + hashes = new(txCount); for (int i = 0; i < txCount; ++i) { diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/NewPooledTransactionHashesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/NewPooledTransactionHashesMessageSerializerTests.cs index 91146bcc669..f48a2a3839b 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/NewPooledTransactionHashesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/NewPooledTransactionHashesMessageSerializerTests.cs @@ -4,6 +4,7 @@ using System.Linq; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Eth.V68.Messages; using NUnit.Framework; @@ -15,7 +16,7 @@ public class NewPooledTransactionHashesMessageSerializerTests { private static void Test(TxType[] types, int[] sizes, Hash256[] hashes, string expected = null) { - NewPooledTransactionHashesMessage68 message = new(types.Select(t => (byte)t).ToList(), sizes, hashes); + using NewPooledTransactionHashesMessage68 message = new(types.Select(t => (byte)t).ToPooledList(types.Length), sizes.ToPooledList(), hashes.ToPooledList()); NewPooledTransactionHashesMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, message, expected); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/AnnounceMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/AnnounceMessageSerializerTests.cs index 8e9058e17b4..ab1384d86dc 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/AnnounceMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/AnnounceMessageSerializerTests.cs @@ -13,7 +13,7 @@ public class AnnounceMessageSerializerTests [Test] public void RoundTripWithRequiredData() { - AnnounceMessage announceMessage = new(); + using AnnounceMessage announceMessage = new(); announceMessage.HeadHash = Keccak.Compute("1"); announceMessage.HeadBlockNo = 4; announceMessage.TotalDifficulty = 131200; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockBodiesSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockBodiesSerializerTests.cs index 9a744bd87f1..38723f845dc 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockBodiesSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockBodiesSerializerTests.cs @@ -24,7 +24,7 @@ public void RoundTrip() var ethMessage = new Network.P2P.Subprotocols.Eth.V62.Messages.BlockBodiesMessage(); ethMessage.Bodies = new(new[] { new BlockBody(new[] { tx }, new[] { header }) }); - BlockBodiesMessage message = new(ethMessage, 1, 1000); + using BlockBodiesMessage message = new(ethMessage, 1, 1000); BlockBodiesMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockHeadersMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockHeadersMessageSerializerTests.cs index 80997846e7b..538ad03f5b6 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockHeadersMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/BlockHeadersMessageSerializerTests.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Les.Messages; using NUnit.Framework; @@ -14,8 +16,8 @@ public class BlockHeadersMessageSerializerTests public void RoundTrip() { var ethMessage = new Network.P2P.Subprotocols.Eth.V62.Messages.BlockHeadersMessage(); - ethMessage.BlockHeaders = new[] { Build.A.BlockHeader.TestObject }; - BlockHeadersMessage message = new(ethMessage, 2, 3000); + ethMessage.BlockHeaders = new ArrayPoolList(1) { Build.A.BlockHeader.TestObject }; + using BlockHeadersMessage message = new(ethMessage, 2, 3000); BlockHeadersMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ContractCodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ContractCodesMessageSerializerTests.cs index 0cf3951977b..0c0e4427a73 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ContractCodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ContractCodesMessageSerializerTests.cs @@ -1,6 +1,7 @@ /// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Les.Messages; using NUnit.Framework; @@ -13,8 +14,8 @@ public class ContractCodesMessageSerializerTests [Test] public void RoundTrip() { - byte[][] data = { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; - ContractCodesMessage message = new(data, 13452, 134); + ArrayPoolList data = new(3) { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; + using ContractCodesMessage message = new(data, 13452, 134); ContractCodesMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetContractCodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetContractCodesMessageSerializerTests.cs index 9dc8537ad4d..dd88c9e3d90 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetContractCodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetContractCodesMessageSerializerTests.cs @@ -20,7 +20,7 @@ public void RoundTrip() new(TestItem.KeccakC, TestItem.KeccakD), }; - GetContractCodesMessage message = new(requests, 774); + using GetContractCodesMessage message = new(requests, 774); GetContractCodesMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetHelperTrieProofsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetHelperTrieProofsMessageSerializerTests.cs index 778577186e0..f58ba84a90f 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetHelperTrieProofsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetHelperTrieProofsMessageSerializerTests.cs @@ -19,7 +19,7 @@ public void RoundTrip() new(HelperTrieType.CHT, 177, TestItem.RandomDataA, 2, 1), new(HelperTrieType.BloomBits, 77, TestItem.RandomDataB, 4, 0), }; - GetHelperTrieProofsMessage message = new(); + using GetHelperTrieProofsMessage message = new(); message.RequestId = 100; message.Requests = requests; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetReceiptsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetReceiptsMessageSerializerTests.cs index 03108d63c11..eb07234cd78 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetReceiptsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/GetReceiptsMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Les.Messages; using NUnit.Framework; @@ -15,9 +16,9 @@ public class GetReceiptsMessageSerializerTests public void RoundTrip() { Hash256[] hashes = { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; - var ethMessage = new Network.P2P.Subprotocols.Eth.V63.Messages.GetReceiptsMessage(hashes); + var ethMessage = new Network.P2P.Subprotocols.Eth.V63.Messages.GetReceiptsMessage(hashes.ToPooledList()); - GetReceiptsMessage getReceiptsMessage = new(ethMessage, 1); + using GetReceiptsMessage getReceiptsMessage = new(ethMessage, 1); GetReceiptsMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ReceiptsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ReceiptsMessageSerializerTests.cs index 77ddc21fcdf..614e8d840c9 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ReceiptsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/ReceiptsMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Extensions; using Nethermind.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.Les.Messages; @@ -16,15 +17,15 @@ public class ReceiptsMessageSerializerTests public void RoundTrip() { TxReceipt[][] data = { new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject }, new[] { Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject }, new[] { Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject } }; - Network.P2P.Subprotocols.Eth.V63.Messages.ReceiptsMessage ethMessage = new(data); - ReceiptsMessage receiptsMessage = new(ethMessage, 1, 2000); + using Network.P2P.Subprotocols.Eth.V63.Messages.ReceiptsMessage ethMessage = new(data.ToPooledList()); + using ReceiptsMessage receiptsMessage = new(ethMessage, 1, 2000); ReceiptsMessageSerializer serializer = new(MainnetSpecProvider.Instance); // Eth.ReceiptsMessageSerializer intentionally excludes fields when deserializing. // I think it's probably best to not copy the test logic checking for this here. byte[] bytes = serializer.Serialize(receiptsMessage); - ReceiptsMessage deserialized = serializer.Deserialize(bytes); + using ReceiptsMessage deserialized = serializer.Deserialize(bytes); Assert.That(deserialized.RequestId, Is.EqualTo(receiptsMessage.RequestId), "RequestId"); Assert.That(deserialized.BufferValue, Is.EqualTo(receiptsMessage.BufferValue), "BufferValue"); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/StatusMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/StatusMessageSerializerTests.cs index 782bde5af52..2b8652d7a6a 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/StatusMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Les/StatusMessageSerializerTests.cs @@ -14,7 +14,7 @@ public class StatusMessageSerializerTests [Test] public void RoundTripWithAllData() { - StatusMessage statusMessage = new(); + using StatusMessage statusMessage = new(); statusMessage.ProtocolVersion = 3; statusMessage.NetworkId = 1; statusMessage.TotalDifficulty = 131200; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageSerializerTests.cs index ac686bbcaf8..78067ae0d74 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.NodeData.Messages; using NUnit.Framework; @@ -13,7 +14,7 @@ public class GetNodeDataMessageSerializerTests { private static void Test(Hash256[] keys) { - GetNodeDataMessage message = new(keys); + GetNodeDataMessage message = new(keys.ToPooledList()); GetNodeDataMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, message); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs index 95200a9ce58..1a9cc558f51 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.Contract.P2P; using Nethermind.Network.P2P.Subprotocols.NodeData; @@ -20,7 +22,7 @@ public class GetNodeDataMessageTests public void Sets_values_from_constructor_argument() { Hash256[] keys = { TestItem.KeccakA, TestItem.KeccakB }; - GetNodeDataMessage message = new(keys); + GetNodeDataMessage message = new(keys.ToPooledList()); keys.Should().BeEquivalentTo(message.Hashes); } @@ -33,7 +35,7 @@ public void Throws_on_null_argument() [Test] public void To_string() { - GetNodeDataMessage message = new(new List()); + GetNodeDataMessage message = new(ArrayPoolList.Empty()); _ = message.ToString(); } @@ -41,7 +43,7 @@ public void To_string() public void Packet_type_and_protocol_are_correct() { Hash256[] keys = { TestItem.KeccakA, TestItem.KeccakB }; - GetNodeDataMessage message = new(keys); + GetNodeDataMessage message = new(keys.ToPooledList()); message.PacketType.Should().Be(NodeDataMessageCode.GetNodeData); message.Protocol.Should().Be(Protocol.NodeData); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageSerializerTests.cs index c262adf0d10..a3794115953 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P.Subprotocols.NodeData.Messages; using NUnit.Framework; @@ -11,9 +12,9 @@ namespace Nethermind.Network.Test.P2P.Subprotocols.NodeData; [Parallelizable(ParallelScope.All)] public class NodeDataMessageSerializerTests { - private static void Test(byte[][] data) + private static void Test(ArrayPoolList data) { - NodeDataMessage message = new(data); + using NodeDataMessage message = new(data); NodeDataMessageSerializer serializer = new(); SerializerTester.TestZero(serializer, message); @@ -22,14 +23,14 @@ private static void Test(byte[][] data) [Test] public void Roundtrip() { - byte[][] data = { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; + ArrayPoolList data = new(3) { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; Test(data); } [Test] public void Zero_roundtrip() { - byte[][] data = { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; + ArrayPoolList data = new(3) { TestItem.KeccakA.BytesToArray(), TestItem.KeccakB.BytesToArray(), TestItem.KeccakC.BytesToArray() }; Test(data); } @@ -42,7 +43,7 @@ public void Roundtrip_with_null_top_level() [Test] public void Roundtrip_with_nulls() { - byte[][] data = { TestItem.KeccakA.BytesToArray(), Array.Empty(), TestItem.KeccakC.BytesToArray() }; + ArrayPoolList data = new(3) { TestItem.KeccakA.BytesToArray(), Array.Empty(), TestItem.KeccakC.BytesToArray() }; Test(data); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageTests.cs index 97c75f4f619..35bad53c252 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataMessageTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Network.Contract.P2P; using Nethermind.Network.P2P.Subprotocols.NodeData; using Nethermind.Network.P2P.Subprotocols.NodeData.Messages; @@ -15,38 +16,38 @@ public class NodeDataMessageTests [Test] public void Accepts_nulls_inside() { - byte[][] data = { new byte[] { 1, 2, 3 }, null }; - NodeDataMessage message = new(data); + ArrayPoolList data = new(2) { new byte[] { 1, 2, 3 }, null }; + using NodeDataMessage message = new(data); data.Should().BeEquivalentTo(message.Data); } [Test] public void Accepts_nulls_top_level() { - NodeDataMessage message = new(null); - message.Data.Length.Should().Be(0); + using NodeDataMessage message = new(null); + message.Data.Count.Should().Be(0); } [Test] public void Sets_values_from_constructor_argument() { - byte[][] data = { new byte[] { 1, 2, 3 }, new byte[] { 4, 5, 6 } }; - NodeDataMessage message = new(data); + ArrayPoolList data = new(2) { new byte[] { 1, 2, 3 }, new byte[] { 4, 5, 6 } }; + using NodeDataMessage message = new(data); data.Should().BeEquivalentTo(message.Data); } [Test] public void To_string() { - NodeDataMessage message = new(new byte[][] { }); + using NodeDataMessage message = new(ArrayPoolList.Empty()); _ = message.ToString(); } [Test] public void Packet_type_and_protocol_are_correct() { - byte[][] data = { new byte[] { 1, 2, 3 }, null }; - NodeDataMessage message = new(data); + ArrayPoolList data = new(2) { new byte[] { 1, 2, 3 }, null }; + using NodeDataMessage message = new(data); message.PacketType.Should().Be(NodeDataMessageCode.NodeData); message.Protocol.Should().Be(Protocol.NodeData); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataProtocolHandlerTests.cs index 5ab867c5c3e..39c591496d5 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/NodeDataProtocolHandlerTests.cs @@ -3,14 +3,18 @@ using System.Collections.Generic; using System.Threading; +using System.Threading.Tasks; using DotNetty.Buffers; using FluentAssertions; using Nethermind.Blockchain.Synchronization; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; using Nethermind.Logging; using Nethermind.Network.P2P; +using Nethermind.Network.P2P.Messages; using Nethermind.Network.P2P.Subprotocols; using Nethermind.Network.P2P.Subprotocols.NodeData; using Nethermind.Network.P2P.Subprotocols.NodeData.Messages; @@ -63,7 +67,7 @@ public void Metadata_correct() [Test] public void Can_handle_get_node_data() { - var msg = new GetNodeDataMessage(new[] { Keccak.Zero, TestItem.KeccakA }); + var msg = new GetNodeDataMessage(new[] { Keccak.Zero, TestItem.KeccakA }.ToPooledList()); HandleZeroMessage(msg, NodeDataMessageCode.GetNodeData); _session.Received().DeliverMessage(Arg.Any()); @@ -72,7 +76,7 @@ public void Can_handle_get_node_data() [Test] public void Can_handle_node_data() { - var msg = new NodeDataMessage(System.Array.Empty()); + var msg = new NodeDataMessage(ArrayPoolList.Empty()); ((INodeDataPeer)_handler).GetNodeData(new List(new[] { Keccak.Zero }), CancellationToken.None); HandleZeroMessage(msg, NodeDataMessageCode.NodeData); @@ -81,15 +85,16 @@ public void Can_handle_node_data() [Test] public void Should_throw_when_receiving_unrequested_node_data() { - var msg = new NodeDataMessage(System.Array.Empty()); + var msg = new NodeDataMessage(ArrayPoolList.Empty()); System.Action act = () => HandleZeroMessage(msg, NodeDataMessageCode.NodeData); act.Should().Throw(); } - private void HandleZeroMessage(T msg, int messageCode) where T : MessageBase + private void HandleZeroMessage(T msg, int messageCode) where T : P2PMessage { IByteBuffer getPacket = _svc.ZeroSerialize(msg); + msg.Dispose(); getPacket.ReadByte(); _handler.HandleMessage(new ZeroPacket(getPacket) { PacketType = (byte)messageCode }); } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializerTests.cs index d6e9787807a..212744a6a7b 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializerTests.cs @@ -3,6 +3,7 @@ using System; using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; @@ -25,8 +26,8 @@ public void Roundtrip_NoAccountsNoProofs_HasCorrectLength() AccountRangeMessage msg = new() { RequestId = 1, - PathsWithAccounts = System.Array.Empty(), - Proofs = Array.Empty() + PathsWithAccounts = ArrayPoolList.Empty(), + Proofs = ArrayPoolList.Empty(), }; AccountRangeMessageSerializer serializer = new(); @@ -39,8 +40,8 @@ public void Roundtrip_NoAccountsNoProofs() AccountRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - PathsWithAccounts = System.Array.Empty(), - Proofs = Array.Empty() + PathsWithAccounts = ArrayPoolList.Empty(), + Proofs = ArrayPoolList.Empty() }; AccountRangeMessageSerializer serializer = new(); @@ -65,8 +66,8 @@ public void Roundtrip_Many() AccountRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - PathsWithAccounts = new[] { new PathWithAccount(TestItem.KeccakA, acc01), new PathWithAccount(TestItem.KeccakB, acc02) }, - Proofs = new[] { TestItem.RandomDataA, TestItem.RandomDataB } + PathsWithAccounts = new ArrayPoolList(2) { new PathWithAccount(TestItem.KeccakA, acc01), new PathWithAccount(TestItem.KeccakB, acc02) }, + Proofs = new ArrayPoolList(2) { TestItem.RandomDataA, TestItem.RandomDataB } }; AccountRangeMessageSerializer serializer = new(); @@ -86,8 +87,8 @@ public void Roundtrip_EmptyStorageRoot() AccountRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - PathsWithAccounts = new[] { new PathWithAccount(TestItem.KeccakB, acc01) }, - Proofs = new[] { TestItem.RandomDataA, TestItem.RandomDataB } + PathsWithAccounts = new ArrayPoolList(1) { new(TestItem.KeccakB, acc01) }, + Proofs = new ArrayPoolList(2) { TestItem.RandomDataA, TestItem.RandomDataB } }; AccountRangeMessageSerializer serializer = new(); @@ -107,8 +108,8 @@ public void Roundtrip_EmptyCode() AccountRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - PathsWithAccounts = new[] { new PathWithAccount(TestItem.KeccakB, acc01) }, - Proofs = new[] { TestItem.RandomDataA, TestItem.RandomDataB } + PathsWithAccounts = new ArrayPoolList(1) { new(TestItem.KeccakB, acc01) }, + Proofs = new ArrayPoolList(2) { TestItem.RandomDataA, TestItem.RandomDataB } }; AccountRangeMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializerTests.cs index 1bd0634a874..cd223db8bf8 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Subprotocols.Snap.Messages; using NUnit.Framework; @@ -13,7 +14,7 @@ public class ByteCodesMessageSerializerTests [Test] public void Roundtrip() { - byte[][] data = { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; + ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; ByteCodesMessage message = new(data); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializerTests.cs index 239e020f151..3f0d5bad639 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializerTests.cs @@ -2,7 +2,9 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P; using Nethermind.Network.P2P.Subprotocols.Snap.Messages; @@ -19,7 +21,7 @@ public void Roundtrip_Many() GetByteCodesMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - Hashes = TestItem.ValueKeccaks, + Hashes = TestItem.ValueKeccaks.ToPooledList(), Bytes = 10 }; @@ -34,7 +36,7 @@ public void Roundtrip_Empty() GetByteCodesMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - Hashes = Array.Empty(), + Hashes = ArrayPoolList.Empty(), Bytes = 10 }; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs index 2a1a643bb0a..7ef1520a08d 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs @@ -3,7 +3,9 @@ using System; using System.Linq; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P; using Nethermind.Network.P2P.Subprotocols.Snap.Messages; @@ -24,7 +26,7 @@ public void Roundtrip_Many() StoragetRange = new() { RootHash = TestItem.KeccakA, - Accounts = TestItem.Keccaks.Select(k => new PathWithAccount(k, null)).ToArray(), + Accounts = TestItem.Keccaks.Select(k => new PathWithAccount(k, null)).ToPooledList(TestItem.Keccaks.Length), StartingHash = new Hash256("0x15d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), LimitHash = new Hash256("0x20d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") }, @@ -45,7 +47,7 @@ public void Roundtrip_Empty() StoragetRange = new() { RootHash = Keccak.OfAnEmptyString, - Accounts = Array.Empty(), + Accounts = ArrayPoolList.Empty(), StartingHash = new Hash256("0x15d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), LimitHash = new Hash256("0x20d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") }, diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs index 52e701a361e..3ab73c0dc69 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs @@ -3,6 +3,7 @@ using System; using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P; using Nethermind.Network.P2P.Subprotocols.Snap.Messages; @@ -21,7 +22,7 @@ public void Roundtrip_NoPaths() { RequestId = MessageConstants.Random.NextLong(), RootHash = TestItem.KeccakA, - Paths = Array.Empty(), + Paths = ArrayPoolList.Empty(), Bytes = 10 }; GetTrieNodesMessageSerializer serializer = new(); @@ -36,9 +37,9 @@ public void Roundtrip_OneAccountPath() { RequestId = MessageConstants.Random.NextLong(), RootHash = TestItem.KeccakA, - Paths = new PathGroup[] + Paths = new ArrayPoolList(1) { - new PathGroup(){Group = new []{TestItem.RandomDataA}} + new(){Group = [TestItem.RandomDataA] } }, Bytes = 10 }; @@ -54,10 +55,10 @@ public void Roundtrip_MultiplePaths() { RequestId = MessageConstants.Random.NextLong(), RootHash = TestItem.KeccakA, - Paths = new PathGroup[] + Paths = new ArrayPoolList(2) { - new PathGroup(){Group = new []{TestItem.RandomDataA, TestItem.RandomDataB}}, - new PathGroup(){Group = new []{TestItem.RandomDataC}} + new(){Group = [TestItem.RandomDataA, TestItem.RandomDataB] }, + new(){Group = [TestItem.RandomDataC] } }, Bytes = 10 }; @@ -73,11 +74,11 @@ public void Roundtrip_MultiplePaths02() { RequestId = MessageConstants.Random.NextLong(), RootHash = TestItem.KeccakA, - Paths = new PathGroup[] + Paths = new ArrayPoolList(3) { - new PathGroup(){Group = new []{TestItem.RandomDataA, TestItem.RandomDataB, TestItem.RandomDataD}}, - new PathGroup(){Group = new []{TestItem.RandomDataC}}, - new PathGroup(){Group = new []{TestItem.RandomDataC, TestItem.RandomDataA, TestItem.RandomDataB, TestItem.RandomDataD}} + new(){Group = [TestItem.RandomDataA, TestItem.RandomDataB, TestItem.RandomDataD] }, + new(){Group = [TestItem.RandomDataC] }, + new(){Group = [TestItem.RandomDataC, TestItem.RandomDataA, TestItem.RandomDataB, TestItem.RandomDataD] } }, Bytes = 10 }; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializerTests.cs index 30860549eb3..d9690349754 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Network.P2P; @@ -22,8 +23,8 @@ public void Roundtrip_NoSlotsNoProofs() StorageRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - Slots = Array.Empty(), - Proofs = Array.Empty() + Slots = ArrayPoolList.Empty(), + Proofs = ArrayPoolList.Empty() }; StorageRangesMessageSerializer serializer = new(); @@ -36,8 +37,8 @@ public void Roundtrip_OneProof() StorageRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - Slots = Array.Empty(), - Proofs = new[] { TestItem.RandomDataA } + Slots = ArrayPoolList.Empty(), + Proofs = new ArrayPoolList(2) { TestItem.RandomDataA } }; StorageRangesMessageSerializer serializer = new(); @@ -54,8 +55,8 @@ public void Roundtrip_OneSlot() StorageRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - Slots = new[] { new PathWithStorageSlot[] { new PathWithStorageSlot(new Hash256("0x10d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), TestItem.RandomDataA) } }, - Proofs = Array.Empty() + Slots = new ArrayPoolList(1) { new PathWithStorageSlot[] { new PathWithStorageSlot(new Hash256("0x10d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), TestItem.RandomDataA) } }, + Proofs = ArrayPoolList.Empty() }; StorageRangesMessageSerializer serializer = new(); @@ -69,7 +70,7 @@ public void Roundtrip_Many() StorageRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - Slots = new[] { + Slots = new ArrayPoolList(2) { new PathWithStorageSlot[] { new PathWithStorageSlot(new Hash256("0x10d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), Rlp.Encode(TestItem.RandomDataA).Bytes) , new PathWithStorageSlot(new Hash256("0x12d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), Rlp.Encode(TestItem.RandomDataB).Bytes) @@ -79,7 +80,7 @@ public void Roundtrip_Many() new PathWithStorageSlot(new Hash256("0x22d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), Rlp.Encode(TestItem.RandomDataC).Bytes) } }, - Proofs = new[] { TestItem.RandomDataA, TestItem.RandomDataB } + Proofs = new ArrayPoolList(2) { TestItem.RandomDataA, TestItem.RandomDataB } }; StorageRangesMessageSerializer serializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs index 234a613f285..8f39b2a721b 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Core.Extensions; using Nethermind.Network.P2P.Subprotocols.Snap.Messages; using NUnit.Framework; @@ -14,7 +15,7 @@ public class TrieNodesMessageSerializerTests [Test] public void Roundtrip() { - byte[][] data = { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; + ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; TrieNodesMessage message = new(data); @@ -26,7 +27,7 @@ public void Roundtrip() [Test] public void RoundtripWithCorrectLength() { - byte[][] data = { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; + ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; TrieNodesMessage message = new(data); message.RequestId = 1; diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/BlockWitnessHashesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/BlockWitnessHashesMessageSerializerTests.cs index 608500c8b7c..26eb269a095 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/BlockWitnessHashesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/BlockWitnessHashesMessageSerializerTests.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using FluentAssertions; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; @@ -16,7 +17,7 @@ public class BlockWitnessHashesMessageSerializerTests public void Can_handle_zero() { BlockWitnessHashesMessageSerializer serializer = new(); - BlockWitnessHashesMessage message = new(1, new Hash256[0]); + using BlockWitnessHashesMessage message = new(1, Array.Empty()); SerializerTester.TestZero(serializer, message); } @@ -24,7 +25,7 @@ public void Can_handle_zero() public void Can_handle_one() { BlockWitnessHashesMessageSerializer serializer = new(); - BlockWitnessHashesMessage message = new(1, new[] { Keccak.Zero }); + using BlockWitnessHashesMessage message = new(1, new[] { Keccak.Zero }); SerializerTester.TestZero(serializer, message); } @@ -32,7 +33,7 @@ public void Can_handle_one() public void Can_handle_many() { BlockWitnessHashesMessageSerializer serializer = new(); - BlockWitnessHashesMessage message = new(1, TestItem.Keccaks); + using BlockWitnessHashesMessage message = new(1, TestItem.Keccaks); SerializerTester.TestZero(serializer, message); } @@ -40,7 +41,7 @@ public void Can_handle_many() public void Can_handle_null() { BlockWitnessHashesMessageSerializer serializer = new(); - BlockWitnessHashesMessage message = new(1, null); + using BlockWitnessHashesMessage message = new(1, null); byte[] serialized = serializer.Serialize(message); serialized[0].Should().Be(194); serializer.Deserialize(serialized); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/GetBlockWitnessHashesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/GetBlockWitnessHashesMessageSerializerTests.cs index 025f3922706..25fdf425b45 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/GetBlockWitnessHashesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/GetBlockWitnessHashesMessageSerializerTests.cs @@ -33,7 +33,7 @@ public class GetBlockWitnessHashesMessageSerializerTests public void Roundtrip_init() { GetBlockWitnessHashesMessageSerializer serializer = new(); - GetBlockWitnessHashesMessage message = new(1, Keccak.Zero); + using GetBlockWitnessHashesMessage message = new(1, Keccak.Zero); SerializerTester.TestZero(serializer, message); } @@ -41,7 +41,7 @@ public void Roundtrip_init() public void Can_handle_null() { GetBlockWitnessHashesMessageSerializer serializer = new(); - GetBlockWitnessHashesMessage message = new(1, null); + using GetBlockWitnessHashesMessage message = new(1, null); SerializerTester.TestZero(serializer, message); } @@ -52,7 +52,7 @@ public void Can_deserialize_trinity() var trinityBytes = Bytes.FromHexString("0xea880ea29ca8028d7edea04bf6040124107de018c753ff2a9e464ca13e9d099c45df6a48ddbf436ce30c83"); var buffer = ByteBufferUtil.DefaultAllocator.Buffer(trinityBytes.Length); buffer.WriteBytes(trinityBytes); - GetBlockWitnessHashesMessage msg = + using GetBlockWitnessHashesMessage msg = ((IZeroMessageSerializer)serializer).Deserialize(buffer); } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/WitProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/WitProtocolHandlerTests.cs index 109a1e98468..fe339024c82 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/WitProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Wit/WitProtocolHandlerTests.cs @@ -90,7 +90,7 @@ public void Can_handle_request_for_an_empty_witness() Context context = new(); context.WitProtocolHandler.Init(); - GetBlockWitnessHashesMessage msg = new(5, Keccak.Zero); + using GetBlockWitnessHashesMessage msg = new(5, Keccak.Zero); GetBlockWitnessHashesMessageSerializer serializer = new(); var serialized = serializer.Serialize(msg); @@ -107,7 +107,7 @@ public void Can_handle_request_for_a_non_empty_witness() context.WitProtocolHandler.Init(); - GetBlockWitnessHashesMessage msg = new(5, Keccak.Zero); + using GetBlockWitnessHashesMessage msg = new(5, Keccak.Zero); GetBlockWitnessHashesMessageSerializer serializer = new(); var serialized = serializer.Serialize(msg); @@ -120,7 +120,7 @@ public void Can_handle_request_for_a_non_empty_witness() public async Task Can_request_non_empty_witness() { Context context = new(); - BlockWitnessHashesMessage msg = new(5, new[] { TestItem.KeccakA, TestItem.KeccakB }); + using BlockWitnessHashesMessage msg = new(5, new[] { TestItem.KeccakA, TestItem.KeccakB }); BlockWitnessHashesMessageSerializer serializer = new(); var serialized = serializer.Serialize(msg); diff --git a/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs b/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs index 498e28e5805..fd99eaf4d3a 100644 --- a/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs @@ -10,6 +10,7 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; @@ -176,7 +177,7 @@ public Context VerifyDisconnected() public Context ReceiveDisconnect() { - DisconnectMessage message = new(EthDisconnectReason.Other); + using DisconnectMessage message = new(EthDisconnectReason.Other); IByteBuffer disconnectPacket = _serializer.ZeroSerialize(message); // to account for AdaptivePacketType byte @@ -211,7 +212,7 @@ public Context Disconnect() public Context ReceiveStatus() { - StatusMessage msg = new(); + using StatusMessage msg = new(); msg.TotalDifficulty = 1; msg.NetworkId = TestBlockchainIds.NetworkId; msg.GenesisHash = _blockTree.Genesis.Hash; @@ -261,8 +262,8 @@ private Context ReceiveHello(HelloMessage msg) public Context ReceiveHello(byte p2pVersion = 5) { - HelloMessage msg = new(); - msg.Capabilities = new List { new("eth", 66) }; + using HelloMessage msg = new(); + msg.Capabilities = new ArrayPoolList(1) { new("eth", 66) }; msg.NodeId = TestItem.PublicKeyB; msg.ClientId = "other client v1"; msg.P2PVersion = p2pVersion; @@ -273,8 +274,8 @@ public Context ReceiveHello(byte p2pVersion = 5) public Context ReceiveHelloNoEth() { - HelloMessage msg = new(); - msg.Capabilities = new List { }; + using HelloMessage msg = new(); + msg.Capabilities = ArrayPoolList.Empty(); msg.NodeId = TestItem.PublicKeyB; msg.ClientId = "other client v1"; msg.P2PVersion = 5; @@ -284,8 +285,8 @@ public Context ReceiveHelloNoEth() public Context ReceiveHelloEth(int protocolVersion) { - HelloMessage msg = new(); - msg.Capabilities = new List { new("eth", 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; @@ -301,7 +302,7 @@ public Context ReceiveHelloWrongEth() public Context ReceiveStatusWrongChain(ulong networkId) { - StatusMessage msg = new(); + using StatusMessage msg = new(); msg.TotalDifficulty = 1; msg.NetworkId = networkId; msg.GenesisHash = TestItem.KeccakA; @@ -313,7 +314,7 @@ public Context ReceiveStatusWrongChain(ulong networkId) public Context ReceiveStatusWrongGenesis() { - StatusMessage msg = new(); + using StatusMessage msg = new(); msg.TotalDifficulty = 1; msg.NetworkId = TestBlockchainIds.NetworkId; msg.GenesisHash = TestItem.KeccakB; diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/HobbitTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/HobbitTests.cs index 6afab427888..faa4b89b62c 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/HobbitTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/HobbitTests.cs @@ -75,7 +75,7 @@ public void Get_block_bodies_there_and_back(StackType inbound, StackType outboun hashes[i] = Keccak.Compute(i.ToString()); } - GetBlockBodiesMessage message = new(hashes); + using GetBlockBodiesMessage message = new(hashes); GetBlockBodiesMessageSerializer serializer = new(); byte[] data = serializer.Serialize(message); @@ -91,7 +91,7 @@ public void Block_there_and_back(StackType inbound, StackType outbound, bool fra Transaction a = Build.A.Transaction.TestObject; Transaction b = Build.A.Transaction.TestObject; Block block = Build.A.Block.WithTransactions(a, b).TestObject; - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = block; NewBlockMessageSerializer newBlockMessageSerializer = new(); @@ -106,7 +106,7 @@ public void Two_frame_block_there_and_back(StackType inbound, StackType outbound { Transaction[] txs = Build.A.Transaction.SignedAndResolved().TestObjectNTimes(10); Block block = Build.A.Block.WithTransactions(txs).TestObject; - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = block; NewBlockMessageSerializer newBlockMessageSerializer = new(); @@ -115,7 +115,7 @@ public void Two_frame_block_there_and_back(StackType inbound, StackType outbound Packet decoded = Run(packet, inbound, outbound, framingEnabled); - NewBlockMessage decodedMessage = newBlockMessageSerializer.Deserialize(decoded.Data); + using NewBlockMessage decodedMessage = newBlockMessageSerializer.Deserialize(decoded.Data); Assert.That(decodedMessage.Block.Transactions.Length, Is.EqualTo(newBlockMessage.Block.Transactions.Length)); } @@ -129,7 +129,7 @@ public void Receipts_message(StackType inbound, StackType outbound, bool framing hashes[i] = Keccak.Compute(i.ToString()); } - GetReceiptsMessage message = new(hashes); + GetReceiptsMessage message = new(hashes.ToPooledList()); GetReceiptsMessageSerializer serializer = new(); byte[] data = serializer.Serialize(message); @@ -144,7 +144,7 @@ public void Receipts_message(StackType inbound, StackType outbound, bool framing [TestCase(StackType.Zero, StackType.Zero, false)] public void Status_message(StackType inbound, StackType outbound, bool framingEnabled) { - StatusMessage message = new(); + using StatusMessage message = new(); message.BestHash = Keccak.Zero; message.GenesisHash = Keccak.Zero; message.ProtocolVersion = 63; @@ -156,7 +156,7 @@ public void Status_message(StackType inbound, StackType outbound, bool framingEn Packet packet = new("eth", 7, data); Packet decoded = Run(packet, inbound, outbound, framingEnabled); - StatusMessage decodedMessage = serializer.Deserialize(decoded.Data); + using StatusMessage decodedMessage = serializer.Deserialize(decoded.Data); Assert.That(decodedMessage.TotalDifficulty, Is.EqualTo(message.TotalDifficulty)); } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs index c121010d812..d4b9301b2c6 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs @@ -164,7 +164,7 @@ public void Can_decode_neth_message() byte[] outputBytes = output.Content.ReadAllBytesAsArray(); HelloMessageSerializer serializer = new(); - HelloMessage helloMessage = serializer.Deserialize(outputBytes); + 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"); diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyPacketSplitterTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyPacketSplitterTests.cs index 55bd16bf3dd..da16f854d3b 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyPacketSplitterTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyPacketSplitterTests.cs @@ -73,7 +73,7 @@ public void Block_is_handled() Transaction a = Build.A.Transaction.TestObject; Transaction b = Build.A.Transaction.TestObject; Block block = Build.A.Block.WithTransactions(a, b).TestObject; - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = block; NewBlockMessageSerializer newBlockMessageSerializer = new(); @@ -96,7 +96,7 @@ public void Big_block_is_handled_when_framing_enabled() { Transaction[] a = Build.A.Transaction.TestObjectNTimes(64); Block block = Build.A.Block.WithTransactions(a).TestObject; - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = block; NewBlockMessageSerializer newBlockMessageSerializer = new(); @@ -120,7 +120,7 @@ public void Big_block_is_handled_when_framing_disabled() { Transaction[] a = Build.A.Transaction.TestObjectNTimes(64); Block block = Build.A.Block.WithTransactions(a).TestObject; - NewBlockMessage newBlockMessage = new(); + using NewBlockMessage newBlockMessage = new(); newBlockMessage.Block = block; NewBlockMessageSerializer newBlockMessageSerializer = new(); diff --git a/src/Nethermind/Nethermind.Network.Test/SnapProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/SnapProtocolHandlerTests.cs index 0e5c7a307c5..e094b654422 100644 --- a/src/Nethermind/Nethermind.Network.Test/SnapProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/SnapProtocolHandlerTests.cs @@ -9,6 +9,7 @@ using DotNetty.Common.Utilities; using FluentAssertions; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test; using Nethermind.Logging; @@ -85,7 +86,7 @@ public Context WithResponseBytesRecorder IByteBuffer buffer = MessageSerializationService.ZeroSerialize(new AccountRangeMessage() { - PathsWithAccounts = new[] { new PathWithAccount(Keccak.Zero, Account.TotallyEmpty) } + PathsWithAccounts = new ArrayPoolList(1) { new PathWithAccount(Keccak.Zero, Account.TotallyEmpty) } }); buffer.ReadByte(); // Need to skip adaptive type @@ -124,18 +125,18 @@ public async Task Test_response_bytes_adjust_with_latency() SnapProtocolHandler protocolHandler = ctx.SnapProtocolHandler; ctx.SimulatedLatency = TimeSpan.Zero; - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); ctx.RecordedMessageSizesShouldIncrease(); ctx.SimulatedLatency = SnapProtocolHandler.LowerLatencyThreshold + TimeSpan.FromMilliseconds(1); - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); ctx.RecordedMessageSizesShouldNotChange(); ctx.SimulatedLatency = SnapProtocolHandler.UpperLatencyThreshold + TimeSpan.FromMilliseconds(1); - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); ctx.RecordedMessageSizesShouldDecrease(); } @@ -149,14 +150,14 @@ public async Task Test_response_bytes_reset_on_error() SnapProtocolHandler protocolHandler = ctx.SnapProtocolHandler; // Just setting baseline - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); ctx.RecordedMessageSizesShouldIncrease(); ctx.SimulatedLatency = Timeouts.Eth + TimeSpan.FromSeconds(1); - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); ctx.SimulatedLatency = TimeSpan.Zero; // The read value is the request down, but it is adjusted on above request - await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None); + (await protocolHandler.GetAccountRange(new AccountRange(Keccak.Zero, Keccak.Zero), CancellationToken.None)).Dispose(); ctx.RecordedMessageSizesShouldDecrease(); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/EventArg/P2PProtocolInitializedEventArgs.cs b/src/Nethermind/Nethermind.Network/P2P/EventArg/P2PProtocolInitializedEventArgs.cs index 7c2da5690fc..8b70791ccc4 100644 --- a/src/Nethermind/Nethermind.Network/P2P/EventArg/P2PProtocolInitializedEventArgs.cs +++ b/src/Nethermind/Nethermind.Network/P2P/EventArg/P2PProtocolInitializedEventArgs.cs @@ -11,7 +11,7 @@ public class P2PProtocolInitializedEventArgs : ProtocolInitializedEventArgs { public byte P2PVersion { get; set; } public string ClientId { get; set; } - public List Capabilities { get; set; } + public IReadOnlyList Capabilities { get; set; } public int ListenPort { get; set; } public P2PProtocolInitializedEventArgs(IProtocolHandler handler) : base(handler) diff --git a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs index 5de6455ecb7..b16a73f2f56 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Stats.Model; @@ -15,7 +16,7 @@ public class HelloMessage : P2PMessage public string ClientId { get; set; } public int ListenPort { get; set; } public PublicKey NodeId { get; set; } - public List Capabilities { get; set; } + public IOwnedReadOnlyList Capabilities { get; set; } public override string ToString() => $"Hello({ClientId}, {string.Join(", ", Capabilities)})"; } diff --git a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs index 4953a9fc654..e87b96377a1 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs @@ -61,13 +61,13 @@ public HelloMessage Deserialize(IByteBuffer msgBytes) HelloMessage helloMessage = new(); helloMessage.P2PVersion = rlpStream.DecodeByte(); helloMessage.ClientId = string.Intern(rlpStream.DecodeString()); - helloMessage.Capabilities = rlpStream.DecodeArray(ctx => + helloMessage.Capabilities = rlpStream.DecodeArrayPoolList(ctx => { ctx.ReadSequenceLength(); string protocolCode = string.Intern(ctx.DecodeString()); int version = ctx.DecodeByte(); return new Capability(protocolCode, version); - }).ToList(); + }); helloMessage.ListenPort = rlpStream.DecodeInt(); diff --git a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs index 253e561439b..9ee3d70deb8 100644 --- a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs @@ -11,7 +11,9 @@ using System.Threading.Tasks; using FastEnumUtility; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Logging; using Nethermind.Network.Contract.P2P; using Nethermind.Network.P2P.EventArg; @@ -22,13 +24,20 @@ namespace Nethermind.Network.P2P.ProtocolHandlers; -public class P2PProtocolHandler : ProtocolHandlerBase, IPingSender, IP2PProtocolHandler +public class P2PProtocolHandler( + ISession session, + PublicKey localNodeId, + INodeStatsManager nodeStatsManager, + IMessageSerializationService serializer, + Regex? clientIdPattern, + ILogManager logManager) + : ProtocolHandlerBase(session, nodeStatsManager, serializer, logManager), IPingSender, IP2PProtocolHandler { private TaskCompletionSource _pongCompletionSource; - private readonly INodeStatsManager _nodeStatsManager; + private readonly INodeStatsManager _nodeStatsManager = nodeStatsManager ?? throw new ArgumentNullException(nameof(nodeStatsManager)); private bool _sentHello; - private List _agreedCapabilities { get; } - private List _availableCapabilities { get; set; } + private readonly List _agreedCapabilities = new(); + private List _availableCapabilities = new(); private byte _protocolVersion = 5; @@ -48,44 +57,26 @@ public class P2PProtocolHandler : ProtocolHandlerBase, IPingSender, IP2PProtocol public IReadOnlyList AgreedCapabilities { get { return _agreedCapabilities; } } public IReadOnlyList AvailableCapabilities { get { return _availableCapabilities; } } - private readonly List SupportedCapabilities = DefaultCapabilities.ToList(); - private readonly Regex? _clientIdPattern; + private readonly List _supportedCapabilities = DefaultCapabilities.ToList(); - public int ListenPort { get; } - public PublicKey LocalNodeId { get; } - public string RemoteClientId { get; private set; } + public int ListenPort { get; } = session.LocalPort; + public PublicKey LocalNodeId { get; } = localNodeId; + private string RemoteClientId { get; set; } - public override event EventHandler ProtocolInitialized; + public override event EventHandler? ProtocolInitialized; - public override event EventHandler SubprotocolRequested; - - public P2PProtocolHandler( - ISession session, - PublicKey localNodeId, - INodeStatsManager nodeStatsManager, - IMessageSerializationService serializer, - Regex? clientIdPattern, - ILogManager logManager) : base(session, nodeStatsManager, serializer, logManager) - { - _nodeStatsManager = nodeStatsManager ?? throw new ArgumentNullException(nameof(nodeStatsManager)); - _clientIdPattern = clientIdPattern; - - LocalNodeId = localNodeId; - ListenPort = session.LocalPort; - _agreedCapabilities = new List(); - _availableCapabilities = new List(); - } + public override event EventHandler? SubprotocolRequested; public bool HasAvailableCapability(Capability capability) => _availableCapabilities.Contains(capability); public bool HasAgreedCapability(Capability capability) => _agreedCapabilities.Contains(capability); public void AddSupportedCapability(Capability capability) { - if (SupportedCapabilities.Contains(capability)) + if (_supportedCapabilities.Contains(capability)) { return; } - SupportedCapabilities.Add(capability); + _supportedCapabilities.Add(capability); } public override void Init() @@ -112,7 +103,7 @@ public override void HandleMessage(Packet msg) case P2PMessageCode.Hello: { Metrics.HellosReceived++; - HelloMessage helloMessage = Deserialize(msg.Data); + using HelloMessage helloMessage = Deserialize(msg.Data); HandleHello(helloMessage); ReportIn(helloMessage, size); @@ -131,24 +122,19 @@ public override void HandleMessage(Packet msg) } case P2PMessageCode.Disconnect: { - DisconnectMessage disconnectMessage = Deserialize(msg.Data); + using DisconnectMessage disconnectMessage = Deserialize(msg.Data); ReportIn(disconnectMessage, size); EthDisconnectReason disconnectReason = FastEnum.IsDefined((byte)disconnectMessage.Reason) - ? ((EthDisconnectReason)disconnectMessage.Reason) + ? (EthDisconnectReason)disconnectMessage.Reason : EthDisconnectReason.Other; if (Logger.IsTrace) { - if (!FastEnum.IsDefined((byte)disconnectMessage.Reason)) - { - Logger.Trace($"{Session} unknown disconnect reason ({disconnectMessage.Reason}) on {Session.RemotePort}"); - } - else - { - Logger.Trace($"{Session} Received disconnect ({disconnectReason}) on {Session.RemotePort}"); - } + Logger.Trace(!FastEnum.IsDefined((byte)disconnectMessage.Reason) + ? $"{Session} unknown disconnect reason ({disconnectMessage.Reason}) on {Session.RemotePort}" + : $"{Session} Received disconnect ({disconnectReason}) on {Session.RemotePort}"); } Close(disconnectReason); @@ -170,12 +156,11 @@ public override void HandleMessage(Packet msg) } case P2PMessageCode.AddCapability: { - AddCapabilityMessage message = Deserialize(msg.Data); + using AddCapabilityMessage message = Deserialize(msg.Data); Capability capability = message.Capability; _agreedCapabilities.Add(message.Capability); - SupportedCapabilities.Add(message.Capability); - if (Logger.IsTrace) - Logger.Trace($"{Session.RemoteNodeId} Starting handler for {capability} on {Session.RemotePort}"); + _supportedCapabilities.Add(message.Capability); + if (Logger.IsTrace) Logger.Trace($"{Session.RemoteNodeId} Starting handler for {capability} on {Session.RemotePort}"); SubprotocolRequested?.Invoke(this, new ProtocolEventArgs(capability.ProtocolCode, capability.Version)); break; } @@ -221,11 +206,11 @@ private void HandleHello(HelloMessage hello) _protocolVersion = hello.P2PVersion; - List capabilities = hello.Capabilities; + IOwnedReadOnlyList? capabilities = hello.Capabilities; _availableCapabilities = new List(capabilities); foreach (Capability theirCapability in capabilities) { - if (SupportedCapabilities.Contains(theirCapability)) + if (_supportedCapabilities.Contains(theirCapability)) { if (Logger.IsTrace) Logger.Trace($"{Session.RemoteNodeId} Agreed on {theirCapability.ProtocolCode} v{theirCapability.Version}"); @@ -247,7 +232,7 @@ private void HandleHello(HelloMessage hello) $"capabilities: {string.Join(", ", capabilities)}"); } - if (_clientIdPattern?.IsMatch(hello.ClientId) == false) + if (clientIdPattern?.IsMatch(hello.ClientId) == false) { Session.InitiateDisconnect( DisconnectReason.ClientFiltered, @@ -260,7 +245,7 @@ private void HandleHello(HelloMessage hello) { P2PVersion = ProtocolVersion, ClientId = RemoteClientId, - Capabilities = capabilities, + Capabilities = _availableCapabilities, ListenPort = hello.ListenPort }; @@ -331,7 +316,7 @@ private void SendHello() HelloMessage helloMessage = new() { - Capabilities = SupportedCapabilities, + Capabilities = _supportedCapabilities.ToPooledList(), ClientId = ProductInfo.ClientId, NodeId = LocalNodeId, ListenPort = ListenPort, diff --git a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs index bdcec76de71..9de5b2d14e5 100644 --- a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs +++ b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; @@ -54,7 +55,7 @@ public abstract class SyncPeerProtocolHandlerBase : ZeroProtocolHandlerBase, ISy protected readonly ITimestamper _timestamper; protected readonly TxDecoder _txDecoder; - protected readonly MessageQueue _headersRequests; + protected readonly MessageQueue> _headersRequests; protected readonly MessageQueue _bodiesRequests; private readonly LatencyAndMessageSizeBasedRequestSizer _bodiesRequestSizer = new( @@ -87,7 +88,7 @@ protected SyncPeerProtocolHandlerBase(ISession session, BackgroundTaskScheduler = new BackgroundTaskSchedulerWrapper(this, backgroundTaskScheduler ?? throw new ArgumentNullException(nameof(BackgroundTaskScheduler))); _timestamper = Timestamper.Default; _txDecoder = new TxDecoder(); - _headersRequests = new MessageQueue(Send); + _headersRequests = new MessageQueue>(Send); _bodiesRequests = new MessageQueue(Send); } @@ -127,11 +128,11 @@ async Task ISyncPeer.GetBlockBodies(IReadOnlyList blo token); } - async Task ISyncPeer.GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + async Task> ISyncPeer.GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) { if (maxBlocks == 0) { - return Array.Empty(); + return ArrayPoolList.Empty(); } GetBlockHeadersMessage msg = new(); @@ -140,11 +141,11 @@ async Task ISyncPeer.GetBlockHeaders(long number, int maxBlocks, msg.Skip = skip; msg.StartBlockNumber = number; - BlockHeader[] headers = await SendRequest(msg, token); + IOwnedReadOnlyList headers = await SendRequest(msg, token); return headers; } - protected virtual async Task SendRequest(GetBlockHeadersMessage message, CancellationToken token) + protected virtual async Task> SendRequest(GetBlockHeadersMessage message, CancellationToken token) { if (Logger.IsTrace) { @@ -172,15 +173,15 @@ protected virtual async Task SendRequest(GetBlockHeadersMessage m msg.Reverse = 0; msg.Skip = 0; - BlockHeader[] headers = await SendRequest(msg, token); - return headers.Length > 0 ? headers[0] : null; + IOwnedReadOnlyList headers = await SendRequest(msg, token); + return headers.Count > 0 ? headers[0] : null; } - async Task ISyncPeer.GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + async Task> ISyncPeer.GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) { if (maxBlocks == 0) { - return Array.Empty(); + return ArrayPoolList.Empty(); } GetBlockHeadersMessage msg = new(); @@ -189,16 +190,16 @@ async Task ISyncPeer.GetBlockHeaders(Hash256 startHash, int maxBl msg.Reverse = 0; msg.Skip = skip; - BlockHeader[] headers = await SendRequest(msg, token); + IOwnedReadOnlyList headers = await SendRequest(msg, token); return headers; } - public virtual Task GetReceipts(IReadOnlyList blockHash, CancellationToken token) + public virtual Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) { throw new NotSupportedException("Fast sync not supported by eth62 protocol"); } - public virtual Task GetNodeData(IReadOnlyList hashes, CancellationToken token) + public virtual Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) { throw new NotSupportedException("Fast sync not supported by eth62 protocol"); } @@ -219,7 +220,7 @@ protected virtual void SendNewTransactionCore(Transaction tx) { if (!tx.SupportsBlobs) //additional protection from sending full tx with blob { - SendMessage(new[] { tx }); + SendMessage(new ArrayPoolList(1) { tx }); } } @@ -251,7 +252,7 @@ protected virtual void SendNewTransactionsCore(IEnumerable txs, boo if (txSize > packetSizeLeft && txsToSend.Count > 0) { SendMessage(txsToSend); - txsToSend.Clear(); + txsToSend = new(1024); packetSizeLeft = TransactionsMessage.MaxPacketSize; } @@ -273,7 +274,7 @@ protected virtual void SendNewTransactionsCore(IEnumerable txs, boo } } - private void SendMessage(IList txsToSend) + private void SendMessage(IOwnedReadOnlyList txsToSend) { TransactionsMessage msg = new(txsToSend); Send(msg); @@ -281,16 +282,17 @@ private void SendMessage(IList txsToSend) protected async Task Handle(GetBlockHeadersMessage getBlockHeadersMessage, CancellationToken cancellationToken) { + using GetBlockHeadersMessage message = getBlockHeadersMessage; Metrics.Eth62GetBlockHeadersReceived++; Stopwatch stopwatch = Stopwatch.StartNew(); if (Logger.IsTrace) { Logger.Trace($"Received headers request from {Session.Node:c}:"); - Logger.Trace($" MaxHeaders: {getBlockHeadersMessage.MaxHeaders}"); - Logger.Trace($" Reverse: {getBlockHeadersMessage.Reverse}"); - Logger.Trace($" Skip: {getBlockHeadersMessage.Skip}"); - Logger.Trace($" StartingBlockhash: {getBlockHeadersMessage.StartBlockHash}"); - Logger.Trace($" StartingBlockNumber: {getBlockHeadersMessage.StartBlockNumber}"); + Logger.Trace($" MaxHeaders: {message.MaxHeaders}"); + Logger.Trace($" Reverse: {message.Reverse}"); + Logger.Trace($" Skip: {message.Skip}"); + Logger.Trace($" StartingBlockhash: {message.StartBlockHash}"); + Logger.Trace($" StartingBlockNumber: {message.StartBlockNumber}"); } // // to clearly state that this client is an ETH client and not ETC (and avoid disconnections on reversed sync) @@ -307,7 +309,7 @@ protected async Task Handle(GetBlockHeadersMessage getBlock // return; // } - BlockHeadersMessage resp = await FulfillBlockHeadersRequest(getBlockHeadersMessage, cancellationToken); + BlockHeadersMessage resp = await FulfillBlockHeadersRequest(message, cancellationToken); stopwatch.Stop(); if (Logger.IsTrace) Logger.Trace($"OUT {Counter:D5} BlockHeaders to {Node:c} in {stopwatch.Elapsed.TotalMilliseconds}ms"); @@ -324,9 +326,9 @@ protected Task FulfillBlockHeadersRequest(GetBlockHeadersMe Hash256 startingHash = msg.StartBlockHash; startingHash ??= SyncServer.FindHash(msg.StartBlockNumber); - BlockHeader[] headers = + IOwnedReadOnlyList headers = startingHash is null - ? Array.Empty() + ? ArrayPoolList.Empty() : SyncServer.FindHeaders(startingHash, (int)msg.MaxHeaders, (int)msg.Skip, msg.Reverse == 1); headers = FixHeadersForGeth(headers); @@ -336,16 +338,17 @@ startingHash is null protected async Task Handle(GetBlockBodiesMessage request, CancellationToken cancellationToken) { + using GetBlockBodiesMessage message = request; Metrics.Eth62GetBlockBodiesReceived++; if (Logger.IsTrace) { - Logger.Trace($"Received bodies request of length {request.BlockHashes.Count} from {Session.Node:c}:"); + Logger.Trace($"Received bodies request of length {message.BlockHashes.Count} from {Session.Node:c}:"); } Stopwatch stopwatch = Stopwatch.StartNew(); Interlocked.Increment(ref Counter); - BlockBodiesMessage resp = await FulfillBlockBodiesRequest(request, cancellationToken); + BlockBodiesMessage resp = await FulfillBlockBodiesRequest(message, cancellationToken); stopwatch.Stop(); if (Logger.IsTrace) Logger.Trace($"OUT {Counter:D5} BlockBodies to {Node:c} in {stopwatch.Elapsed.TotalMilliseconds}ms"); return resp; @@ -354,17 +357,17 @@ protected async Task Handle(GetBlockBodiesMessage request, C protected Task FulfillBlockBodiesRequest(GetBlockBodiesMessage getBlockBodiesMessage, CancellationToken cancellationToken) { IReadOnlyList hashes = getBlockBodiesMessage.BlockHashes; - Block[] blocks = new Block[hashes.Count]; + using ArrayPoolList blocks = new(hashes.Count); ulong sizeEstimate = 0; for (int i = 0; i < hashes.Count; i++) { - blocks[i] = SyncServer.Find(hashes[i]); - sizeEstimate += MessageSizeEstimator.EstimateSize(blocks[i]); + Block block = SyncServer.Find(hashes[i]); + blocks.Add(block); + sizeEstimate += MessageSizeEstimator.EstimateSize(block); if (sizeEstimate > SoftOutgoingMessageSizeLimit || cancellationToken.IsCancellationRequested) { - Array.Resize(ref blocks, i + 1); break; } } @@ -386,14 +389,15 @@ protected void HandleBodies(BlockBodiesMessage blockBodiesMessage, long size) protected async Task Handle(GetReceiptsMessage msg, CancellationToken cancellationToken) { + using var message = msg; Metrics.Eth63GetReceiptsReceived++; - if (msg.Hashes.Count > 512) + if (message.Hashes.Count > 512) { throw new EthSyncException("Incoming receipts request for more than 512 blocks"); } Stopwatch stopwatch = Stopwatch.StartNew(); - ReceiptsMessage resp = await FulfillReceiptsRequest(msg, cancellationToken); + ReceiptsMessage resp = await FulfillReceiptsRequest(message, cancellationToken); stopwatch.Stop(); if (Logger.IsTrace) Logger.Trace($"OUT {Counter:D5} Receipts to {Node:c} in {stopwatch.Elapsed.TotalMilliseconds}ms"); @@ -402,12 +406,12 @@ protected async Task Handle(GetReceiptsMessage msg, Cancellatio protected Task FulfillReceiptsRequest(GetReceiptsMessage getReceiptsMessage, CancellationToken cancellationToken) { - TxReceipt[][] txReceipts = new TxReceipt[getReceiptsMessage.Hashes.Count][]; + ArrayPoolList txReceipts = new(getReceiptsMessage.Hashes.Count); ulong sizeEstimate = 0; for (int i = 0; i < getReceiptsMessage.Hashes.Count; i++) { - txReceipts[i] = SyncServer.GetReceipts(getReceiptsMessage.Hashes[i]); + txReceipts.Add(SyncServer.GetReceipts(getReceiptsMessage.Hashes[i])); for (int j = 0; j < txReceipts[i].Length; j++) { sizeEstimate += MessageSizeEstimator.EstimateSize(txReceipts[i][j]); @@ -415,7 +419,6 @@ protected Task FulfillReceiptsRequest(GetReceiptsMessage getRec if (sizeEstimate > SoftOutgoingMessageSizeLimit || cancellationToken.IsCancellationRequested) { - Array.Resize(ref txReceipts, i + 1); break; } } @@ -423,12 +426,12 @@ protected Task FulfillReceiptsRequest(GetReceiptsMessage getRec return Task.FromResult(new ReceiptsMessage(txReceipts)); } - private static BlockHeader[] FixHeadersForGeth(BlockHeader[] headers) + private static IOwnedReadOnlyList FixHeadersForGeth(IOwnedReadOnlyList headers) { int emptyBlocksAtTheEnd = 0; - for (int i = 0; i < headers.Length; i++) + for (int i = 0; i < headers.Count; i++) { - if (headers[headers.Length - 1 - i] is null) + if (headers[headers.Count - 1 - i] is null) { emptyBlocksAtTheEnd++; } @@ -440,8 +443,16 @@ private static BlockHeader[] FixHeadersForGeth(BlockHeader[] headers) if (emptyBlocksAtTheEnd != 0) { - BlockHeader[] gethFriendlyHeaders = headers.AsSpan(0, headers.Length - emptyBlocksAtTheEnd).ToArray(); - headers = gethFriendlyHeaders; + int toTake = headers.Count - emptyBlocksAtTheEnd; + if (headers is ArrayPoolList asArrayPoolList) + { + asArrayPoolList.Truncate(toTake); + return headers; + } + + ArrayPoolList newList = new ArrayPoolList(toTake, headers.Take(toTake)); + headers.Dispose(); + return newList; } return headers; diff --git a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/ZeroProtocolHandlerBase.cs b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/ZeroProtocolHandlerBase.cs index 5fa02d2969a..cfba1eca3b2 100644 --- a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/ZeroProtocolHandlerBase.cs +++ b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/ZeroProtocolHandlerBase.cs @@ -11,13 +11,9 @@ namespace Nethermind.Network.P2P.ProtocolHandlers { - public abstract class ZeroProtocolHandlerBase : ProtocolHandlerBase, IZeroProtocolHandler + public abstract class ZeroProtocolHandlerBase(ISession session, INodeStatsManager nodeStats, IMessageSerializationService serializer, ILogManager logManager) + : ProtocolHandlerBase(session, nodeStats, serializer, logManager), IZeroProtocolHandler { - protected ZeroProtocolHandlerBase(ISession session, INodeStatsManager nodeStats, IMessageSerializationService serializer, ILogManager logManager) - : base(session, nodeStats, serializer, logManager) - { - } - public override void HandleMessage(Packet message) { ZeroPacket zeroPacket = new(message); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessage.cs index d84af181935..dd6319fd2f5 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessage.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Network.P2P.Messages; @@ -10,12 +11,12 @@ namespace Nethermind.Network.P2P.Subprotocols.Eth { public abstract class HashesMessage : P2PMessage { - protected HashesMessage(IReadOnlyList hashes) + protected HashesMessage(IOwnedReadOnlyList hashes) { Hashes = hashes ?? throw new ArgumentNullException(nameof(hashes)); } - public IReadOnlyList Hashes { get; } + public IOwnedReadOnlyList Hashes { get; } public override string ToString() { @@ -25,7 +26,7 @@ public override string ToString() public override void Dispose() { base.Dispose(); - if (Hashes is IDisposable disposable) disposable.Dispose(); + Hashes.Dispose(); } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs index b11cc993ebb..c23250cc5be 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Serialization.Rlp; @@ -21,6 +22,17 @@ protected static Hash256[] DeserializeHashes(RlpStream rlpStream) return hashes; } + protected ArrayPoolList DeserializeHashesArrayPool(IByteBuffer byteBuffer) + { + NettyRlpStream nettyRlpStream = new(byteBuffer); + return DeserializeHashesArrayPool(nettyRlpStream); + } + + protected static ArrayPoolList DeserializeHashesArrayPool(RlpStream rlpStream) + { + return rlpStream.DecodeArrayPoolList(itemContext => itemContext.DecodeKeccak()); + } + public void Serialize(IByteBuffer byteBuffer, T message) { int length = GetLength(message, out int contentLength); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs index 55aaa358e80..0181aa0c9cd 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs @@ -30,8 +30,7 @@ public PooledTxsRequestor(ITxPool txPool, ITxPoolConfig txPoolConfig) public void RequestTransactions(Action send, IReadOnlyList hashes) { - ArrayPoolList discoveredTxHashes = new(hashes.Count); - AddMarkUnknownHashes(hashes, discoveredTxHashes); + ArrayPoolList discoveredTxHashes = AddMarkUnknownHashes(hashes); if (discoveredTxHashes.Count != 0) { @@ -41,8 +40,7 @@ public void RequestTransactions(Action send, IRead public void RequestTransactionsEth66(Action send, IReadOnlyList hashes) { - ArrayPoolList discoveredTxHashes = new(hashes.Count); - AddMarkUnknownHashes(hashes, discoveredTxHashes); + using ArrayPoolList discoveredTxHashes = AddMarkUnknownHashes(hashes); if (discoveredTxHashes.Count != 0) { @@ -74,8 +72,7 @@ public void RequestTransactionsEth66(Action send, IReadOnlyList hashes, IReadOnlyList sizes, IReadOnlyList types) { - using ArrayPoolList<(Hash256 Hash, byte Type, int Size)> discoveredTxHashesAndSizes = new(hashes.Count); - AddMarkUnknownHashesEth68(hashes, sizes, types, discoveredTxHashesAndSizes); + using ArrayPoolList<(Hash256 Hash, byte Type, int Size)> discoveredTxHashesAndSizes = AddMarkUnknownHashesEth68(hashes, sizes, types); if (discoveredTxHashesAndSizes.Count != 0) { @@ -108,9 +105,10 @@ public void RequestTransactionsEth68(Action hashes, ArrayPoolList discoveredTxHashes) + private ArrayPoolList AddMarkUnknownHashes(IReadOnlyList hashes) { int count = hashes.Count; + ArrayPoolList discoveredTxHashes = new ArrayPoolList(count); for (int i = 0; i < count; i++) { Hash256 hash = hashes[i]; @@ -119,10 +117,14 @@ private void AddMarkUnknownHashes(IReadOnlyList hashes, ArrayPoolList hashes, IReadOnlyList sizes, IReadOnlyList types, ArrayPoolList<(Hash256, byte, int)> discoveredTxHashesAndSizes) + + private ArrayPoolList<(Hash256, byte, int)> AddMarkUnknownHashesEth68(IReadOnlyList hashes, IReadOnlyList sizes, IReadOnlyList types) { int count = hashes.Count; + ArrayPoolList<(Hash256, byte, int)> discoveredTxHashesAndSizes = new(count); for (int i = 0; i < count; i++) { Hash256 hash = hashes[i]; @@ -131,18 +133,20 @@ private void AddMarkUnknownHashesEth68(IReadOnlyList hashes, IReadOnlyL discoveredTxHashesAndSizes.Add((hash, types[i], sizes[i])); } } + + return discoveredTxHashesAndSizes; } - private static void RequestPooledTransactions(Action send, IReadOnlyList hashesToRequest) + private static void RequestPooledTransactions(Action send, IOwnedReadOnlyList hashesToRequest) { send(new GetPooledTransactionsMessage(hashesToRequest)); Metrics.Eth65GetPooledTransactionsRequested++; } - private static void RequestPooledTransactionsEth66(Action send, IReadOnlyList hashesToRequest) + private static void RequestPooledTransactionsEth66(Action send, IOwnedReadOnlyList hashesToRequest) { GetPooledTransactionsMessage msg65 = new(hashesToRequest); - send(new V66.Messages.GetPooledTransactionsMessage() { EthMessage = msg65 }); + send(new V66.Messages.GetPooledTransactionsMessage { EthMessage = msg65 }); Metrics.Eth66GetPooledTransactionsRequested++; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs index 762f8988a5a..11e75e066ff 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs @@ -144,16 +144,17 @@ bool CanAcceptBlockGossip() switch (packetType) { case Eth62MessageCode.Status: - StatusMessage statusMsg = Deserialize(message.Content); - ReportIn(statusMsg, size); - Handle(statusMsg); - break; + { + using StatusMessage statusMsg = Deserialize(message.Content); + ReportIn(statusMsg, size); + Handle(statusMsg); + break; + } case Eth62MessageCode.NewBlockHashes: Metrics.Eth62NewBlockHashesReceived++; if (CanAcceptBlockGossip()) { - NewBlockHashesMessage newBlockHashesMessage = - Deserialize(message.Content); + using NewBlockHashesMessage newBlockHashesMessage = Deserialize(message.Content); ReportIn(newBlockHashesMessage, size); Handle(newBlockHashesMessage); } @@ -182,8 +183,7 @@ bool CanAcceptBlockGossip() break; case Eth62MessageCode.GetBlockHeaders: - GetBlockHeadersMessage getBlockHeadersMessage - = Deserialize(message.Content); + GetBlockHeadersMessage getBlockHeadersMessage = Deserialize(message.Content); ReportIn(getBlockHeadersMessage, size); BackgroundTaskScheduler.ScheduleSyncServe(getBlockHeadersMessage, Handle); break; @@ -206,7 +206,7 @@ GetBlockHeadersMessage getBlockHeadersMessage Metrics.Eth62NewBlockReceived++; if (CanAcceptBlockGossip()) { - NewBlockMessage newBlockMsg = Deserialize(message.Content); + using NewBlockMessage newBlockMsg = Deserialize(message.Content); ReportIn(newBlockMsg, size); Handle(newBlockMsg); } @@ -259,29 +259,40 @@ private void Handle(StatusMessage status) protected void Handle(TransactionsMessage msg) { - IList iList = msg.Transactions; + IOwnedReadOnlyList iList = msg.Transactions; BackgroundTaskScheduler.ScheduleBackgroundTask((iList, 0), HandleSlow); } - private ValueTask HandleSlow((IList txs, int startIndex) request, CancellationToken cancellationToken) + private ValueTask HandleSlow((IOwnedReadOnlyList txs, int startIndex) request, CancellationToken cancellationToken) { - IList transactions = request.txs; - int startIdx = request.startIndex; - - bool isTrace = Logger.IsTrace; - int count = transactions.Count; - for (int i = startIdx; i < count; i++) + IOwnedReadOnlyList transactions = request.txs; + try { - if (cancellationToken.IsCancellationRequested) + int startIdx = request.startIndex; + bool isTrace = Logger.IsTrace; + int count = transactions.Count; + for (int i = startIdx; i < count; i++) { - // Reschedule and with different start index - BackgroundTaskScheduler.ScheduleBackgroundTask((transactions, i), HandleSlow); - return ValueTask.CompletedTask; + if (cancellationToken.IsCancellationRequested) + { + // Reschedule and with different start index + BackgroundTaskScheduler.ScheduleBackgroundTask((transactions, i), HandleSlow); + return ValueTask.CompletedTask; + } + + PrepareAndSubmitTransaction(transactions[i], isTrace); } - PrepareAndSubmitTransaction(transactions[i], isTrace); + transactions.Dispose(); } + catch + { + transactions.Dispose(); + throw; + } + + return ValueTask.CompletedTask; } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/MessageSizeEstimator.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/MessageSizeEstimator.cs index 714015bee07..af5e7915978 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/MessageSizeEstimator.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/MessageSizeEstimator.cs @@ -28,7 +28,7 @@ public static ulong EstimateSize(Transaction tx) return 100UL + (ulong)(tx.Data?.Length ?? 0); } - public static ulong EstimateSize(Block block) + public static ulong EstimateSize(Block? block) { if (block is null) { diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs index 876b927ac79..730e231b2fa 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Collections.Generic; using Nethermind.Core; using Nethermind.Network.P2P.Messages; @@ -17,10 +18,10 @@ public BlockBodiesMessage() { } - public BlockBodiesMessage(Block[] blocks) + public BlockBodiesMessage(IReadOnlyList blocks) { - BlockBody[] bodies = new BlockBody[blocks.Length]; - for (int i = 0; i < blocks.Length; i++) + BlockBody[] bodies = new BlockBody[blocks.Count]; + for (int i = 0; i < blocks.Count; i++) { bodies[i] = blocks[i]?.Body; } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessage.cs index e294020cc37..8e78cc48e84 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessage.cs @@ -1,7 +1,10 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Collections.Generic; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Messages; namespace Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages @@ -11,17 +14,22 @@ public class BlockHeadersMessage : P2PMessage public override int PacketType { get; } = Eth62MessageCode.BlockHeaders; public override string Protocol { get; } = "eth"; - public BlockHeader[] BlockHeaders { get; set; } + public IOwnedReadOnlyList? BlockHeaders { get; set; } public BlockHeadersMessage() { } - public BlockHeadersMessage(BlockHeader[] blockHeaders) + public BlockHeadersMessage(IOwnedReadOnlyList? blockHeaders) { BlockHeaders = blockHeaders; } - public override string ToString() => $"{nameof(BlockHeadersMessage)}({BlockHeaders?.Length ?? 0})"; + public override void Dispose() + { + BlockHeaders?.Dispose(); + } + + public override string ToString() => $"{nameof(BlockHeadersMessage)}({BlockHeaders?.Count ?? 0})"; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessageSerializer.cs index 2c0353eb1de..30e182a4c9c 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockHeadersMessageSerializer.cs @@ -18,7 +18,7 @@ public void Serialize(IByteBuffer byteBuffer, BlockHeadersMessage message) RlpStream rlpStream = new NettyRlpStream(byteBuffer); rlpStream.StartSequence(contentLength); - for (int i = 0; i < message.BlockHeaders.Length; i++) + for (int i = 0; i < message.BlockHeaders.Count; i++) { rlpStream.Encode(message.BlockHeaders[i]); } @@ -33,7 +33,7 @@ public BlockHeadersMessage Deserialize(IByteBuffer byteBuffer) public int GetLength(BlockHeadersMessage message, out int contentLength) { contentLength = 0; - for (int i = 0; i < message.BlockHeaders.Length; i++) + for (int i = 0; i < message.BlockHeaders.Count; i++) { contentLength += _headerDecoder.GetLength(message.BlockHeaders[i], RlpBehaviors.None); } @@ -44,7 +44,7 @@ public int GetLength(BlockHeadersMessage message, out int contentLength) public static BlockHeadersMessage Deserialize(RlpStream rlpStream) { BlockHeadersMessage message = new(); - message.BlockHeaders = Rlp.DecodeArray(rlpStream); + message.BlockHeaders = Rlp.DecodeArrayPool(rlpStream); return message; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessage.cs index 4fb320bfe54..e9a5658adbd 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessage.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Messages; namespace Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages @@ -16,9 +17,9 @@ public class TransactionsMessage : P2PMessage public override int PacketType { get; } = Eth62MessageCode.Transactions; public override string Protocol { get; } = "eth"; - public IList Transactions { get; } + public IOwnedReadOnlyList Transactions { get; } - public TransactionsMessage(IList transactions) + public TransactionsMessage(IOwnedReadOnlyList transactions) { Transactions = transactions; } @@ -28,7 +29,7 @@ public TransactionsMessage(IList transactions) public override void Dispose() { base.Dispose(); - if (Transactions is IDisposable disposable) disposable.Dispose(); + Transactions?.Dispose(); } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs index f5c83b762d2..4887018e90a 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs @@ -3,6 +3,7 @@ using DotNetty.Buffers; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages @@ -27,7 +28,7 @@ public void Serialize(IByteBuffer byteBuffer, TransactionsMessage message) public TransactionsMessage Deserialize(IByteBuffer byteBuffer) { NettyRlpStream rlpStream = new(byteBuffer); - Transaction[] txs = DeserializeTxs(rlpStream); + IOwnedReadOnlyList txs = DeserializeTxs(rlpStream); return new TransactionsMessage(txs); } @@ -42,9 +43,9 @@ public int GetLength(TransactionsMessage message, out int contentLength) return Rlp.LengthOfSequence(contentLength); } - public static Transaction[] DeserializeTxs(RlpStream rlpStream) + public static IOwnedReadOnlyList DeserializeTxs(RlpStream rlpStream) { - return Rlp.DecodeArray(rlpStream, RlpBehaviors.InMempoolForm); + return Rlp.DecodeArrayPool(rlpStream, RlpBehaviors.InMempoolForm); } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandler.cs index a620fc7d5c1..e2c6b3caeca 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandler.cs @@ -9,7 +9,9 @@ using Nethermind.Consensus; using Nethermind.Consensus.Scheduler; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Logging; using Nethermind.Network.Contract.P2P; using Nethermind.Network.P2P.Subprotocols.Eth.V62; @@ -23,9 +25,9 @@ namespace Nethermind.Network.P2P.Subprotocols.Eth.V63 { public class Eth63ProtocolHandler : Eth62ProtocolHandler { - private readonly MessageQueue _nodeDataRequests; + private readonly MessageQueue> _nodeDataRequests; - private readonly MessageQueue _receiptsRequests; + private readonly MessageQueue, long)> _receiptsRequests; private readonly LatencyAndMessageSizeBasedRequestSizer _receiptsRequestSizer = new( minRequestLimit: 1, @@ -55,8 +57,8 @@ public Eth63ProtocolHandler(ISession session, ITxGossipPolicy? transactionsGossipPolicy = null) : base(session, serializer, nodeStatsManager, syncServer, backgroundTaskScheduler, txPool, gossipPolicy, logManager, transactionsGossipPolicy) { - _nodeDataRequests = new MessageQueue(Send); - _receiptsRequests = new MessageQueue(Send); + _nodeDataRequests = new MessageQueue>(Send); + _receiptsRequests = new MessageQueue, long)>(Send); } public override byte ProtocolVersion => EthVersions.Eth63; @@ -103,13 +105,13 @@ protected virtual void Handle(ReceiptsMessage msg, long size) private async Task Handle(GetNodeDataMessage msg, CancellationToken cancellationToken) { + using var message = msg; Metrics.Eth63GetNodeDataReceived++; Stopwatch stopwatch = Stopwatch.StartNew(); - NodeDataMessage response = await FulfillNodeDataRequest(msg, cancellationToken); + NodeDataMessage response = await FulfillNodeDataRequest(message, cancellationToken); stopwatch.Stop(); - if (Logger.IsTrace) - Logger.Trace($"OUT {Counter:D5} NodeData to {Node:c} in {stopwatch.Elapsed.TotalMilliseconds}ms"); + if (Logger.IsTrace) Logger.Trace($"OUT {Counter:D5} NodeData to {Node:c} in {stopwatch.Elapsed.TotalMilliseconds}ms"); return response; } @@ -121,7 +123,7 @@ protected Task FulfillNodeDataRequest(GetNodeDataMessage msg, C throw new EthSyncException("Incoming node data request for more than 4096 nodes"); } - byte[][] nodeData = SyncServer.GetNodeData(msg.Hashes, cancellationToken); + IOwnedReadOnlyList nodeData = SyncServer.GetNodeData(msg.Hashes, cancellationToken); return Task.FromResult(new NodeDataMessage(nodeData)); } @@ -132,34 +134,34 @@ protected virtual void Handle(NodeDataMessage msg, int size) _nodeDataRequests.Handle(msg.Data, size); } - public override async Task GetNodeData(IReadOnlyList keys, CancellationToken token) + public override async Task> GetNodeData(IReadOnlyList keys, CancellationToken token) { if (keys.Count == 0) { - return Array.Empty(); + return ArrayPoolList.Empty(); } - GetNodeDataMessage msg = new(keys); + GetNodeDataMessage msg = new(keys.ToPooledList()); // if node data is a disposable pooled array wrapper here then we could save around 1.6% allocations // on a sample 3M blocks Goerli fast sync - byte[][] nodeData = await SendRequest(msg, token); + IOwnedReadOnlyList nodeData = await SendRequest(msg, token); return nodeData; } - public override async Task GetReceipts(IReadOnlyList blockHashes, CancellationToken token) + public override async Task> GetReceipts(IReadOnlyList blockHashes, CancellationToken token) { if (blockHashes.Count == 0) { - return Array.Empty(); + return ArrayPoolList.Empty(); } - TxReceipt[][] txReceipts = await _receiptsRequestSizer.Run(blockHashes, async clampedBlockHashes => - await SendRequest(new GetReceiptsMessage(clampedBlockHashes), token)); + IOwnedReadOnlyList txReceipts = await _receiptsRequestSizer.Run(blockHashes, async clampedBlockHashes => + await SendRequest(new GetReceiptsMessage(clampedBlockHashes.ToPooledList()), token)); return txReceipts; } - protected virtual async Task SendRequest(GetNodeDataMessage message, CancellationToken token) + protected virtual async Task> SendRequest(GetNodeDataMessage message, CancellationToken token) { if (Logger.IsTrace) { @@ -175,7 +177,7 @@ protected virtual async Task SendRequest(GetNodeDataMessage message, C token); } - protected virtual async Task<(TxReceipt[][], long)> SendRequest(GetReceiptsMessage message, CancellationToken token) + protected virtual async Task<(IOwnedReadOnlyList, long)> SendRequest(GetReceiptsMessage message, CancellationToken token) { if (Logger.IsTrace) { diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessage.cs index cf6b662a1f4..9386b0b2d75 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessage.cs @@ -2,18 +2,14 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages { - public class GetNodeDataMessage : HashesMessage + public class GetNodeDataMessage(IOwnedReadOnlyList keys) : HashesMessage(keys) { public override int PacketType { get; } = Eth63MessageCode.GetNodeData; public override string Protocol { get; } = "eth"; - - public GetNodeDataMessage(IReadOnlyList keys) - : base(keys) - { - } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessageSerializer.cs index 343f736b71e..336296fa3f3 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetNodeDataMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages @@ -10,7 +11,7 @@ public class GetNodeDataMessageSerializer : HashesMessageSerializer? keys = DeserializeHashesArrayPool(byteBuffer); return new GetNodeDataMessage(keys); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessage.cs index fa16c227f15..f78350cb8b7 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessage.cs @@ -2,18 +2,14 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages { - public class GetReceiptsMessage : HashesMessage + public class GetReceiptsMessage(IOwnedReadOnlyList blockHashes) : HashesMessage(blockHashes) { public override int PacketType { get; } = Eth63MessageCode.GetReceipts; public override string Protocol { get; } = "eth"; - - public GetReceiptsMessage(IReadOnlyList blockHashes) - : base(blockHashes) - { - } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessageSerializer.cs index adadd99357d..c32282c676e 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/GetReceiptsMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Serialization.Rlp; @@ -12,7 +13,7 @@ public class GetReceiptsMessageSerializer : HashesMessageSerializer itemContext.DecodeKeccak()); + ArrayPoolList? hashes = rlpStream.DecodeArrayPoolList(itemContext => itemContext.DecodeKeccak()); return new GetReceiptsMessage(hashes); } @@ -24,7 +25,7 @@ public override GetReceiptsMessage Deserialize(IByteBuffer byteBuffer) public static GetReceiptsMessage Deserialize(RlpStream rlpStream) { - Hash256[] hashes = DeserializeHashes(rlpStream); + ArrayPoolList? hashes = HashesMessageSerializer.DeserializeHashesArrayPool(rlpStream); return new GetReceiptsMessage(hashes); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessage.cs index 1369cf8de91..b1fd514f370 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessage.cs @@ -2,21 +2,24 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Linq; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Messages; namespace Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages { - public class NodeDataMessage : P2PMessage + public class NodeDataMessage(IOwnedReadOnlyList? data) : P2PMessage { - public byte[][] Data { get; } + public IOwnedReadOnlyList Data { get; } = data ?? ArrayPoolList.Empty(); public override int PacketType { get; } = Eth63MessageCode.NodeData; public override string Protocol { get; } = "eth"; - public NodeDataMessage(byte[][]? data) + public override string ToString() => $"{nameof(NodeDataMessage)}({Data.Count})"; + + public override void Dispose() { - Data = data ?? Array.Empty(); + base.Dispose(); + Data.Dispose(); } - - public override string ToString() => $"{nameof(NodeDataMessage)}({Data.Length})"; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessageSerializer.cs index 141e49833e3..7b047b5da04 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/NodeDataMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages @@ -15,7 +16,7 @@ public void Serialize(IByteBuffer byteBuffer, NodeDataMessage message) RlpStream rlpStream = new NettyRlpStream(byteBuffer); rlpStream.StartSequence(contentLength); - for (int i = 0; i < message.Data.Length; i++) + for (int i = 0; i < message.Data.Count; i++) { rlpStream.Encode(message.Data[i]); } @@ -24,14 +25,14 @@ public void Serialize(IByteBuffer byteBuffer, NodeDataMessage message) public NodeDataMessage Deserialize(IByteBuffer byteBuffer) { RlpStream rlpStream = new NettyRlpStream(byteBuffer); - byte[][] result = rlpStream.DecodeArray(stream => stream.DecodeByteArray()); + ArrayPoolList result = rlpStream.DecodeArrayPoolList(stream => stream.DecodeByteArray()); return new NodeDataMessage(result); } public int GetLength(NodeDataMessage message, out int contentLength) { contentLength = 0; - for (int i = 0; i < message.Data.Length; i++) + for (int i = 0; i < message.Data.Count; i++) { contentLength += Rlp.LengthOf(message.Data[i]); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessage.cs index a3e75dd67c6..61a522fdc33 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessage.cs @@ -3,24 +3,26 @@ using System; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Messages; namespace Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages { - public class ReceiptsMessage : P2PMessage + public class ReceiptsMessage(IOwnedReadOnlyList txReceipts) : P2PMessage { - public TxReceipt[][] TxReceipts { get; } + public IOwnedReadOnlyList TxReceipts { get; } = txReceipts ?? ArrayPoolList.Empty(); public override int PacketType { get; } = Eth63MessageCode.Receipts; public override string Protocol { get; } = "eth"; private static ReceiptsMessage? _empty; public static ReceiptsMessage Empty => _empty ??= new ReceiptsMessage(null); - public ReceiptsMessage(TxReceipt[][] txReceipts) + public override string ToString() => $"{nameof(ReceiptsMessage)}({TxReceipts?.Count ?? 0})"; + + public override void Dispose() { - TxReceipts = txReceipts ?? Array.Empty(); + base.Dispose(); + TxReceipts?.Dispose(); } - - public override string ToString() => $"{nameof(ReceiptsMessage)}({TxReceipts?.Length ?? 0})"; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs index 2462096632f..342b608cfec 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs @@ -4,6 +4,7 @@ using System; using DotNetty.Buffers; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Serialization.Rlp; @@ -74,7 +75,7 @@ public ReceiptsMessage Deserialize(IByteBuffer byteBuffer) public ReceiptsMessage Deserialize(RlpStream rlpStream) { - TxReceipt[][] data = rlpStream.DecodeArray(itemContext => + ArrayPoolList data = rlpStream.DecodeArrayPoolList(itemContext => itemContext.DecodeArray(nestedContext => _decoder.Decode(nestedContext)) ?? Array.Empty(), true); ReceiptsMessage message = new(data); @@ -85,7 +86,7 @@ public int GetLength(ReceiptsMessage message, out int contentLength) { contentLength = 0; - for (int i = 0; i < message.TxReceipts.Length; i++) + for (int i = 0; i < message.TxReceipts.Count; i++) { TxReceipt?[]? txReceipts = message.TxReceipts[i]; if (txReceipts is null) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs index e9320849ebd..443f69e00b2 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs @@ -59,8 +59,7 @@ public override void HandleMessage(ZeroPacket message) case Eth65MessageCode.PooledTransactions: if (CanReceiveTransactions) { - PooledTransactionsMessage pooledTxMsg - = Deserialize(message.Content); + PooledTransactionsMessage pooledTxMsg = Deserialize(message.Content); Metrics.Eth65PooledTransactionsReceived++; ReportIn(pooledTxMsg, size); Handle(pooledTxMsg); @@ -73,16 +72,14 @@ PooledTransactionsMessage pooledTxMsg break; case Eth65MessageCode.GetPooledTransactions: - GetPooledTransactionsMessage getPooledTxMsg - = Deserialize(message.Content); + GetPooledTransactionsMessage getPooledTxMsg = Deserialize(message.Content); ReportIn(getPooledTxMsg, size); BackgroundTaskScheduler.ScheduleBackgroundTask(getPooledTxMsg, Handle); break; case Eth65MessageCode.NewPooledTransactionHashes: if (CanReceiveTransactions) { - NewPooledTransactionHashesMessage newPooledTxMsg = - Deserialize(message.Content); + NewPooledTransactionHashesMessage newPooledTxMsg = Deserialize(message.Content); ReportIn(newPooledTxMsg, size); Handle(newPooledTxMsg); } @@ -123,10 +120,11 @@ protected void AddNotifiedTransactions(IReadOnlyList hashes) private async ValueTask Handle(GetPooledTransactionsMessage msg, CancellationToken cancellationToken) { + using var message = msg; Metrics.Eth65GetPooledTransactionsReceived++; Stopwatch stopwatch = Stopwatch.StartNew(); - Send(await FulfillPooledTransactionsRequest(msg, cancellationToken)); + Send(await FulfillPooledTransactionsRequest(message, cancellationToken)); stopwatch.Stop(); if (Logger.IsTrace) Logger.Trace($"OUT {Counter:D5} {nameof(GetPooledTransactionsMessage)} to {Node:c} " + @@ -174,8 +172,8 @@ protected override void SendNewTransactionsCore(IEnumerable txs, bo { if (hashes.Count == NewPooledTransactionHashesMessage.MaxCount) { - SendMessage(hashes); - hashes.Clear(); + SendNewPooledTransactionMessage(hashes); + hashes = new(NewPooledTransactionHashesMessage.MaxCount); } if (tx.Hash is not null) @@ -187,7 +185,7 @@ protected override void SendNewTransactionsCore(IEnumerable txs, bo if (hashes.Count > 0) { - SendMessage(hashes); + SendNewPooledTransactionMessage(hashes); } else { @@ -195,7 +193,7 @@ protected override void SendNewTransactionsCore(IEnumerable txs, bo } } - private void SendMessage(IReadOnlyList hashes) + private void SendNewPooledTransactionMessage(IOwnedReadOnlyList hashes) { NewPooledTransactionHashesMessage msg = new(hashes); Send(msg); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessage.cs index 4a88fc96727..1a2d12079da 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessage.cs @@ -2,20 +2,16 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages { - public class GetPooledTransactionsMessage : HashesMessage + public class GetPooledTransactionsMessage(IOwnedReadOnlyList hashes) : HashesMessage(hashes) { public override int PacketType { get; } = Eth65MessageCode.GetPooledTransactions; public override string Protocol { get; } = "eth"; - public GetPooledTransactionsMessage(IReadOnlyList hashes) - : base(hashes) - { - } - public override string ToString() => $"{nameof(GetPooledTransactionsMessage)}({Hashes?.Count})"; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessageSerializer.cs index 8f87b3f8a39..22d16d8b79e 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/GetPooledTransactionsMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages @@ -10,7 +11,7 @@ public class GetPooledTransactionsMessageSerializer : HashesMessageSerializer? hashes = DeserializeHashesArrayPool(byteBuffer); return new GetPooledTransactionsMessage(hashes); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessage.cs index 7e1a561e6f6..051c6ff2fda 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessage.cs @@ -2,11 +2,12 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages { - public class NewPooledTransactionHashesMessage : HashesMessage + public class NewPooledTransactionHashesMessage(IOwnedReadOnlyList hashes) : HashesMessage(hashes) { // we are able to safely send message with up to 3102 hashes to not exceed message size of 102400 bytes // which is used by Geth and us as max message size. (3102 items message has 102370 bytes) @@ -15,11 +16,6 @@ public class NewPooledTransactionHashesMessage : HashesMessage public override int PacketType { get; } = Eth65MessageCode.NewPooledTransactionHashes; public override string Protocol { get; } = "eth"; - public NewPooledTransactionHashesMessage(IReadOnlyList hashes) - : base(hashes) - { - } - public override string ToString() => $"{nameof(NewPooledTransactionHashesMessage)}({Hashes?.Count})"; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessageSerializer.cs index 8a145c6ada5..dd3580492e9 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/NewPooledTransactionHashesMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages @@ -11,7 +12,7 @@ public class NewPooledTransactionHashesMessageSerializer { public override NewPooledTransactionHashesMessage Deserialize(IByteBuffer byteBuffer) { - Hash256[] hashes = DeserializeHashes(byteBuffer); + ArrayPoolList? hashes = DeserializeHashesArrayPool(byteBuffer); return new NewPooledTransactionHashesMessage(hashes); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessage.cs index 8bd64a45065..58b632b0618 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessage.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages; namespace Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages @@ -12,7 +13,7 @@ public class PooledTransactionsMessage : TransactionsMessage public override int PacketType { get; } = Eth65MessageCode.PooledTransactions; public override string Protocol { get; } = "eth"; - public PooledTransactionsMessage(IList transactions) + public PooledTransactionsMessage(IOwnedReadOnlyList transactions) : base(transactions) { } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessageSerializer.cs index 838c26a1787..f49fceab87c 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Messages/PooledTransactionsMessageSerializer.cs @@ -3,6 +3,7 @@ using DotNetty.Buffers; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages; using Nethermind.Serialization.Rlp; @@ -20,7 +21,7 @@ public void Serialize(IByteBuffer byteBuffer, PooledTransactionsMessage message) public PooledTransactionsMessage Deserialize(IByteBuffer byteBuffer) { NettyRlpStream rlpStream = new(byteBuffer); - Transaction[] txs = TransactionsMessageSerializer.DeserializeTxs(rlpStream); + IOwnedReadOnlyList txs = TransactionsMessageSerializer.DeserializeTxs(rlpStream); return new PooledTransactionsMessage(txs); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandler.cs index fba10b722ce..a8e37ec11b6 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V66/Eth66ProtocolHandler.cs @@ -29,10 +29,10 @@ namespace Nethermind.Network.P2P.Subprotocols.Eth.V66 ///
public class Eth66ProtocolHandler : Eth65ProtocolHandler { - private readonly MessageDictionary _headersRequests66; + private readonly MessageDictionary> _headersRequests66; private readonly MessageDictionary _bodiesRequests66; - private readonly MessageDictionary _nodeDataRequests66; - private readonly MessageDictionary _receiptsRequests66; + private readonly MessageDictionary> _nodeDataRequests66; + private readonly MessageDictionary, long)> _receiptsRequests66; private readonly IPooledTxsRequestor _pooledTxsRequestor; private readonly Action _sendAction; @@ -49,10 +49,10 @@ public Eth66ProtocolHandler(ISession session, ITxGossipPolicy? transactionsGossipPolicy = null) : base(session, serializer, nodeStatsManager, syncServer, backgroundTaskScheduler, txPool, pooledTxsRequestor, gossipPolicy, forkInfo, logManager, transactionsGossipPolicy) { - _headersRequests66 = new MessageDictionary(Send); + _headersRequests66 = new MessageDictionary>(Send); _bodiesRequests66 = new MessageDictionary(Send); - _nodeDataRequests66 = new MessageDictionary(Send); - _receiptsRequests66 = new MessageDictionary(Send); + _nodeDataRequests66 = new MessageDictionary>(Send); + _receiptsRequests66 = new MessageDictionary, long)>(Send); _pooledTxsRequestor = pooledTxsRequestor; // Capture Action once rather than per call _sendAction = Send; @@ -69,8 +69,7 @@ public override void HandleMessage(ZeroPacket message) switch (message.PacketType) { case Eth66MessageCode.GetBlockHeaders: - GetBlockHeadersMessage getBlockHeadersMessage - = Deserialize(message.Content); + GetBlockHeadersMessage getBlockHeadersMessage = Deserialize(message.Content); Metrics.Eth66GetBlockHeadersReceived++; ReportIn(getBlockHeadersMessage, size); BackgroundTaskScheduler.ScheduleSyncServe(getBlockHeadersMessage, Handle); @@ -148,32 +147,37 @@ PooledTransactionsMessage pooledTxMsg private async Task Handle(GetBlockHeadersMessage getBlockHeaders, CancellationToken cancellationToken) { - V62.Messages.BlockHeadersMessage ethBlockHeadersMessage = await FulfillBlockHeadersRequest(getBlockHeaders.EthMessage, cancellationToken); - return new BlockHeadersMessage(getBlockHeaders.RequestId, ethBlockHeadersMessage); + using var message = getBlockHeaders; + V62.Messages.BlockHeadersMessage ethBlockHeadersMessage = await FulfillBlockHeadersRequest(message.EthMessage, cancellationToken); + return new BlockHeadersMessage(message.RequestId, ethBlockHeadersMessage); } private async Task Handle(GetBlockBodiesMessage getBlockBodies, CancellationToken cancellationToken) { - V62.Messages.BlockBodiesMessage ethBlockBodiesMessage = await FulfillBlockBodiesRequest(getBlockBodies.EthMessage, cancellationToken); - return new BlockBodiesMessage(getBlockBodies.RequestId, ethBlockBodiesMessage); + using var message = getBlockBodies; + V62.Messages.BlockBodiesMessage ethBlockBodiesMessage = await FulfillBlockBodiesRequest(message.EthMessage, cancellationToken); + return new BlockBodiesMessage(message.RequestId, ethBlockBodiesMessage); } private async Task Handle(GetPooledTransactionsMessage getPooledTransactions, CancellationToken cancellationToken) { - return new PooledTransactionsMessage(getPooledTransactions.RequestId, - await FulfillPooledTransactionsRequest(getPooledTransactions.EthMessage, cancellationToken)); + using var message = getPooledTransactions; + return new PooledTransactionsMessage(message.RequestId, + await FulfillPooledTransactionsRequest(message.EthMessage, cancellationToken)); } private async Task Handle(GetReceiptsMessage getReceiptsMessage, CancellationToken cancellationToken) { - V63.Messages.ReceiptsMessage receiptsMessage = await FulfillReceiptsRequest(getReceiptsMessage.EthMessage, cancellationToken); - return new ReceiptsMessage(getReceiptsMessage.RequestId, receiptsMessage); + using var message = getReceiptsMessage; + V63.Messages.ReceiptsMessage receiptsMessage = await FulfillReceiptsRequest(message.EthMessage, cancellationToken); + return new ReceiptsMessage(message.RequestId, receiptsMessage); } private async Task Handle(GetNodeDataMessage getNodeDataMessage, CancellationToken cancellationToken) { - V63.Messages.NodeDataMessage nodeDataMessage = await FulfillNodeDataRequest(getNodeDataMessage.EthMessage, cancellationToken); - return new NodeDataMessage(getNodeDataMessage.RequestId, nodeDataMessage); + using var message = getNodeDataMessage; + V63.Messages.NodeDataMessage nodeDataMessage = await FulfillNodeDataRequest(message.EthMessage, cancellationToken); + return new NodeDataMessage(message.RequestId, nodeDataMessage); } private void Handle(BlockHeadersMessage message, long size) @@ -198,11 +202,12 @@ private void Handle(ReceiptsMessage msg, long size) protected override void Handle(NewPooledTransactionHashesMessage msg) { + using var message = msg; bool isTrace = Logger.IsTrace; Stopwatch? stopwatch = isTrace ? Stopwatch.StartNew() : null; - TxPool.Metrics.PendingTransactionsHashesReceived += msg.Hashes.Count; - _pooledTxsRequestor.RequestTransactionsEth66(_sendAction, msg.Hashes); + TxPool.Metrics.PendingTransactionsHashesReceived += message.Hashes.Count; + _pooledTxsRequestor.RequestTransactionsEth66(_sendAction, message.Hashes); stopwatch?.Stop(); if (isTrace) @@ -210,7 +215,7 @@ protected override void Handle(NewPooledTransactionHashesMessage msg) $"in {stopwatch.Elapsed.TotalMilliseconds}ms"); } - protected override async Task SendRequest(V62.Messages.GetBlockHeadersMessage message, CancellationToken token) + protected override async Task> SendRequest(V62.Messages.GetBlockHeadersMessage message, CancellationToken token) { if (Logger.IsTrace) { @@ -249,7 +254,7 @@ protected override async Task SendRequest(V62.Messages.GetBlockHe token); } - protected override async Task SendRequest(V63.Messages.GetNodeDataMessage message, CancellationToken token) + protected override async Task> SendRequest(V63.Messages.GetNodeDataMessage message, CancellationToken token) { if (Logger.IsTrace) { @@ -266,7 +271,7 @@ protected override async Task SendRequest(V63.Messages.GetNodeDataMess token); } - protected override async Task<(TxReceipt[][], long)> SendRequest(V63.Messages.GetReceiptsMessage message, CancellationToken token) + protected override async Task<(IOwnedReadOnlyList, long)> SendRequest(V63.Messages.GetReceiptsMessage message, CancellationToken token) { if (Logger.IsTrace) { diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs index 7ea765a5401..575417bb54c 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandler.cs @@ -75,8 +75,9 @@ public override void HandleMessage(ZeroPacket message) } } - private void Handle(NewPooledTransactionHashesMessage68 message) + private void Handle(NewPooledTransactionHashesMessage68 msg) { + using var message = msg; bool isTrace = Logger.IsTrace; if (message.Hashes.Count != message.Types.Count || message.Hashes.Count != message.Sizes.Count) { @@ -111,7 +112,11 @@ protected override void SendNewTransactionCore(Transaction tx) } else { - SendMessage(new[] { (byte)tx.Type }, new int[] { tx.GetLength() }, new Hash256[] { tx.Hash }); + SendMessage( + new ArrayPoolList((byte)tx.Type), + new ArrayPoolList(tx.GetLength()), + new ArrayPoolList(1) { tx.Hash } + ); } } @@ -158,7 +163,7 @@ protected override void SendNewTransactionsCore(IEnumerable txs, bo } } - private void SendMessage(IReadOnlyList types, IReadOnlyList sizes, IReadOnlyList hashes) + private void SendMessage(IOwnedReadOnlyList types, IOwnedReadOnlyList sizes, IOwnedReadOnlyList hashes) { NewPooledTransactionHashesMessage68 message = new(types, sizes, hashes); Metrics.Eth68NewPooledTransactionHashesSent++; diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessage68.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessage68.cs index d5de956833f..ae7c147697e 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessage68.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessage68.cs @@ -3,12 +3,16 @@ using System; using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Network.P2P.Messages; namespace Nethermind.Network.P2P.Subprotocols.Eth.V68.Messages { - public class NewPooledTransactionHashesMessage68 : P2PMessage + public class NewPooledTransactionHashesMessage68( + IOwnedReadOnlyList types, + IOwnedReadOnlyList sizes, + IOwnedReadOnlyList hashes) : P2PMessage { // we are able to safely send message with up to 2925 hashes+types+lengths to not exceed message size // of 102400 bytes which is used by Geth and us as max message size. (2925 items message has 102385 bytes) @@ -17,25 +21,18 @@ public class NewPooledTransactionHashesMessage68 : P2PMessage public override int PacketType { get; } = Eth68MessageCode.NewPooledTransactionHashes; public override string Protocol { get; } = "eth"; - public readonly IReadOnlyList Types; - public readonly IReadOnlyList Sizes; - public readonly IReadOnlyList Hashes; - - public NewPooledTransactionHashesMessage68(IReadOnlyList types, IReadOnlyList sizes, IReadOnlyList hashes) - { - Types = types; - Sizes = sizes; - Hashes = hashes; - } + public readonly IOwnedReadOnlyList Types = types; + public readonly IOwnedReadOnlyList Sizes = sizes; + public readonly IOwnedReadOnlyList Hashes = hashes; public override string ToString() => $"{nameof(NewPooledTransactionHashesMessage68)}({Hashes.Count})"; public override void Dispose() { base.Dispose(); - if (Types is IDisposable disposable) disposable.Dispose(); - if (Sizes is IDisposable disposable2) disposable2.Dispose(); - if (Hashes is IDisposable disposable3) disposable3.Dispose(); + Types.Dispose(); + Sizes.Dispose(); + Hashes.Dispose(); } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs index cb1cc6d0d37..485f3792d53 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Serialization.Rlp; @@ -14,9 +15,9 @@ public NewPooledTransactionHashesMessage68 Deserialize(IByteBuffer byteBuffer) { NettyRlpStream rlpStream = new(byteBuffer); rlpStream.ReadSequenceLength(); - byte[] types = rlpStream.DecodeByteArray(); - int[] sizes = rlpStream.DecodeArray(item => item.DecodeInt()); - Hash256[] hashes = rlpStream.DecodeArray(item => item.DecodeKeccak()); + ArrayPoolList types = rlpStream.DecodeByteArrayPoolList(); + ArrayPoolList sizes = rlpStream.DecodeArrayPoolList(item => item.DecodeInt()); + ArrayPoolList hashes = rlpStream.DecodeArrayPoolList(item => item.DecodeKeccak()); return new NewPooledTransactionHashesMessage68(types, sizes, hashes); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/LesProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/LesProtocolHandler.cs index 04d4b935f2e..963da8db843 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/LesProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/LesProtocolHandler.cs @@ -9,6 +9,7 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus.Scheduler; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Int256; @@ -117,10 +118,12 @@ public override void HandleMessage(ZeroPacket message) switch (message.PacketType) { case LesMessageCode.Status: - StatusMessage statusMessage = Deserialize(message.Content); - if (NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, statusMessage.ToString(), size); - Handle(statusMessage); - break; + { + using StatusMessage statusMessage = Deserialize(message.Content); + if (NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, statusMessage.ToString(), size); + Handle(statusMessage); + break; + } case LesMessageCode.GetBlockHeaders: GetBlockHeadersMessage getBlockHeadersMessage = Deserialize(message.Content); if (NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, getBlockHeadersMessage.ToString(), size); @@ -203,40 +206,45 @@ public void Handle(StatusMessage status) public async Task Handle(GetBlockHeadersMessage getBlockHeaders, CancellationToken cancellationToken) { - Eth.V62.Messages.BlockHeadersMessage ethBlockHeadersMessage = await FulfillBlockHeadersRequest(getBlockHeaders.EthMessage, cancellationToken); + using var message = getBlockHeaders; + Eth.V62.Messages.BlockHeadersMessage ethBlockHeadersMessage = await FulfillBlockHeadersRequest(message.EthMessage, cancellationToken); // todo - implement cost tracking - return new BlockHeadersMessage(ethBlockHeadersMessage, getBlockHeaders.RequestId, int.MaxValue); + return new BlockHeadersMessage(ethBlockHeadersMessage, message.RequestId, int.MaxValue); } public async Task Handle(GetBlockBodiesMessage getBlockBodies, CancellationToken cancellationToken) { - Eth.V62.Messages.BlockBodiesMessage ethBlockBodiesMessage = await FulfillBlockBodiesRequest(getBlockBodies.EthMessage, cancellationToken); + using var message = getBlockBodies; + Eth.V62.Messages.BlockBodiesMessage ethBlockBodiesMessage = await FulfillBlockBodiesRequest(message.EthMessage, cancellationToken); // todo - implement cost tracking - return new BlockBodiesMessage(ethBlockBodiesMessage, getBlockBodies.RequestId, int.MaxValue); + return new BlockBodiesMessage(ethBlockBodiesMessage, message.RequestId, int.MaxValue); } public async Task Handle(GetReceiptsMessage getReceipts, CancellationToken cancellationToken) { - Eth.V63.Messages.ReceiptsMessage ethReceiptsMessage = await FulfillReceiptsRequest(getReceipts.EthMessage, cancellationToken); + using var message = getReceipts; + Eth.V63.Messages.ReceiptsMessage ethReceiptsMessage = await FulfillReceiptsRequest(message.EthMessage, cancellationToken); // todo - implement cost tracking - return new ReceiptsMessage(ethReceiptsMessage, getReceipts.RequestId, int.MaxValue); + return new ReceiptsMessage(ethReceiptsMessage, message.RequestId, int.MaxValue); } public Task Handle(GetContractCodesMessage getContractCodes, CancellationToken cancellationToken) { - var codes = SyncServer.GetNodeData(getContractCodes.RequestAddresses, cancellationToken, NodeDataType.Code); + using var message = getContractCodes; + var codes = SyncServer.GetNodeData(message.RequestAddresses, cancellationToken, NodeDataType.Code); // todo - implement cost tracking - return Task.FromResult(new ContractCodesMessage(codes, getContractCodes.RequestId, int.MaxValue)); + return Task.FromResult(new ContractCodesMessage(codes, message.RequestId, int.MaxValue)); } public Task Handle(GetHelperTrieProofsMessage getHelperTrieProofs, CancellationToken cancellationToken) { + using var message = getHelperTrieProofs; List proofNodes = new(); List auxData = new(); - for (int requestNo = 0; requestNo < getHelperTrieProofs.Requests.Length; requestNo++) + for (int requestNo = 0; requestNo < message.Requests.Length; requestNo++) { - var request = getHelperTrieProofs.Requests[requestNo]; + var request = message.Requests[requestNo]; switch (request.SubType) { case HelperTrieType.CHT: @@ -247,7 +255,7 @@ public Task Handle(GetHelperTrieProofsMessage getHelper } } - return Task.FromResult(new HelperTrieProofsMessage(proofNodes.Distinct().ToArray(), auxData.ToArray(), getHelperTrieProofs.RequestId, int.MaxValue)); + return Task.FromResult(new HelperTrieProofsMessage(proofNodes.Distinct().ToArray(), auxData.ToArray(), message.RequestId, int.MaxValue)); } public void GetCHTData(HelperTrieRequest request, List proofNodes, List auxData) @@ -262,8 +270,8 @@ public void GetCHTData(HelperTrieRequest request, List proofNodes, List< else if (request.AuxiliaryData == 2) { (Hash256 hash, _) = cht.Get(request.Key); - var headerResult = SyncServer.FindHeaders(hash, 1, 0, false); - if (headerResult.Length != 1) throw new SubprotocolException($"Unable to find header for block {request.Key.WithoutLeadingZeros().ToArray().ToLongFromBigEndianByteArrayWithoutLeadingZeros()} for GetHelperProofs response."); + using IOwnedReadOnlyList headerResult = SyncServer.FindHeaders(hash, 1, 0, false); + if (headerResult.Count != 1) throw new SubprotocolException($"Unable to find header for block {request.Key.WithoutLeadingZeros().ToArray().ToLongFromBigEndianByteArrayWithoutLeadingZeros()} for GetHelperProofs response."); auxData.Add(Rlp.Encode(headerResult[0]).Bytes); } proofNodes.AddRange(Synchronization.LesSync.CanonicalHashTrie.BuildProof(request.Key, request.SectionIndex, request.FromLevel)); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessage.cs index c5d68994764..3c01e93dbfd 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessage.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.Network.P2P.Messages; namespace Nethermind.Network.P2P.Subprotocols.Les.Messages @@ -11,17 +12,23 @@ public class ContractCodesMessage : P2PMessage public override string Protocol { get; } = Contract.P2P.Protocol.Les; public long RequestId; public int BufferValue; - public byte[][] Codes; + public IOwnedReadOnlyList Codes; public ContractCodesMessage() { } - public ContractCodesMessage(byte[][] codes, long requestId, int bufferValue) + public ContractCodesMessage(IOwnedReadOnlyList codes, long requestId, int bufferValue) { Codes = codes; RequestId = requestId; BufferValue = bufferValue; } + + public override void Dispose() + { + base.Dispose(); + Codes.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessageSerializer.cs index 9e23e560053..274d453311d 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/ContractCodesMessageSerializer.cs @@ -11,7 +11,7 @@ public class ContractCodesMessageSerializer : IZeroMessageSerializer stream.DecodeByteArray()); + contractCodesMessage.Codes = rlpStream.DecodeArrayPoolList(stream => stream.DecodeByteArray()); return contractCodesMessage; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/GetBlockHeadersMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/GetBlockHeadersMessage.cs index 42dd7bcd117..ba7ba020278 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/GetBlockHeadersMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/GetBlockHeadersMessage.cs @@ -21,5 +21,11 @@ public GetBlockHeadersMessage(Eth.V62.Messages.GetBlockHeadersMessage ethMessage EthMessage = ethMessage; RequestId = requestId; } + + public override void Dispose() + { + base.Dispose(); + EthMessage?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessage.cs index ced8bf488de..79faea912f8 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessage.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.NodeData.Messages; @@ -11,7 +12,7 @@ public class GetNodeDataMessage : Eth.V63.Messages.GetNodeDataMessage public override int PacketType { get; } = NodeDataMessageCode.GetNodeData; public override string Protocol { get; } = "nodedata"; - public GetNodeDataMessage(IReadOnlyList keys) + public GetNodeDataMessage(IOwnedReadOnlyList keys) : base(keys) { } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessageSerializer.cs index eb6ea7030d7..531e35015fe 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/GetNodeDataMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Network.P2P.Subprotocols.Eth; @@ -11,7 +12,7 @@ public class GetNodeDataMessageSerializer : HashesMessageSerializer keys = DeserializeHashesArrayPool(byteBuffer); return new GetNodeDataMessage(keys); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessage.cs index 83cfa809ced..3edbae80c91 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessage.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; + namespace Nethermind.Network.P2P.Subprotocols.NodeData.Messages; public class NodeDataMessage : Eth.V63.Messages.NodeDataMessage @@ -8,7 +10,7 @@ public class NodeDataMessage : Eth.V63.Messages.NodeDataMessage public override int PacketType { get; } = NodeDataMessageCode.NodeData; public override string Protocol { get; } = "nodedata"; - public NodeDataMessage(byte[][]? data) + public NodeDataMessage(IOwnedReadOnlyList? data) : base(data) { } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessageSerializer.cs index 37554421383..07e85c051c9 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/Messages/NodeDataMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.P2P.Subprotocols.NodeData.Messages; @@ -15,7 +16,7 @@ public void Serialize(IByteBuffer byteBuffer, NodeDataMessage message) RlpStream rlpStream = new NettyRlpStream(byteBuffer); rlpStream.StartSequence(contentLength); - for (int i = 0; i < message.Data.Length; i++) + for (int i = 0; i < message.Data.Count; i++) { rlpStream.Encode(message.Data[i]); } @@ -24,14 +25,14 @@ public void Serialize(IByteBuffer byteBuffer, NodeDataMessage message) public NodeDataMessage Deserialize(IByteBuffer byteBuffer) { RlpStream rlpStream = new NettyRlpStream(byteBuffer); - byte[][] result = rlpStream.DecodeArray(stream => stream.DecodeByteArray()); + ArrayPoolList? result = rlpStream.DecodeArrayPoolList(stream => stream.DecodeByteArray()); return new NodeDataMessage(result); } public int GetLength(NodeDataMessage message, out int contentLength) { contentLength = 0; - for (int i = 0; i < message.Data.Length; i++) + for (int i = 0; i < message.Data.Count; i++) { contentLength += Rlp.LengthOf(message.Data[i]); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/NodeDataProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/NodeDataProtocolHandler.cs index edef9c42721..5357626835d 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/NodeDataProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/NodeData/NodeDataProtocolHandler.cs @@ -7,7 +7,9 @@ using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus.Scheduler; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Logging; using Nethermind.Network.Contract.P2P; using Nethermind.Network.P2P.EventArg; @@ -25,7 +27,7 @@ namespace Nethermind.Network.P2P.Subprotocols.NodeData; public class NodeDataProtocolHandler : ZeroProtocolHandlerBase, INodeDataPeer { private readonly ISyncServer _syncServer; - private readonly MessageQueue _nodeDataRequests; + private readonly MessageQueue> _nodeDataRequests; private readonly BackgroundTaskSchedulerWrapper _backgroundTaskScheduler; public override string Name => "nodedata1"; @@ -44,7 +46,7 @@ public NodeDataProtocolHandler(ISession session, { _syncServer = syncServer ?? throw new ArgumentNullException(nameof(syncServer)); _backgroundTaskScheduler = new BackgroundTaskSchedulerWrapper(this, backgroundTaskScheduler ?? throw new ArgumentNullException(nameof(backgroundTaskScheduler))); ; - _nodeDataRequests = new MessageQueue(Send); + _nodeDataRequests = new MessageQueue>(Send); } public override void Init() { @@ -73,23 +75,34 @@ public override void HandleMessage(ZeroPacket message) switch (message.PacketType) { case NodeDataMessageCode.GetNodeData: - GetNodeDataMessage getNodeDataMessage = Deserialize(message.Content); - Metrics.GetNodeDataReceived++; - ReportIn(getNodeDataMessage, size); - _backgroundTaskScheduler.ScheduleSyncServe(getNodeDataMessage, Handle); - break; + { + GetNodeDataMessage getNodeDataMessage = Deserialize(message.Content); + Metrics.GetNodeDataReceived++; + ReportIn(getNodeDataMessage, size); + _backgroundTaskScheduler.ScheduleSyncServe(getNodeDataMessage, Handle); + break; + } case NodeDataMessageCode.NodeData: - NodeDataMessage nodeDataMessage = Deserialize(message.Content); - Metrics.NodeDataReceived++; - ReportIn(nodeDataMessage, size); - Handle(nodeDataMessage, size); - break; + { + NodeDataMessage nodeDataMessage = Deserialize(message.Content); + Metrics.NodeDataReceived++; + ReportIn(nodeDataMessage, size); + Handle(nodeDataMessage, size); + break; + } } } private Task Handle(GetNodeDataMessage getNodeDataMessage, CancellationToken cancellationToken) { - return Task.FromResult(FulfillNodeDataRequest(getNodeDataMessage, cancellationToken)); + try + { + return Task.FromResult(FulfillNodeDataRequest(getNodeDataMessage, cancellationToken)); + } + finally + { + getNodeDataMessage.Dispose(); + } } private NodeDataMessage FulfillNodeDataRequest(GetNodeDataMessage msg, CancellationToken cancellationToken) @@ -99,7 +112,7 @@ private NodeDataMessage FulfillNodeDataRequest(GetNodeDataMessage msg, Cancellat throw new EthSyncException("NODEDATA protocol: Incoming node data request for more than 4096 nodes"); } - byte[][] nodeData = _syncServer.GetNodeData(msg.Hashes, cancellationToken); + IOwnedReadOnlyList? nodeData = _syncServer.GetNodeData(msg.Hashes, cancellationToken); return new NodeDataMessage(nodeData); } @@ -109,25 +122,25 @@ private void Handle(NodeDataMessage msg, int size) _nodeDataRequests.Handle(msg.Data, size); } - public async Task GetNodeData(IReadOnlyList keys, CancellationToken token) + public async Task> GetNodeData(IReadOnlyList keys, CancellationToken token) { if (keys.Count == 0) { - return Array.Empty(); + return ArrayPoolList.Empty(); } - GetNodeDataMessage msg = new(keys); - byte[][] nodeData = await SendRequest(msg, token); + GetNodeDataMessage msg = new(keys.ToPooledList()); + IOwnedReadOnlyList nodeData = await SendRequest(msg, token); return nodeData; } - private async Task SendRequest(GetNodeDataMessage message, CancellationToken token) + private async Task> SendRequest(GetNodeDataMessage message, CancellationToken token) { if (Logger.IsTrace) Logger.Trace($"NODEDATA protocol: Sending node data request with keys count: {message.Hashes.Count}"); - Request? request = new(message); + Request>? request = new(message); _nodeDataRequests.Send(request); - return await HandleResponse(request, TransferSpeedType.NodeData, static (_) => $"{nameof(GetNodeDataMessage)}", token); + return await HandleResponse(request, TransferSpeedType.NodeData, static _ => $"{nameof(GetNodeDataMessage)}", token); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs index e9684180260..c751c01ea1b 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.State.Snap; namespace Nethermind.Network.P2P.Subprotocols.Snap.Messages @@ -12,11 +13,18 @@ public class AccountRangeMessage : SnapMessageBase /// /// List of consecutive accounts from the trie /// - public PathWithAccount[] PathsWithAccounts { get; set; } + public IOwnedReadOnlyList PathsWithAccounts { get; set; } /// /// List of trie nodes proving the account range /// - public byte[][] Proofs { get; set; } + public IOwnedReadOnlyList Proofs { get; set; } + + public override void Dispose() + { + base.Dispose(); + PathsWithAccounts.Dispose(); + Proofs.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs index 4f274673e54..d7b9fa8258d 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs @@ -21,14 +21,14 @@ public void Serialize(IByteBuffer byteBuffer, AccountRangeMessage message) stream.StartSequence(contentLength); stream.Encode(message.RequestId); - if (message.PathsWithAccounts is null || message.PathsWithAccounts.Length == 0) + if (message.PathsWithAccounts is null || message.PathsWithAccounts.Count == 0) { stream.EncodeNullObject(); } else { stream.StartSequence(pwasLength); - for (int i = 0; i < message.PathsWithAccounts.Length; i++) + for (int i = 0; i < message.PathsWithAccounts.Count; i++) { PathWithAccount pwa = message.PathsWithAccounts[i]; @@ -41,14 +41,14 @@ public void Serialize(IByteBuffer byteBuffer, AccountRangeMessage message) } } - if (message.Proofs is null || message.Proofs.Length == 0) + if (message.Proofs is null || message.Proofs.Count == 0) { stream.EncodeNullObject(); } else { stream.StartSequence(proofsLength); - for (int i = 0; i < message.Proofs.Length; i++) + for (int i = 0; i < message.Proofs.Count; i++) { stream.Encode(message.Proofs[i]); } @@ -63,8 +63,8 @@ public AccountRangeMessage Deserialize(IByteBuffer byteBuffer) rlpStream.ReadSequenceLength(); message.RequestId = rlpStream.DecodeLong(); - message.PathsWithAccounts = rlpStream.DecodeArray(DecodePathWithRlpData); - message.Proofs = rlpStream.DecodeArray(s => s.DecodeByteArray()); + message.PathsWithAccounts = rlpStream.DecodeArrayPoolList(DecodePathWithRlpData); + message.Proofs = rlpStream.DecodeArrayPoolList(s => s.DecodeByteArray()); return message; } @@ -83,13 +83,13 @@ private PathWithAccount DecodePathWithRlpData(RlpStream stream) int contentLength = Rlp.LengthOf(message.RequestId); int pwasLength = 0; - if (message.PathsWithAccounts is null || message.PathsWithAccounts.Length == 0) + if (message.PathsWithAccounts is null || message.PathsWithAccounts.Count == 0) { pwasLength = 0; } else { - for (int i = 0; i < message.PathsWithAccounts.Length; i++) + for (int i = 0; i < message.PathsWithAccounts.Count; i++) { PathWithAccount pwa = message.PathsWithAccounts[i]; int itemLength = Rlp.LengthOf(pwa.Path); @@ -102,13 +102,13 @@ private PathWithAccount DecodePathWithRlpData(RlpStream stream) contentLength += Rlp.LengthOfSequence(pwasLength); int proofsLength = 0; - if (message.Proofs is null || message.Proofs.Length == 0) + if (message.Proofs is null || message.Proofs.Count == 0) { proofsLength = 0; } else { - for (int i = 0; i < message.Proofs.Length; i++) + for (int i = 0; i < message.Proofs.Count; i++) { proofsLength += Rlp.LengthOf(message.Proofs[i]); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessage.cs index 7e1516987cc..967fa3919e6 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessage.cs @@ -2,18 +2,20 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core.Collections; namespace Nethermind.Network.P2P.Subprotocols.Snap.Messages { - public class ByteCodesMessage : SnapMessageBase + public class ByteCodesMessage(IOwnedReadOnlyList? data) : SnapMessageBase { - public ByteCodesMessage(byte[][]? data) - { - Codes = data ?? Array.Empty(); - } - public override int PacketType => SnapMessageCode.ByteCodes; - public byte[][] Codes { get; } + public IOwnedReadOnlyList Codes { get; } = data ?? ArrayPoolList.Empty(); + + public override void Dispose() + { + base.Dispose(); + Codes.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs index cbf7682fd25..421430feaed 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.P2P.Subprotocols.Snap.Messages @@ -17,7 +18,7 @@ public void Serialize(IByteBuffer byteBuffer, ByteCodesMessage message) rlpStream.StartSequence(contentLength); rlpStream.Encode(message.RequestId); rlpStream.StartSequence(codesLength); - for (int i = 0; i < message.Codes.Length; i++) + for (int i = 0; i < message.Codes.Count; i++) { rlpStream.Encode(message.Codes[i]); } @@ -30,7 +31,7 @@ public ByteCodesMessage Deserialize(IByteBuffer byteBuffer) rlpStream.ReadSequenceLength(); long requestId = rlpStream.DecodeLong(); - byte[][] result = rlpStream.DecodeArray(stream => stream.DecodeByteArray()); + IOwnedReadOnlyList result = rlpStream.DecodeArrayPoolList(stream => stream.DecodeByteArray()); return new ByteCodesMessage(result) { RequestId = requestId }; } @@ -38,7 +39,7 @@ public ByteCodesMessage Deserialize(IByteBuffer byteBuffer) public static (int contentLength, int codesLength) GetLength(ByteCodesMessage message) { int codesLength = 0; - for (int i = 0; i < message.Codes.Length; i++) + for (int i = 0; i < message.Codes.Count; i++) { codesLength += Rlp.LengthOf(message.Codes[i]); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessage.cs index 590597abc14..437fd6cc87f 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessage.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Network.P2P.Subprotocols.Snap.Messages @@ -13,11 +14,17 @@ public class GetByteCodesMessage : SnapMessageBase /// /// Code hashes to retrieve the code for /// - public IReadOnlyList Hashes { get; set; } + public IOwnedReadOnlyList Hashes { get; set; } /// /// Soft limit at which to stop returning data /// public long Bytes { get; set; } + + public override void Dispose() + { + base.Dispose(); + Hashes?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializer.cs index 3aea9da7706..db43e1f4984 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetByteCodesMessageSerializer.cs @@ -23,7 +23,7 @@ protected override GetByteCodesMessage Deserialize(RlpStream rlpStream) rlpStream.ReadSequenceLength(); message.RequestId = rlpStream.DecodeLong(); - message.Hashes = rlpStream.DecodeArray(_ => rlpStream.DecodeValueKeccak(out var keccak) ? keccak : default); + message.Hashes = rlpStream.DecodeArrayPoolList(_ => rlpStream.DecodeValueKeccak(out var keccak) ? keccak : default); message.Bytes = rlpStream.DecodeLong(); return message; diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs index a3b80213a0f..ba5f037bd7f 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs @@ -32,7 +32,7 @@ protected override GetStorageRangeMessage Deserialize(RlpStream rlpStream) message.StoragetRange = new(); message.StoragetRange.RootHash = rlpStream.DecodeKeccak(); - message.StoragetRange.Accounts = rlpStream.DecodeArray(DecodePathWithRlpData); + message.StoragetRange.Accounts = rlpStream.DecodeArrayPoolList(DecodePathWithRlpData); message.StoragetRange.StartingHash = rlpStream.DecodeKeccak(); message.StoragetRange.LimitHash = rlpStream.DecodeKeccak(); message.ResponseBytes = rlpStream.DecodeLong(); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessage.cs index ee0cb64a918..8779e1ebcb8 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessage.cs @@ -1,6 +1,8 @@ // 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.State.Snap; @@ -18,11 +20,17 @@ public class GetTrieNodesMessage : SnapMessageBase /// /// Trie paths to retrieve the nodes for, grouped by account /// - public PathGroup[] Paths { get; set; } + public IOwnedReadOnlyList Paths { get; set; } /// /// Soft limit at which to stop returning data /// public long Bytes { get; set; } + + public override void Dispose() + { + base.Dispose(); + Paths?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs index 63beecc3c48..e50227aa2fb 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs @@ -24,7 +24,7 @@ public void Serialize(IByteBuffer byteBuffer, GetTrieNodesMessage message) stream.Encode(message.RequestId); stream.Encode(message.RootHash); - if (message.Paths is null || message.Paths.Length == 0) + if (message.Paths is null || message.Paths.Count == 0) { stream.EncodeNullObject(); } @@ -32,7 +32,7 @@ public void Serialize(IByteBuffer byteBuffer, GetTrieNodesMessage message) { stream.StartSequence(allPathsLength); - for (int i = 0; i < message.Paths.Length; i++) + for (int i = 0; i < message.Paths.Count; i++) { PathGroup group = message.Paths[i]; @@ -58,7 +58,7 @@ public GetTrieNodesMessage Deserialize(IByteBuffer byteBuffer) message.RequestId = stream.DecodeLong(); message.RootHash = stream.DecodeKeccak(); PathGroup defaultValue = _defaultPathGroup; - message.Paths = stream.DecodeArray(DecodeGroup, defaultElement: defaultValue); + message.Paths = stream.DecodeArrayPoolList(DecodeGroup, defaultElement: defaultValue); message.Bytes = stream.DecodeLong(); @@ -77,15 +77,15 @@ private static (int contentLength, int allPathsLength, int[] pathsLengths) Calcu contentLength += Rlp.LengthOf(message.RootHash); int allPathsLength = 0; - int[] pathsLengths = new int[message.Paths.Length]; + int[] pathsLengths = new int[message.Paths.Count]; - if (message.Paths is null || message.Paths.Length == 0) + if (message.Paths is null || message.Paths.Count == 0) { allPathsLength = 1; } else { - for (var i = 0; i < message.Paths.Length; i++) + for (var i = 0; i < message.Paths.Count; i++) { PathGroup pathGroup = message.Paths[i]; int groupLength = 0; diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangeMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangeMessage.cs index 4634d5c39b6..5c8031b8932 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangeMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangeMessage.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.State.Snap; namespace Nethermind.Network.P2P.Subprotocols.Snap.Messages @@ -12,11 +13,18 @@ public class StorageRangeMessage : SnapMessageBase /// /// List of list of consecutive slots from the trie (one list per account) /// - public PathWithStorageSlot[][] Slots { get; set; } + public IOwnedReadOnlyList Slots { get; set; } /// /// List of trie nodes proving the slot range /// - public byte[][] Proofs { get; set; } + public IOwnedReadOnlyList Proofs { get; set; } + + public override void Dispose() + { + base.Dispose(); + Slots?.Dispose(); + Proofs?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs index 90d498c4a3e..6408dec6ab5 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs @@ -32,7 +32,7 @@ public void Serialize(IByteBuffer byteBuffer, StorageRangeMessage message) stream.Encode(message.RequestId); - if (message.Slots is null || message.Slots.Length == 0) + if (message.Slots is null || message.Slots.Count == 0) { stream.EncodeNullObject(); } @@ -40,7 +40,7 @@ public void Serialize(IByteBuffer byteBuffer, StorageRangeMessage message) { stream.StartSequence(allSlotsLength); - for (int i = 0; i < message.Slots.Length; i++) + for (int i = 0; i < message.Slots.Count; i++) { stream.StartSequence(accountSlotsLengths[i]); @@ -60,14 +60,14 @@ public void Serialize(IByteBuffer byteBuffer, StorageRangeMessage message) } } - if (message.Proofs is null || message.Proofs.Length == 0) + if (message.Proofs is null || message.Proofs.Count == 0) { stream.EncodeNullObject(); } else { stream.StartSequence(proofsLength); - for (int i = 0; i < message.Proofs.Length; i++) + for (int i = 0; i < message.Proofs.Count; i++) { stream.Encode(message.Proofs[i]); } @@ -82,8 +82,8 @@ public StorageRangeMessage Deserialize(IByteBuffer byteBuffer) stream.ReadSequenceLength(); message.RequestId = stream.DecodeLong(); - message.Slots = stream.DecodeArray(_decodeSlotArray); - message.Proofs = stream.DecodeArray(s => s.DecodeByteArray()); + message.Slots = stream.DecodeArrayPoolList(_decodeSlotArray); + message.Proofs = stream.DecodeArrayPoolList(s => s.DecodeByteArray()); return message; } @@ -104,15 +104,15 @@ private static (int contentLength, int allSlotsLength, int[] accountSlotsLengths int contentLength = Rlp.LengthOf(message.RequestId); int allSlotsLength = 0; - int[] accountSlotsLengths = new int[message.Slots.Length]; + int[] accountSlotsLengths = new int[message.Slots.Count]; - if (message.Slots is null || message.Slots.Length == 0) + if (message.Slots is null || message.Slots.Count == 0) { allSlotsLength = 1; } else { - for (var i = 0; i < message.Slots.Length; i++) + for (var i = 0; i < message.Slots.Count; i++) { int accountSlotsLength = 0; @@ -131,14 +131,14 @@ private static (int contentLength, int allSlotsLength, int[] accountSlotsLengths contentLength += Rlp.LengthOfSequence(allSlotsLength); int proofsLength = 0; - if (message.Proofs is null || message.Proofs.Length == 0) + if (message.Proofs is null || message.Proofs.Count == 0) { proofsLength = 1; contentLength++; } else { - for (int i = 0; i < message.Proofs.Length; i++) + for (int i = 0; i < message.Proofs.Count; i++) { proofsLength += Rlp.LengthOf(message.Proofs[i]); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessage.cs index 73eceb46b63..6983dd63858 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessage.cs @@ -2,18 +2,20 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core.Collections; namespace Nethermind.Network.P2P.Subprotocols.Snap.Messages { - public class TrieNodesMessage : SnapMessageBase + public class TrieNodesMessage(IOwnedReadOnlyList? data) : SnapMessageBase { - public TrieNodesMessage(byte[][]? data) - { - Nodes = data ?? Array.Empty(); - } - public override int PacketType => SnapMessageCode.TrieNodes; - public byte[][] Nodes { get; set; } + public IOwnedReadOnlyList Nodes { get; set; } = data ?? ArrayPoolList.Empty(); + + public override void Dispose() + { + base.Dispose(); + Nodes.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs index 9d55e7a3c9e..f1481d07398 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using DotNetty.Buffers; +using Nethermind.Core.Collections; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.P2P.Subprotocols.Snap.Messages @@ -19,7 +20,7 @@ public void Serialize(IByteBuffer byteBuffer, TrieNodesMessage message) rlpStream.StartSequence(contentLength); rlpStream.Encode(message.RequestId); rlpStream.StartSequence(nodesLength); - for (int i = 0; i < message.Nodes.Length; i++) + for (int i = 0; i < message.Nodes.Count; i++) { rlpStream.Encode(message.Nodes[i]); } @@ -32,14 +33,14 @@ public TrieNodesMessage Deserialize(IByteBuffer byteBuffer) rlpStream.ReadSequenceLength(); long requestId = rlpStream.DecodeLong(); - byte[][] result = rlpStream.DecodeArray(stream => stream.DecodeByteArray()); + IOwnedReadOnlyList result = rlpStream.DecodeArrayPoolList(stream => stream.DecodeByteArray()); return new TrieNodesMessage(result) { RequestId = requestId }; } public static (int contentLength, int nodesLength) GetLength(TrieNodesMessage message) { int nodesLength = 0; - for (int i = 0; i < message.Nodes.Length; i++) + for (int i = 0; i < message.Nodes.Count; i++) { nodesLength += Rlp.LengthOf(message.Nodes[i]); } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs index 3b2a0015b73..87a70bf9dd2 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs @@ -8,7 +8,9 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus.Scheduler; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Logging; using Nethermind.Network.Contract.P2P; using Nethermind.Network.P2P.EventArg; @@ -27,7 +29,7 @@ public class SnapProtocolHandler : ZeroProtocolHandlerBase, ISnapSyncPeer { public static TimeSpan LowerLatencyThreshold = TimeSpan.FromMilliseconds(2000); public static TimeSpan UpperLatencyThreshold = TimeSpan.FromMilliseconds(3000); - private static TrieNodesMessage EmptyTrieNodesMessage = new TrieNodesMessage(Array.Empty()); + private static TrieNodesMessage EmptyTrieNodesMessage = new TrieNodesMessage(ArrayPoolList.Empty()); private readonly LatencyBasedRequestSizer _requestSizer = new( minRequestLimit: 50000, @@ -192,33 +194,37 @@ private void Handle(TrieNodesMessage msg, long size) private ValueTask Handle(GetAccountRangeMessage getAccountRangeMessage, CancellationToken cancellationToken) { + using GetAccountRangeMessage message = getAccountRangeMessage; Metrics.SnapGetAccountRangeReceived++; - AccountRangeMessage? response = FulfillAccountRangeMessage(getAccountRangeMessage, cancellationToken); - response.RequestId = getAccountRangeMessage.RequestId; + AccountRangeMessage? response = FulfillAccountRangeMessage(message, cancellationToken); + response.RequestId = message.RequestId; return new ValueTask(response); } private ValueTask Handle(GetStorageRangeMessage getStorageRangesMessage, CancellationToken cancellationToken) { + using GetStorageRangeMessage message = getStorageRangesMessage; Metrics.SnapGetStorageRangesReceived++; - StorageRangeMessage? response = FulfillStorageRangeMessage(getStorageRangesMessage, cancellationToken); - response.RequestId = getStorageRangesMessage.RequestId; + StorageRangeMessage? response = FulfillStorageRangeMessage(message, cancellationToken); + response.RequestId = message.RequestId; return new ValueTask(response); } private ValueTask Handle(GetByteCodesMessage getByteCodesMessage, CancellationToken cancellationToken) { + using GetByteCodesMessage message = getByteCodesMessage; Metrics.SnapGetByteCodesReceived++; - ByteCodesMessage? response = FulfillByteCodesMessage(getByteCodesMessage, cancellationToken); - response.RequestId = getByteCodesMessage.RequestId; + ByteCodesMessage? response = FulfillByteCodesMessage(message, cancellationToken); + response.RequestId = message.RequestId; return new ValueTask(response); } private ValueTask Handle(GetTrieNodesMessage getTrieNodesMessage, CancellationToken cancellationToken) { + using GetTrieNodesMessage message = getTrieNodesMessage; Metrics.SnapGetTrieNodesReceived++; - TrieNodesMessage? response = FulfillTrieNodesMessage(getTrieNodesMessage, cancellationToken); - response.RequestId = getTrieNodesMessage.RequestId; + TrieNodesMessage? response = FulfillTrieNodesMessage(message, cancellationToken); + response.RequestId = message.RequestId; return new ValueTask(response); } @@ -230,19 +236,19 @@ public override void DisconnectProtocol(DisconnectReason disconnectReason, strin private TrieNodesMessage FulfillTrieNodesMessage(GetTrieNodesMessage getTrieNodesMessage, CancellationToken cancellationToken) { if (SyncServer is null) return EmptyTrieNodesMessage; - var trieNodes = SyncServer.GetTrieNodes(getTrieNodesMessage.Paths, getTrieNodesMessage.RootHash, cancellationToken); + IOwnedReadOnlyList? trieNodes = SyncServer.GetTrieNodes(getTrieNodesMessage.Paths, getTrieNodesMessage.RootHash, cancellationToken); return new TrieNodesMessage(trieNodes); } private AccountRangeMessage FulfillAccountRangeMessage(GetAccountRangeMessage getAccountRangeMessage, CancellationToken cancellationToken) { - if (SyncServer is null) return new AccountRangeMessage() + if (SyncServer is null) return new AccountRangeMessage { - Proofs = Array.Empty(), - PathsWithAccounts = Array.Empty(), + Proofs = ArrayPoolList.Empty(), + PathsWithAccounts = ArrayPoolList.Empty(), }; AccountRange? accountRange = getAccountRangeMessage.AccountRange; - (PathWithAccount[]? ranges, byte[][]? proofs) = SyncServer.GetAccountRanges(accountRange.RootHash, accountRange.StartingHash, + (IOwnedReadOnlyList? ranges, IOwnedReadOnlyList? proofs) = SyncServer.GetAccountRanges(accountRange.RootHash, accountRange.StartingHash, accountRange.LimitHash, getAccountRangeMessage.ResponseBytes, cancellationToken); AccountRangeMessage? response = new() { Proofs = proofs, PathsWithAccounts = ranges }; return response; @@ -252,11 +258,11 @@ private StorageRangeMessage FulfillStorageRangeMessage(GetStorageRangeMessage ge { if (SyncServer is null) return new StorageRangeMessage() { - Proofs = Array.Empty(), - Slots = Array.Empty(), + Proofs = ArrayPoolList.Empty(), + Slots = ArrayPoolList.Empty(), }; StorageRange? storageRange = getStorageRangeMessage.StoragetRange; - (PathWithStorageSlot[][]? ranges, byte[][]? proofs) = SyncServer.GetStorageRanges(storageRange.RootHash, storageRange.Accounts, + (IOwnedReadOnlyList? ranges, IOwnedReadOnlyList? proofs) = SyncServer.GetStorageRanges(storageRange.RootHash, storageRange.Accounts, storageRange.StartingHash, storageRange.LimitHash, getStorageRangeMessage.ResponseBytes, cancellationToken); StorageRangeMessage? response = new() { Proofs = proofs, Slots = ranges }; return response; @@ -264,14 +270,14 @@ private StorageRangeMessage FulfillStorageRangeMessage(GetStorageRangeMessage ge private ByteCodesMessage FulfillByteCodesMessage(GetByteCodesMessage getByteCodesMessage, CancellationToken cancellationToken) { - if (SyncServer is null) return new ByteCodesMessage(Array.Empty()); - var byteCodes = SyncServer.GetByteCodes(getByteCodesMessage.Hashes, getByteCodesMessage.Bytes, cancellationToken); + if (SyncServer is null) return new ByteCodesMessage(ArrayPoolList.Empty()); + IOwnedReadOnlyList? byteCodes = SyncServer.GetByteCodes(getByteCodesMessage.Hashes, getByteCodesMessage.Bytes, cancellationToken); return new ByteCodesMessage(byteCodes); } public async Task GetAccountRange(AccountRange range, CancellationToken token) { - AccountRangeMessage response = await _requestSizer.MeasureLatency((bytesLimit) => + AccountRangeMessage response = await _requestSizer.MeasureLatency(bytesLimit => SendRequest(new GetAccountRangeMessage() { AccountRange = range, @@ -280,12 +286,12 @@ public async Task GetAccountRange(AccountRange range, Cancell Metrics.SnapGetAccountRangeSent++; - return new AccountsAndProofs() { PathAndAccounts = response.PathsWithAccounts, Proofs = response.Proofs }; + return new AccountsAndProofs { PathAndAccounts = response.PathsWithAccounts, Proofs = response.Proofs }; } public async Task GetStorageRange(StorageRange range, CancellationToken token) { - StorageRangeMessage response = await _requestSizer.MeasureLatency((bytesLimit) => + StorageRangeMessage response = await _requestSizer.MeasureLatency(bytesLimit => SendRequest(new GetStorageRangeMessage() { StoragetRange = range, @@ -294,15 +300,15 @@ public async Task GetStorageRange(StorageRange range, Cancellati Metrics.SnapGetStorageRangesSent++; - return new SlotsAndProofs() { PathsAndSlots = response.Slots, Proofs = response.Proofs }; + return new SlotsAndProofs { PathsAndSlots = response.Slots, Proofs = response.Proofs }; } - public async Task GetByteCodes(IReadOnlyList codeHashes, CancellationToken token) + public async Task> GetByteCodes(IReadOnlyList codeHashes, CancellationToken token) { - ByteCodesMessage response = await _requestSizer.MeasureLatency((bytesLimit) => - SendRequest(new GetByteCodesMessage() + ByteCodesMessage response = await _requestSizer.MeasureLatency(bytesLimit => + SendRequest(new GetByteCodesMessage { - Hashes = codeHashes, + Hashes = codeHashes.ToPooledList(), Bytes = bytesLimit, }, _getByteCodesRequests, token)); @@ -311,22 +317,22 @@ public async Task GetByteCodes(IReadOnlyList codeHashes, return response.Codes; } - public async Task GetTrieNodes(AccountsToRefreshRequest request, CancellationToken token) + public async Task> GetTrieNodes(AccountsToRefreshRequest request, CancellationToken token) { - PathGroup[] groups = GetPathGroups(request); + IOwnedReadOnlyList groups = GetPathGroups(request); return await GetTrieNodes(request.RootHash, groups, token); } - public async Task GetTrieNodes(GetTrieNodesRequest request, CancellationToken token) + public async Task> GetTrieNodes(GetTrieNodesRequest request, CancellationToken token) { return await GetTrieNodes(request.RootHash, request.AccountAndStoragePaths, token); } - private async Task GetTrieNodes(ValueHash256 rootHash, PathGroup[] groups, CancellationToken token) + private async Task> GetTrieNodes(ValueHash256 rootHash, IOwnedReadOnlyList groups, CancellationToken token) { TrieNodesMessage response = await _requestSizer.MeasureLatency((bytesLimit) => - SendRequest(new GetTrieNodesMessage() + SendRequest(new GetTrieNodesMessage { RootHash = rootHash, Paths = groups, @@ -338,14 +344,14 @@ private async Task GetTrieNodes(ValueHash256 rootHash, PathGroup[] gro return response.Nodes; } - private static PathGroup[] GetPathGroups(AccountsToRefreshRequest request) + private static IOwnedReadOnlyList GetPathGroups(AccountsToRefreshRequest request) { - PathGroup[] groups = new PathGroup[request.Paths.Length]; + ArrayPoolList groups = new(request.Paths.Count); - for (int i = 0; i < request.Paths.Length; i++) + for (int i = 0; i < request.Paths.Count; i++) { AccountWithStorageStartingHash path = request.Paths[i]; - groups[i] = new PathGroup() { Group = new[] { path.PathAndAccount.Path.Bytes.ToArray(), _emptyBytes } }; + groups.Add(new PathGroup { Group = [path.PathAndAccount.Path.Bytes.ToArray(), _emptyBytes] }); } return groups; @@ -359,7 +365,7 @@ private async Task SendRequest(TIn msg, MessageQueue requestQueue, msg, TransferSpeedType.SnapRanges, - static (request) => request.ToString(), + static request => request.ToString(), token); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/Messages/BlockWitnessHashesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/Messages/BlockWitnessHashesMessage.cs index 1e4cf4170df..a6092bd0859 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/Messages/BlockWitnessHashesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/Messages/BlockWitnessHashesMessage.cs @@ -6,20 +6,14 @@ namespace Nethermind.Network.P2P.Subprotocols.Wit.Messages { - public class BlockWitnessHashesMessage : P2PMessage + public class BlockWitnessHashesMessage(long requestId, Hash256[] hashes) : P2PMessage { public override int PacketType { get; } = WitMessageCode.BlockWitnessHashes; public override string Protocol { get; } = "wit"; - public long RequestId { get; } + public long RequestId { get; } = requestId; - public Hash256[] Hashes { get; } - - public BlockWitnessHashesMessage(long requestId, Hash256[] hashes) - { - RequestId = requestId; - Hashes = hashes; - } + public Hash256[] Hashes { get; } = hashes; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/WitProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/WitProtocolHandler.cs index 91becac4c89..586b9044eb1 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/WitProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Wit/WitProtocolHandler.cs @@ -65,15 +65,19 @@ public override void HandleMessage(ZeroPacket message) switch (packetType) { case WitMessageCode.GetBlockWitnessHashes: - GetBlockWitnessHashesMessage requestMsg = Deserialize(message.Content); - ReportIn(requestMsg, size); - Handle(requestMsg); - break; + { + using GetBlockWitnessHashesMessage requestMsg = Deserialize(message.Content); + ReportIn(requestMsg, size); + Handle(requestMsg); + break; + } case WitMessageCode.BlockWitnessHashes: - BlockWitnessHashesMessage responseMsg = Deserialize(message.Content); - ReportIn(responseMsg, size); - Handle(responseMsg, size); - break; + { + BlockWitnessHashesMessage responseMsg = Deserialize(message.Content); + ReportIn(responseMsg, size); + Handle(responseMsg, size); + break; + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Utils/BackgroundTaskSchedulerWrapper.cs b/src/Nethermind/Nethermind.Network/P2P/Utils/BackgroundTaskSchedulerWrapper.cs index 03c8b4a360f..733c2155882 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Utils/BackgroundTaskSchedulerWrapper.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Utils/BackgroundTaskSchedulerWrapper.cs @@ -57,15 +57,7 @@ private async Task BackgroundTaskFailureHandlerValueTask((TReq Request, Fu } catch (Exception e) { - if (e is EthSyncException) - { - handler.Session.InitiateDisconnect(DisconnectReason.EthSyncException, e.Message); - } - else - { - handler.Session.InitiateDisconnect(DisconnectReason.BackgroundTaskFailure, e.Message); - } - + handler.Session.InitiateDisconnect(e is EthSyncException ? DisconnectReason.EthSyncException : DisconnectReason.BackgroundTaskFailure, e.Message); if (handler.Logger.IsDebug) handler.Logger.Debug($"Failure running background task on session {handler.Session}, {e}"); } } diff --git a/src/Nethermind/Nethermind.Network/ProtocolsManager.cs b/src/Nethermind/Nethermind.Network/ProtocolsManager.cs index efadf7270d9..bd2e15e2def 100644 --- a/src/Nethermind/Nethermind.Network/ProtocolsManager.cs +++ b/src/Nethermind/Nethermind.Network/ProtocolsManager.cs @@ -325,7 +325,7 @@ private void InitP2PProtocol(ISession session, P2PProtocolHandler handler) _stats.ReportP2PInitializationEvent(session.Node, new P2PNodeDetails { ClientId = typedArgs.ClientId, - Capabilities = typedArgs.Capabilities.ToArray(), + Capabilities = typedArgs.Capabilities, P2PVersion = typedArgs.P2PVersion, ListenPort = typedArgs.ListenPort }); @@ -442,17 +442,14 @@ public void SendNewCapability(Capability capability) AddCapabilityMessage message = new(capability); foreach ((Guid _, ISession session) in _sessions) { - if (session.HasAgreedCapability(capability)) + if (!session.HasAgreedCapability(capability) && session.HasAvailableCapability(capability)) { - continue; + session.DeliverMessage(message); } - - if (!session.HasAvailableCapability(capability)) + else { - continue; + message.Dispose(); } - - session.DeliverMessage(message); } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index bc8f1015591..306eaa6e15b 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; using System.Text; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Int256; @@ -154,6 +155,30 @@ public static T[] DecodeArray(RlpStream rlpStream, IRlpStreamDecoder? rlpD return result; } + public static ArrayPoolList DecodeArrayPool(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + IRlpStreamDecoder? rlpDecoder = GetStreamDecoder(); + if (rlpDecoder is not null) + { + return DecodeArrayPool(rlpStream, rlpDecoder, rlpBehaviors); + } + + throw new RlpException($"{nameof(Rlp)} does not support decoding {typeof(T).Name}"); + } + + public static ArrayPoolList DecodeArrayPool(RlpStream rlpStream, IRlpStreamDecoder? rlpDecoder, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + int checkPosition = rlpStream.ReadSequenceLength() + rlpStream.Position; + int length = rlpStream.PeekNumberOfItemsRemaining(checkPosition); + ArrayPoolList result = new ArrayPoolList(length); + for (int i = 0; i < length; i++) + { + result.Add(rlpDecoder.Decode(rlpStream, rlpBehaviors)); + } + + return result; + } + internal static byte[] ByteSpanToArray(ReadOnlySpan span) { if (span.Length == 0) @@ -174,6 +199,26 @@ internal static byte[] ByteSpanToArray(ReadOnlySpan span) return span.ToArray(); } + internal static ArrayPoolList ByteSpanToArrayPool(ReadOnlySpan span) + { + if (span.Length == 0) + { + return ArrayPoolList.Empty(); + } + + if (span.Length == 1) + { + int value = span[0]; + var arrays = RlpStream.SingleByteArrays; + if ((uint)value < (uint)arrays.Length) + { + return arrays[value].ToPooledList(); + } + } + + return span.ToPooledList(); + } + public static IRlpValueDecoder? GetValueDecoder() => Decoders.TryGetValue(typeof(T), out IRlpDecoder value) ? value as IRlpValueDecoder : null; public static IRlpStreamDecoder? GetStreamDecoder() => Decoders.TryGetValue(typeof(T), out IRlpDecoder value) ? value as IRlpStreamDecoder : null; public static IRlpObjectDecoder? GetObjectDecoder() => Decoders.TryGetValue(typeof(T), out IRlpDecoder value) ? value as IRlpObjectDecoder : null; diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs index 5c626cc4c22..159760a392f 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs @@ -12,6 +12,7 @@ using System.Text; using Nethermind.Core; using Nethermind.Core.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Int256; @@ -1136,6 +1137,28 @@ public T[] DecodeArray(Func decodeItem, bool checkPositions = t return result; } + public ArrayPoolList DecodeArrayPoolList(Func decodeItem, bool checkPositions = true, + T defaultElement = default) + { + int positionCheck = ReadSequenceLength() + Position; + int count = PeekNumberOfItemsRemaining(checkPositions ? positionCheck : (int?)null); + ArrayPoolList result = new ArrayPoolList(count, count); + for (int i = 0; i < result.Count; i++) + { + if (PeekByte() == Rlp.OfEmptySequence[0]) + { + result[i] = defaultElement; + Position++; + } + else + { + result[i] = decodeItem(this); + } + } + + return result; + } + public string DecodeString() { ReadOnlySpan bytes = DecodeByteArraySpan(); @@ -1308,6 +1331,11 @@ public byte[] DecodeByteArray() return Rlp.ByteSpanToArray(DecodeByteArraySpan()); } + public ArrayPoolList DecodeByteArrayPoolList() + { + return Rlp.ByteSpanToArrayPool(DecodeByteArraySpan()); + } + public ReadOnlySpan DecodeByteArraySpan() { int prefix = ReadByte(); diff --git a/src/Nethermind/Nethermind.State/Snap/AccountsAndProofs.cs b/src/Nethermind/Nethermind.State/Snap/AccountsAndProofs.cs index bdad8248148..d2ec164acfd 100644 --- a/src/Nethermind/Nethermind.State/Snap/AccountsAndProofs.cs +++ b/src/Nethermind/Nethermind.State/Snap/AccountsAndProofs.cs @@ -1,11 +1,20 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using Nethermind.Core.Collections; + namespace Nethermind.State.Snap { - public class AccountsAndProofs + public class AccountsAndProofs : IDisposable { - public PathWithAccount[] PathAndAccounts { get; set; } - public byte[][] Proofs { get; set; } + public IOwnedReadOnlyList PathAndAccounts { get; set; } + public IOwnedReadOnlyList Proofs { get; set; } + + public void Dispose() + { + PathAndAccounts?.Dispose(); + Proofs?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.State/Snap/AccountsToRefreshRequest.cs b/src/Nethermind/Nethermind.State/Snap/AccountsToRefreshRequest.cs index 17d5c308028..2d752ed573e 100644 --- a/src/Nethermind/Nethermind.State/Snap/AccountsToRefreshRequest.cs +++ b/src/Nethermind/Nethermind.State/Snap/AccountsToRefreshRequest.cs @@ -1,22 +1,29 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.State.Snap { - public class AccountsToRefreshRequest + public class AccountsToRefreshRequest : IDisposable { /// /// Root hash of the account trie to serve /// public ValueHash256 RootHash { get; set; } - public AccountWithStorageStartingHash[] Paths { get; set; } + public IOwnedReadOnlyList Paths { get; set; } public override string ToString() { - return $"AccountsToRefreshRequest: ({RootHash}, {Paths.Length})"; + return $"AccountsToRefreshRequest: ({RootHash}, {Paths.Count})"; + } + + public void Dispose() + { + Paths?.Dispose(); } } diff --git a/src/Nethermind/Nethermind.State/Snap/GetTrieNodesRequest.cs b/src/Nethermind/Nethermind.State/Snap/GetTrieNodesRequest.cs index 82d8781dae3..b004ee697d9 100644 --- a/src/Nethermind/Nethermind.State/Snap/GetTrieNodesRequest.cs +++ b/src/Nethermind/Nethermind.State/Snap/GetTrieNodesRequest.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.State.Snap @@ -9,6 +10,6 @@ public class GetTrieNodesRequest { public ValueHash256 RootHash { get; set; } - public PathGroup[] AccountAndStoragePaths { get; set; } + public IOwnedReadOnlyList AccountAndStoragePaths { get; set; } } } diff --git a/src/Nethermind/Nethermind.State/Snap/SlotsAndProofs.cs b/src/Nethermind/Nethermind.State/Snap/SlotsAndProofs.cs index 7dab28849f9..dbcb0e47ea4 100644 --- a/src/Nethermind/Nethermind.State/Snap/SlotsAndProofs.cs +++ b/src/Nethermind/Nethermind.State/Snap/SlotsAndProofs.cs @@ -1,11 +1,20 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using Nethermind.Core.Collections; + namespace Nethermind.State.Snap { - public class SlotsAndProofs + public class SlotsAndProofs : IDisposable { - public PathWithStorageSlot[][] PathsAndSlots { get; set; } - public byte[][] Proofs { get; set; } + public IOwnedReadOnlyList PathsAndSlots { get; set; } + public IOwnedReadOnlyList Proofs { get; set; } + + public void Dispose() + { + PathsAndSlots?.Dispose(); + Proofs?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.State/Snap/StorageRange.cs b/src/Nethermind/Nethermind.State/Snap/StorageRange.cs index 7996d757c4a..3d0843757fe 100644 --- a/src/Nethermind/Nethermind.State/Snap/StorageRange.cs +++ b/src/Nethermind/Nethermind.State/Snap/StorageRange.cs @@ -1,11 +1,15 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; namespace Nethermind.State.Snap { - public class StorageRange + public class StorageRange : IDisposable { public long? BlockNumber { get; set; } @@ -17,7 +21,7 @@ public class StorageRange /// /// Accounts of the storage tries to serve /// - public PathWithAccount[] Accounts { get; set; } + public IOwnedReadOnlyList Accounts { get; set; } /// /// Account hash of the first to retrieve @@ -29,9 +33,26 @@ public class StorageRange /// public ValueHash256? LimitHash { get; set; } + public StorageRange Copy() + { + return new StorageRange() + { + BlockNumber = BlockNumber, + RootHash = RootHash, + Accounts = Accounts.ToPooledList(Accounts.Count), + StartingHash = StartingHash, + LimitHash = LimitHash, + }; + } + public override string ToString() { return $"StorageRange: ({BlockNumber}, {RootHash}, {StartingHash}, {LimitHash})"; } + + public void Dispose() + { + Accounts?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs index 4abc1531674..64c167a98cd 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs @@ -7,13 +7,16 @@ using System.Threading; using System.Threading.Tasks; using FluentAssertions; +using Microsoft.ClearScript.JavaScript; using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; @@ -568,7 +571,7 @@ public async Task Validate_always_the_last_seal_and_random_seal_in_the_package() }; BlockDownloader downloader = ctx.BlockDownloader; - BlockHeader[] blockHeaders = await ctx.ResponseBuilder.BuildHeaderResponse(0, 512, Response.AllCorrect); + IOwnedReadOnlyList? blockHeaders = await ctx.ResponseBuilder.BuildHeaderResponse(0, 512, Response.AllCorrect); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) @@ -582,7 +585,7 @@ public async Task Validate_always_the_last_seal_and_random_seal_in_the_package() sealValidator.Received(2).ValidateSeal(Arg.Any(), true); sealValidator.Received(510).ValidateSeal(Arg.Any(), false); - sealValidator.Received().ValidateSeal(blockHeaders[^1], true); + sealValidator.Received().ValidateSeal(blockHeaders![^1], true); } private class ThrowingPeer : ISyncPeer @@ -615,12 +618,12 @@ public Task GetBlockBodies(IReadOnlyList blockHashes, throw new NotImplementedException(); } - public Task GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) { throw new NotImplementedException(); } - public Task GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) { throw new Exception(); } @@ -642,12 +645,12 @@ public void SendNewTransactions(IEnumerable txs, bool sendFullTx) throw new NotImplementedException(); } - public Task GetReceipts(IReadOnlyList blockHash, CancellationToken token) + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) { throw new NotImplementedException(); } - public Task GetNodeData(IReadOnlyList hashes, CancellationToken token) + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) { throw new NotImplementedException(); } @@ -722,7 +725,7 @@ public async Task Throws_on_receipt_task_exception_when_downloading_receipts(int .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(Task.FromException(new TimeoutException())); + .Returns(Task.FromException>(new TimeoutException())); PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); @@ -773,9 +776,11 @@ public async Task Throws_on_null_receipt_downloaded(int options, bool shouldThro syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) .Returns(async ci => { - TxReceipt[]?[] receipts = await syncPeerInternal.GetReceipts(ci.ArgAt>(0), ci.ArgAt(1)); + ArrayPoolList receipts = (await syncPeerInternal + .GetReceipts(ci.ArgAt>(0), ci.ArgAt(1))) + .ToPooledList(); receipts[^1] = null; - return receipts; + return (IOwnedReadOnlyList)receipts; }); syncPeer.TotalDifficulty.Returns(_ => syncPeerInternal.TotalDifficulty); @@ -819,7 +824,7 @@ public async Task Throws_on_block_bodies_count_higher_than_receipts_list_count(i .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) - .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result.Skip(1).ToArray()); + .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result.Skip(1).ToPooledList(10)); PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); @@ -848,7 +853,7 @@ public async Task Does_throw_on_transaction_count_different_than_receipts_count_ 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()).ToArray()); + .Result.Select(r => r is null || r.Length == 0 ? r : r.Skip(1).ToArray()).ToPooledList(10)); PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); @@ -1093,12 +1098,12 @@ public async Task GetBlockBodies(IReadOnlyList blockH headers[i++] = BlockTree.FindBlock(blockHash, BlockTreeLookupOptions.None)!.Body; } - BlockBodiesMessage message = new(headers); + using BlockBodiesMessage message = new(headers); byte[] messageSerialized = _bodiesSerializer.Serialize(message); return await Task.FromResult(_bodiesSerializer.Deserialize(messageSerialized).Bodies!); } - public async Task GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + public async Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) { bool justFirst = _flags.HasFlag(Response.JustFirst); bool timeoutOnFullBatch = _flags.HasFlag(Response.TimeoutOnFullBatch); @@ -1114,12 +1119,12 @@ public async Task GetBlockHeaders(long number, int maxBlocks, int headers[i] = BlockTree.FindHeader(number + i, BlockTreeLookupOptions.None)!; } - BlockHeadersMessage message = new(headers); + 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) + public async Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) { TxReceipt[][] receipts = new TxReceipt[blockHash.Count][]; int i = 0; @@ -1130,7 +1135,7 @@ public async Task GetBlockHeaders(long number, int maxBlocks, int receipts[i++] = blockReceipts; } - ReceiptsMessage message = new(receipts); + using ReceiptsMessage message = new(receipts.ToPooledList()); byte[] messageSerialized = _receiptsSerializer.Serialize(message); return await Task.FromResult(_receiptsSerializer.Deserialize(messageSerialized).TxReceipts); } @@ -1140,7 +1145,7 @@ public void Disconnect(DisconnectReason reason, string details) throw new NotImplementedException(); } - public Task GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) { throw new NotImplementedException(); } @@ -1160,7 +1165,7 @@ public void SendNewTransactions(IEnumerable txs, bool sendFullTx) throw new NotImplementedException(); } - public Task GetNodeData(IReadOnlyList hashes, CancellationToken token) + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) { throw new NotImplementedException(); } @@ -1187,7 +1192,7 @@ public ResponseBuilder(IBlockTree blockTree, Dictionary testHeade _testHeaderMapping = testHeaderMapping; } - public async Task BuildHeaderResponse(long startNumber, int number, Response flags) + public async Task?> BuildHeaderResponse(long startNumber, int number, Response flags) { bool consistent = flags.HasFlag(Response.Consistent); bool justFirst = flags.HasFlag(Response.JustFirst); @@ -1235,7 +1240,7 @@ public async Task BuildHeaderResponse(long startNumber, int numbe _headers[header.Hash!] = header; } - BlockHeadersMessage message = new(headers); + using BlockHeadersMessage message = new(headers.ToPooledList()); byte[] messageSerialized = _headersSerializer.Serialize(message); return await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders); } @@ -1308,12 +1313,12 @@ Block BuildBlockForHeader(BlockHeader header, int txSeed) } } - BlockBodiesMessage message = new(blockBodies); + 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) + public async Task> BuildReceiptsResponse(IList blockHashes, Response flags = Response.AllCorrect) { TxReceipt[][] receipts = new TxReceipt[blockHashes.Count][]; for (int i = 0; i < receipts.Length; i++) @@ -1333,7 +1338,7 @@ Block BuildBlockForHeader(BlockHeader header, int txSeed) : ReceiptTrie.CalculateRoot(MainnetSpecProvider.Instance.GetSpec((ForkActivation)_headers[blockHashes[i]].Number), receipts[i], ReceiptMessageDecoder.Instance); } - ReceiptsMessage message = new(receipts); + 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/BodiesSyncFeedTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/BodiesSyncFeedTests.cs index b0c4eed5118..79e278e23a4 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/BodiesSyncFeedTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/BodiesSyncFeedTests.cs @@ -98,6 +98,8 @@ async Task HandleAndPrepareNextRequest() _syncingFromBlockTree.FindBlock(info!.BlockNumber, BlockTreeLookupOptions.None)!.Body).ToArray()); _feed.HandleResponse(req); + req.Dispose(); + req = (await _feed.PrepareRequest())!; } @@ -112,13 +114,14 @@ async Task HandleAndPrepareNextRequest() await HandleAndPrepareNextRequest(); _blocksDb.FlushCount.Should().Be(3); + req.Dispose(); } [Test] public async Task ShouldRecoverOnInsertFailure() { _feed.InitializeFeed(); - BodiesSyncBatch req = (await _feed.PrepareRequest())!; + using BodiesSyncBatch req = (await _feed.PrepareRequest())!; req.Response = new OwnedBlockBodies(req.Infos.Take(8).Select((info) => _syncingFromBlockTree.FindBlock(info!.BlockNumber, BlockTreeLookupOptions.None)!.Body).ToArray()); @@ -135,9 +138,8 @@ public async Task ShouldRecoverOnInsertFailure() Func act = () => _feed.HandleResponse(req); act.Should().Throw(); - req = (await _feed.PrepareRequest())!; - - req.Infos[0]!.BlockNumber.Should().Be(95); + using BodiesSyncBatch req2 = (await _feed.PrepareRequest())!; + req2.Infos[0]!.BlockNumber.Should().Be(95); } [TestCase(1, 99, false, null, false)] diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs index dc3fce6c84f..cc174c6a56a 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/FastHeadersSyncTests.cs @@ -11,6 +11,7 @@ using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; @@ -110,14 +111,14 @@ void FulfillBatch(HeadersSyncBatch batch) { batch.Response = remoteBlockTree.FindHeaders( remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false); + false)!; batch.ResponseSourcePeer = peerInfo; } - HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; - HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; - HeadersSyncBatch batch3 = (await feed.PrepareRequest())!; - HeadersSyncBatch batch4 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch3 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch4 = (await feed.PrepareRequest())!; FulfillBatch(batch1); FulfillBatch(batch2); @@ -168,17 +169,17 @@ void FulfillBatch(HeadersSyncBatch batch) { batch.Response = remoteBlockTree.FindHeaders( remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false); + false)!; } await feed.PrepareRequest(); - HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; FulfillBatch(batch1); feed.Reset(); await feed.PrepareRequest(); - HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; FulfillBatch(batch2); feed.HandleResponse(batch2); @@ -216,15 +217,15 @@ void FulfillBatch(HeadersSyncBatch batch) { batch.Response = remoteBlockTree.FindHeaders( remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false); + false)!; } // First batch need to be handled first before handle dependencies can do anything - HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; FulfillBatch(batch1); feed.HandleResponse(batch1); - HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; FulfillBatch(batch2); int maxHeaderBatchToProcess = 4; @@ -246,7 +247,7 @@ void FulfillBatch(HeadersSyncBatch batch) feed.HandleResponse(batch2); // HandleDependantBatch would start from first batch in batches, stopped at second last, not processing the last one - HeadersSyncBatch newBatch = (await feed.PrepareRequest())!; + using HeadersSyncBatch newBatch = (await feed.PrepareRequest())!; blockTree.LowestInsertedHeader!.Number.Should().Be(batches[^2].StartNumber); // New batch would be at end of batch 5 (batch 6). @@ -290,10 +291,10 @@ void FulfillBatch(HeadersSyncBatch batch) { batch.Response = remoteBlockTree.FindHeaders( remoteBlockTree.FindHeader(batch.StartNumber, BlockTreeLookupOptions.None)!.Hash, batch.RequestSize, 0, - false); + false)!; } - HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch1 = (await feed.PrepareRequest())!; FulfillBatch(batch1); // Initiate a process batch which should hang in the middle @@ -309,7 +310,7 @@ void FulfillBatch(HeadersSyncBatch batch) await resetTask; // A new batch is creating, starting at hang block - HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; + using HeadersSyncBatch batch2 = (await feed.PrepareRequest())!; FulfillBatch(batch2); feed.HandleResponse(batch2); @@ -341,7 +342,7 @@ public async Task Can_keep_returning_nulls_after_all_batches_were_prepared() await feed.PrepareRequest(); } - HeadersSyncBatch? result = await feed.PrepareRequest(); + using HeadersSyncBatch? result = await feed.PrepareRequest(); result.Should().BeNull(); } @@ -357,7 +358,7 @@ public async Task Finishes_when_all_downloaded() HeadersSyncFeed feed = new(blockTree, Substitute.For(), new SyncConfig { FastSync = true, FastBlocks = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }, report, LimboLogs.Instance); await feed.PrepareRequest(); blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).TestObject); - HeadersSyncBatch? result = await feed.PrepareRequest(); + using HeadersSyncBatch? result = await feed.PrepareRequest(); result.Should().BeNull(); feed.CurrentState.Should().Be(SyncFeedState.Finished); @@ -379,7 +380,7 @@ public async Task Can_resume_downloading_from_parent_of_lowest_inserted_header() HeadersSyncFeed feed = new(blockTree, Substitute.For(), new SyncConfig { FastSync = true, FastBlocks = true, PivotNumber = "1000", PivotHash = Keccak.Zero.ToString(), PivotTotalDifficulty = "1000" }, report, LimboLogs.Instance); feed.InitializeFeed(); - HeadersSyncBatch? result = await feed.PrepareRequest(); + using HeadersSyncBatch? result = await feed.PrepareRequest(); result.Should().NotBeNull(); result!.EndNumber.Should().Be(499); @@ -443,7 +444,7 @@ public async Task Will_never_lose_batch_on_invalid_batch() BlockHeader randomBlockHeader = Build.A.BlockHeader.WithNumber(999999).TestObject; await foreach (HeadersSyncBatch headersSyncBatch in batchToProcess.Reader.ReadAllAsync()) { - headersSyncBatch.Response = new[] { randomBlockHeader }; + headersSyncBatch.Response = new ArrayPoolList(1) { randomBlockHeader }; feed.HandleResponse(headersSyncBatch); } @@ -451,7 +452,7 @@ public async Task Will_never_lose_batch_on_invalid_batch() while (true) { - HeadersSyncBatch? batch = await feed.PrepareRequest(); + using HeadersSyncBatch? batch = await feed.PrepareRequest(); if (batch is null) break; batches.Add(batch); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs index 38b207348d0..12b8b2fef2d 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastBlocks/ReceiptsSyncFeedTests.cs @@ -11,6 +11,7 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -168,7 +169,7 @@ public async Task Should_finish_on_start_when_receipts_not_stored() LimboLogs.Instance); _feed.InitializeFeed(); - ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); request.Should().BeNull(); _feed.CurrentState.Should().Be(SyncFeedState.Finished); } @@ -211,9 +212,9 @@ public void When_no_bodies_downloaded_then_request_will_be_empty() public async Task Returns_same_batch_until_filled() { LoadScenario(_256BodiesWithOneTxEach); - ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); _feed.HandleResponse(request); - ReceiptsSyncBatch? request2 = await _feed.PrepareRequest(); + using ReceiptsSyncBatch? request2 = await _feed.PrepareRequest(); request2?.MinNumber.Should().Be(request?.MinNumber); } @@ -221,7 +222,7 @@ public async Task Returns_same_batch_until_filled() public async Task Can_create_a_final_batch() { LoadScenario(_64BodiesWithOneTxEachFollowedByEmpty); - ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); request.Should().NotBeNull(); request!.MinNumber.Should().Be(1024); request.Prioritized.Should().Be(true); @@ -233,7 +234,7 @@ public async Task When_configured_to_skip_receipts_then_finishes_immediately() LoadScenario(_256BodiesWithOneTxEach); _syncConfig.DownloadReceiptsInFastSync = false; - ReceiptsSyncBatch? request = await _feed.PrepareRequest(); + using ReceiptsSyncBatch? request = await _feed.PrepareRequest(); request.Should().BeNull(); _feed.CurrentState.Should().Be(SyncFeedState.Finished); _measuredProgress.HasEnded.Should().BeTrue(); @@ -362,12 +363,14 @@ so most of our requests will be empty */ public async Task If_receipts_root_comes_invalid_then_reports_breach_of_protocol() { LoadScenario(_1024BodiesWithOneTxEach); - ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); - batch!.Response = new TxReceipt[batch.Infos.Length][]; + using ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); + var response = new ArrayPoolList(batch!.Infos.Length, batch!.Infos.Length); // 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 - batch.Response[0] = new[] { Build.A.Receipt.WithStatusCode(1).TestObject }; + response[0] = new[] { Build.A.Receipt.WithStatusCode(1).TestObject }; + + batch!.Response = response!; PeerInfo peerInfo = new(Substitute.For()); batch.ResponseSourcePeer = peerInfo; @@ -380,18 +383,20 @@ public async Task If_receipts_root_comes_invalid_then_reports_breach_of_protocol private static void FillBatchResponses(ReceiptsSyncBatch batch) { - batch.Response = new TxReceipt[batch.Infos.Length][]; - for (int i = 0; i < batch.Response.Length; i++) + var response = new ArrayPoolList(batch.Infos.Length, batch.Infos.Length); + for (int i = 0; i < response.Count; i++) { - batch.Response[i] = new[] { Build.A.Receipt.TestObject }; + response[i] = new[] { Build.A.Receipt.TestObject }; } + + batch.Response = response; } [Test] public async Task Can_sync_final_batch() { LoadScenario(_64BodiesWithOneTxEach); - ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); + using ReceiptsSyncBatch? batch = await _feed.PrepareRequest(); FillBatchResponses(batch!); _feed.HandleResponse(batch); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs index 008311220f8..b91055dbc87 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs @@ -66,7 +66,7 @@ public async Task Eth66Peer_RunGetNodeData() peer.TotalDifficulty.Returns(new Int256.UInt256(1_000_000_000)); _pool.AddPeer(peer); - StateSyncBatch batch = new( + using StateSyncBatch batch = new( Keccak.OfAnEmptyString, NodeDataType.State, new[] { new StateSyncItem(Keccak.EmptyTreeHash, Array.Empty(), Array.Empty(), NodeDataType.State) }); @@ -100,7 +100,7 @@ public async Task GroupMultipleStorageSlotsByAccount() StateSyncItem item05 = new(Keccak.EmptyTreeHash, new byte[] { 11 }, new byte[] { 1 }, NodeDataType.State); StateSyncItem item06 = new(Keccak.EmptyTreeHash, new byte[] { 22 }, new byte[] { 22 }, NodeDataType.State); - StateSyncBatch batch = new( + using StateSyncBatch batch = new( Keccak.OfAnEmptyString, NodeDataType.State, new[] { item01, item02, item03, item04, item05, item06 }); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs index 49a30c32adc..76d5a9d12cb 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs @@ -369,7 +369,7 @@ public async Task When_empty_response_received_return_lesser_quality() ctx.Feed.SyncModeSelectorOnChanged(SyncMode.StateNodes | SyncMode.FastBlocks); ctx.TreeFeed.ResetStateRoot(100, dbContext.RemoteStateTree.RootHash, SyncFeedState.Dormant); - StateSyncBatch? request = await ctx.Feed.PrepareRequest(); + using StateSyncBatch? request = await ctx.Feed.PrepareRequest(); request.Should().NotBeNull(); ctx.Feed.HandleResponse(request, new PeerInfo(Substitute.For())) @@ -392,7 +392,7 @@ public async Task When_empty_response_received_with_no_peer_return_not_allocated ctx.Feed.SyncModeSelectorOnChanged(SyncMode.StateNodes | SyncMode.FastBlocks); ctx.TreeFeed.ResetStateRoot(100, dbContext.RemoteStateTree.RootHash, SyncFeedState.Dormant); - StateSyncBatch? request = await ctx.Feed.PrepareRequest(); + using StateSyncBatch? request = await ctx.Feed.PrepareRequest(); request.Should().NotBeNull(); ctx.Feed.HandleResponse(request, peer: null) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTestsBase.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTestsBase.cs index cdf176852bf..58c8e79df0e 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTestsBase.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTestsBase.cs @@ -10,6 +10,7 @@ using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; @@ -222,13 +223,13 @@ protected class SyncPeerMock : ISyncPeer private readonly IDb _stateDb; private Hash256[]? _filter; - private readonly Func, Task>? _executorResultFunction; + private readonly Func, Task>>? _executorResultFunction; private readonly long _maxRandomizedLatencyMs; public SyncPeerMock( IDb stateDb, IDb codeDb, - Func, Task>? executorResultFunction = null, + Func, Task>>? executorResultFunction = null, long? maxRandomizedLatencyMs = null, Node? node = null ) @@ -254,7 +255,7 @@ public SyncPeerMock( public PublicKey Id => Node.Id; - public async Task GetNodeData(IReadOnlyList hashes, CancellationToken token) + public async Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) { if (_maxRandomizedLatencyMs != 0) { @@ -263,7 +264,7 @@ public async Task GetNodeData(IReadOnlyList hashes, Cancellat if (_executorResultFunction is not null) return await _executorResultFunction(hashes); - byte[][] responses = new byte[hashes.Count][]; + ArrayPoolList responses = new(hashes.Count, hashes.Count); int i = 0; foreach (Hash256 item in hashes) @@ -304,12 +305,12 @@ public Task GetBlockBodies(IReadOnlyList blockHashes, throw new NotImplementedException(); } - public Task GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) { throw new NotImplementedException(); } - public Task GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) { throw new NotImplementedException(); } @@ -329,7 +330,7 @@ public void SendNewTransactions(IEnumerable txs, bool sendFullTx) throw new NotImplementedException(); } - public Task GetReceipts(IReadOnlyList blockHash, CancellationToken token) + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) { throw new NotImplementedException(); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs index 21f401ce367..5615e6a6fb4 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs @@ -13,6 +13,7 @@ using Nethermind.Consensus; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; @@ -376,10 +377,10 @@ public async Task Does_not_do_full_sync_when_not_needed_with_split() public void Can_retrieve_node_values() { _stateDb.Set(TestItem.KeccakA, TestItem.RandomDataA); - byte[]?[] data = _syncServer.GetNodeData(new[] { TestItem.KeccakA, TestItem.KeccakB }, CancellationToken.None); + IOwnedReadOnlyList data = _syncServer.GetNodeData(new[] { TestItem.KeccakA, TestItem.KeccakB }, CancellationToken.None); Assert.That(data, Is.Not.Null); - Assert.That(data.Length, Is.EqualTo(2), "data.Length"); + Assert.That(data.Count, Is.EqualTo(2), "data.Length"); Assert.That(data[0], Is.EqualTo(TestItem.RandomDataA), "data[0]"); Assert.That(data[1], Is.EqualTo(null), "data[1]"); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/ReceiptSyncFeedTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/ReceiptSyncFeedTests.cs index b3a178bf287..fbf36d608b4 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/ReceiptSyncFeedTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/ReceiptSyncFeedTests.cs @@ -9,6 +9,7 @@ using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Db; using Nethermind.Logging; @@ -69,8 +70,8 @@ public async Task ShouldRecoverOnInsertFailure() ); syncFeed.InitializeFeed(); - ReceiptsSyncBatch req = (await syncFeed.PrepareRequest())!; - req.Response = req.Infos.Take(8).Select((info) => syncingFromReceiptStore.Get(info!.BlockHash)).ToArray(); + using ReceiptsSyncBatch req = (await syncFeed.PrepareRequest())!; + req.Response = req.Infos.Take(8).Select(info => syncingFromReceiptStore.Get(info!.BlockHash)).ToPooledList(8)!; receiptStorage .When((it) => it.Insert(Arg.Any(), Arg.Any(), Arg.Any())) @@ -82,8 +83,7 @@ public async Task ShouldRecoverOnInsertFailure() Func act = () => syncFeed.HandleResponse(req); act.Should().Throw(); - req = (await syncFeed.PrepareRequest())!; - - req.Infos[0]!.BlockNumber.Should().Be(95); + using ReceiptsSyncBatch req2 = (await syncFeed.PrepareRequest())!; + req2.Infos[0]!.BlockNumber.Should().Be(95); } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs index 921b5baa7df..0769a33f4cf 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using FluentAssertions; using Nethermind.Blockchain; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; @@ -26,7 +27,7 @@ public async Task Did_not_have_race_issue() ProgressTracker progressTracker = new(blockTree, new MemDb(), LimboLogs.Instance); progressTracker.EnqueueStorageRange(new StorageRange() { - Accounts = Array.Empty(), + Accounts = ArrayPoolList.Empty(), }); int loopIteration = 100000; @@ -34,9 +35,9 @@ public async Task Did_not_have_race_issue() { for (int i = 0; i < loopIteration; i++) { - (SnapSyncBatch snapSyncBatch, bool ok) = progressTracker.GetNextRequest(); - ok.Should().BeFalse(); - progressTracker.EnqueueStorageRange(snapSyncBatch.StorageRangeRequest!); + bool finished = progressTracker.IsFinished(out SnapSyncBatch? snapSyncBatch); + finished.Should().BeFalse(); + progressTracker.EnqueueStorageRange(snapSyncBatch!.StorageRangeRequest!); } }); @@ -56,33 +57,37 @@ public async Task Did_not_have_race_issue() public void Will_create_multiple_get_address_range_request() { BlockTree blockTree = Build.A.BlockTree().WithBlocks(Build.A.Block.TestObject).TestObject; - ProgressTracker progressTracker = new ProgressTracker(blockTree, new MemDb(), LimboLogs.Instance, 4); + ProgressTracker progressTracker = new(blockTree, new MemDb(), LimboLogs.Instance, 4); - (SnapSyncBatch request, bool finished) = progressTracker.GetNextRequest(); - request.AccountRangeRequest.Should().NotBeNull(); + bool finished = progressTracker.IsFinished(out SnapSyncBatch? request); + request!.AccountRangeRequest.Should().NotBeNull(); request.AccountRangeRequest!.StartingHash.Bytes[0].Should().Be(0); request.AccountRangeRequest.LimitHash!.Value.Bytes[0].Should().Be(64); finished.Should().BeFalse(); + request.Dispose(); - (request, finished) = progressTracker.GetNextRequest(); - request.AccountRangeRequest.Should().NotBeNull(); + finished = progressTracker.IsFinished(out request); + request!.AccountRangeRequest.Should().NotBeNull(); request.AccountRangeRequest!.StartingHash.Bytes[0].Should().Be(64); request.AccountRangeRequest.LimitHash!.Value.Bytes[0].Should().Be(128); finished.Should().BeFalse(); + request.Dispose(); - (request, finished) = progressTracker.GetNextRequest(); - request.AccountRangeRequest.Should().NotBeNull(); + finished = progressTracker.IsFinished(out request); + request!.AccountRangeRequest.Should().NotBeNull(); request.AccountRangeRequest!.StartingHash.Bytes[0].Should().Be(128); request.AccountRangeRequest.LimitHash!.Value.Bytes[0].Should().Be(192); finished.Should().BeFalse(); + request.Dispose(); - (request, finished) = progressTracker.GetNextRequest(); - request.AccountRangeRequest.Should().NotBeNull(); + finished = progressTracker.IsFinished(out request); + request!.AccountRangeRequest.Should().NotBeNull(); request.AccountRangeRequest!.StartingHash.Bytes[0].Should().Be(192); request.AccountRangeRequest.LimitHash!.Value.Bytes[0].Should().Be(255); finished.Should().BeFalse(); + request.Dispose(); - (request, finished) = progressTracker.GetNextRequest(); + finished = progressTracker.IsFinished(out request); request.Should().BeNull(); finished.Should().BeFalse(); } @@ -106,10 +111,10 @@ public void Will_deque_code_request_if_high_even_if_storage_queue_is_not_empty() progressTracker.EnqueueCodeHashes(new[] { TestItem.ValueKeccaks[0] }); } - (SnapSyncBatch request, bool _) = progressTracker.GetNextRequest(); - - request.CodesRequest.Should().NotBeNull(); + progressTracker.IsFinished(out SnapSyncBatch? request); + request!.CodesRequest.Should().NotBeNull(); request.StorageRangeRequest.Should().BeNull(); + request.Dispose(); } [Test] @@ -131,10 +136,10 @@ public void Will_deque_storage_request_if_high() progressTracker.EnqueueCodeHashes(new[] { TestItem.ValueKeccaks[0] }); } - (SnapSyncBatch request, bool _) = progressTracker.GetNextRequest(); - - request.CodesRequest.Should().BeNull(); + progressTracker.IsFinished(out SnapSyncBatch? request); + request!.CodesRequest.Should().BeNull(); request.StorageRangeRequest.Should().NotBeNull(); + request.Dispose(); } [Test] @@ -143,14 +148,15 @@ public void Will_mark_progress_and_flush_when_finished() BlockTree blockTree = Build.A.BlockTree().WithBlocks(Build.A.Block .WithStateRoot(Keccak.EmptyTreeHash) .TestObject).TestObject; - TestMemDb memDb = new TestMemDb(); - ProgressTracker progressTracker = new ProgressTracker(blockTree, memDb, LimboLogs.Instance, 1); + TestMemDb memDb = new(); + ProgressTracker progressTracker = new(blockTree, memDb, LimboLogs.Instance, 1); - (SnapSyncBatch request, bool finished) = progressTracker.GetNextRequest(); - request.AccountRangeRequest.Should().NotBeNull(); + progressTracker.IsFinished(out SnapSyncBatch? request); + request!.AccountRangeRequest.Should().NotBeNull(); progressTracker.UpdateAccountRangePartitionProgress(request.AccountRangeRequest!.LimitHash!.Value, Keccak.MaxValue, false); progressTracker.ReportAccountRangePartitionFinished(request.AccountRangeRequest!.LimitHash!.Value); - (_, finished) = progressTracker.GetNextRequest(); + request.Dispose(); + bool finished = progressTracker.IsFinished(out _); finished.Should().BeTrue(); memDb.WasFlushed.Should().BeTrue(); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapServerTest.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapServerTest.cs index bd7f64f9942..a2e0126897d 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapServerTest.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapServerTest.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using FluentAssertions; using Nethermind.Blockchain.Utils; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Db; +using Nethermind.Evm.Tracing.GethStyle.JavaScript; using Nethermind.Logging; using Nethermind.State; using Nethermind.State.Snap; @@ -57,11 +60,11 @@ public void TestGetAccountRange() Context context = CreateContext(); TestItem.Tree.FillStateTreeWithTestAccounts(context.Tree); - (PathWithAccount[] accounts, byte[][] proofs) = + (IOwnedReadOnlyList accounts, IOwnedReadOnlyList proofs) = context.Server.GetAccountRanges(context.Tree.RootHash, Keccak.Zero, Keccak.MaxValue, 4000, CancellationToken.None); AddRangeResult result = context.SnapProvider.AddAccountRange(1, context.Tree.RootHash, Keccak.Zero, - accounts, proofs); + accounts.ToArray(), proofs.ToArray()); result.Should().Be(AddRangeResult.OK); context.ClientStateDb.Keys.Count.Should().Be(10); @@ -72,16 +75,16 @@ public void TestNoState() { Context context = CreateContext(stateRootTracker: CreateConstantStateRootTracker(false)); - (PathWithAccount[] accounts, byte[][] _) = + (IOwnedReadOnlyList accounts, IOwnedReadOnlyList _) = context.Server.GetAccountRanges(context.Tree.RootHash, Keccak.Zero, Keccak.MaxValue, 4000, CancellationToken.None); - accounts.Length.Should().Be(0); + accounts.Count.Should().Be(0); - (PathWithStorageSlot[][] storageSlots, byte[][]? _) = + (IOwnedReadOnlyList storageSlots, IOwnedReadOnlyList? proofs) = context.Server.GetStorageRanges(context.Tree.RootHash, new PathWithAccount[] { TestItem.Tree.AccountsWithPaths[0] }, Keccak.Zero, Keccak.MaxValue, 10, CancellationToken.None); - storageSlots.Length.Should().Be(0); + storageSlots.Count.Should().Be(0); } [Test] @@ -93,7 +96,7 @@ public void TestGetAccountRangeMultiple() Hash256 startRange = Keccak.Zero; while (true) { - (PathWithAccount[] accounts, byte[][] proofs) = + (IOwnedReadOnlyList accounts, IOwnedReadOnlyList proofs) = context.Server.GetAccountRanges(context.Tree.RootHash, startRange, Keccak.MaxValue, 100, CancellationToken.None); AddRangeResult result = context.SnapProvider.AddAccountRange(1, context.Tree.RootHash, startRange, @@ -121,7 +124,7 @@ public void TestGetAccountRangeMultipleLarger(int stateSize, int byteLimit) Hash256 startRange = Keccak.Zero; while (true) { - (PathWithAccount[] accounts, byte[][] proofs) = + (IOwnedReadOnlyList accounts, IOwnedReadOnlyList proofs) = context.Server.GetAccountRanges(context.Tree.RootHash, startRange, Keccak.MaxValue, byteLimit, CancellationToken.None); AddRangeResult result = context.SnapProvider.AddAccountRange(1, context.Tree.RootHash, startRange, @@ -149,7 +152,7 @@ public void TestGetAccountRangeArtificialLimit(int stateSize, int byteLimit) ValueHash256 limit = new ValueHash256("0x8000000000000000000000000000000000000000000000000000000000000000"); while (true) { - (PathWithAccount[] accounts, byte[][] proofs) = context.Server + (IOwnedReadOnlyList accounts, IOwnedReadOnlyList proofs) = context.Server .GetAccountRanges(context.Tree.RootHash, startRange, limit, byteLimit, CancellationToken.None); AddRangeResult result = context.SnapProvider.AddAccountRange(1, context.Tree.RootHash, startRange, @@ -182,7 +185,7 @@ public void TestGetStorageRange() ProgressTracker progressTracker = new(null!, dbProviderClient.StateDb, LimboLogs.Instance); SnapProvider snapProvider = new(progressTracker, dbProviderClient, LimboLogs.Instance); - (PathWithStorageSlot[][] storageSlots, byte[][]? proofs) = + (IOwnedReadOnlyList storageSlots, IOwnedReadOnlyList? proofs) = server.GetStorageRanges(InputStateTree.RootHash, new PathWithAccount[] { TestItem.Tree.AccountsWithPaths[0] }, Keccak.Zero, Keccak.MaxValue, 10, CancellationToken.None); @@ -213,7 +216,7 @@ public void TestGetStorageRangeMulti() Hash256 startRange = Keccak.Zero; while (true) { - (PathWithStorageSlot[][] storageSlots, byte[][]? proofs) = + (IOwnedReadOnlyList storageSlots, IOwnedReadOnlyList? proofs) = server.GetStorageRanges(InputStateTree.RootHash, new PathWithAccount[] { TestItem.Tree.AccountsWithPaths[0] }, startRange, Keccak.MaxValue, 10000, CancellationToken.None); @@ -263,54 +266,54 @@ public void TestWithHugeTree() SnapServer server = new(store.AsReadOnly(), codeDb, CreateConstantStateRootTracker(true), LimboLogs.Instance); - PathWithAccount[] accounts; + IOwnedReadOnlyList accounts; // size of one PathWithAccount ranges from 39 -> 72 (accounts, _) = server.GetAccountRanges(stateTree.RootHash, Keccak.Zero, Keccak.MaxValue, 10, CancellationToken.None); - accounts.Length.Should().Be(1); + accounts.Count.Should().Be(1); (accounts, _) = server.GetAccountRanges(stateTree.RootHash, Keccak.Zero, Keccak.MaxValue, 100, CancellationToken.None); - accounts.Length.Should().BeGreaterThan(2); + accounts.Count.Should().BeGreaterThan(2); (accounts, _) = server.GetAccountRanges(stateTree.RootHash, Keccak.Zero, Keccak.MaxValue, 10000, CancellationToken.None); - accounts.Length.Should().BeGreaterThan(138); + accounts.Count.Should().BeGreaterThan(138); // TODO: Double check the threshold (accounts, _) = server.GetAccountRanges(stateTree.RootHash, Keccak.Zero, Keccak.MaxValue, 720000, CancellationToken.None); - accounts.Length.Should().Be(10009); + accounts.Count.Should().Be(10009); (accounts, _) = server.GetAccountRanges(stateTree.RootHash, Keccak.Zero, Keccak.MaxValue, 10000000, CancellationToken.None); - accounts.Length.Should().Be(10009); + accounts.Count.Should().Be(10009); var accountWithStorageArray = accountWithStorage.ToArray(); - PathWithStorageSlot[][] slots; - byte[][]? proofs; + IOwnedReadOnlyList slots; + IOwnedReadOnlyList? proofs; (slots, proofs) = server.GetStorageRanges(stateTree.RootHash, accountWithStorageArray[..1], Keccak.Zero, Keccak.MaxValue, 10, CancellationToken.None); - slots.Length.Should().Be(1); + slots.Count.Should().Be(1); slots[0].Length.Should().Be(1); proofs.Should().NotBeNull(); (slots, proofs) = server.GetStorageRanges(stateTree.RootHash, accountWithStorageArray[..1], Keccak.Zero, Keccak.MaxValue, 1000000, CancellationToken.None); - slots.Length.Should().Be(1); + slots.Count.Should().Be(1); slots[0].Length.Should().Be(1000); proofs.Should().BeEmpty(); (slots, proofs) = server.GetStorageRanges(stateTree.RootHash, accountWithStorageArray[..2], Keccak.Zero, Keccak.MaxValue, 10, CancellationToken.None); - slots.Length.Should().Be(1); + slots.Count.Should().Be(1); slots[0].Length.Should().Be(1); proofs.Should().NotBeNull(); (slots, proofs) = server.GetStorageRanges(stateTree.RootHash, accountWithStorageArray[..2], Keccak.Zero, Keccak.MaxValue, 100000, CancellationToken.None); - slots.Length.Should().Be(2); + slots.Count.Should().Be(2); slots[0].Length.Should().Be(1000); slots[1].Length.Should().Be(539); proofs.Should().NotBeNull(); @@ -319,7 +322,7 @@ public void TestWithHugeTree() // incomplete tree will be returned as the hard limit is 2000000 (slots, proofs) = server.GetStorageRanges(stateTree.RootHash, accountWithStorageArray, Keccak.Zero, Keccak.MaxValue, 3000000, CancellationToken.None); - slots.Length.Should().Be(8); + slots.Count.Should().Be(8); slots[^1].Length.Should().BeLessThan(8000); proofs.Should().NotBeEmpty(); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncBatchTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncBatchTests.cs index f9b79435bb9..93ea6471c70 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncBatchTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncBatchTests.cs @@ -1,8 +1,12 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Linq; using FluentAssertions; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Core.Test.Builders; using Nethermind.State.Snap; using Nethermind.Synchronization.SnapSync; using NUnit.Framework; @@ -14,7 +18,7 @@ public class SnapSyncBatchTests [Test] public void TestAccountRangeToString() { - SnapSyncBatch batch = new() + using SnapSyncBatch batch = new() { AccountRangeRequest = new AccountRange(Keccak.Zero, Keccak.MaxValue, Keccak.Compute("abc"), 999) }; @@ -25,13 +29,13 @@ public void TestAccountRangeToString() [Test] public void TestStorageRangeToString() { - SnapSyncBatch batch = new() + using SnapSyncBatch batch = new() { StorageRangeRequest = new StorageRange() { BlockNumber = 123, RootHash = Keccak.Zero, - Accounts = new PathWithAccount[9], + Accounts = new PathWithAccount[9].ToPooledList(), StartingHash = Keccak.MaxValue, LimitHash = Keccak.Compute("abc"), } @@ -43,9 +47,9 @@ public void TestStorageRangeToString() [Test] public void TestCodeRequestsToString() { - SnapSyncBatch batch = new() + using SnapSyncBatch batch = new() { - CodesRequest = new ValueHash256[9], + CodesRequest = new ArrayPoolList(9, Enumerable.Repeat(TestItem.KeccakA.ValueHash256, 9)), }; batch.ToString().Should().Be("CodesRequest: (9)"); @@ -54,12 +58,12 @@ public void TestCodeRequestsToString() [Test] public void TestAccountToRefreshToString() { - SnapSyncBatch batch = new() + using SnapSyncBatch batch = new() { AccountsToRefreshRequest = new AccountsToRefreshRequest() { RootHash = Keccak.Zero, - Paths = new AccountWithStorageStartingHash[9], + Paths = new ArrayPoolList(9, Enumerable.Repeat(new AccountWithStorageStartingHash(), 9)) } }; diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncFeed/SnapSyncFeedTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncFeed/SnapSyncFeedTests.cs index e140c8160a9..8938ff148fb 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncFeed/SnapSyncFeedTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/SnapSyncFeed/SnapSyncFeedTests.cs @@ -25,11 +25,11 @@ public void WhenAccountRequestEmpty_ReturnNoProgress() snapProvider.AddAccountRange(Arg.Any(), Arg.Any()) .Returns(AddRangeResult.ExpiredRootHash); - SnapSyncBatch response = new SnapSyncBatch(); + using SnapSyncBatch response = new(); response.AccountRangeRequest = new AccountRange(Keccak.Zero, Keccak.Zero); response.AccountRangeResponse = new AccountsAndProofs(); - PeerInfo peer = new PeerInfo(Substitute.For()); + PeerInfo peer = new(Substitute.For()); feed.HandleResponse(response, peer).Should().Be(SyncResponseHandlingResult.NoProgress); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerMock.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerMock.cs index d2af56bf41b..d3b14e642e9 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerMock.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerMock.cs @@ -9,7 +9,9 @@ using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; using Nethermind.Int256; using Nethermind.Stats.Model; @@ -90,13 +92,13 @@ public Task GetBlockBodies(IReadOnlyList blockHashes, return Task.FromResult(new OwnedBlockBodies(result)); } - public Task GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) { - BlockHeader[] result = new BlockHeader[maxBlocks]; + ArrayPoolList result = new ArrayPoolList(maxBlocks, maxBlocks); long? firstNumber = _remoteTree.FindHeader(blockHash, BlockTreeLookupOptions.RequireCanonical)?.Number; if (!firstNumber.HasValue) { - return Task.FromResult(result); + return Task.FromResult?>(result); } for (int i = 0; i < maxBlocks; i++) @@ -104,16 +106,16 @@ public Task GetBlockHeaders(Hash256 blockHash, int maxBlocks, int result[i] = _remoteTree.FindHeader(firstNumber.Value + i + skip, BlockTreeLookupOptions.RequireCanonical)!; } - return Task.FromResult(result); + return Task.FromResult?>(result); } - public Task GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) { - BlockHeader[] result = new BlockHeader[maxBlocks]; + ArrayPoolList result = new ArrayPoolList(maxBlocks, maxBlocks); long? firstNumber = _remoteTree.FindHeader(number, BlockTreeLookupOptions.RequireCanonical)?.Number; if (!firstNumber.HasValue) { - return Task.FromResult(result); + return Task.FromResult>(result)!; } for (int i = 0; i < maxBlocks; i++) @@ -129,7 +131,7 @@ public Task GetBlockHeaders(long number, int maxBlocks, int skip, } } - return Task.FromResult(result); + return Task.FromResult>(result)!; } public Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) @@ -165,7 +167,7 @@ private void HintNewBlock(Hash256 blockHash, long number) public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { } - public Task GetReceipts(IReadOnlyList blockHash, CancellationToken token) + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) { TxReceipt[]?[] result = new TxReceipt[blockHash.Count][]; for (int i = 0; i < blockHash.Count; i++) @@ -173,10 +175,10 @@ public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { result[i] = _remoteSyncServer?.GetReceipts(blockHash[i])!; } - return Task.FromResult(result); + return Task.FromResult>(result.ToPooledList()); } - public Task GetNodeData(IReadOnlyList hashes, CancellationToken token) => Task.FromResult(_remoteSyncServer?.GetNodeData(hashes, token))!; + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) => Task.FromResult(_remoteSyncServer?.GetNodeData(hashes, token))!; public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class { diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs index 8d5e6a26052..943f2786062 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs @@ -10,6 +10,7 @@ using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Int256; @@ -79,14 +80,14 @@ public Task GetBlockBodies(IReadOnlyList blockHashes, return Task.FromResult(new OwnedBlockBodies(Array.Empty())); } - public Task GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) { - return Task.FromResult(Array.Empty()); + return Task.FromResult?>(ArrayPoolList.Empty()); } - public Task GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) { - return Task.FromResult(Array.Empty()); + return Task.FromResult?>(ArrayPoolList.Empty()); } public async Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) @@ -118,14 +119,14 @@ public void NotifyOfNewBlock(Block block, SendBlockMode mode) public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { } - public Task GetReceipts(IReadOnlyList blockHash, CancellationToken token) + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) { - return Task.FromResult(Array.Empty()); + return Task.FromResult>(ArrayPoolList.Empty()); } - public Task GetNodeData(IReadOnlyList hashes, CancellationToken token) + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) { - return Task.FromResult(Array.Empty()); + return Task.FromResult>(ArrayPoolList.Empty()); } private int? _headerResponseTime; diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index 3d2cfd28eef..0ec476cecef 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -15,6 +15,7 @@ using Nethermind.Consensus; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; @@ -139,16 +140,16 @@ public Task GetBlockBodies(IReadOnlyList blockHashes, return Task.FromResult(new OwnedBlockBodies(result)); } - public Task GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) { if (_causeTimeoutOnHeaders) { - return Task.FromException(new TimeoutException()); + return Task.FromException?>(new TimeoutException()); } int filled = 0; bool started = false; - BlockHeader[] result = new BlockHeader[maxBlocks]; + ArrayPoolList result = new ArrayPoolList(maxBlocks, maxBlocks); foreach (Block block in Blocks) { if (block.Number == number) @@ -167,10 +168,10 @@ public Task GetBlockHeaders(long number, int maxBlocks, int skip, } } - return Task.FromResult(result); + return Task.FromResult?>(result); } - public Task GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) + public Task?> GetBlockHeaders(Hash256 startHash, int maxBlocks, int skip, CancellationToken token) { throw new NotImplementedException(); } @@ -212,12 +213,12 @@ public void NotifyOfNewBlock(Block block, SendBlockMode mode) public void SendNewTransactions(IEnumerable txs, bool sendFullTx) { } - public Task GetReceipts(IReadOnlyList blockHash, CancellationToken token) + public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) { throw new NotImplementedException(); } - public Task GetNodeData(IReadOnlyList hashes, CancellationToken token) + public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) { throw new NotImplementedException(); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/Trie/HealingTreeTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/Trie/HealingTreeTests.cs index c26f2d98a67..f0338db56ad 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/Trie/HealingTreeTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/Trie/HealingTreeTests.cs @@ -55,7 +55,7 @@ HealingStateTree CreateHealingStateTree(ITrieStore trieStore, ITrieNodeRecovery< private static bool PathMatch(GetTrieNodesRequest r, byte[] path, int lastPathIndex) => r.RootHash == _key - && r.AccountAndStoragePaths.Length == 1 + && r.AccountAndStoragePaths.Count == 1 && r.AccountAndStoragePaths[0].Group.Length == lastPathIndex + 1 && Bytes.AreEqual(r.AccountAndStoragePaths[0].Group[lastPathIndex], Nibbles.EncodePath(path)); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/Trie/RecoveryTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/Trie/RecoveryTests.cs index eedecafed43..12674f078ba 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/Trie/RecoveryTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/Trie/RecoveryTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using FluentAssertions; using Nethermind.Blockchain.Synchronization; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Logging; using Nethermind.Network.Contract.P2P; @@ -42,12 +43,12 @@ public void SetUp() _syncPeerEth66 = Substitute.For(); _syncPeerEth66.ProtocolVersion.Returns(EthVersions.Eth66); _syncPeerEth66.GetNodeData(Arg.Is>(l => l.Contains(_key)), Arg.Any()) - .Returns(_ => Task.FromResult(new[] { _returnedRlp })); + .Returns(_ => Task.FromResult>(new ArrayPoolList(1) { _returnedRlp })); _peerEth66 = new(_syncPeerEth66); _snapSyncPeer = Substitute.For(); _snapSyncPeer.GetTrieNodes(Arg.Any(), Arg.Any()) - .Returns(c => Task.FromResult(new[] { _returnedRlp })); + .Returns(c => Task.FromResult>(new ArrayPoolList(1) { _returnedRlp })); _syncPeerEth67 = Substitute.For(); _syncPeerEth67.ProtocolVersion.Returns(EthVersions.Eth67); _syncPeerEth67.TryGetSatelliteProtocol(Protocol.Snap, out Arg.Any()) @@ -58,7 +59,7 @@ public void SetUp() }); _peerEth67 = new(_syncPeerEth67); - _snapRequest = new GetTrieNodesRequest { AccountAndStoragePaths = Array.Empty() }; + _snapRequest = new GetTrieNodesRequest { AccountAndStoragePaths = ArrayPoolList.Empty() }; _syncPeerPool = Substitute.For(); _snapRecovery = new SnapTrieNodeRecovery(_syncPeerPool, LimboLogs.Instance); _nodeDataRecovery = new GetNodeDataTrieNodeRecovery(_syncPeerPool, LimboLogs.Instance); @@ -85,7 +86,7 @@ public async Task cannot_recover_eth66_no_peers() public async Task cannot_recover_eth66_empty_response() { _syncPeerEth66.GetNodeData(Arg.Is>(l => l.Contains(_key)), Arg.Any()) - .Returns(Task.FromResult(Array.Empty())); + .Returns(Task.FromResult>(ArrayPoolList.Empty())); byte[]? rlp = await Recover(_nodeDataRecovery, new List { _key }, _peerEth66); rlp.Should().BeNull(); } @@ -116,7 +117,7 @@ public async Task cannot_recover_eth67_no_peers() public async Task cannot_recover_eth67_empty_response() { _snapSyncPeer.GetTrieNodes(Arg.Any(), Arg.Any()) - .Returns(Task.FromResult(Array.Empty())); + .Returns(Task.FromResult>(ArrayPoolList.Empty())); byte[]? rlp = await Recover(_snapRecovery, _snapRequest, _peerEth67); rlp.Should().BeNull(); } diff --git a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloadContext.cs b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloadContext.cs index 9087adff631..be0ee1c626d 100644 --- a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloadContext.cs +++ b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloadContext.cs @@ -22,7 +22,7 @@ public class BlockDownloadContext private readonly bool _downloadReceipts; private readonly IReceiptsRecovery _receiptsRecovery; - public BlockDownloadContext(ISpecProvider specProvider, PeerInfo syncPeer, BlockHeader?[] headers, + public BlockDownloadContext(ISpecProvider specProvider, PeerInfo syncPeer, IReadOnlyList headers, bool downloadReceipts, IReceiptsRecovery receiptsRecovery) { _indexMapping = new Dictionary(); @@ -31,7 +31,7 @@ public BlockDownloadContext(ISpecProvider specProvider, PeerInfo syncPeer, Block _specProvider = specProvider; _syncPeer = syncPeer; - Blocks = new Block[headers.Length - 1]; + Blocks = new Block[headers.Count - 1]; NonEmptyBlockHashes = new List(); if (_downloadReceipts) @@ -40,7 +40,7 @@ public BlockDownloadContext(ISpecProvider specProvider, PeerInfo syncPeer, Block } int currentBodyIndex = 0; - for (int i = 1; i < headers.Length; i++) + for (int i = 1; i < headers.Count; i++) { BlockHeader? header = headers[i]; if (header?.Hash is null) diff --git a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs index bd1c64359a1..8285ad5edb7 100644 --- a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs +++ b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs @@ -12,6 +12,7 @@ using Nethermind.Consensus; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Core.Extensions; @@ -167,7 +168,7 @@ bool HasMoreToSync() if (_logger.IsDebug) _logger.Debug($"Headers request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more."); Stopwatch sw = Stopwatch.StartNew(); - BlockHeader?[] headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); + IOwnedReadOnlyList headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); Hash256? startHeaderHash = headers[0]?.Hash; BlockHeader? startHeader = (startHeaderHash is null) @@ -189,7 +190,7 @@ bool HasMoreToSync() ancestorLookupLevel = 0; AdjustSyncBatchSize(sw.Elapsed); - for (int i = 1; i < headers.Length; i++) + for (int i = 1; i < headers.Count; i++) { if (cancellation.IsCancellationRequested) { @@ -280,8 +281,8 @@ bool HasMoreToSync() if (_logger.IsTrace) _logger.Trace($"Full sync request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more."); if (cancellation.IsCancellationRequested) return blocksSynced; // check before every heavy operation - BlockHeader[] headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); - if (headers.Length < 2) + IOwnedReadOnlyList headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); + if (headers.Count < 2) { // Peer dont have new header break; @@ -423,15 +424,15 @@ private ValueTask DownloadFailHandler(Task downloadTask, string entities) return default; } - protected virtual async Task RequestHeaders(PeerInfo peer, CancellationToken cancellation, long currentNumber, int headersToRequest) + protected virtual async Task> RequestHeaders(PeerInfo peer, CancellationToken cancellation, long currentNumber, int headersToRequest) { _sealValidator.HintValidationRange(_sealValidatorUserGuid, currentNumber - 1028, currentNumber + 30000); - Task headersRequest = peer.SyncPeer.GetBlockHeaders(currentNumber, headersToRequest, 0, cancellation); + Task> headersRequest = peer.SyncPeer.GetBlockHeaders(currentNumber, headersToRequest, 0, cancellation); await headersRequest.ContinueWith(t => DownloadFailHandler(t, "headers"), cancellation); cancellation.ThrowIfCancellationRequested(); - BlockHeader[] headers = headersRequest.Result; + IOwnedReadOnlyList headers = headersRequest.Result; ValidateSeals(headers, cancellation); ValidateBatchConsistencyAndSetParents(peer, headers); return headers; @@ -477,12 +478,12 @@ protected async Task RequestReceipts(PeerInfo peer, CancellationToken cancellati while (offset != context.NonEmptyBlockHashes.Count) { IReadOnlyList hashesToRequest = context.GetHashesByOffset(offset, peer.MaxReceiptsPerRequest()); - Task request = peer.SyncPeer.GetReceipts(hashesToRequest, cancellation); + Task> request = peer.SyncPeer.GetReceipts(hashesToRequest, cancellation); await request.ContinueWith(_ => DownloadFailHandler(request, "receipts"), cancellation); - TxReceipt[][] result = request.Result; + IOwnedReadOnlyList result = request.Result; - for (int i = 0; i < result.Length; i++) + for (int i = 0; i < result.Count; i++) { TxReceipt[] txReceipts = result[i]; Block block = context.GetBlockByRequestIdx(i + offset); @@ -497,20 +498,20 @@ protected async Task RequestReceipts(PeerInfo peer, CancellationToken cancellati } } - if (result.Length == 0) + if (result.Count == 0) { throw new EthSyncException("Empty receipts response received"); } - offset += result.Length; + offset += result.Count; } } - private void ValidateBatchConsistencyAndSetParents(PeerInfo bestPeer, BlockHeader?[] headers) + private void ValidateBatchConsistencyAndSetParents(PeerInfo bestPeer, IReadOnlyList headers) { // in the past (version 1.11) and possibly now too Parity was sending non canonical blocks in responses // so we need to confirm that the blocks form a valid subchain - for (int i = 1; i < headers.Length; i++) + for (int i = 1; i < headers.Count; i++) { if (headers[i] is not null && headers[i]?.ParentHash != headers[i - 1]?.Hash) { @@ -530,12 +531,12 @@ private void ValidateBatchConsistencyAndSetParents(PeerInfo bestPeer, BlockHeade } } - protected void ValidateSeals(BlockHeader?[] headers, CancellationToken cancellation) + protected void ValidateSeals(IReadOnlyList headers, CancellationToken cancellation) { if (_logger.IsTrace) _logger.Trace("Starting seal validation"); ConcurrentQueue exceptions = new(); - int randomNumberForValidation = _rnd.Next(Math.Max(0, headers.Length - 2)); - Parallel.For(0, headers.Length, (i, state) => + int randomNumberForValidation = _rnd.Next(Math.Max(0, headers.Count - 2)); + Parallel.For(0, headers.Count, (i, state) => { if (cancellation.IsCancellationRequested) { @@ -552,11 +553,11 @@ protected void ValidateSeals(BlockHeader?[] headers, CancellationToken cancellat try { - bool lastBlock = i == headers.Length - 1; + bool lastBlock = i == headers.Count - 1; // PoSSwitcher can't determine if a block is a terminal block if TD is missing due to another // problem. In theory, this should not be a problem, but additional seal check does no harm. bool terminalBlock = !lastBlock - && headers.Length > 1 + && headers.Count > 1 && headers[i + 1].Difficulty == 0 && headers[i].Difficulty != 0; bool forceValidation = lastBlock || i == randomNumberForValidation || terminalBlock; diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncBatch.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncBatch.cs index 214129f8cd6..9b0dd4a22c8 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncBatch.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncBatch.cs @@ -5,14 +5,15 @@ namespace Nethermind.Synchronization.FastBlocks { - public class BodiesSyncBatch : FastBlocksBatch + public class BodiesSyncBatch(BlockInfo[] infos) : FastBlocksBatch { - public BodiesSyncBatch(BlockInfo[] infos) + public BlockInfo?[] Infos { get; } = infos; + public OwnedBlockBodies? Response { get; set; } + + public override void Dispose() { - Infos = infos; + base.Dispose(); + Response?.Dispose(); } - - public BlockInfo?[] Infos { get; } - public OwnedBlockBodies? Response { get; set; } } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs index d2809c473e0..e9f992988c7 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs @@ -186,7 +186,7 @@ public override SyncResponseHandlingResult HandleResponse(BodiesSyncBatch? batch } finally { - batch.Response?.Dispose(); + batch?.Dispose(); batch?.MarkHandlingEnd(); } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastBlocksBatch.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastBlocksBatch.cs index 2df793393d3..82cd89e683a 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastBlocksBatch.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastBlocksBatch.cs @@ -1,12 +1,13 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Diagnostics; using Nethermind.Synchronization.Peers; namespace Nethermind.Synchronization.FastBlocks { - public abstract class FastBlocksBatch + public abstract class FastBlocksBatch : IDisposable { private readonly Stopwatch _stopwatch = new(); private long? _scheduledLastTime; @@ -81,5 +82,6 @@ public double? WaitingTime public double? HandlingTime => (_handlingEndTime ?? _stopwatch.ElapsedMilliseconds) - (_handlingStartTime ?? _stopwatch.ElapsedMilliseconds); public long? MinNumber { get; set; } + public virtual void Dispose() { } } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastHeadersSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastHeadersSyncFeed.cs index e6a0ffefbc0..fc5bce0dfdc 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastHeadersSyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/FastHeadersSyncFeed.cs @@ -13,6 +13,7 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Int256; using Nethermind.Logging; using Nethermind.Stats.Model; @@ -108,7 +109,7 @@ private long CalculateHeadersInQueue() long count = 0; while (enumerator.MoveNext()) { - count += enumerator.Current.Value.Response?.Length ?? 0; + count += enumerator.Current.Value.Response?.Count ?? 0; } // Stop gap method to reduce allocations from non-struct enumerator @@ -400,7 +401,7 @@ public override SyncResponseHandlingResult HandleResponse(HeadersSyncBatch? batc return SyncResponseHandlingResult.Ignored; } - if ((batch.Response?.Length ?? 0) == 0) + if ((batch.Response?.Count ?? 0) == 0) { batch.MarkHandlingStart(); if (_logger.IsTrace) _logger.Trace($"{batch} - came back EMPTY"); @@ -431,6 +432,7 @@ public override SyncResponseHandlingResult HandleResponse(HeadersSyncBatch? batc finally { _resetLock.ExitReadLock(); + batch.Dispose(); } } @@ -456,11 +458,12 @@ private static HeadersSyncBatch BuildDependentBatch(HeadersSyncBatch batch, long { HeadersSyncBatch dependentBatch = new(); dependentBatch.StartNumber = batch.StartNumber; - dependentBatch.RequestSize = (int)(addedLast - addedEarliest + 1); + int count = (int)(addedLast - addedEarliest + 1); + dependentBatch.RequestSize = count; dependentBatch.MinNumber = batch.MinNumber; dependentBatch.Response = batch.Response! .Skip((int)(addedEarliest - batch.StartNumber)) - .Take((int)(addedLast - addedEarliest + 1)).ToArray(); + .Take(count).ToPooledList(count); dependentBatch.ResponseSourcePeer = batch.ResponseSourcePeer; return dependentBatch; } @@ -472,16 +475,16 @@ protected virtual int InsertHeaders(HeadersSyncBatch batch) return 0; } - if (batch.Response.Length > batch.RequestSize) + if (batch.Response.Count > batch.RequestSize) { if (_logger.IsDebug) - _logger.Debug($"Peer sent too long response ({batch.Response.Length}) to {batch}"); + _logger.Debug($"Peer sent too long response ({batch.Response.Count}) to {batch}"); if (batch.ResponseSourcePeer is not null) { _syncPeerPool.ReportBreachOfProtocol( batch.ResponseSourcePeer, DisconnectReason.HeaderResponseTooLong, - $"response too long ({batch.Response.Length})"); + $"response too long ({batch.Response.Count})"); } _pending.Enqueue(batch); @@ -491,7 +494,7 @@ protected virtual int InsertHeaders(HeadersSyncBatch batch) long addedLast = batch.StartNumber - 1; long addedEarliest = batch.EndNumber + 1; int skippedAtTheEnd = 0; - for (int i = batch.Response.Length - 1; i >= 0; i--) + for (int i = batch.Response.Count - 1; i >= 0; i--) { BlockHeader? header = batch.Response[i]; if (header is null) @@ -513,7 +516,7 @@ protected virtual int InsertHeaders(HeadersSyncBatch batch) break; } - bool isFirst = i == batch.Response.Length - 1 - skippedAtTheEnd; + bool isFirst = i == batch.Response.Count - 1 - skippedAtTheEnd; if (isFirst) { BlockHeader lowestInserted = LowestInsertedBlockHeader; @@ -573,7 +576,7 @@ protected virtual int InsertHeaders(HeadersSyncBatch batch) throw new InvalidOperationException($"Only one header dependency expected ({batch})"); } - for (int j = 0; j < batch.Response.Length; j++) + for (int j = 0; j < batch.Response.Count; j++) { BlockHeader? current = batch.Response[j]; if (current is not null) diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/HeadersSyncBatch.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/HeadersSyncBatch.cs index 78cec75b186..9a5a8345023 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/HeadersSyncBatch.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/HeadersSyncBatch.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Collections; namespace Nethermind.Synchronization.FastBlocks { @@ -10,12 +11,18 @@ public class HeadersSyncBatch : FastBlocksBatch public long StartNumber { get; set; } public long EndNumber => StartNumber + RequestSize - 1; public int RequestSize { get; set; } - public BlockHeader?[]? Response { get; set; } + public IOwnedReadOnlyList? Response { get; set; } public override string ToString() { string details = $"[{StartNumber}, {EndNumber}]({RequestSize})"; return $"HEADERS {details} [{(Prioritized ? "HIGH" : "LOW")}] [times: S:{SchedulingTime:F0}ms|R:{RequestTime:F0}ms|V:{ValidationTime:F0}ms|W:{WaitingTime:F0}ms|H:{HandlingTime:F0}ms|A:{AgeInMs:F0}ms, retries {Retries}] min#: {MinNumber} {ResponseSourcePeer}"; } + + public override void Dispose() + { + base.Dispose(); + Response?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncBatch.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncBatch.cs index c77f218aea8..2a3f4705010 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncBatch.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncBatch.cs @@ -2,17 +2,19 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Core.Collections; namespace Nethermind.Synchronization.FastBlocks { - public class ReceiptsSyncBatch : FastBlocksBatch + public class ReceiptsSyncBatch(BlockInfo?[] infos) : FastBlocksBatch { - public BlockInfo?[] Infos { get; } - public TxReceipt[]?[]? Response { get; set; } + public BlockInfo?[] Infos { get; } = infos; + public IOwnedReadOnlyList? Response { get; set; } - public ReceiptsSyncBatch(BlockInfo?[] infos) + public override void Dispose() { - Infos = infos; + base.Dispose(); + Response?.Dispose(); } } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs index 847c4b69184..aab2343b1a9 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs @@ -172,6 +172,7 @@ public override SyncResponseHandlingResult HandleResponse(ReceiptsSyncBatch? bat } finally { + batch?.Dispose(); batch?.MarkHandlingEnd(); } } @@ -213,7 +214,7 @@ private int InsertReceipts(ReceiptsSyncBatch batch) for (int i = 0; i < blockInfos.Length; i++) { BlockInfo? blockInfo = blockInfos[i]; - TxReceipt[]? receipts = (batch.Response?.Length ?? 0) <= i + TxReceipt[]? receipts = (batch.Response?.Count ?? 0) <= i ? null : (batch.Response![i] ?? Array.Empty()); diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncBatch.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncBatch.cs index 0767f93e415..d55b521f0fa 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncBatch.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncBatch.cs @@ -1,35 +1,35 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Collections.Generic; using System.Diagnostics; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; namespace Nethermind.Synchronization.FastSync { [DebuggerDisplay("Requested Nodes: {RequestedNodes?.Count ?? 0}, Responses: {Responses?.Length ?? 0}, Assigned: {AssignedPeer?.Current}")] - public class StateSyncBatch + public class StateSyncBatch(Hash256 stateRoot, NodeDataType nodeDataType, IList requestedNodes) : IDisposable { - public StateSyncBatch(Hash256 stateRoot, NodeDataType nodeDataType, IList requestedNodes) - { - StateRoot = stateRoot; - NodeDataType = nodeDataType; - RequestedNodes = requestedNodes; - } - - public NodeDataType NodeDataType { get; } + public NodeDataType NodeDataType { get; } = nodeDataType; - public Hash256 StateRoot; + public Hash256 StateRoot = stateRoot; - public IList? RequestedNodes { get; } + public IList? RequestedNodes { get; } = requestedNodes; - public byte[][]? Responses { get; set; } + public IOwnedReadOnlyList? Responses { get; set; } public int ConsumerId { get; set; } public override string ToString() { - return $"{RequestedNodes?.Count ?? 0} state sync requests with {Responses?.Length ?? 0} responses"; + return $"{RequestedNodes?.Count ?? 0} state sync requests with {Responses?.Count ?? 0} responses"; + } + + public void Dispose() + { + Responses?.Dispose(); } } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncFeed.cs index 3531875f6e5..875eb380899 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncFeed.cs @@ -49,7 +49,7 @@ public StateSyncFeed( return EmptyBatch!; } - return await _treeSync.PrepareRequest(_currentSyncMode); + return await _treeSync.PrepareRequest(); } catch (Exception e) { @@ -60,7 +60,8 @@ public StateSyncFeed( public override SyncResponseHandlingResult HandleResponse(StateSyncBatch? batch, PeerInfo? peer = null) { - return _treeSync.HandleResponse(batch, peer); + using StateSyncBatch? b = batch; + return _treeSync.HandleResponse(b, peer); } public void Dispose() diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs index 62b126085de..5da5557778c 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using NonBlocking; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -21,6 +20,7 @@ using Nethermind.Synchronization.Peers; using Nethermind.Trie; using Nethermind.Trie.Pruning; +using NonBlocking; namespace Nethermind.Synchronization.FastSync { @@ -90,7 +90,7 @@ public TreeSync(SyncMode syncMode, IDb codeDb, IDb stateDb, IBlockTree blockTree _branchProgress = new BranchProgress(0, _logger); } - public async Task PrepareRequest(SyncMode syncMode) + public async Task PrepareRequest() { try { @@ -151,7 +151,7 @@ public SyncResponseHandlingResult HandleResponse(StateSyncBatch? batch, PeerInfo } int requestLength = batch.RequestedNodes?.Count ?? 0; - int responseLength = batch.Responses?.Length ?? 0; + int responseLength = batch.Responses?.Count ?? 0; void AddAgainAllItems() { @@ -207,7 +207,7 @@ void AddAgainAllItems() /* if the peer has limit on number of requests in a batch then the response will possibly be shorter than the request */ - if (batch.Responses.Length < i + 1) + if (batch.Responses.Count < i + 1) { AddNodeToPending(currentStateSyncItem, null, "missing", true); continue; @@ -335,6 +335,7 @@ shorter than the request */ finally { _syncStateLock.ExitReadLock(); + batch.Dispose(); } } catch (Exception e) @@ -459,10 +460,12 @@ public void ResetStateRoot(long blockNumber, Hash256 stateRoot, SyncFeedState cu foreach ((StateSyncBatch pendingRequest, _) in _pendingRequests) { // re-add the pending request - for (int i = 0; i < pendingRequest.RequestedNodes.Count; i++) + for (int i = 0; i < pendingRequest.RequestedNodes?.Count; i++) { AddNodeToPending(pendingRequest.RequestedNodes[i], null, "pending request", true); } + + pendingRequest.Dispose(); } } diff --git a/src/Nethermind/Nethermind.Synchronization/ISyncServer.cs b/src/Nethermind/Nethermind.Synchronization/ISyncServer.cs index 511c52f67e8..a7228c0e224 100644 --- a/src/Nethermind/Nethermind.Synchronization/ISyncServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/ISyncServer.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Synchronization.FastSync; using Nethermind.Synchronization.LesSync; @@ -24,8 +25,8 @@ public interface ISyncServer : IDisposable public Task BuildCHT(); public CanonicalHashTrie? GetCHT(); Hash256? FindHash(long number); - BlockHeader[] FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse); - byte[]?[] GetNodeData(IReadOnlyList keys, CancellationToken cancellationToken, NodeDataType includedTypes = NodeDataType.Code | NodeDataType.State); + IOwnedReadOnlyList FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse); + IOwnedReadOnlyList GetNodeData(IReadOnlyList keys, CancellationToken cancellationToken, NodeDataType includedTypes = NodeDataType.Code | NodeDataType.State); int GetPeerCount(); ulong NetworkId { get; } BlockHeader Genesis { get; } diff --git a/src/Nethermind/Nethermind.Synchronization/Nethermind.Synchronization.csproj b/src/Nethermind/Nethermind.Synchronization/Nethermind.Synchronization.csproj index ee7087d2c59..de511fc6dbc 100644 --- a/src/Nethermind/Nethermind.Synchronization/Nethermind.Synchronization.csproj +++ b/src/Nethermind/Nethermind.Synchronization/Nethermind.Synchronization.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs index 40cca61b6ce..50c38f3384b 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs @@ -102,8 +102,7 @@ public async Task Start(CancellationToken cancellationToken) if (Logger.IsTrace) Logger.Trace($"SyncDispatcher request: {request}, AllocatedPeer {allocation.Current}"); // Use Task.Run to make sure it queues it instead of running part of it synchronously. - Task task = Task.Run(() => DoDispatch(cancellationToken, allocatedPeer, request, - allocation), cancellationToken); + Task task = Task.Run(() => DoDispatch(cancellationToken, allocatedPeer, request, allocation), cancellationToken); if (!Feed.IsMultiFeed) { diff --git a/src/Nethermind/Nethermind.Synchronization/Peers/ISyncPeerPool.cs b/src/Nethermind/Nethermind.Synchronization/Peers/ISyncPeerPool.cs index d666be7f841..503a3646d7f 100644 --- a/src/Nethermind/Nethermind.Synchronization/Peers/ISyncPeerPool.cs +++ b/src/Nethermind/Nethermind.Synchronization/Peers/ISyncPeerPool.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Stats.Model; using Nethermind.Synchronization.Peers.AllocationStrategies; @@ -131,25 +132,24 @@ public static async Task AllocateAndRun( public static async Task FetchHeaderFromPeer(this ISyncPeerPool syncPeerPool, Hash256 hash, CancellationToken cancellationToken = default) { - BlockHeader[]? headers = null; try { using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); cts.CancelAfter(Timeouts.DefaultFetchHeaderTimeout); - headers = await syncPeerPool.AllocateAndRun( + using IOwnedReadOnlyList? headers = await syncPeerPool.AllocateAndRun( peer => peer.GetBlockHeaders(hash, 1, 0, cancellationToken), BySpeedStrategy.FastestHeader, AllocationContexts.Headers, cts.Token); + + return headers?.Count == 1 ? headers[0] : null; } catch (Exception ex) when (ex is OperationCanceledException or TimeoutException) { // Timeout or no peer. return null; } - - return headers?.Length == 1 ? headers[0] : null; } } } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapProvider.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapProvider.cs index c441fd3bc76..c55ff822c79 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapProvider.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapProvider.cs @@ -1,6 +1,8 @@ // 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.State.Snap; @@ -8,7 +10,7 @@ namespace Nethermind.Synchronization.SnapSync { public interface ISnapProvider { - (SnapSyncBatch request, bool finished) GetNextRequest(); + bool IsFinished(out SnapSyncBatch? nextBatch); bool CanSync(); @@ -16,9 +18,9 @@ public interface ISnapProvider AddRangeResult AddStorageRange(StorageRange request, SlotsAndProofs response); - void AddCodes(ValueHash256[] requestedHashes, byte[][] codes); + void AddCodes(IReadOnlyList requestedHashes, IOwnedReadOnlyList codes); - void RefreshAccounts(AccountsToRefreshRequest request, byte[][] response); + void RefreshAccounts(AccountsToRefreshRequest request, IOwnedReadOnlyList response); void RetryRequest(SnapSyncBatch batch); diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs index 23f48c32f08..bf3230c3502 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.Threading; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.State.Snap; @@ -24,19 +25,19 @@ namespace Nethermind.Synchronization.SnapSync; public interface ISnapServer { - byte[][]? GetTrieNodes(PathGroup[] pathSet, in ValueHash256 rootHash, CancellationToken cancellationToken); - byte[][] GetByteCodes(IReadOnlyList requestedHashes, long byteLimit, CancellationToken cancellationToken); + IOwnedReadOnlyList? GetTrieNodes(IReadOnlyList pathSet, in ValueHash256 rootHash, CancellationToken cancellationToken); + IOwnedReadOnlyList GetByteCodes(IReadOnlyList requestedHashes, long byteLimit, CancellationToken cancellationToken); - (PathWithAccount[], byte[][]) GetAccountRanges( + (IOwnedReadOnlyList, IOwnedReadOnlyList) GetAccountRanges( in ValueHash256 rootHash, in ValueHash256 startingHash, in ValueHash256? limitHash, long byteLimit, CancellationToken cancellationToken); - (PathWithStorageSlot[][], byte[][]?) GetStorageRanges( + (IOwnedReadOnlyList, IOwnedReadOnlyList?) GetStorageRanges( in ValueHash256 rootHash, - PathWithAccount[] accounts, + IReadOnlyList accounts, in ValueHash256? startingHash, in ValueHash256? limitHash, long byteLimit, diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index 838ec7f1a7e..017b78a4d02 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -4,11 +4,13 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading; using Nethermind.Blockchain; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Db; using Nethermind.Logging; @@ -132,90 +134,82 @@ public void UpdatePivot() _pivot.UpdateHeaderForcefully(); } - public (SnapSyncBatch request, bool finished) GetNextRequest() + public bool IsFinished(out SnapSyncBatch? nextBatch) { Interlocked.Increment(ref _reqCount); - var pivotHeader = _pivot.GetPivotHeader(); - var rootHash = pivotHeader.StateRoot; + BlockHeader? pivotHeader = _pivot.GetPivotHeader(); + Hash256 rootHash = pivotHeader.StateRoot!; var blockNumber = pivotHeader.Number; - SnapSyncBatch request = new(); - if (!AccountsToRefresh.IsEmpty) { - return DequeAccountToRefresh(request, rootHash); + nextBatch = DequeAccountToRefresh(rootHash); } - - if (ShouldRequestAccountRequests() && AccountRangeReadyForRequest.TryDequeue(out AccountRangePartition partition)) + else if (ShouldRequestAccountRequests() && AccountRangeReadyForRequest.TryDequeue(out AccountRangePartition partition)) { - return CreateAccountRangeRequest(rootHash, partition, blockNumber, request); + nextBatch = CreateAccountRangeRequest(rootHash, partition, blockNumber); } - - if (TryDequeNextSlotRange(out StorageRange slotRange)) + else if (TryDequeNextSlotRange(out StorageRange slotRange)) { - return CreateNextSlowRangeRequest(slotRange, rootHash, blockNumber, request); + nextBatch = CreateNextSlowRangeRequest(slotRange, rootHash, blockNumber); } - - if (StoragesToRetrieve.Count >= HIGH_STORAGE_QUEUE_SIZE) + else if (StoragesToRetrieve.Count >= HIGH_STORAGE_QUEUE_SIZE) { - return DequeStorageToRetrieveRequest(rootHash, blockNumber, request); + nextBatch = DequeStorageToRetrieveRequest(rootHash, blockNumber); } - - if (CodesToRetrieve.Count >= HIGH_CODES_QUEUE_SIZE) + else if (CodesToRetrieve.Count >= HIGH_CODES_QUEUE_SIZE) { - return DequeCodeRequest(request); + nextBatch = DequeCodeRequest(); } - - if (!StoragesToRetrieve.IsEmpty) + else if (!StoragesToRetrieve.IsEmpty) { - return DequeStorageToRetrieveRequest(rootHash, blockNumber, request); + nextBatch = DequeStorageToRetrieveRequest(rootHash, blockNumber); } - - if (!CodesToRetrieve.IsEmpty) + else if (!CodesToRetrieve.IsEmpty) { - return DequeCodeRequest(request); + nextBatch = DequeCodeRequest(); } - - bool rangePhaseFinished = IsSnapGetRangesFinished(); - if (rangePhaseFinished) + else { - _logger.Info($"Snap - State Ranges (Phase 1) finished."); - FinishRangePhase(); - } + nextBatch = null; + bool rangePhaseFinished = IsSnapGetRangesFinished(); + if (rangePhaseFinished) + { + _logger.Info("Snap - State Ranges (Phase 1) finished."); + FinishRangePhase(); + } - LogRequest(NO_REQUEST); + LogRequest(NO_REQUEST); - return (null, IsSnapGetRangesFinished()); + return IsSnapGetRangesFinished(); + } + + return false; } - private (SnapSyncBatch request, bool finished) DequeCodeRequest(SnapSyncBatch request) + private SnapSyncBatch DequeCodeRequest() { Interlocked.Increment(ref _activeCodeRequests); - // TODO: optimize this - List codesToQuery = new(CODES_BATCH_SIZE); + ArrayPoolList codesToQuery = new(CODES_BATCH_SIZE); for (int i = 0; i < CODES_BATCH_SIZE && CodesToRetrieve.TryDequeue(out ValueHash256 codeHash); i++) { codesToQuery.Add(codeHash); } - codesToQuery.Sort(); + codesToQuery.AsSpan().Sort(); LogRequest($"CodesToRetrieve:{codesToQuery.Count}"); - request.CodesRequest = codesToQuery.ToArray(); - - return (request, false); + return new SnapSyncBatch { CodesRequest = codesToQuery }; } - private (SnapSyncBatch request, bool finished) DequeStorageToRetrieveRequest(Hash256 rootHash, long blockNumber, - SnapSyncBatch request) + private SnapSyncBatch DequeStorageToRetrieveRequest(Hash256 rootHash, long blockNumber) { Interlocked.Increment(ref _activeStorageRequests); - // TODO: optimize this - List storagesToQuery = new(STORAGE_BATCH_SIZE); + ArrayPoolList storagesToQuery = new(STORAGE_BATCH_SIZE); for (int i = 0; i < STORAGE_BATCH_SIZE && StoragesToRetrieve.TryDequeue(out PathWithAccount storage); i++) { storagesToQuery.Add(storage); @@ -224,33 +218,27 @@ public void UpdatePivot() StorageRange storageRange = new() { RootHash = rootHash, - Accounts = storagesToQuery.ToArray(), + Accounts = storagesToQuery, StartingHash = ValueKeccak.Zero, BlockNumber = blockNumber }; LogRequest($"StoragesToRetrieve:{storagesToQuery.Count}"); - request.StorageRangeRequest = storageRange; - - return (request, false); + return new SnapSyncBatch { StorageRangeRequest = storageRange }; } - private (SnapSyncBatch request, bool finished) CreateNextSlowRangeRequest(StorageRange slotRange, Hash256 rootHash, - long blockNumber, SnapSyncBatch request) + private SnapSyncBatch CreateNextSlowRangeRequest(StorageRange slotRange, Hash256 rootHash, long blockNumber) { slotRange.RootHash = rootHash; slotRange.BlockNumber = blockNumber; - LogRequest($"NextSlotRange:{slotRange.Accounts.Length}"); - - request.StorageRangeRequest = slotRange; + LogRequest($"NextSlotRange:{slotRange.Accounts.Count}"); - return (request, false); + return new SnapSyncBatch { StorageRangeRequest = slotRange }; } - private (SnapSyncBatch request, bool finished) CreateAccountRangeRequest(Hash256 rootHash, - AccountRangePartition partition, long blockNumber, SnapSyncBatch request) + private SnapSyncBatch CreateAccountRangeRequest(Hash256 rootHash, AccountRangePartition partition, long blockNumber) { Interlocked.Increment(ref _activeAccountRequests); @@ -261,29 +249,24 @@ public void UpdatePivot() blockNumber); LogRequest("AccountRange"); - - request.AccountRangeRequest = range; - - return (request, false); + return new SnapSyncBatch { AccountRangeRequest = range }; } - private (SnapSyncBatch request, bool finished) DequeAccountToRefresh(SnapSyncBatch request, Hash256 rootHash) + private SnapSyncBatch DequeAccountToRefresh(Hash256 rootHash) { Interlocked.Increment(ref _activeAccRefreshRequests); LogRequest($"AccountsToRefresh: {AccountsToRefresh.Count}"); int queueLength = AccountsToRefresh.Count; - AccountWithStorageStartingHash[] paths = new AccountWithStorageStartingHash[queueLength]; + ArrayPoolList paths = new(queueLength); - for (int i = 0; i < queueLength && AccountsToRefresh.TryDequeue(out var acc); i++) + for (int i = 0; i < queueLength && AccountsToRefresh.TryDequeue(out AccountWithStorageStartingHash acc); i++) { - paths[i] = acc; + paths.Add(acc); } - request.AccountsToRefreshRequest = new AccountsToRefreshRequest() { RootHash = rootHash, Paths = paths }; - - return (request, false); + return new SnapSyncBatch { AccountsToRefreshRequest = new AccountsToRefreshRequest { RootHash = rootHash, Paths = paths } }; } private bool ShouldRequestAccountRequests() @@ -332,11 +315,14 @@ public void EnqueueAccountRefresh(PathWithAccount pathWithAccount, in ValueHash2 AccountsToRefresh.Enqueue(new AccountWithStorageStartingHash() { PathAndAccount = pathWithAccount, StorageStartingHash = startingHash.GetValueOrDefault() }); } - public void ReportFullStorageRequestFinished(ReadOnlySpan storages = default) + public void ReportFullStorageRequestFinished(IEnumerable storages = default) { - for (int index = 0; index < storages.Length; index++) + if (storages is not null) { - EnqueueAccountStorage(storages[index]); + foreach (PathWithAccount pathWithAccount in storages) + { + EnqueueAccountStorage(pathWithAccount); + } } Interlocked.Decrement(ref _activeStorageRequests); diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs index d2f51406c0e..8234bb65d32 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using Microsoft.Extensions.ObjectPool; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Db; @@ -40,13 +41,13 @@ public SnapProvider(ProgressTracker progressTracker, IDbProvider dbProvider, ILo public bool CanSync() => _progressTracker.CanSync(); - public (SnapSyncBatch request, bool finished) GetNextRequest() => _progressTracker.GetNextRequest(); + public bool IsFinished(out SnapSyncBatch? nextBatch) => _progressTracker.IsFinished(out nextBatch); public AddRangeResult AddAccountRange(AccountRange request, AccountsAndProofs response) { AddRangeResult result; - if (response.PathAndAccounts.Length == 0 && response.Proofs.Length == 0) + if (response.PathAndAccounts.Count == 0 && response.Proofs.Count == 0) { _logger.Trace($"SNAP - GetAccountRange - requested expired RootHash:{request.RootHash}"); @@ -58,16 +59,17 @@ public AddRangeResult AddAccountRange(AccountRange request, AccountsAndProofs re if (result == AddRangeResult.OK) { - Interlocked.Add(ref Metrics.SnapSyncedAccounts, response.PathAndAccounts.Length); + Interlocked.Add(ref Metrics.SnapSyncedAccounts, response.PathAndAccounts.Count); } } _progressTracker.ReportAccountRangePartitionFinished(request.LimitHash.Value); + response.Dispose(); return result; } - public AddRangeResult AddAccountRange(long blockNumber, in ValueHash256 expectedRootHash, in ValueHash256 startingHash, PathWithAccount[] accounts, byte[][] proofs = null, in ValueHash256? hashLimit = null!) + public AddRangeResult AddAccountRange(long blockNumber, in ValueHash256 expectedRootHash, in ValueHash256 startingHash, IReadOnlyList accounts, IReadOnlyList proofs = null, in ValueHash256? hashLimit = null!) { ITrieStore store = _trieStorePool.Get(); try @@ -110,12 +112,12 @@ public AddRangeResult AddStorageRange(StorageRange request, SlotsAndProofs respo { AddRangeResult result = AddRangeResult.OK; - PathWithStorageSlot[][] responses = response.PathsAndSlots; - if (responses.Length == 0 && response.Proofs.Length == 0) + IReadOnlyList responses = response.PathsAndSlots; + if (responses.Count == 0 && response.Proofs.Count == 0) { - _logger.Trace($"SNAP - GetStorageRange - expired BlockNumber:{request.BlockNumber}, RootHash:{request.RootHash}, (Accounts:{request.Accounts.Length}), {request.StartingHash}"); + _logger.Trace($"SNAP - GetStorageRange - expired BlockNumber:{request.BlockNumber}, RootHash:{request.RootHash}, (Accounts:{request.Accounts.Count}), {request.StartingHash}"); - _progressTracker.ReportStorageRangeRequestFinished(request); + _progressTracker.ReportStorageRangeRequestFinished(request.Copy()); return AddRangeResult.ExpiredRootHash; } @@ -123,13 +125,13 @@ public AddRangeResult AddStorageRange(StorageRange request, SlotsAndProofs respo { int slotCount = 0; - int requestLength = request.Accounts.Length; + int requestLength = request.Accounts.Count; - for (int i = 0; i < responses.Length; i++) + for (int i = 0; i < responses.Count; i++) { // only the last can have proofs - byte[][] proofs = null; - if (i == responses.Length - 1) + IReadOnlyList proofs = null; + if (i == responses.Count - 1) { proofs = response.Proofs; } @@ -140,9 +142,9 @@ public AddRangeResult AddStorageRange(StorageRange request, SlotsAndProofs respo slotCount += responses[i].Length; } - if (requestLength > responses.Length) + if (requestLength > responses.Count) { - _progressTracker.ReportFullStorageRequestFinished(request.Accounts.AsSpan(responses.Length, requestLength - responses.Length)); + _progressTracker.ReportFullStorageRequestFinished(request.Accounts.Skip(responses.Count)); } else { @@ -155,10 +157,11 @@ public AddRangeResult AddStorageRange(StorageRange request, SlotsAndProofs respo } } + response.Dispose(); return result; } - public AddRangeResult AddStorageRange(long blockNumber, PathWithAccount pathWithAccount, in ValueHash256 expectedRootHash, in ValueHash256? startingHash, PathWithStorageSlot[] slots, byte[][]? proofs = null) + public AddRangeResult AddStorageRange(long blockNumber, PathWithAccount pathWithAccount, in ValueHash256 expectedRootHash, in ValueHash256? startingHash, IReadOnlyList slots, IReadOnlyList? proofs = null) { ITrieStore store = _trieStorePool.Get(); StorageTree tree = new(store, _logManager); @@ -172,7 +175,7 @@ public AddRangeResult AddStorageRange(long blockNumber, PathWithAccount pathWith { StorageRange range = new() { - Accounts = new[] { pathWithAccount }, + Accounts = new ArrayPoolList(1) { pathWithAccount }, StartingHash = slots[^1].Path }; @@ -200,13 +203,13 @@ public AddRangeResult AddStorageRange(long blockNumber, PathWithAccount pathWith } } - public void RefreshAccounts(AccountsToRefreshRequest request, byte[][] response) + public void RefreshAccounts(AccountsToRefreshRequest request, IOwnedReadOnlyList response) { - int respLength = response.Length; + int respLength = response.Count; ITrieStore store = _trieStorePool.Get(); try { - for (int reqi = 0; reqi < request.Paths.Length; reqi++) + for (int reqi = 0; reqi < request.Paths.Count; reqi++) { var requestedPath = request.Paths[reqi]; @@ -233,7 +236,7 @@ public void RefreshAccounts(AccountsToRefreshRequest request, byte[][] response) { StorageRange range = new() { - Accounts = new[] { requestedPath.PathAndAccount }, + Accounts = new ArrayPoolList(1) { requestedPath.PathAndAccount }, StartingHash = requestedPath.StorageStartingHash }; @@ -260,6 +263,7 @@ public void RefreshAccounts(AccountsToRefreshRequest request, byte[][] response) } finally { + response.Dispose(); _trieStorePool.Return(store); } } @@ -269,13 +273,13 @@ private void RetryAccountRefresh(AccountWithStorageStartingHash requestedPath) _progressTracker.EnqueueAccountRefresh(requestedPath.PathAndAccount, requestedPath.StorageStartingHash); } - public void AddCodes(ValueHash256[] requestedHashes, byte[][] codes) + public void AddCodes(IReadOnlyList requestedHashes, IOwnedReadOnlyList codes) { HashSet set = requestedHashes.ToHashSet(); using (IWriteBatch writeBatch = _dbProvider.CodeDb.StartWriteBatch()) { - for (int i = 0; i < codes.Length; i++) + for (int i = 0; i < codes.Count; i++) { byte[] code = codes[i]; ValueHash256 codeHash = ValueKeccak.Compute(code); @@ -288,8 +292,8 @@ public void AddCodes(ValueHash256[] requestedHashes, byte[][] codes) } } - Interlocked.Add(ref Metrics.SnapSyncedCodes, codes.Length); - + Interlocked.Add(ref Metrics.SnapSyncedCodes, codes.Count); + codes.Dispose(); _progressTracker.ReportCodeRequestFinished(set.ToArray()); } @@ -301,11 +305,11 @@ public void RetryRequest(SnapSyncBatch batch) } else if (batch.StorageRangeRequest is not null) { - _progressTracker.ReportStorageRangeRequestFinished(batch.StorageRangeRequest); + _progressTracker.ReportStorageRangeRequestFinished(batch.StorageRangeRequest.Copy()); } else if (batch.CodesRequest is not null) { - _progressTracker.ReportCodeRequestFinished(batch.CodesRequest); + _progressTracker.ReportCodeRequestFinished(batch.CodesRequest.AsSpan()); } else if (batch.AccountsToRefreshRequest is not null) { diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index 3acdcae49b6..62a930bd6a8 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -25,8 +25,8 @@ public static (AddRangeResult result, bool moreChildrenToRight, List accounts, + IReadOnlyList proofs = null ) { // TODO: Check the accounts boundaries and sorting @@ -44,7 +44,7 @@ public static (AddRangeResult result, bool moreChildrenToRight, List accountsWithStorage = new(); List codeHashes = new(); - for (var index = 0; index < accounts.Length; index++) + for (var index = 0; index < accounts.Count; index++) { PathWithAccount account = accounts[index]; if (account.Account.HasStorage) @@ -82,9 +82,9 @@ public static (AddRangeResult result, bool moreChildrenToRight) AddStorageRange( StorageTree tree, long blockNumber, in ValueHash256? startingHash, - PathWithStorageSlot[] slots, + IReadOnlyList slots, in ValueHash256 expectedRootHash, - byte[][]? proofs = null + IReadOnlyList? proofs = null ) { // TODO: Check the slots boundaries and sorting @@ -99,7 +99,7 @@ public static (AddRangeResult result, bool moreChildrenToRight) AddStorageRange( return (result, true); } - for (var index = 0; index < slots.Length; index++) + for (var index = 0; index < slots.Count; index++) { PathWithStorageSlot slot = slots[index]; Interlocked.Add(ref Metrics.SnapStateSynced, slot.SlotRlpValue.Length); @@ -127,10 +127,10 @@ private static (AddRangeResult result, List sortedBoundaryList, bool m in ValueHash256 endHash, in ValueHash256 limitHash, in ValueHash256 expectedRootHash, - byte[][]? proofs = null + IReadOnlyList? proofs = null ) { - if (proofs is null || proofs.Length == 0) + if (proofs is null || proofs.Count == 0) { return (AddRangeResult.OK, null, false); } @@ -250,11 +250,11 @@ private static (AddRangeResult result, List sortedBoundaryList, bool m return (AddRangeResult.OK, sortedBoundaryList, moreChildrenToRight); } - private static Dictionary CreateProofDict(byte[][] proofs, ITrieStore store) + private static Dictionary CreateProofDict(IReadOnlyList proofs, ITrieStore store) { Dictionary dict = new(); - for (int i = 0; i < proofs.Length; i++) + for (int i = 0; i < proofs.Count; i++) { byte[] proof = proofs[i]; TrieNode node = new(NodeType.Unknown, proof, isDirty: true); diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs index 37be467c82e..2a210aa3a6c 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs @@ -67,14 +67,14 @@ private bool IsRootMissing(in ValueHash256 stateRoot) return !_stateRootTracker.HasStateRoot(stateRoot.ToCommitment()); } - public byte[][]? GetTrieNodes(PathGroup[] pathSet, in ValueHash256 rootHash, CancellationToken cancellationToken) + public IOwnedReadOnlyList? GetTrieNodes(IReadOnlyList pathSet, in ValueHash256 rootHash, CancellationToken cancellationToken) { - if (IsRootMissing(rootHash)) return Array.Empty(); + if (IsRootMissing(rootHash)) return ArrayPoolList.Empty(); - if (_logger.IsDebug) _logger.Debug($"Get trie nodes {pathSet.Length}"); + if (_logger.IsDebug) _logger.Debug($"Get trie nodes {pathSet.Count}"); // TODO: use cache to reduce node retrieval from disk - int pathLength = pathSet.Length; - using ArrayPoolList response = new(pathLength); + int pathLength = pathSet.Count; + ArrayPoolList response = new(pathLength); StateTree tree = new(_store, _logManager); bool abort = false; @@ -123,14 +123,14 @@ private bool IsRootMissing(in ValueHash256 stateRoot) } } - if (response.Count == 0) return Array.Empty(); - return response.ToArray(); + if (response.Count == 0) return ArrayPoolList.Empty(); + return response; } - public byte[][] GetByteCodes(IReadOnlyList requestedHashes, long byteLimit, CancellationToken cancellationToken) + public IOwnedReadOnlyList GetByteCodes(IReadOnlyList requestedHashes, long byteLimit, CancellationToken cancellationToken) { long currentByteCount = 0; - using ArrayPoolList response = new(requestedHashes.Count); + ArrayPoolList response = new(requestedHashes.Count); if (byteLimit > HardResponseByteLimit) { @@ -161,31 +161,29 @@ public byte[][] GetByteCodes(IReadOnlyList requestedHashes, long b } } - return response.ToArray(); + return response; } - public (PathWithAccount[], byte[][]) GetAccountRanges(in ValueHash256 rootHash, in ValueHash256 startingHash, in ValueHash256? limitHash, long byteLimit, CancellationToken cancellationToken) + public (IOwnedReadOnlyList, IOwnedReadOnlyList) GetAccountRanges(in ValueHash256 rootHash, in ValueHash256 startingHash, in ValueHash256? limitHash, long byteLimit, CancellationToken cancellationToken) { - if (IsRootMissing(rootHash)) return (Array.Empty(), Array.Empty()); + if (IsRootMissing(rootHash)) return (ArrayPoolList.Empty(), ArrayPoolList.Empty()); byteLimit = Math.Max(Math.Min(byteLimit, HardResponseByteLimit), 1); - (IDictionary? requiredNodes, long _, byte[][] proofs, bool stoppedEarly) = GetNodesFromTrieVisitor(rootHash, startingHash, + (IDictionary? requiredNodes, long _, IOwnedReadOnlyList? proofs, bool stoppedEarly) = GetNodesFromTrieVisitor(rootHash, startingHash, limitHash?.ToCommitment() ?? Keccak.MaxValue, byteLimit, null, null, cancellationToken); - PathWithAccount[] nodes = new PathWithAccount[requiredNodes.Count]; - int index = 0; + ArrayPoolList nodes = new ArrayPoolList(requiredNodes.Count); foreach (PathWithAccount? result in requiredNodes.Select(res => new PathWithAccount(res.Key, _decoder.Decode(new RlpStream(res.Value))))) { - nodes[index] = result; - index += 1; + nodes.Add(result); } - return nodes.Length == 0 ? (nodes, Array.Empty()) : (nodes, proofs); + return nodes.Count == 0 ? (nodes, ArrayPoolList.Empty()) : (nodes, proofs.ToPooledList()); } - public (PathWithStorageSlot[][], byte[][]?) GetStorageRanges(in ValueHash256 rootHash, PathWithAccount[] accounts, in ValueHash256? startingHash, in ValueHash256? limitHash, long byteLimit, CancellationToken cancellationToken) + public (IOwnedReadOnlyList, IOwnedReadOnlyList?) GetStorageRanges(in ValueHash256 rootHash, IReadOnlyList accounts, in ValueHash256? startingHash, in ValueHash256? limitHash, long byteLimit, CancellationToken cancellationToken) { - if (IsRootMissing(rootHash)) return (Array.Empty(), Array.Empty()); + if (IsRootMissing(rootHash)) return (ArrayPoolList.Empty(), ArrayPoolList.Empty()); byteLimit = Math.Max(Math.Min(byteLimit, HardResponseByteLimit), 1); long responseSize = 0; @@ -198,8 +196,8 @@ public byte[][] GetByteCodes(IReadOnlyList requestedHashes, long b limitHash1 = ValueKeccak.MaxValue; } - using ArrayPoolList responseNodes = new(accounts.Length); - for (int i = 0; i < accounts.Length; i++) + ArrayPoolList responseNodes = new(accounts.Count); + for (int i = 0; i < accounts.Count; i++) { if (responseSize > byteLimit || cancellationToken.IsCancellationRequested) { @@ -208,18 +206,18 @@ public byte[][] GetByteCodes(IReadOnlyList requestedHashes, long b if (responseSize > 1 && (Math.Min(byteLimit, HardResponseByteLimit) - responseSize) < 10000) { - return (responseNodes.ToArray(), Array.Empty()); + break; } Account accountNeth = GetAccountByPath(tree, rootHash, accounts[i].Path.Bytes.ToArray()); if (accountNeth is null) { - return (responseNodes.ToArray(), Array.Empty()); + break; } Hash256? storagePath = accounts[i].Path.ToCommitment(); - (IDictionary? requiredNodes, long innerResponseSize, byte[][] proofs, bool stoppedEarly) = GetNodesFromTrieVisitor( + (IDictionary? requiredNodes, long innerResponseSize, IOwnedReadOnlyList? proofs, bool stoppedEarly) = GetNodesFromTrieVisitor( rootHash, startingHash1, limitHash1, @@ -230,7 +228,7 @@ public byte[][] GetByteCodes(IReadOnlyList requestedHashes, long b if (requiredNodes.Count == 0) { - return (responseNodes.ToArray(), Array.Empty()); + break; } PathWithStorageSlot[] nodes = new PathWithStorageSlot[requiredNodes.Count]; @@ -243,14 +241,15 @@ public byte[][] GetByteCodes(IReadOnlyList requestedHashes, long b responseNodes.Add(nodes); if (stoppedEarly || startingHash1 != Keccak.Zero) { - return (responseNodes.ToArray(), proofs); + return (responseNodes, proofs.ToPooledList()); } responseSize += innerResponseSize; } - return (responseNodes.ToArray(), Array.Empty()); + + return (responseNodes, ArrayPoolList.Empty()); } - private (IDictionary?, long, byte[][], bool) GetNodesFromTrieVisitor(in ValueHash256 rootHash, in ValueHash256 startingHash, in ValueHash256 limitHash, + private (IDictionary?, long, IOwnedReadOnlyList, bool) GetNodesFromTrieVisitor(in ValueHash256 rootHash, in ValueHash256 startingHash, in ValueHash256 limitHash, long byteLimit, in ValueHash256? storage, in ValueHash256? storageRoot, CancellationToken cancellationToken) { bool isStorage = storage is not null; @@ -260,9 +259,7 @@ public byte[][] GetByteCodes(IReadOnlyList requestedHashes, long b tree.Accept(visitor, rootHash.ToCommitment(), opt, storageAddr: storage?.ToCommitment(), storageRoot: storageRoot?.ToCommitment()); (IDictionary? requiredNodes, long responseSize) = visitor.GetNodesAndSize(); - byte[][] proofs = Array.Empty(); - if (startingHash != Keccak.Zero || visitor.StoppedEarly) proofs = visitor.GetProofs(); - + ArrayPoolList proofs = startingHash != Keccak.Zero || visitor.StoppedEarly ? visitor.GetProofs() : ArrayPoolList.Empty(); return (requiredNodes, responseSize, proofs, visitor.StoppedEarly); } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncBatch.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncBatch.cs index df3ad0fa5d4..bc7ed1dcd46 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncBatch.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncBatch.cs @@ -1,12 +1,14 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.State.Snap; namespace Nethermind.Synchronization.SnapSync { - public class SnapSyncBatch + public class SnapSyncBatch : IDisposable { public AccountRange? AccountRangeRequest { get; set; } public AccountsAndProofs? AccountRangeResponse { get; set; } @@ -14,11 +16,11 @@ public class SnapSyncBatch public StorageRange? StorageRangeRequest { get; set; } public SlotsAndProofs? StorageRangeResponse { get; set; } - public ValueHash256[]? CodesRequest { get; set; } - public byte[][]? CodesResponse { get; set; } + public IOwnedReadOnlyList? CodesRequest { get; set; } + public IOwnedReadOnlyList? CodesResponse { get; set; } public AccountsToRefreshRequest? AccountsToRefreshRequest { get; set; } - public byte[][]? AccountsToRefreshResponse { get; set; } + public IOwnedReadOnlyList? AccountsToRefreshResponse { get; set; } public override string ToString() { @@ -32,7 +34,7 @@ public override string ToString() } else if (CodesRequest is not null) { - return $"CodesRequest: ({CodesRequest.Length})"; + return $"CodesRequest: ({CodesRequest.Count})"; } else if (AccountsToRefreshRequest is not null) { @@ -43,5 +45,16 @@ public override string ToString() return "Empty snap sync batch"; } } + + public void Dispose() + { + AccountRangeResponse?.Dispose(); + StorageRangeResponse?.Dispose(); + CodesResponse?.Dispose(); + AccountsToRefreshResponse?.Dispose(); + CodesRequest?.Dispose(); + StorageRangeRequest?.Dispose(); + AccountsToRefreshRequest?.Dispose(); + } } } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncDownloader.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncDownloader.cs index 57cc1de379a..28690a51013 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncDownloader.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncDownloader.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; using Nethermind.Logging; +using Nethermind.Network.Contract.P2P; using Nethermind.Synchronization.ParallelSync; using Nethermind.Synchronization.Peers; @@ -24,8 +25,7 @@ public async Task Dispatch(PeerInfo peerInfo, SnapSyncBatch batch, CancellationT { ISyncPeer peer = peerInfo.SyncPeer; - //TODO: replace with a constant "snap" - if (peer.TryGetSatelliteProtocol("snap", out var handler)) + if (peer.TryGetSatelliteProtocol(Protocol.Snap, out var handler)) { try { diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncFeed.cs index f7e24eb7ca9..abcdf0b9f09 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapSyncFeed.cs @@ -37,7 +37,7 @@ public SnapSyncFeed(ISnapProvider snapProvider, ILogManager logManager) { try { - (SnapSyncBatch request, bool finished) = _snapProvider.GetNextRequest(); + bool finished = _snapProvider.IsFinished(out SnapSyncBatch request); if (request is null) { @@ -68,36 +68,43 @@ public override SyncResponseHandlingResult HandleResponse(SnapSyncBatch? batch, AddRangeResult result = AddRangeResult.OK; - if (batch.AccountRangeResponse is not null) - { - result = _snapProvider.AddAccountRange(batch.AccountRangeRequest, batch.AccountRangeResponse); - } - else if (batch.StorageRangeResponse is not null) - { - result = _snapProvider.AddStorageRange(batch.StorageRangeRequest, batch.StorageRangeResponse); - } - else if (batch.CodesResponse is not null) - { - _snapProvider.AddCodes(batch.CodesRequest, batch.CodesResponse); - } - else if (batch.AccountsToRefreshResponse is not null) - { - _snapProvider.RefreshAccounts(batch.AccountsToRefreshRequest, batch.AccountsToRefreshResponse); - } - else + try { - _snapProvider.RetryRequest(batch); - - if (peer is null) + if (batch.AccountRangeResponse is not null) + { + result = _snapProvider.AddAccountRange(batch.AccountRangeRequest, batch.AccountRangeResponse); + } + else if (batch.StorageRangeResponse is not null) + { + result = _snapProvider.AddStorageRange(batch.StorageRangeRequest, batch.StorageRangeResponse); + } + else if (batch.CodesResponse is not null) { - return SyncResponseHandlingResult.NotAssigned; + _snapProvider.AddCodes(batch.CodesRequest, batch.CodesResponse); + } + else if (batch.AccountsToRefreshResponse is not null) + { + _snapProvider.RefreshAccounts(batch.AccountsToRefreshRequest, batch.AccountsToRefreshResponse); } else { - _logger.Trace($"SNAP - timeout {peer}"); - return SyncResponseHandlingResult.LesserQuality; + _snapProvider.RetryRequest(batch); + + if (peer is null) + { + return SyncResponseHandlingResult.NotAssigned; + } + else + { + _logger.Trace($"SNAP - timeout {peer}"); + return SyncResponseHandlingResult.LesserQuality; + } } } + finally + { + batch.Dispose(); + } return AnalyzeResponsePerPeer(result, peer); } diff --git a/src/Nethermind/Nethermind.Synchronization/StateSync/StateSyncDownloader.cs b/src/Nethermind/Nethermind.Synchronization/StateSync/StateSyncDownloader.cs index f11f39409f5..b07a449dd05 100644 --- a/src/Nethermind/Nethermind.Synchronization/StateSync/StateSyncDownloader.cs +++ b/src/Nethermind/Nethermind.Synchronization/StateSync/StateSyncDownloader.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Logging; @@ -36,7 +37,7 @@ public async Task Dispatch(PeerInfo peerInfo, StateSyncBatch batch, Cancellation } ISyncPeer peer = peerInfo.SyncPeer; - Task task = null; + Task> task = null; HashList? hashList = null; // Use GETNODEDATA if possible. Firstly via dedicated NODEDATA protocol if (peer.TryGetSatelliteProtocol(Protocol.NodeData, out INodeDataPeer nodeDataHandler)) @@ -115,14 +116,17 @@ private GetTrieNodesRequest GetGroupedRequest(StateSyncBatch batch) } } - request.AccountAndStoragePaths = new PathGroup[accountTreePaths.Count + itemsGroupedByAccount.Count]; + ArrayPoolList accountAndStoragePath = new ArrayPoolList( + accountTreePaths.Count + itemsGroupedByAccount.Count, + accountTreePaths.Count + itemsGroupedByAccount.Count); + request.AccountAndStoragePaths = accountAndStoragePath; int requestedNodeIndex = 0; int accountPathIndex = 0; for (; accountPathIndex < accountTreePaths.Count; accountPathIndex++) { (byte[] path, StateSyncItem syncItem) accountPath = accountTreePaths[accountPathIndex]; - request.AccountAndStoragePaths[accountPathIndex] = new PathGroup() { Group = new[] { Nibbles.EncodePath(accountPath.path) } }; + accountAndStoragePath[accountPathIndex] = new PathGroup() { Group = new[] { Nibbles.EncodePath(accountPath.path) } }; // We validate the order of the response later and it has to be the same as RequestedNodes batch.RequestedNodes[requestedNodeIndex] = accountPath.syncItem; @@ -146,7 +150,7 @@ private GetTrieNodesRequest GetGroupedRequest(StateSyncBatch batch) requestedNodeIndex++; } - request.AccountAndStoragePaths[accountPathIndex] = new PathGroup() { Group = group }; + accountAndStoragePath[accountPathIndex] = new PathGroup() { Group = group }; accountPathIndex++; } diff --git a/src/Nethermind/Nethermind.Synchronization/SyncServer.cs b/src/Nethermind/Nethermind.Synchronization/SyncServer.cs index 4cd77514234..03d4ffc27d2 100644 --- a/src/Nethermind/Nethermind.Synchronization/SyncServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SyncServer.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.IO; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -16,6 +17,7 @@ using Nethermind.Core; using Nethermind.Core.Attributes; using Nethermind.Core.Caching; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Int256; @@ -385,21 +387,22 @@ public TxReceipt[] GetReceipts(Hash256? blockHash) return blockHash is not null ? _receiptFinder.Get(blockHash) : Array.Empty(); } - public BlockHeader[] FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse) + public IOwnedReadOnlyList FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse) { return _blockTree.FindHeaders(hash, numberOfBlocks, skip, reverse); } - public byte[]?[] GetNodeData(IReadOnlyList keys, CancellationToken cancellationToken, NodeDataType includedTypes = NodeDataType.State | NodeDataType.Code) + public IOwnedReadOnlyList GetNodeData(IReadOnlyList keys, CancellationToken cancellationToken, NodeDataType includedTypes = NodeDataType.State | NodeDataType.Code) { - byte[]?[] values = new byte[keys.Count][]; + ArrayPoolList values = new ArrayPoolList(keys.Count); for (int i = 0; i < keys.Count; i++) { if (cancellationToken.IsCancellationRequested) { - values = values[..i]; + return values; } - values[i] = null; + + values.Add(null); if ((includedTypes & NodeDataType.State) == NodeDataType.State) { values[i] = _stateDb[keys[i].Bytes]; diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/GetNodeDataTrieNodeRecovery.cs b/src/Nethermind/Nethermind.Synchronization/Trie/GetNodeDataTrieNodeRecovery.cs index b513a5b732b..96d6ce4a60b 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/GetNodeDataTrieNodeRecovery.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/GetNodeDataTrieNodeRecovery.cs @@ -2,9 +2,11 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Logging; using Nethermind.Network.Contract.P2P; @@ -25,11 +27,11 @@ public GetNodeDataTrieNodeRecovery(ISyncPeerPool syncPeerPool, ILogManager? logM protected override async Task RecoverRlpFromPeerBase(ValueHash256 rlpHash, ISyncPeer peer, IReadOnlyList request, CancellationTokenSource cts) { - byte[][] rlp = await (peer.TryGetSatelliteProtocol(Protocol.NodeData, out INodeDataPeer nodeDataHandler) + using IOwnedReadOnlyList rlp = await (peer.TryGetSatelliteProtocol(Protocol.NodeData, out INodeDataPeer nodeDataHandler) ? nodeDataHandler.GetNodeData(request, cts.Token) : peer.GetNodeData(request, cts.Token)); - if (rlp.Length == 1) + if (rlp.Count == 1) { byte[] recoveredRlp = rlp[0]; if (ValueKeccak.Compute(recoveredRlp) == rlpHash) diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs index 32cdee612d5..0bcac7bde70 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStateTree.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Logging; using Nethermind.State; @@ -70,11 +71,11 @@ private bool Recover(in ValueHash256 rlpHash, ReadOnlySpan pathPart, Hash2 GetTrieNodesRequest request = new() { RootHash = rootHash, - AccountAndStoragePaths = new[] + AccountAndStoragePaths = new ArrayPoolList(1) { - new PathGroup + new() { - Group = new[] { Nibbles.EncodePath(pathPart) } + Group = [Nibbles.EncodePath(pathPart)] } } }; diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs index 63fee9d2581..e7c917cab11 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/HealingStorageTree.cs @@ -3,6 +3,7 @@ using System; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Logging; using Nethermind.State; @@ -69,11 +70,11 @@ private bool Recover(in ValueHash256 rlpHash, ReadOnlySpan pathPart) GetTrieNodesRequest request = new() { RootHash = _stateRoot, - AccountAndStoragePaths = new[] + AccountAndStoragePaths = new ArrayPoolList(1) { - new PathGroup + new() { - Group = new[] { ValueKeccak.Compute(_address.Bytes).ToByteArray(), Nibbles.EncodePath(pathPart) } + Group = [ValueKeccak.Compute(_address.Bytes).ToByteArray(), Nibbles.EncodePath(pathPart)] } } }; diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/SnapTrieNodeRecovery.cs b/src/Nethermind/Nethermind.Synchronization/Trie/SnapTrieNodeRecovery.cs index 6969d81c143..8cf080307cb 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/SnapTrieNodeRecovery.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/SnapTrieNodeRecovery.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Logging; @@ -38,8 +39,8 @@ private string GetMissingNodes(PathGroup requestAccountAndStoragePaths) => { if (peer.TryGetSatelliteProtocol(Protocol.Snap, out ISnapSyncPeer? snapPeer)) { - byte[][] rlp = await snapPeer.GetTrieNodes(request, cts.Token); - if (rlp.Length == 1 && rlp[0]?.Length > 0 && ValueKeccak.Compute(rlp[0]) == rlpHash) + IOwnedReadOnlyList rlp = await snapPeer.GetTrieNodes(request, cts.Token); + if (rlp.Count == 1 && rlp[0]?.Length > 0 && ValueKeccak.Compute(rlp[0]) == rlpHash) { return rlp[0]; } diff --git a/src/Nethermind/Nethermind.Trie/RangeQueryVisitor.cs b/src/Nethermind/Nethermind.Trie/RangeQueryVisitor.cs index 44b6669ab2b..0bb905798f3 100644 --- a/src/Nethermind/Nethermind.Trie/RangeQueryVisitor.cs +++ b/src/Nethermind/Nethermind.Trie/RangeQueryVisitor.cs @@ -21,7 +21,9 @@ using System.Threading; using Nethermind.Core; using Nethermind.Core.Buffers; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Serialization.Rlp; namespace Nethermind.Trie; @@ -125,9 +127,9 @@ public bool ShouldVisit(in TreePathContext ctx, Hash256 nextNode) return (_collectedNodes, _currentBytesCount); } - public byte[][] GetProofs() + public ArrayPoolList GetProofs() { - if (_leftLeafProof is null) return Array.Empty(); + if (_leftLeafProof is null) return ArrayPoolList.Empty(); HashSet proofs = new(); // Note: although nethermind works just fine without left proof if start with zero starting hash, @@ -161,7 +163,7 @@ public byte[][] GetProofs() } } - return proofs.ToArray(); + return proofs.ToPooledList(); } public void VisitTree(in TreePathContext nodeContext, Hash256 rootHash, TrieVisitContext trieVisitContext) diff --git a/src/Nethermind/Nethermind.TxPool/ITxPool.cs b/src/Nethermind/Nethermind.TxPool/ITxPool.cs index 326a134e09e..e6ba750b865 100644 --- a/src/Nethermind/Nethermind.TxPool/ITxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/ITxPool.cs @@ -39,7 +39,7 @@ public interface ITxPool AcceptTxResult SubmitTx(Transaction tx, TxHandlingOptions handlingOptions); bool RemoveTransaction(Hash256? hash); bool IsKnown(Hash256 hash); - bool TryGetPendingTransaction(Hash256 hash, out Transaction? transaction); + bool TryGetPendingTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? transaction); bool TryGetPendingBlobTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? blobTransaction); UInt256 GetLatestPendingNonce(Address address); event EventHandler NewDiscovered; diff --git a/src/Nethermind/Nethermind.TxPool/NullTxPool.cs b/src/Nethermind/Nethermind.TxPool/NullTxPool.cs index 80a914a9a34..3df7080af87 100644 --- a/src/Nethermind/Nethermind.TxPool/NullTxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/NullTxPool.cs @@ -42,7 +42,7 @@ public void RemovePeer(PublicKey nodeId) { } public bool IsKnown(Hash256 hash) => false; - public bool TryGetPendingTransaction(Hash256 hash, out Transaction? transaction) + public bool TryGetPendingTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? transaction) { transaction = null; return false; diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index ee34c3bd0c6..7841ea39993 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -641,17 +641,13 @@ public bool ContainsTx(Hash256 hash, TxType txType) => txType == TxType.Blob ? _blobTransactions.ContainsKey(hash) : _transactions.ContainsKey(hash) || _broadcaster.ContainsTx(hash); - public bool TryGetPendingTransaction(Hash256 hash, out Transaction? transaction) - { - return _transactions.TryGetValue(hash, out transaction) - || _blobTransactions.TryGetValue(hash, out transaction) - || _broadcaster.TryGetPersistentTx(hash, out transaction); - } + public bool TryGetPendingTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? transaction) => + _transactions.TryGetValue(hash, out transaction) + || _blobTransactions.TryGetValue(hash, out transaction) + || _broadcaster.TryGetPersistentTx(hash, out transaction); - public bool TryGetPendingBlobTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? blobTransaction) - { - return _blobTransactions.TryGetValue(hash, out blobTransaction); - } + public bool TryGetPendingBlobTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? blobTransaction) => + _blobTransactions.TryGetValue(hash, out blobTransaction); // only for tests - to test sorting internal void TryGetBlobTxSortingEquivalent(Hash256 hash, out Transaction? transaction) From eb00487e6e2858d77960a6268c018e76dce36ddf Mon Sep 17 00:00:00 2001 From: Lukasz Rozmej Date: Thu, 29 Feb 2024 14:17:27 +0100 Subject: [PATCH 6/8] Dispose HelloMessage (#6796) --- src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs | 2 +- .../Nethermind.Network/P2P/Messages/HelloMessage.cs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs index f94f8342984..2016ed58947 100644 --- a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs +++ b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs @@ -329,7 +329,7 @@ public void Dispose() { if (!_disposed) { - throw new InvalidOperationException($"{nameof(ArrayPoolList)} hasn't been disposed. Created at: {_creationStackTrace}"); + throw new InvalidOperationException($"{nameof(ArrayPoolList)} hasn't been disposed. Created {_creationStackTrace}"); } } #endif diff --git a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs index b16a73f2f56..6fb0ff6dc33 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessage.cs @@ -19,5 +19,11 @@ public class HelloMessage : P2PMessage public IOwnedReadOnlyList Capabilities { get; set; } public override string ToString() => $"Hello({ClientId}, {string.Join(", ", Capabilities)})"; + + public override void Dispose() + { + base.Dispose(); + Capabilities?.Dispose(); + } } } From 0cef9f5ceca46a31ffa15f860d4fe7a5634d054c Mon Sep 17 00:00:00 2001 From: Lukasz Rozmej Date: Thu, 29 Feb 2024 16:03:41 +0100 Subject: [PATCH 7/8] More missed disposes (#6797) --- .../Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs | 2 +- .../Synchronization/PeerRefresher.cs | 2 +- .../P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs | 2 +- .../P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs | 2 +- .../Nethermind.Synchronization.Test/BlockDownloaderTests.cs | 5 +++-- .../FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs | 2 +- .../Nethermind.Synchronization/Blocks/BlockDownloader.cs | 6 +++--- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs b/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs index 6a841cf2bb1..802115d08a6 100644 --- a/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs +++ b/src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptFixMigration.cs @@ -123,7 +123,7 @@ private async Task DownloadReceiptsForBlock(Block block) { try { - IOwnedReadOnlyList receipts = await currentSyncPeer.GetReceipts(new List { block.Hash }, _cancellationToken); + using IOwnedReadOnlyList receipts = await currentSyncPeer.GetReceipts(new List { block.Hash }, _cancellationToken); TxReceipt[]? txReceipts = receipts.FirstOrDefault(); if (txReceipts is not null) { diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs index 529960e4f96..0e64b0a3c2e 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs @@ -102,7 +102,7 @@ internal async Task RefreshPeerForFcu( try { - IOwnedReadOnlyList? headAndParentHeaders = await getHeadParentHeaderTask; + using IOwnedReadOnlyList? headAndParentHeaders = await getHeadParentHeaderTask; if (!TryGetHeadAndParent(headBlockhash, headParentBlockhash, headAndParentHeaders!, out headBlockHeader, out headParentBlockHeader)) { _syncPeerPool.ReportRefreshFailed(syncPeer, "ForkChoiceUpdate: unexpected response length"); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs index 4e8d247533d..4081491962e 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/Eth63ProtocolHandlerTests.cs @@ -50,7 +50,7 @@ public async Task Can_request_and_handle_receipts() ctx.ProtocolHandler.HandleMessage(receiptsPacket); - var result = await task; + using var result = await task; result.Should().HaveCount(1000); } diff --git a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs index 9de5b2d14e5..56c784b6fb9 100644 --- a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs +++ b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/SyncPeerProtocolHandlerBase.cs @@ -173,7 +173,7 @@ protected virtual async Task> SendRequest(GetBlo msg.Reverse = 0; msg.Skip = 0; - IOwnedReadOnlyList headers = await SendRequest(msg, token); + using IOwnedReadOnlyList headers = await SendRequest(msg, token); return headers.Count > 0 ? headers[0] : null; } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs index 64c167a98cd..05b0944a1fc 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs @@ -571,7 +571,8 @@ public async Task Validate_always_the_last_seal_and_random_seal_in_the_package() }; BlockDownloader downloader = ctx.BlockDownloader; - IOwnedReadOnlyList? blockHeaders = await ctx.ResponseBuilder.BuildHeaderResponse(0, 512, Response.AllCorrect); + 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()) @@ -585,7 +586,7 @@ public async Task Validate_always_the_last_seal_and_random_seal_in_the_package() sealValidator.Received(2).ValidateSeal(Arg.Any(), true); sealValidator.Received(510).ValidateSeal(Arg.Any(), false); - sealValidator.Received().ValidateSeal(blockHeaders![^1], true); + sealValidator.Received().ValidateSeal(blockHeadersCopy![^1], true); } private class ThrowingPeer : ISyncPeer diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs index b91055dbc87..edd178f6dc2 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/SnapProtocolTests/StateSyncDispatcherTests.cs @@ -73,7 +73,7 @@ public async Task Eth66Peer_RunGetNodeData() await _dispatcher.ExecuteDispatch(batch, 1); - await peer.ReceivedWithAnyArgs(1).GetNodeData(default!, default); + using var _ = await peer.ReceivedWithAnyArgs(1).GetNodeData(default!, default); } [Test] diff --git a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs index 8285ad5edb7..2cf6f952080 100644 --- a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs +++ b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs @@ -168,7 +168,7 @@ bool HasMoreToSync() if (_logger.IsDebug) _logger.Debug($"Headers request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more."); Stopwatch sw = Stopwatch.StartNew(); - IOwnedReadOnlyList headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); + using IOwnedReadOnlyList headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); Hash256? startHeaderHash = headers[0]?.Hash; BlockHeader? startHeader = (startHeaderHash is null) @@ -281,7 +281,7 @@ bool HasMoreToSync() if (_logger.IsTrace) _logger.Trace($"Full sync request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more."); if (cancellation.IsCancellationRequested) return blocksSynced; // check before every heavy operation - IOwnedReadOnlyList headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); + using IOwnedReadOnlyList headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); if (headers.Count < 2) { // Peer dont have new header @@ -481,7 +481,7 @@ protected async Task RequestReceipts(PeerInfo peer, CancellationToken cancellati Task> request = peer.SyncPeer.GetReceipts(hashesToRequest, cancellation); await request.ContinueWith(_ => DownloadFailHandler(request, "receipts"), cancellation); - IOwnedReadOnlyList result = request.Result; + using IOwnedReadOnlyList result = request.Result; for (int i = 0; i < result.Count; i++) { From d18e4f695d979060804237aae16f92488c8f8d1f Mon Sep 17 00:00:00 2001 From: Marcin Sobczak <77129288+marcindsobczak@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:48:51 +0100 Subject: [PATCH 8/8] Set eth67 and eth68 as default capabilities (#6785) --- .../Nethermind.Init/Steps/InitializeNetwork.cs | 11 ----------- .../Modules/Eth/EthRpcModuleTests.cs | 2 +- .../P2P/P2PProtocolHandlerTests.cs | 2 +- .../P2P/P2PProtocolInfoProviderTests.cs | 4 ++-- .../P2P/ProtocolHandlers/P2PProtocolHandler.cs | 2 ++ 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs index 188af350539..faa3742db87 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs @@ -201,17 +201,6 @@ await InitPeer().ContinueWith(initPeerTask => } }); - bool stateSyncFinished = _api.Synchronizer.SyncProgressResolver.FindBestFullState() != 0; - - if (_syncConfig.SnapSync || stateSyncFinished || !_syncConfig.FastSync) - { - // we can't add eth67 capability as default, because it needs snap protocol for syncing (GetNodeData is - // no longer available). Eth67 should be added if snap is enabled OR sync is finished OR in archive nodes (no state sync) - _api.ProtocolsManager!.AddSupportedCapability(new Capability(Protocol.Eth, 67)); - _api.ProtocolsManager!.AddSupportedCapability(new Capability(Protocol.Eth, 68)); - } - else if (_logger.IsDebug) _logger.Debug("Skipped enabling eth67 & eth68 capabilities"); - if (_syncConfig.SnapSync) { if (!_syncConfig.SnapServingEnabled) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs index bcacbd6c0a4..9e5b6988a81 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs @@ -696,7 +696,7 @@ public async Task Eth_protocol_version() { using Context ctx = await Context.Create(); string serialized = await ctx.Test.TestEthRpc("eth_protocolVersion"); - Assert.That(serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":\"0x42\",\"id\":67}")); + Assert.That(serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":\"0x44\",\"id\":67}")); } [Test] diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs index 26ce82f8973..b216c17ae05 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs @@ -88,7 +88,7 @@ public void On_init_sends_a_hello_message_with_capabilities() p2PProtocolHandler.AddSupportedCapability(new Capability(Protocol.Wit, 0)); p2PProtocolHandler.Init(); - string[] expectedCapabilities = { "eth66", "nodedata1", "wit0" }; + string[] expectedCapabilities = { "eth66", "eth67", "eth68", "nodedata1", "wit0" }; _session.Received(1).DeliverMessage( Arg.Is(m => m.Capabilities.Select(c => c.ToString()).SequenceEqual(expectedCapabilities))); } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolInfoProviderTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolInfoProviderTests.cs index 0abdf954d57..9dae1f494a3 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolInfoProviderTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolInfoProviderTests.cs @@ -14,14 +14,14 @@ public class P2PProtocolInfoProviderTests public void GetHighestVersionOfEthProtocol_ReturnExpectedResult() { int result = P2PProtocolInfoProvider.GetHighestVersionOfEthProtocol(); - Assert.That(result, Is.EqualTo(66)); + Assert.That(result, Is.EqualTo(68)); } [Test] public void DefaultCapabilitiesToString_ReturnExpectedResult() { string result = P2PProtocolInfoProvider.DefaultCapabilitiesToString(); - Assert.That(result, Is.EqualTo("eth/66,nodedata/1")); + Assert.That(result, Is.EqualTo("eth/68,eth/67,eth/66,nodedata/1")); } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs index 9ee3d70deb8..abb7807f894 100644 --- a/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/ProtocolHandlers/P2PProtocolHandler.cs @@ -52,6 +52,8 @@ public class P2PProtocolHandler( public static readonly IEnumerable DefaultCapabilities = new Capability[] { new(Protocol.Eth, 66), + new(Protocol.Eth, 67), + new(Protocol.Eth, 68), new(Protocol.NodeData, 1) };