diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs index 7a56124ded3..fdd18b07f61 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs @@ -24,7 +24,7 @@ namespace Nethermind.Consensus.Processing; public sealed class BlockCachePreWarmer(ReadOnlyTxProcessingEnvFactory envFactory, ISpecProvider specProvider, ILogManager logManager, PreBlockCaches? preBlockCaches = null) : IBlockCachePreWarmer { - private readonly ObjectPool _envPool = new DefaultObjectPool(new ReadOnlyTxProcessingEnvPooledObjectPolicy(envFactory), Environment.ProcessorCount * 4); + private readonly ObjectPool _envPool = new DefaultObjectPool(new ReadOnlyTxProcessingEnvPooledObjectPolicy(envFactory), Environment.ProcessorCount * 2); private readonly ILogger _logger = logManager.GetClassLogger(); public Task PreWarmCaches(Block suggestedBlock, Hash256? parentStateRoot, IReleaseSpec spec, CancellationToken cancellationToken = default, params ReadOnlySpan systemAccessLists) @@ -135,9 +135,14 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp try { - ParallelUnbalancedWork.For(0, block.Transactions.Length, parallelOptions, new(this, block, stateRoot, spec), static (i, state) => + BlockState blockState = new(this, block, stateRoot, spec); + ParallelUnbalancedWork.For( + 0, + block.Transactions.Length, + parallelOptions, + blockState.InitThreadState, + static (i, state) => { - IReadOnlyTxProcessorSource env = state.PreWarmer._envPool.Get(); Transaction? tx = null; try { @@ -145,12 +150,12 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp if (state.Block.TransactionProcessed > i) return state; tx = state.Block.Transactions[i]; - using IReadOnlyTxProcessingScope scope = env.Build(state.StateRoot); Address senderAddress = tx.SenderAddress!; - if (!scope.WorldState.AccountExists(senderAddress)) + IWorldState worldState = state.Scope.WorldState; + if (!worldState.AccountExists(senderAddress)) { - scope.WorldState.CreateAccountIfNotExists(senderAddress, UInt256.Zero); + worldState.CreateAccountIfNotExists(senderAddress, UInt256.Zero); } UInt256 nonceDelta = UInt256.Zero; @@ -164,14 +169,14 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp if (!nonceDelta.IsZero) { - scope.WorldState.IncrementNonce(senderAddress, nonceDelta); + worldState.IncrementNonce(senderAddress, nonceDelta); } if (state.Spec.UseTxAccessLists) { - scope.WorldState.WarmUp(tx.AccessList); // eip-2930 + worldState.WarmUp(tx.AccessList); // eip-2930 } - TransactionResult result = scope.TransactionProcessor.Warmup(tx, new BlockExecutionContext(state.BlockHeader, state.Spec), NullTxTracer.Instance); + TransactionResult result = state.Scope.TransactionProcessor.Warmup(tx, new BlockExecutionContext(state.BlockHeader, state.Spec), NullTxTracer.Instance); if (state.PreWarmer._logger.IsTrace) state.PreWarmer._logger.Trace($"Finished pre-warming cache for tx[{i}] {tx.Hash} with {result}"); } catch (Exception ex) when (ex is EvmException or OverflowException) @@ -182,13 +187,10 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp { if (state.PreWarmer._logger.IsDebug) state.PreWarmer._logger.Error($"DEBUG/ERROR Error pre-warming cache {tx?.Hash}", ex); } - finally - { - state.PreWarmer._envPool.Return(env); - } return state; - }); + }, + BlockState.FinallyAction); } catch (OperationCanceledException) { @@ -345,13 +347,32 @@ private class ReadOnlyTxProcessingEnvPooledObjectPolicy(ReadOnlyTxProcessingEnvF public bool Return(IReadOnlyTxProcessorSource obj) => true; } - private readonly struct BlockState(BlockCachePreWarmer preWarmer, Block block, Hash256 stateRoot, IReleaseSpec spec) + private readonly struct BlockState(BlockCachePreWarmer preWarmer, Block block, Hash256 stateRoot, IReleaseSpec spec, IReadOnlyTxProcessorSource env = null, IReadOnlyTxProcessingScope scope = null) { + public static Action FinallyAction { get; } = DisposeThreadState; + public readonly BlockCachePreWarmer PreWarmer = preWarmer; public readonly Block Block = block; public readonly Hash256 StateRoot = stateRoot; public readonly IReleaseSpec Spec = spec; public readonly BlockHeader BlockHeader => Block.Header; + public readonly IReadOnlyTxProcessorSource Env = env; + public readonly IReadOnlyTxProcessingScope Scope = scope; + + public BlockState InitThreadState() + { + IReadOnlyTxProcessorSource env = PreWarmer._envPool.Get(); + IReadOnlyTxProcessingScope scope = env.Build(StateRoot); + return new(PreWarmer, Block, StateRoot, Spec, env, scope); + } + + public void Dispose() + { + Scope.Dispose(); + PreWarmer._envPool.Return(Env); + } + + private static void DisposeThreadState(BlockState state) => state.Dispose(); } }