diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs index a0d03305873..22a50743061 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs @@ -1170,6 +1170,38 @@ public void Loads_lowest_inserted_header_correctly(long beginIndex, long inserte Assert.That(loadedTree.LowestInsertedHeader?.Number, Is.EqualTo(expectedResult), "loaded tree"); } + [TestCase(5, 10)] + [TestCase(10, 10)] + [TestCase(12, 0)] + public void Does_not_load_bestKnownNumber_before_syncPivot(long syncPivot, long expectedBestKnownNumber) + { + SyncConfig syncConfig = new() + { + FastSync = true, + PivotNumber = $"{syncPivot}" + }; + + MemDb blockInfosDb = new MemDb(); + MemDb headersDb = new MemDb(); + MemDb blockDb = new MemDb(); + + _ = Build.A.BlockTree() + .WithHeadersDb(headersDb) + .WithBlockInfoDb(blockInfosDb) + .WithBlocksDb(blockDb) + .OfChainLength(11) + .TestObject; + + BlockTree tree = Build.A.BlockTree() + .WithSyncConfig(syncConfig) + .WithHeadersDb(headersDb) + .WithBlockInfoDb(blockInfosDb) + .WithBlocksDb(blockDb) + .TestObject; + + Assert.That(tree.BestKnownNumber, Is.EqualTo(expectedBestKnownNumber)); + } + private static readonly object[] SourceOfBSearchTestCases = { new object[] {1L, 0L}, diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTree.Initializer.cs b/src/Nethermind/Nethermind.Blockchain/BlockTree.Initializer.cs index 61290c3ff63..ef52ac0b413 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockTree.Initializer.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockTree.Initializer.cs @@ -140,30 +140,15 @@ private void LoadBestKnown() long right = Math.Max(0, left) + BestKnownSearchLimit; - long bestKnownNumberFound = - BinarySearchBlockNumber(1, left, LevelExists) ?? 0; - long bestKnownNumberAlternative = - BinarySearchBlockNumber(left, right, LevelExists) ?? 0; - - long bestSuggestedHeaderNumber = - BinarySearchBlockNumber(1, left, HeaderExists) ?? 0; - long bestSuggestedHeaderNumberAlternative - = BinarySearchBlockNumber(left, right, HeaderExists) ?? 0; - - long bestSuggestedBodyNumber - = BinarySearchBlockNumber(1, left, BodyExists) ?? 0; - long bestSuggestedBodyNumberAlternative - = BinarySearchBlockNumber(left, right, BodyExists) ?? 0; + long bestKnownNumberFound = BinarySearchBlockNumber(left, right, LevelExists) ?? 0; + long bestSuggestedHeaderNumber = BinarySearchBlockNumber(left, right, HeaderExists) ?? 0; + long bestSuggestedBodyNumber = BinarySearchBlockNumber(left, right, BodyExists) ?? 0; if (_logger.IsInfo) _logger.Info("Numbers resolved, " + - $"level = Max({bestKnownNumberFound}, {bestKnownNumberAlternative}), " + - $"header = Max({bestSuggestedHeaderNumber}, {bestSuggestedHeaderNumberAlternative}), " + - $"body = Max({bestSuggestedBodyNumber}, {bestSuggestedBodyNumberAlternative})"); - - bestKnownNumberFound = Math.Max(bestKnownNumberFound, bestKnownNumberAlternative); - bestSuggestedHeaderNumber = Math.Max(bestSuggestedHeaderNumber, bestSuggestedHeaderNumberAlternative); - bestSuggestedBodyNumber = Math.Max(bestSuggestedBodyNumber, bestSuggestedBodyNumberAlternative); + $"level = {bestKnownNumberFound}, " + + $"header = {bestSuggestedHeaderNumber}, " + + $"body = {bestSuggestedBodyNumber}"); if (bestKnownNumberFound < 0 || bestSuggestedHeaderNumber < 0 || @@ -187,7 +172,7 @@ long bestSuggestedBodyNumberAlternative } } - BestKnownNumber = Math.Max(bestKnownNumberFound, bestKnownNumberAlternative); + BestKnownNumber = bestKnownNumberFound; BestSuggestedHeader = FindHeader(bestSuggestedHeaderNumber, BlockTreeLookupOptions.None); BlockHeader? bestSuggestedBodyHeader = FindHeader(bestSuggestedBodyNumber, BlockTreeLookupOptions.None); BestSuggestedBody = bestSuggestedBodyHeader is null diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTreeExtensions.cs b/src/Nethermind/Nethermind.Blockchain/BlockTreeExtensions.cs index 99412dc594b..a0f7a216525 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockTreeExtensions.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockTreeExtensions.cs @@ -10,5 +10,14 @@ public static class BlockTreeExtensions public static ReadOnlyBlockTree AsReadOnly(this IBlockTree blockTree) => new(blockTree); public static BlockHeader? GetProducedBlockParent(this IBlockTree blockTree, BlockHeader? parentHeader) => parentHeader ?? blockTree.Head?.Header; + + public static (bool isSyncing, long headNumber, long bestSuggested) IsSyncing(this IBlockTree blockTree, int maxDistanceForSynced = 0) + { + long bestSuggestedNumber = blockTree.FindBestSuggestedHeader()?.Number ?? 0; + long headNumberOrZero = blockTree.Head?.Number ?? 0; + bool isSyncing = bestSuggestedNumber == 0 || bestSuggestedNumber > headNumberOrZero + maxDistanceForSynced; + + return (isSyncing, headNumberOrZero, bestSuggestedNumber); + } } } diff --git a/src/Nethermind/Nethermind.Blockchain/ChainHeadInfoProvider.cs b/src/Nethermind/Nethermind.Blockchain/ChainHeadInfoProvider.cs index 3c90e3dc736..77cccd0e7d5 100644 --- a/src/Nethermind/Nethermind.Blockchain/ChainHeadInfoProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/ChainHeadInfoProvider.cs @@ -17,6 +17,10 @@ namespace Nethermind.Blockchain { public class ChainHeadInfoProvider : IChainHeadInfoProvider { + private readonly IBlockTree _blockTree; + // For testing + public bool HasSynced { private get; init; } + public ChainHeadInfoProvider(ISpecProvider specProvider, IBlockTree blockTree, IStateReader stateReader, ICodeInfoRepository codeInfoRepository) : this(new ChainHeadSpecProvider(specProvider, blockTree), blockTree, new ChainHeadReadOnlyStateProvider(blockTree, stateReader), codeInfoRepository) { @@ -35,6 +39,7 @@ public ChainHeadInfoProvider(IChainHeadSpecProvider specProvider, IBlockTree blo CodeInfoRepository = codeInfoRepository; blockTree.BlockAddedToMain += OnHeadChanged; + _blockTree = blockTree; } public IChainHeadSpecProvider SpecProvider { get; } @@ -51,6 +56,20 @@ public ChainHeadInfoProvider(IChainHeadSpecProvider specProvider, IBlockTree blo public UInt256 CurrentFeePerBlobGas { get; internal set; } + public bool IsSyncing + { + get + { + if (HasSynced) + { + return false; + } + + (bool isSyncing, _, _) = _blockTree.IsSyncing(maxDistanceForSynced: 2); + return isSyncing; + } + } + public event EventHandler? HeadChanged; private void OnHeadChanged(object? sender, BlockReplacementEventArgs e) diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs index 53b97a680b4..9643fb56daa 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading; +using System.Threading.Channels; using System.Threading.Tasks; using System.Timers; using Nethermind.Blockchain; @@ -67,8 +68,7 @@ public CliqueBlockProducerRunner( _timer.Start(); } - private readonly BlockingCollection _signalsQueue = - new(new ConcurrentQueue()); + private readonly Channel _signalsQueue = Channel.CreateUnbounded(); private Block? _scheduledBlock; @@ -91,7 +91,7 @@ public void UncastVote(Address signer) public void ProduceOnTopOf(Hash256 hash) { - _signalsQueue.Add(_blockTree.FindBlock(hash, BlockTreeLookupOptions.None)); + _signalsQueue.Writer.TryWrite(_blockTree.FindBlock(hash, BlockTreeLookupOptions.None)); } public IReadOnlyDictionary GetProposals() => _blockProducer.Proposals.ToDictionary(); @@ -111,7 +111,7 @@ private void TimerOnElapsed(object sender, ElapsedEventArgs e) { if (_blockTree.Head.Timestamp + _config.BlockPeriod < _timestamper.UnixTime.Seconds) { - _signalsQueue.Add(_blockTree.FindBlock(_blockTree.Head.Hash, BlockTreeLookupOptions.None)); + _signalsQueue.Writer.TryWrite(_blockTree.FindBlock(_blockTree.Head.Hash, BlockTreeLookupOptions.None)); } _timer.Enabled = true; @@ -216,17 +216,17 @@ private Task RunConsumeSignal() private void BlockTreeOnNewHeadBlock(object? sender, BlockEventArgs e) { - _signalsQueue.Add(e.Block); + _signalsQueue.Writer.TryWrite(e.Block); } private async Task ConsumeSignal() { _lastProducedBlock = DateTime.UtcNow; - foreach (Block signal in _signalsQueue.GetConsumingEnumerable(_cancellationTokenSource.Token)) + await foreach (Block signal in _signalsQueue.Reader.ReadAllAsync(_cancellationTokenSource.Token)) { // TODO: Maybe use IBlockProducer specific to clique? Block parentBlock = signal; - while (_signalsQueue.TryTake(out Block? nextSignal)) + while (_signalsQueue.Reader.TryRead(out Block? nextSignal)) { if (parentBlock.Number <= nextSignal.Number) { @@ -259,6 +259,7 @@ public async Task StopAsync() _blockTree.NewHeadBlock -= BlockTreeOnNewHeadBlock; _cancellationTokenSource?.Cancel(); await (_producerTask ?? Task.CompletedTask); + _signalsQueue.Writer.TryComplete(); } bool IBlockProducerRunner.IsProducingBlocks(ulong? maxProducingInterval) @@ -273,11 +274,12 @@ bool IBlockProducerRunner.IsProducingBlocks(ulong? maxProducingInterval) public event EventHandler? BlockProduced; - public void Dispose() { _cancellationTokenSource?.Dispose(); _timer?.Dispose(); + _signalsQueue.Writer.TryComplete(); + BlockProduced = null; } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs index 018da79aa26..ace943c6a4c 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs @@ -69,13 +69,8 @@ public CensorshipDetector( private bool IsSyncing() { - long bestSuggestedNumber = _blockTree.FindBestSuggestedHeader()?.Number ?? 0; - if (bestSuggestedNumber == 0) - { - return true; - } - long headNumberOrZero = _blockTree.Head?.Number ?? 0; - return bestSuggestedNumber > headNumberOrZero; + (bool isSyncing, _, _) = _blockTree.IsSyncing(); + return isSyncing; } private void OnBlockProcessing(object? sender, BlockEventArgs e) diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index d8411dcd46d..cb721272e2a 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -320,7 +320,7 @@ protected virtual TxPool.TxPool CreateTxPool(CodeInfoRepository codeInfoReposito new( EthereumEcdsa, new BlobTxStorage(), - new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(SpecProvider), BlockTree, ReadOnlyState, codeInfoRepository), + new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(SpecProvider), BlockTree, ReadOnlyState, codeInfoRepository) { HasSynced = true }, new TxPoolConfig { BlobsSupport = BlobsSupportMode.InMemory }, new TxValidator(SpecProvider.ChainId), LogManager, diff --git a/src/Nethermind/Nethermind.Core/Caching/ClockCache.cs b/src/Nethermind/Nethermind.Core/Caching/ClockCache.cs index 8d30ef44fce..774b36c8cfa 100644 --- a/src/Nethermind/Nethermind.Core/Caching/ClockCache.cs +++ b/src/Nethermind/Nethermind.Core/Caching/ClockCache.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; - +using System.Runtime.InteropServices; using Nethermind.Core.Collections; using Nethermind.Core.Threading; @@ -24,7 +24,7 @@ public TValue Get(TKey key) { if (MaxCapacity == 0) return default!; - if (_cacheMap.TryGetValue(key, out LruCacheItem? ov)) + if (_cacheMap.TryGetValue(key, out LruCacheItem ov)) { MarkAccessed(ov.Offset); return ov.Value; @@ -37,7 +37,7 @@ public bool TryGet(TKey key, out TValue value) value = default!; if (MaxCapacity == 0) return false; - if (_cacheMap.TryGetValue(key, out LruCacheItem? ov)) + if (_cacheMap.TryGetValue(key, out LruCacheItem ov)) { MarkAccessed(ov.Offset); value = ov.Value; @@ -56,9 +56,9 @@ public bool Set(TKey key, TValue val) return Delete(key); } - if (_cacheMap.TryGetValue(key, out LruCacheItem? ov)) + if (_cacheMap.TryGetValue(key, out LruCacheItem ov)) { - ov.Value = val; + _cacheMap[key] = new(val, ov.Offset); MarkAccessed(ov.Offset); return false; } @@ -71,9 +71,9 @@ private bool SetSlow(TKey key, TValue val) using var lockRelease = _lock.Acquire(); // Recheck under lock - if (_cacheMap.TryGetValue(key, out LruCacheItem? ov)) + if (_cacheMap.TryGetValue(key, out LruCacheItem ov)) { - ov.Value = val; + _cacheMap[key] = new(val, ov.Offset); MarkAccessed(ov.Offset); return false; } @@ -89,7 +89,7 @@ private bool SetSlow(TKey key, TValue val) offset = Replace(key); } - _cacheMap[key] = new LruCacheItem(offset, val); + _cacheMap[key] = new(val, offset); KeyToOffset[offset] = key; _count++; Debug.Assert(_cacheMap.Count == _count); @@ -138,7 +138,7 @@ public bool Delete(TKey key) using var lockRelease = _lock.Acquire(); - if (_cacheMap.Remove(key, out LruCacheItem? ov)) + if (_cacheMap.Remove(key, out LruCacheItem ov)) { _count--; KeyToOffset[ov.Offset] = default; @@ -166,9 +166,10 @@ public bool Contains(TKey key) return _cacheMap.ContainsKey(key); } - private class LruCacheItem(int offset, TValue v) + [StructLayout(LayoutKind.Auto)] + private readonly struct LruCacheItem(TValue v, int offset) { + public readonly TValue Value = v; public readonly int Offset = offset; - public TValue Value = v; } } diff --git a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs index a49c7aea622..574e574992b 100644 --- a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs +++ b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs @@ -93,7 +93,11 @@ public void AddRange(ReadOnlySpan items) Count += items.Length; } - public void Clear() => Count = 0; + public void Clear() + { + ClearToCount(_array); + Count = 0; + } public bool Contains(T item) { @@ -140,6 +144,7 @@ public void ReduceCount(int count) _array.AsSpan(0, count).CopyTo(newArray); T[] oldArray = Interlocked.Exchange(ref _array, newArray); _capacity = newArray.Length; + ClearToCount(oldArray); _arrayPool.Return(oldArray); } else if (RuntimeHelpers.IsReferenceOrContainsReferences()) @@ -154,6 +159,16 @@ void ThrowOnlyReduce(int count) } } + private void ClearToCount(T[] array) + { + int count = Count; + // Release any references to the objects in the array so can be GC'd. + if (count > 0 && RuntimeHelpers.IsReferenceOrContainsReferences()) + { + Array.Clear(array, 0, count); + } + } + public void Sort(Comparison comparison) { ArgumentNullException.ThrowIfNull(comparison); @@ -223,6 +238,7 @@ private void GuardResize(int itemsToAdd = 1) _array.CopyTo(newArray, 0); T[] oldArray = Interlocked.Exchange(ref _array, newArray); _capacity = newArray.Length; + ClearToCount(oldArray); _arrayPool.Return(oldArray); } } @@ -249,6 +265,10 @@ private bool RemoveAtInternal(int index, bool shouldThrow) } Count--; + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + _array[Count] = default!; + } } return isValid; @@ -335,13 +355,14 @@ public void Dispose() if (!_disposed) { _disposed = true; - Count = 0; T[]? array = _array; + _array = null!; if (array is not null) { - _arrayPool.Return(_array); - _array = null!; + ClearToCount(array); + _arrayPool.Return(array); } + Count = 0; } #if DEBUG diff --git a/src/Nethermind/Nethermind.Facade/Eth/EthSyncingInfo.cs b/src/Nethermind/Nethermind.Facade/Eth/EthSyncingInfo.cs index 42bf48b4c50..f55d158d411 100644 --- a/src/Nethermind/Nethermind.Facade/Eth/EthSyncingInfo.cs +++ b/src/Nethermind/Nethermind.Facade/Eth/EthSyncingInfo.cs @@ -40,9 +40,7 @@ public EthSyncingInfo( public SyncingResult GetFullInfo() { - long bestSuggestedNumber = _blockTree.FindBestSuggestedHeader()?.Number ?? 0; - long headNumberOrZero = _blockTree.Head?.Number ?? 0; - bool isSyncing = bestSuggestedNumber > headNumberOrZero + 8; + (bool isSyncing, long headNumberOrZero, long bestSuggestedNumber) = _blockTree.IsSyncing(maxDistanceForSynced: 8); SyncMode syncMode = _syncModeSelector.Current; if (_logger.IsTrace) _logger.Trace($"Start - EthSyncingInfo - BestSuggestedNumber: {bestSuggestedNumber}, HeadNumberOrZero: {headNumberOrZero}, IsSyncing: {isSyncing} {_syncConfig}. LowestInsertedBodyNumber: {_syncPointers.LowestInsertedBodyNumber} LowestInsertedReceiptBlockNumber: {_syncPointers.LowestInsertedReceiptBlockNumber}"); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/ParityRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/ParityRpcModuleTests.cs index b2603727410..66ac673179d 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/ParityRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/ParityRpcModuleTests.cs @@ -76,7 +76,7 @@ public void Initialize() _txPool = new TxPool.TxPool(_ethereumEcdsa, new BlobTxStorage(), - new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(specProvider), _blockTree, stateProvider, new CodeInfoRepository()), + new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(specProvider), _blockTree, stateProvider, new CodeInfoRepository()) { HasSynced = true }, new TxPoolConfig(), new TxValidator(specProvider.ChainId), LimboLogs.Instance, diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index d429cac1300..236a200ae12 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -28,6 +28,7 @@ using Nethermind.Specs.Test; using Nethermind.JsonRpc.Data; using Nethermind.Serialization.Rlp; +using Nethermind.State; using Newtonsoft.Json.Linq; namespace Nethermind.JsonRpc.Test.Modules; @@ -45,6 +46,7 @@ public async Task Build(ISpecProvider? specProvider = null, bool isAura = false) await Blockchain.AddFunds(TestItem.AddressB, 1000.Ether()); await Blockchain.AddFunds(TestItem.AddressC, 1000.Ether()); + Hash256 stateRoot = Blockchain.BlockTree.Head!.StateRoot!; for (int i = 1; i < 10; i++) { List transactions = new(); @@ -52,10 +54,12 @@ public async Task Build(ISpecProvider? specProvider = null, bool isAura = false) { transactions.Add(Core.Test.Builders.Build.A.Transaction .WithTo(Address.Zero) - .WithNonce(Blockchain.State.GetNonce(TestItem.AddressB) + (UInt256)j) + .WithNonce(Blockchain.StateReader.GetNonce(stateRoot, TestItem.AddressB) + (UInt256)j) .SignedAndResolved(Blockchain.EthereumEcdsa, TestItem.PrivateKeyB).TestObject); } await Blockchain.AddBlock(transactions.ToArray()); + + stateRoot = Blockchain.BlockTree.Head!.StateRoot!; } Factory = new( diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json index 048ac615c2c..ab6414bcdc2 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 22990000, - "PivotHash": "0xc729e80336902c7ceeb2af714f9add4434e1fbfc7b8e41f28698742160bd8535", + "PivotNumber": 23100000, + "PivotHash": "0xdae463b199e43a393bc75bd11332c9d5bf6c2639c5c27342eb5f2ae23d1a5fa6", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json index b9ed2276b67..eb8bb1219e9 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 18500000, - "PivotHash": "0xf02c06395fca279452eec89b9a16fd6764312f75f5776ff42e5157ce163f08fb", + "PivotNumber": 18610000, + "PivotHash": "0xf5c1be202907568363af3ba9643b089a207a5497a7fe9a97fa1505d2e358a1d8", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.json b/src/Nethermind/Nethermind.Runner/configs/chiado.json index 669b62121a8..bd15388639a 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.json +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.json @@ -16,8 +16,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 13030000, - "PivotHash": "0x95ada4054aab7d4ec861ef1c57111d6ca02d4c763cded077d9584804ce9e5772", + "PivotNumber": 13070000, + "PivotHash": "0x473a8b01df14b82dd2e89576d292f8b62bfcacfa4039145c1b80451a7204f580", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", "FastSyncCatchUpHeightDelta": "10000000000", "UseGethLimitsInFastBlocks": false diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb.json b/src/Nethermind/Nethermind.Runner/configs/energyweb.json index 8ce975fa12b..a2ba0bcf21f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.json +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.json @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 33020000, - "PivotHash": "0xb5b267d07638ca300da6a54a8a433f7a97bf63c309f39188acf9879f21e09123", - "PivotTotalDifficulty": "11236123755729388063560629537396986341897685812", + "PivotNumber": 33060000, + "PivotHash": "0xa944eb14a0eb04fd18d00a92502ebdabc5eef1251b9e86ffdd53663c1471dd36", + "PivotTotalDifficulty": "11249735050406225602099164521694257070355841331", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama.json b/src/Nethermind/Nethermind.Runner/configs/exosama.json index ca572a8f782..11a67304371 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.json +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.json @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 13270000, - "PivotHash": "0x2c9747816ad7aa6489fcae1b4cb9f817d3d4e14df288078bb318b54f994281e4", - "PivotTotalDifficulty": "4515547009040853410158981040619564165661433283", + "PivotNumber": 13310000, + "PivotHash": "0x753a91d0212478ff84a764dc685777feb89b2348e581703e3b2df367d5281823", + "PivotTotalDifficulty": "4529158303717690948697516024916834894119593282", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.json b/src/Nethermind/Nethermind.Runner/configs/gnosis.json index 37feffd7b25..467f1707b4a 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.json +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.json @@ -13,8 +13,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 37240000, - "PivotHash": "0xe04265e7b5a3c274b4b505c37aac6cce1bfad81fa21afe1550989d9e6ae2d2e1", + "PivotNumber": 37280000, + "PivotHash": "0xffdf05bd6e0b2a1ea66647cec5e7e66ab9562a5aece15768a162d59d8dd097cc", "PivotTotalDifficulty": "8626000110427538733349499292577475819600160930", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json index f788af5021e..a4de141222b 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 14630000, - "PivotHash": "0xd9185715bede87b96e7c282a0ed7d52a3e8b7ea550fe7e2f290282b89362fa23", - "PivotTotalDifficulty": "28635797" + "PivotNumber": 14670000, + "PivotHash": "0x608525796e84b63d4758442ddbe0f5f78b8cb395c99760f09ab3d1d4f0fb6dca", + "PivotTotalDifficulty": "28692401" }, "Metrics": { "NodeName": "JOC-Mainnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json index a07dd125d35..47b1e2c6219 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 8240000, - "PivotHash": "0xdd3a33d583d2192dafce0e8d469ba5d011e1a187d9104596337dacb5da8a9199", - "PivotTotalDifficulty": "14806762" + "PivotNumber": 8280000, + "PivotHash": "0x38d9958d5a82723ec6c217fbe37c7ea2829c22c3e8dc838765cc996002e5cf94", + "PivotTotalDifficulty": "14865312" }, "Metrics": { "NodeName": "JOC-Testnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json index 229e37a123a..bc970f53d51 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json @@ -16,9 +16,9 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 12630000, - "PivotHash": "0x8839adda5953b7294aac20c71193407c643d2d460b81217fcc554bdb8f6f65a9", - "PivotTotalDifficulty": "25260001" + "PivotNumber": 12730000, + "PivotHash": "0x8113f7ed2f64c246ce1c29259b427bd263e9c17b2d0f71f94773df8b03b74ff4", + "PivotTotalDifficulty": "25460001" }, "JsonRpc": { "Enabled": true, diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json index 3a25cf0faf4..028d4724de9 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json @@ -16,9 +16,9 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 6420000, - "PivotHash": "0xca464ef9ec6636bd194ea059ef932ae3938ae48956b0c5936e9ebcc5b0823ac1", - "PivotTotalDifficulty": "12840001" + "PivotNumber": 6530000, + "PivotHash": "0xa897fe765b7a27e95799aeefe03dfbcb2dbac9dbbc63d6439320b602384cdb30", + "PivotTotalDifficulty": "13060001" }, "JsonRpc": { "Enabled": true, diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.json b/src/Nethermind/Nethermind.Runner/configs/mainnet.json index 1a77df6e72f..a9b223d5c24 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.json @@ -9,8 +9,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 21285000, - "PivotHash": "0x313760f259dda6ca0909b353bbfd8a8e02ccbd132b2a8d48dba17c8bdbe085ab", + "PivotNumber": 21303000, + "PivotHash": "0xb7df0dcbb96842bed2fccc51e28dbbd2fddc6e3eb52ea972ecf473a2005be820", "PivotTotalDifficulty": "58750003716598352816469", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json index 5669f2d9020..28386125096 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json @@ -16,8 +16,8 @@ "AncientBodiesBarrier": 105235063, "AncientReceiptsBarrier": 105235063, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 128590000, - "PivotHash": "0x4418eac3a427325f43bf6c0f140acb7a8f5d8c8a80a3234db34c0c48b0f0aca5", + "PivotNumber": 128690000, + "PivotHash": "0x6ba4ae18a363b318dad04a6dc638a60cad1d5b42a8d8c05048408ffadcb100c8", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json index 9b15639430b..69571fbc5ea 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 20490000, - "PivotHash": "0xd2d8b3b7b14182c73c0c55a6736888c96491bbb93ef643438b023e013ab4df4e", + "PivotNumber": 20590000, + "PivotHash": "0xfd0deea4ebadfb45c4688f269c436ee91f0ee4a33f1b5fa93dc0553443dd5191", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.json b/src/Nethermind/Nethermind.Runner/configs/sepolia.json index a8c90daa4cc..3313fbddc28 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.json @@ -17,8 +17,8 @@ "FastSync": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 7169000, - "PivotHash": "0xb919fdc4e52fae3b99db49f5f3e251f2cba95f94ac3e4f21c1a3bb100ff193c6", + "PivotNumber": 7185000, + "PivotHash": "0x13fcdf643750023999d19a7ce52c338cebc591f704aaf0e6c14060c1216834f9", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.json b/src/Nethermind/Nethermind.Runner/configs/volta.json index 427e764804e..75de098999a 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.json +++ b/src/Nethermind/Nethermind.Runner/configs/volta.json @@ -15,9 +15,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 30120000, - "PivotHash": "0xd80df7e7b2d8e9d216b372f9e56acf9a43fa30e50da6b62e9142830e825e85af", - "PivotTotalDifficulty": "10249304891658666519516843175844858528678183947", + "PivotNumber": 30140000, + "PivotHash": "0x1377f22defd21de16f23b4f88bf1dda892ad290e1ed396c202c42d5d31e3148d", + "PivotTotalDifficulty": "10256110538997085288786110667993493892907252336", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index a15eeeca50c..a90a9a393a5 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -56,7 +56,7 @@ public void Setup() var codeDb = new MemDb(); _stateProvider = new WorldState(trieStore, codeDb, _logManager); _blockTree = Substitute.For(); - Block block = Build.A.Block.WithNumber(0).TestObject; + Block block = Build.A.Block.WithNumber(10000000 - 1).TestObject; _blockTree.Head.Returns(block); _blockTree.FindBestSuggestedHeader().Returns(Build.A.BlockHeader.WithNumber(10000000).TestObject); @@ -1121,6 +1121,8 @@ public void should_accept_access_list_transactions_only_when_eip2930_enabled([Va if (!eip2930Enabled) { _blockTree.FindBestSuggestedHeader().Returns(Build.A.BlockHeader.WithNumber(MainnetSpecProvider.BerlinBlockNumber - 1).TestObject); + Block block = Build.A.Block.WithNumber(MainnetSpecProvider.BerlinBlockNumber - 2).TestObject; + _blockTree.Head.Returns(block); } _txPool = CreatePool(null, new TestSpecProvider(eip2930Enabled ? Berlin.Instance : Istanbul.Instance)); @@ -1134,6 +1136,26 @@ public void should_accept_access_list_transactions_only_when_eip2930_enabled([Va result.Should().Be(eip2930Enabled ? AcceptTxResult.Accepted : AcceptTxResult.Invalid); } + [Test] + public void should_accept_only_when_synced([Values(false, true)] bool isSynced) + { + if (!isSynced) + { + _blockTree.FindBestSuggestedHeader().Returns(Build.A.BlockHeader.WithNumber(MainnetSpecProvider.BerlinBlockNumber - 1).TestObject); + Block block = Build.A.Block.WithNumber(1).TestObject; + _blockTree.Head.Returns(block); + } + + _txPool = CreatePool(null, new TestSpecProvider(Berlin.Instance)); + Transaction tx = Build.A.Transaction + .WithChainId(TestBlockchainIds.ChainId) + .SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).TestObject; + EnsureSenderBalance(tx); + AcceptTxResult result = _txPool.SubmitTx(tx, TxHandlingOptions.PersistentBroadcast); + _txPool.GetPendingTransactionsCount().Should().Be(isSynced ? 1 : 0); + result.Should().Be(isSynced ? AcceptTxResult.Accepted : AcceptTxResult.Syncing); + } + [Test] public void When_MaxFeePerGas_is_lower_than_MaxPriorityFeePerGas_tx_is_invalid() { diff --git a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs index 40cc45e94a6..fc2cc0c1a1c 100644 --- a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs +++ b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs @@ -90,6 +90,11 @@ namespace Nethermind.TxPool /// public static readonly AcceptTxResult NotSupportedTxType = new(15, nameof(NotSupportedTxType)); + /// + /// The node is syncing and cannot accept transactions at this time. + /// + public static readonly AcceptTxResult Syncing = new(503, nameof(Syncing)); + private int Id { get; } private string Code { get; } private string? Message { get; } diff --git a/src/Nethermind/Nethermind.TxPool/IChainHeadInfoProvider.cs b/src/Nethermind/Nethermind.TxPool/IChainHeadInfoProvider.cs index ca89bd82aec..7a34c1fcf8e 100644 --- a/src/Nethermind/Nethermind.TxPool/IChainHeadInfoProvider.cs +++ b/src/Nethermind/Nethermind.TxPool/IChainHeadInfoProvider.cs @@ -26,6 +26,8 @@ public interface IChainHeadInfoProvider public UInt256 CurrentFeePerBlobGas { get; } + bool IsSyncing { get; } + event EventHandler HeadChanged; } } diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index e9786211d4b..3417ede0714 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -194,6 +194,8 @@ public bool TryGetBlobAndProof(byte[] blobVersionedHash, private void OnHeadChange(object? sender, BlockReplacementEventArgs e) { + if (_headInfo.IsSyncing) return; + try { _headBlocksChannel.Writer.TryWrite(e); @@ -408,6 +410,8 @@ public void RemovePeer(PublicKey nodeId) public AcceptTxResult SubmitTx(Transaction tx, TxHandlingOptions handlingOptions) { + if (_headInfo.IsSyncing) return AcceptTxResult.Syncing; + Metrics.PendingTransactionsReceived++; // assign a sequence number to transaction so we can order them by arrival times when