diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index bd40861ae50..e8e5d5fb974 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -15,7 +15,6 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Transactions; using Nethermind.Consensus.Validators; -using Nethermind.Consensus.Withdrawals; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -31,399 +30,395 @@ using Nethermind.State.Repositories; using Nethermind.Db.Blooms; using Nethermind.Evm.TransactionProcessing; -using Nethermind.Synchronization.FastSync; using Nethermind.Specs.Test; -using Nethermind.Trie; using Nethermind.Trie.Pruning; using Nethermind.TxPool; -using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; using Nethermind.Config; -namespace Nethermind.Core.Test.Blockchain +namespace Nethermind.Core.Test.Blockchain; + +public class TestBlockchain : IDisposable { - public class TestBlockchain : IDisposable + public const int DefaultTimeout = 4000; + public IStateReader StateReader { get; private set; } = null!; + public IEthereumEcdsa EthereumEcdsa { get; private set; } = null!; + public TransactionProcessor TxProcessor { get; set; } = null!; + public IStorageProvider Storage { get; set; } = null!; + public IReceiptStorage ReceiptStorage { get; set; } = null!; + public ITxPool TxPool { get; set; } = null!; + public IDb CodeDb => DbProvider.CodeDb; + public IBlockProcessor BlockProcessor { get; set; } = null!; + public IBlockchainProcessor BlockchainProcessor { get; set; } = null!; + + public IBlockPreprocessorStep BlockPreprocessorStep { get; set; } = null!; + + public IBlockProcessingQueue BlockProcessingQueue { get; set; } = null!; + public IBlockTree BlockTree { get; set; } = null!; + + public IBlockFinder BlockFinder { - public const int DefaultTimeout = 4000; - public IStateReader StateReader { get; private set; } = null!; - public IEthereumEcdsa EthereumEcdsa { get; private set; } = null!; - public TransactionProcessor TxProcessor { get; set; } = null!; - public IStorageProvider Storage { get; set; } = null!; - public IReceiptStorage ReceiptStorage { get; set; } = null!; - public ITxPool TxPool { get; set; } = null!; - public IDb CodeDb => DbProvider.CodeDb; - public IBlockProcessor BlockProcessor { get; set; } = null!; - public IBlockchainProcessor BlockchainProcessor { get; set; } = null!; - - public IBlockPreprocessorStep BlockPreprocessorStep { get; set; } = null!; - - public IBlockProcessingQueue BlockProcessingQueue { get; set; } = null!; - public IBlockTree BlockTree { get; set; } = null!; - - public IBlockFinder BlockFinder - { - get => _blockFinder ?? BlockTree; - set => _blockFinder = value; - } + get => _blockFinder ?? BlockTree; + set => _blockFinder = value; + } - public ILogFinder LogFinder { get; private set; } = null!; - public IJsonSerializer JsonSerializer { get; set; } = null!; - public IStateProvider State { get; set; } = null!; - public IReadOnlyStateProvider ReadOnlyState { get; private set; } = null!; - public IDb StateDb => DbProvider.StateDb; - public TrieStore TrieStore { get; set; } = null!; - public IBlockProducer BlockProducer { get; private set; } = null!; - public IDbProvider DbProvider { get; set; } = null!; - public ISpecProvider SpecProvider { get; set; } = null!; + public ILogFinder LogFinder { get; private set; } = null!; + public IJsonSerializer JsonSerializer { get; set; } = null!; + public IStateProvider State { get; set; } = null!; + public IReadOnlyStateProvider ReadOnlyState { get; private set; } = null!; + public IDb StateDb => DbProvider.StateDb; + public TrieStore TrieStore { get; set; } = null!; + public IBlockProducer BlockProducer { get; private set; } = null!; + public IDbProvider DbProvider { get; set; } = null!; + public ISpecProvider SpecProvider { get; set; } = null!; - public ISealEngine SealEngine { get; set; } = null!; + public ISealEngine SealEngine { get; set; } = null!; - public ITransactionComparerProvider TransactionComparerProvider { get; set; } = null!; + public ITransactionComparerProvider TransactionComparerProvider { get; set; } = null!; - public IPoSSwitcher PoSSwitcher { get; set; } = null!; + public IPoSSwitcher PoSSwitcher { get; set; } = null!; - protected TestBlockchain() - { - } + protected TestBlockchain() + { + } - public string SealEngineType { get; set; } = null!; + public string SealEngineType { get; set; } = null!; - public static Address AccountA = TestItem.AddressA; - public static Address AccountB = TestItem.AddressB; - public static Address AccountC = TestItem.AddressC; - public SemaphoreSlim _resetEvent = null!; - private ManualResetEvent _suggestedBlockResetEvent = null!; - private AutoResetEvent _oneAtATime = new(true); - private IBlockFinder _blockFinder = null!; + public static Address AccountA = TestItem.AddressA; + public static Address AccountB = TestItem.AddressB; + public static Address AccountC = TestItem.AddressC; + public SemaphoreSlim _resetEvent = null!; + private ManualResetEvent _suggestedBlockResetEvent = null!; + private AutoResetEvent _oneAtATime = new(true); + private IBlockFinder _blockFinder = null!; - public static readonly UInt256 InitialValue = 1000.Ether(); - private TrieStoreBoundaryWatcher _trieStoreWatcher = null!; - public IHeaderValidator HeaderValidator { get; set; } = null!; + public static readonly UInt256 InitialValue = 1000.Ether(); + private TrieStoreBoundaryWatcher _trieStoreWatcher = null!; + public IHeaderValidator HeaderValidator { get; set; } = null!; - public IBlockValidator BlockValidator { get; set; } = null!; - public BuildBlocksWhenRequested BlockProductionTrigger { get; } = new(); + public IBlockValidator BlockValidator { get; set; } = null!; + public BuildBlocksWhenRequested BlockProductionTrigger { get; } = new(); - public IReadOnlyTrieStore ReadOnlyTrieStore { get; private set; } = null!; + public IReadOnlyTrieStore ReadOnlyTrieStore { get; private set; } = null!; - public ManualTimestamper Timestamper { get; protected set; } = null!; + public ManualTimestamper Timestamper { get; protected set; } = null!; - public ProducedBlockSuggester Suggester { get; protected set; } = null!; + public ProducedBlockSuggester Suggester { get; protected set; } = null!; - public static TransactionBuilder BuildSimpleTransaction => Builders.Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyA).To(AccountB); + public static TransactionBuilder BuildSimpleTransaction => Builders.Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyA).To(AccountB); - protected virtual async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null) + protected virtual async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null) + { + Timestamper = new ManualTimestamper(new DateTime(2020, 2, 15, 12, 50, 30, DateTimeKind.Utc)); + JsonSerializer = new EthereumJsonSerializer(); + SpecProvider = CreateSpecProvider(specProvider ?? MainnetSpecProvider.Instance); + EthereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId, LogManager); + DbProvider = await CreateDbProvider(); + TrieStore = new TrieStore(StateDb, LogManager); + State = new StateProvider(TrieStore, DbProvider.CodeDb, LogManager); + State.CreateAccount(TestItem.AddressA, (initialValues ?? InitialValue)); + State.CreateAccount(TestItem.AddressB, (initialValues ?? InitialValue)); + State.CreateAccount(TestItem.AddressC, (initialValues ?? InitialValue)); + byte[] code = Bytes.FromHexString("0xabcd"); + Keccak codeHash = Keccak.Compute(code); + State.UpdateCode(code); + State.UpdateCodeHash(TestItem.AddressA, codeHash, SpecProvider.GenesisSpec); + + Storage = new StorageProvider(TrieStore, State, LogManager); + Storage.Set(new StorageCell(TestItem.AddressA, UInt256.One), Bytes.FromHexString("0xabcdef")); + Storage.Commit(); + + State.Commit(SpecProvider.GenesisSpec); + State.CommitTree(0); + + ReadOnlyTrieStore = TrieStore.AsReadOnly(StateDb); + StateReader = new StateReader(ReadOnlyTrieStore, CodeDb, LogManager); + + IDb blockDb = new MemDb(); + IDb headerDb = new MemDb(); + IDb blockInfoDb = new MemDb(); + BlockTree = new BlockTree(blockDb, headerDb, blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), SpecProvider, NullBloomStorage.Instance, LimboLogs.Instance); + ReadOnlyState = new ChainHeadReadOnlyStateProvider(BlockTree, StateReader); + TransactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockTree); + TxPool = CreateTxPool(); + + _trieStoreWatcher = new TrieStoreBoundaryWatcher(TrieStore, BlockTree, LogManager); + + ReceiptStorage = new InMemoryReceiptStorage(); + VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, LogManager), SpecProvider, LogManager); + TxProcessor = new TransactionProcessor(SpecProvider, State, Storage, virtualMachine, LogManager); + BlockPreprocessorStep = new RecoverSignatures(EthereumEcdsa, TxPool, SpecProvider, LogManager); + HeaderValidator = new HeaderValidator(BlockTree, Always.Valid, SpecProvider, LogManager); + + new ReceiptCanonicalityMonitor(BlockTree, ReceiptStorage, LogManager); + + BlockValidator = new BlockValidator( + new TxValidator(SpecProvider.ChainId), + HeaderValidator, + Always.Valid, + SpecProvider, + LogManager); + + PoSSwitcher = NoPoS.Instance; + ISealer sealer = new NethDevSealEngine(TestItem.AddressD); + SealEngine = new SealEngine(sealer, Always.Valid); + + BloomStorage bloomStorage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); + ReceiptsRecovery receiptsRecovery = new(new EthereumEcdsa(SpecProvider.ChainId, LimboLogs.Instance), SpecProvider); + LogFinder = new LogFinder(BlockTree, ReceiptStorage, ReceiptStorage, bloomStorage, LimboLogs.Instance, receiptsRecovery); + BlockProcessor = CreateBlockProcessor(); + + BlockchainProcessor chainProcessor = new(BlockTree, BlockProcessor, BlockPreprocessorStep, StateReader, LogManager, Consensus.Processing.BlockchainProcessor.Options.Default); + BlockchainProcessor = chainProcessor; + BlockProcessingQueue = chainProcessor; + chainProcessor.Start(); + + TxPoolTxSource txPoolTxSource = CreateTxPoolTxSource(); + ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockFinder); + BlockProducer = CreateTestBlockProducer(txPoolTxSource, sealer, transactionComparerProvider); + await BlockProducer.Start(); + Suggester = new ProducedBlockSuggester(BlockTree, BlockProducer); + + _resetEvent = new SemaphoreSlim(0); + _suggestedBlockResetEvent = new ManualResetEvent(true); + BlockTree.NewHeadBlock += OnNewHeadBlock; + BlockProducer.BlockProduced += (s, e) => { - Timestamper = new ManualTimestamper(new DateTime(2020, 2, 15, 12, 50, 30, DateTimeKind.Utc)); - JsonSerializer = new EthereumJsonSerializer(); - SpecProvider = CreateSpecProvider(specProvider ?? MainnetSpecProvider.Instance); - EthereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId, LogManager); - DbProvider = await CreateDbProvider(); - TrieStore = new TrieStore(StateDb, LogManager); - State = new StateProvider(TrieStore, DbProvider.CodeDb, LogManager); - State.CreateAccount(TestItem.AddressA, (initialValues ?? InitialValue)); - State.CreateAccount(TestItem.AddressB, (initialValues ?? InitialValue)); - State.CreateAccount(TestItem.AddressC, (initialValues ?? InitialValue)); - byte[] code = Bytes.FromHexString("0xabcd"); - Keccak codeHash = Keccak.Compute(code); - State.UpdateCode(code); - State.UpdateCodeHash(TestItem.AddressA, codeHash, SpecProvider.GenesisSpec); - - Storage = new StorageProvider(TrieStore, State, LogManager); - Storage.Set(new StorageCell(TestItem.AddressA, UInt256.One), Bytes.FromHexString("0xabcdef")); - Storage.Commit(); - - State.Commit(SpecProvider.GenesisSpec); - State.CommitTree(0); - - ReadOnlyTrieStore = TrieStore.AsReadOnly(StateDb); - StateReader = new StateReader(ReadOnlyTrieStore, CodeDb, LogManager); - - IDb blockDb = new MemDb(); - IDb headerDb = new MemDb(); - IDb blockInfoDb = new MemDb(); - BlockTree = new BlockTree(blockDb, headerDb, blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), SpecProvider, NullBloomStorage.Instance, LimboLogs.Instance); - ReadOnlyState = new ChainHeadReadOnlyStateProvider(BlockTree, StateReader); - TransactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockTree); - TxPool = CreateTxPool(); - - _trieStoreWatcher = new TrieStoreBoundaryWatcher(TrieStore, BlockTree, LogManager); - - ReceiptStorage = new InMemoryReceiptStorage(); - VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, LogManager), SpecProvider, LogManager); - TxProcessor = new TransactionProcessor(SpecProvider, State, Storage, virtualMachine, LogManager); - BlockPreprocessorStep = new RecoverSignatures(EthereumEcdsa, TxPool, SpecProvider, LogManager); - HeaderValidator = new HeaderValidator(BlockTree, Always.Valid, SpecProvider, LogManager); - - new ReceiptCanonicalityMonitor(BlockTree, ReceiptStorage, LogManager); - - BlockValidator = new BlockValidator( - new TxValidator(SpecProvider.ChainId), - HeaderValidator, - Always.Valid, - SpecProvider, - LogManager); - - PoSSwitcher = NoPoS.Instance; - ISealer sealer = new NethDevSealEngine(TestItem.AddressD); - SealEngine = new SealEngine(sealer, Always.Valid); - - BloomStorage bloomStorage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); - ReceiptsRecovery receiptsRecovery = new(new EthereumEcdsa(SpecProvider.ChainId, LimboLogs.Instance), SpecProvider); - LogFinder = new LogFinder(BlockTree, ReceiptStorage, ReceiptStorage, bloomStorage, LimboLogs.Instance, receiptsRecovery); - BlockProcessor = CreateBlockProcessor(); - - BlockchainProcessor chainProcessor = new(BlockTree, BlockProcessor, BlockPreprocessorStep, StateReader, LogManager, Consensus.Processing.BlockchainProcessor.Options.Default); - BlockchainProcessor = chainProcessor; - BlockProcessingQueue = chainProcessor; - chainProcessor.Start(); - - TxPoolTxSource txPoolTxSource = CreateTxPoolTxSource(); - ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockFinder); - BlockProducer = CreateTestBlockProducer(txPoolTxSource, sealer, transactionComparerProvider); - await BlockProducer.Start(); - Suggester = new ProducedBlockSuggester(BlockTree, BlockProducer); - - _resetEvent = new SemaphoreSlim(0); - _suggestedBlockResetEvent = new ManualResetEvent(true); - BlockTree.NewHeadBlock += OnNewHeadBlock; - BlockProducer.BlockProduced += (s, e) => - { - _suggestedBlockResetEvent.Set(); - }; - - Block? genesis = GetGenesisBlock(); - BlockTree.SuggestBlock(genesis); - - await WaitAsync(_resetEvent, "Failed to process genesis in time."); - await AddBlocksOnStart(); - return this; - } + _suggestedBlockResetEvent.Set(); + }; - private static ISpecProvider CreateSpecProvider(ISpecProvider specProvider) - { - return specProvider is TestSpecProvider { AllowTestChainOverride: false } - ? specProvider - : new OverridableSpecProvider(specProvider, s => new OverridableReleaseSpec(s) { IsEip3607Enabled = false }); - } + Block? genesis = GetGenesisBlock(); + BlockTree.SuggestBlock(genesis); - private void OnNewHeadBlock(object? sender, BlockEventArgs e) - { - _resetEvent.Release(1); - } + await WaitAsync(_resetEvent, "Failed to process genesis in time."); + await AddBlocksOnStart(); + return this; + } - protected virtual Task CreateDbProvider() => TestMemDbProvider.InitAsync(); + private static ISpecProvider CreateSpecProvider(ISpecProvider specProvider) + { + return specProvider is TestSpecProvider { AllowTestChainOverride: false } + ? specProvider + : new OverridableSpecProvider(specProvider, s => new OverridableReleaseSpec(s) { IsEip3607Enabled = false }); + } - private async Task WaitAsync(SemaphoreSlim semaphore, string error, int timeout = DefaultTimeout) - { - if (!await semaphore.WaitAsync(timeout)) - { - throw new InvalidOperationException(error); - } - } + private void OnNewHeadBlock(object? sender, BlockEventArgs e) + { + _resetEvent.Release(1); + } - private async Task WaitAsync(EventWaitHandle eventWaitHandle, string error, int timeout = DefaultTimeout) + protected virtual Task CreateDbProvider() => TestMemDbProvider.InitAsync(); + + private async Task WaitAsync(SemaphoreSlim semaphore, string error, int timeout = DefaultTimeout) + { + if (!await semaphore.WaitAsync(timeout)) { - if (!await eventWaitHandle.WaitOneAsync(timeout, CancellationToken.None)) - { - throw new InvalidOperationException(error); - } + throw new InvalidOperationException(error); } + } - protected virtual IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer, ITransactionComparerProvider transactionComparerProvider) + private async Task WaitAsync(EventWaitHandle eventWaitHandle, string error, int timeout = DefaultTimeout) + { + if (!await eventWaitHandle.WaitOneAsync(timeout, CancellationToken.None)) { - BlocksConfig blocksConfig = new(); - - BlockProducerEnvFactory blockProducerEnvFactory = new( - DbProvider, - BlockTree, - ReadOnlyTrieStore, - SpecProvider, - BlockValidator, - NoBlockRewards.Instance, - ReceiptStorage, - BlockPreprocessorStep, - TxPool, - transactionComparerProvider, - blocksConfig, - LogManager); - - BlockProducerEnv env = blockProducerEnvFactory.Create(txPoolTxSource); - return new TestBlockProducer( - env.TxSource, - env.ChainProcessor, - env.ReadOnlyStateProvider, - sealer, - BlockTree, - BlockProductionTrigger, - Timestamper, - SpecProvider, - LogManager, - blocksConfig); + throw new InvalidOperationException(error); } + } - public virtual ILogManager LogManager { get; } = LimboLogs.Instance; + protected virtual IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer, ITransactionComparerProvider transactionComparerProvider) + { + BlocksConfig blocksConfig = new(); + + BlockProducerEnvFactory blockProducerEnvFactory = new( + DbProvider, + BlockTree, + ReadOnlyTrieStore, + SpecProvider, + BlockValidator, + NoBlockRewards.Instance, + ReceiptStorage, + BlockPreprocessorStep, + TxPool, + transactionComparerProvider, + blocksConfig, + LogManager); + + BlockProducerEnv env = blockProducerEnvFactory.Create(txPoolTxSource); + return new TestBlockProducer( + env.TxSource, + env.ChainProcessor, + env.ReadOnlyStateProvider, + sealer, + BlockTree, + BlockProductionTrigger, + Timestamper, + SpecProvider, + LogManager, + blocksConfig); + } + + public virtual ILogManager LogManager { get; set; } = LimboLogs.Instance; - protected virtual TxPool.TxPool CreateTxPool() => - new( - EthereumEcdsa, - new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(SpecProvider), BlockTree, ReadOnlyState), - new TxPoolConfig(), - new TxValidator(SpecProvider.ChainId), - LogManager, - TransactionComparerProvider.GetDefaultComparer()); + protected virtual TxPool.TxPool CreateTxPool() => + new( + EthereumEcdsa, + new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(SpecProvider), BlockTree, ReadOnlyState), + new TxPoolConfig(), + new TxValidator(SpecProvider.ChainId), + LogManager, + TransactionComparerProvider.GetDefaultComparer()); - protected virtual TxPoolTxSource CreateTxPoolTxSource() + protected virtual TxPoolTxSource CreateTxPoolTxSource() + { + BlocksConfig blocksConfig = new() { - BlocksConfig blocksConfig = new() - { - MinGasPrice = 0 - }; - ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(LimboLogs.Instance, - SpecProvider, blocksConfig); - return new TxPoolTxSource(TxPool, SpecProvider, TransactionComparerProvider, LogManager, txFilterPipeline); - } + MinGasPrice = 0 + }; + ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(LimboLogs.Instance, + SpecProvider, blocksConfig); + return new TxPoolTxSource(TxPool, SpecProvider, TransactionComparerProvider, LogManager, txFilterPipeline); + } - public BlockBuilder GenesisBlockBuilder { get; set; } = null!; + public BlockBuilder GenesisBlockBuilder { get; set; } = null!; - protected virtual Block GetGenesisBlock() + protected virtual Block GetGenesisBlock() + { + BlockBuilder genesisBlockBuilder = Builders.Build.A.Block.Genesis; + if (GenesisBlockBuilder is not null) { - BlockBuilder genesisBlockBuilder = Builders.Build.A.Block.Genesis; - if (GenesisBlockBuilder is not null) - { - genesisBlockBuilder = GenesisBlockBuilder; - } - - genesisBlockBuilder.WithStateRoot(State.StateRoot); - if (SealEngineType == Nethermind.Core.SealEngineType.AuRa) - { - genesisBlockBuilder.WithAura(0, new byte[65]); - } - - return genesisBlockBuilder.TestObject; + genesisBlockBuilder = GenesisBlockBuilder; } - protected virtual async Task AddBlocksOnStart() + genesisBlockBuilder.WithStateRoot(State.StateRoot); + if (SealEngineType == Nethermind.Core.SealEngineType.AuRa) { - await AddBlock(); - await AddBlock(BuildSimpleTransaction.WithNonce(0).TestObject); - await AddBlock(BuildSimpleTransaction.WithNonce(1).TestObject, BuildSimpleTransaction.WithNonce(2).TestObject); + genesisBlockBuilder.WithAura(0, new byte[65]); } - protected virtual IBlockProcessor CreateBlockProcessor() => - new BlockProcessor( - SpecProvider, - BlockValidator, - NoBlockRewards.Instance, - new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State), - State, - Storage, - ReceiptStorage, - NullWitnessCollector.Instance, - LogManager); - - public async Task WaitForNewHead() - { - await WaitAsync(_resetEvent, "Failed to produce new head in time."); - _suggestedBlockResetEvent.Reset(); - } + return genesisBlockBuilder.TestObject; + } - public async Task AddBlock(params Transaction[] transactions) - { - await AddBlockInternal(transactions); + protected virtual async Task AddBlocksOnStart() + { + await AddBlock(); + await AddBlock(BuildSimpleTransaction.WithNonce(0).TestObject); + await AddBlock(BuildSimpleTransaction.WithNonce(1).TestObject, BuildSimpleTransaction.WithNonce(2).TestObject); + } - await WaitAsync(_resetEvent, "Failed to produce new head in time."); - _suggestedBlockResetEvent.Reset(); - _oneAtATime.Set(); - } + protected virtual IBlockProcessor CreateBlockProcessor() => + new BlockProcessor( + SpecProvider, + BlockValidator, + NoBlockRewards.Instance, + new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State), + State, + Storage, + ReceiptStorage, + NullWitnessCollector.Instance, + LogManager); + + public async Task WaitForNewHead() + { + await WaitAsync(_resetEvent, "Failed to produce new head in time."); + _suggestedBlockResetEvent.Reset(); + } - public async Task AddBlock(bool shouldWaitForHead = true, params Transaction[] transactions) - { - await AddBlockInternal(transactions); - - if (shouldWaitForHead) - { - await WaitAsync(_resetEvent, "Failed to produce new head in time."); - } - else - { - await WaitAsync(_suggestedBlockResetEvent, "Failed to produce new suggested block in time."); - } - - _oneAtATime.Set(); - } + public async Task AddBlock(params Transaction[] transactions) + { + await AddBlockInternal(transactions); + + await WaitAsync(_resetEvent, "Failed to produce new head in time."); + _suggestedBlockResetEvent.Reset(); + _oneAtATime.Set(); + } - private async Task AddBlockInternal(params Transaction[] transactions) + public async Task AddBlock(bool shouldWaitForHead = true, params Transaction[] transactions) + { + await AddBlockInternal(transactions); + + if (shouldWaitForHead) { - // we want it to be last event, so lets re-register - BlockTree.NewHeadBlock -= OnNewHeadBlock; - BlockTree.NewHeadBlock += OnNewHeadBlock; - - await WaitAsync(_oneAtATime, "Multiple block produced at once."); - AcceptTxResult[] txResults = transactions.Select(t => TxPool.SubmitTx(t, TxHandlingOptions.None)).ToArray(); - Timestamper.Add(TimeSpan.FromSeconds(1)); - await BlockProductionTrigger.BuildBlock(); - return txResults; + await WaitAsync(_resetEvent, "Failed to produce new head in time."); } - - public void AddTransactions(params Transaction[] txs) + else { - for (int i = 0; i < txs.Length; i++) - { - TxPool.SubmitTx(txs[i], TxHandlingOptions.None); - } + await WaitAsync(_suggestedBlockResetEvent, "Failed to produce new suggested block in time."); } - public virtual void Dispose() + _oneAtATime.Set(); + } + + private async Task AddBlockInternal(params Transaction[] transactions) + { + // we want it to be last event, so lets re-register + BlockTree.NewHeadBlock -= OnNewHeadBlock; + BlockTree.NewHeadBlock += OnNewHeadBlock; + + await WaitAsync(_oneAtATime, "Multiple block produced at once."); + AcceptTxResult[] txResults = transactions.Select(t => TxPool.SubmitTx(t, TxHandlingOptions.None)).ToArray(); + Timestamper.Add(TimeSpan.FromSeconds(1)); + await BlockProductionTrigger.BuildBlock(); + return txResults; + } + + public void AddTransactions(params Transaction[] txs) + { + for (int i = 0; i < txs.Length; i++) { - BlockProducer?.StopAsync(); - CodeDb?.Dispose(); - StateDb?.Dispose(); - _trieStoreWatcher?.Dispose(); - DbProvider?.Dispose(); + TxPool.SubmitTx(txs[i], TxHandlingOptions.None); } + } - /// - /// Creates a simple transfer transaction with value defined by - /// from a rich account to - /// - /// Address to add funds to - /// Value of ether to add to the account - /// - public async Task AddFunds(Address address, UInt256 ether) => - await AddBlock(GetFundsTransaction(address, ether)); + public virtual void Dispose() + { + BlockProducer?.StopAsync(); + CodeDb?.Dispose(); + StateDb?.Dispose(); + _trieStoreWatcher?.Dispose(); + DbProvider?.Dispose(); + } - public async Task AddFunds(params (Address address, UInt256 ether)[] funds) => - await AddBlock(funds.Select((f, i) => GetFundsTransaction(f.address, f.ether, (uint)i)).ToArray()); + /// + /// Creates a simple transfer transaction with value defined by + /// from a rich account to + /// + /// Address to add funds to + /// Value of ether to add to the account + /// + public async Task AddFunds(Address address, UInt256 ether) => + await AddBlock(GetFundsTransaction(address, ether)); - public async Task AddFundsAfterLondon(params (Address address, UInt256 ether)[] funds) => - await AddBlock(funds.Select((f, i) => GetFunds1559Transaction(f.address, f.ether, (uint)i)).ToArray()); + public async Task AddFunds(params (Address address, UInt256 ether)[] funds) => + await AddBlock(funds.Select((f, i) => GetFundsTransaction(f.address, f.ether, (uint)i)).ToArray()); - private Transaction GetFundsTransaction(Address address, UInt256 ether, uint index = 0) - { - UInt256 nonce = StateReader.GetNonce(BlockTree.Head!.StateRoot!, TestItem.AddressA); - Transaction tx = Builders.Build.A.Transaction - .SignedAndResolved(TestItem.PrivateKeyA) - .To(address) - .WithNonce(nonce + index) - .WithValue(ether) - .TestObject; - return tx; - } + public async Task AddFundsAfterLondon(params (Address address, UInt256 ether)[] funds) => + await AddBlock(funds.Select((f, i) => GetFunds1559Transaction(f.address, f.ether, (uint)i)).ToArray()); - private Transaction GetFunds1559Transaction(Address address, UInt256 ether, uint index = 0) - { - UInt256 nonce = StateReader.GetNonce(BlockTree.Head!.StateRoot!, TestItem.AddressA); - Transaction tx = Builders.Build.A.Transaction - .SignedAndResolved(TestItem.PrivateKeyA) - .To(address) - .WithNonce(nonce + index) - .WithMaxFeePerGas(20.GWei()) - .WithMaxPriorityFeePerGas(5.GWei()) - .WithType(TxType.EIP1559) - .WithValue(ether) - .WithChainId(MainnetSpecProvider.Instance.ChainId) - .TestObject; - return tx; - } + private Transaction GetFundsTransaction(Address address, UInt256 ether, uint index = 0) + { + UInt256 nonce = StateReader.GetNonce(BlockTree.Head!.StateRoot!, TestItem.AddressA); + Transaction tx = Builders.Build.A.Transaction + .SignedAndResolved(TestItem.PrivateKeyA) + .To(address) + .WithNonce(nonce + index) + .WithValue(ether) + .TestObject; + return tx; + } + + private Transaction GetFunds1559Transaction(Address address, UInt256 ether, uint index = 0) + { + UInt256 nonce = StateReader.GetNonce(BlockTree.Head!.StateRoot!, TestItem.AddressA); + Transaction tx = Builders.Build.A.Transaction + .SignedAndResolved(TestItem.PrivateKeyA) + .To(address) + .WithNonce(nonce + index) + .WithMaxFeePerGas(20.GWei()) + .WithMaxPriorityFeePerGas(5.GWei()) + .WithType(TxType.EIP1559) + .WithValue(ether) + .WithChainId(MainnetSpecProvider.Instance.ChainId) + .TestObject; + return tx; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index bddfbaeb6a9..d8513ad68e0 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -139,7 +139,7 @@ public MergeTestBlockchain(IMergeConfig? mergeConfig = null, IPayloadPreparation protected override Task AddBlocksOnStart() => Task.CompletedTask; - public sealed override ILogManager LogManager { get; } = LimboLogs.Instance; + public sealed override ILogManager LogManager { get; set; } = LimboLogs.Instance; public IEthSyncingInfo? EthSyncingInfo { get; protected set; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs index 1485cd95ab2..bcc3036d862 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs @@ -24,12 +24,14 @@ using Nethermind.JsonRpc.Modules.Eth; using Nethermind.JsonRpc.Test; using Nethermind.JsonRpc.Test.Modules; +using Nethermind.Logging; using Nethermind.Merge.Plugin.Data; using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.State; using Nethermind.Trie; using Newtonsoft.Json; +using NSubstitute; using NUnit.Framework; namespace Nethermind.Merge.Plugin.Test; @@ -1666,7 +1668,6 @@ public async Task Should_return_capabilities() { using var chain = await CreateBlockChain(); var rpcModule = CreateEngineModule(chain); - var expected = new[] { "engine_exchangeTransitionConfigurationV1", @@ -1686,6 +1687,22 @@ public async Task Should_return_capabilities() result.Data.Should().BeEquivalentTo(expected); } + [Test] + public async Task Should_warn_for_missing_capabilities() + { + using var chain = await CreateBlockChain(); + chain.LogManager = Substitute.For(); + chain.LogManager.GetClassLogger().IsWarn.Returns(true); + + var rpcModule = CreateEngineModule(chain); + var unsupportedMethod = "unsupportedMethod"; + + var result = await rpcModule.engine_exchangeCapabilities(new[] { unsupportedMethod }); + + chain.LogManager.GetClassLogger().Received().Warn( + Arg.Is(a => a.Contains(unsupportedMethod, StringComparison.Ordinal))); + } + private async Task BuildAndGetPayloadResult( IEngineRpcModule rpc, MergeTestBlockchain chain, Keccak headBlockHash, Keccak finalizedBlockHash, Keccak safeBlockHash,