diff --git a/.travis.yml b/.travis.yml index 4054559c979..0b90ac5d9e8 100755 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,12 @@ jobs: - stage: run tests script: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[Nethermind.HashLib]*" src/Nethermind/Ethereum.Basic.Test name: "Ethereum.Basic.Test" + - script: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[Nethermind.HashLib]*" src/Nethermind.DataMarketplace.Consumers.Test + name: "Nethermind.DataMarketplace.Consumers.Test" + - script: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[Nethermind.HashLib]*" src/Nethermind.DataMarketplace.Integration.Test + name: "Nethermind.DataMarketplace.Integration.Test" + - script: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[Nethermind.HashLib]*" src/Nethermind.DataMarketplace.Test + name: "Nethermind.DataMarketplace.Test" - script: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[Nethermind.HashLib]*" src/Nethermind/Ethereum.Blockchain.Block.Test name: "Ethereum.Blockchain.Block.Test" - script: dotnet test src/Nethermind/Ethereum.Blockchain.Test diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index 41a59f026f7..3767efe76d9 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -571,7 +571,7 @@ private static Block Convert(TestBlockJson testBlockJson) BlockHeader header = Convert(testBlockJson.BlockHeader); BlockHeader[] ommers = testBlockJson.UncleHeaders?.Select(Convert).ToArray() ?? new BlockHeader[0]; Block block = new Block(header, ommers); - block.Transactions = testBlockJson.Transactions?.Select(Convert).ToArray(); + block.Body.Transactions = testBlockJson.Transactions?.Select(Convert).ToArray(); return block; } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs index 02c13ddda69..53f2fb73818 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs @@ -167,7 +167,7 @@ public void Add_and_find_branch() BlockTree blockTree = BuildBlockTree(); Block block = Build.A.Block.TestObject; blockTree.SuggestBlock(block); - Block found = blockTree.FindBlock(block.Hash, false); + Block found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.None); Assert.AreEqual(block.Hash, BlockHeader.CalculateHash(found.Header)); } @@ -177,7 +177,7 @@ public void Add_on_branch_move_find() BlockTree blockTree = BuildBlockTree(); Block block = Build.A.Block.TestObject; AddToMain(blockTree, block); - Block found = blockTree.FindBlock(block.Hash, true); + Block found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.RequireCanonical); Assert.AreEqual(block.Hash, BlockHeader.CalculateHash(found.Header)); } @@ -187,7 +187,7 @@ public void Add_on_branch_and_not_find_on_main() BlockTree blockTree = BuildBlockTree(); Block block = Build.A.Block.TestObject; blockTree.SuggestBlock(block); - Block found = blockTree.FindBlock(block.Hash, true); + Block found = blockTree.FindBlock(block.Hash, BlockTreeLookupOptions.RequireCanonical); Assert.IsNull(found); } @@ -473,7 +473,7 @@ public void Stores_multiple_blocks_per_level() AddToMain(blockTree, block1); blockTree.SuggestBlock(block1B); - Block found = blockTree.FindBlock(block1B.Hash, false); + Block found = blockTree.FindBlock(block1B.Hash, BlockTreeLookupOptions.None); Assert.AreEqual(block1B.Hash, BlockHeader.CalculateHash(found.Header)); } @@ -1147,6 +1147,34 @@ public void Can_batch_insert_blocks() tree.Insert(blocks); } + + [Test] + public void Block_loading_is_lazy() + { + MemDb blocksDb = new MemDb(); + MemDb blockInfosDb = new MemDb(); + MemDb headersDb = new MemDb(); + + SyncConfig syncConfig = new SyncConfig(); + syncConfig.PivotNumber = 0L.ToString(); + + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = new BlockTree(blocksDb, headersDb, blockInfosDb, MainNetSpecProvider.Instance, NullTxPool.Instance, syncConfig, LimboLogs.Instance); + tree.SuggestBlock(genesis); + + Block previousBlock = genesis; + for (int i = 1; i < 10; i++) + { + Block block = Build.A.Block.WithNumber(i).WithParent(previousBlock).TestObject; + tree.SuggestBlock(block); + previousBlock = block; + } + + Block lastBlock = previousBlock; + + BlockTree loadedTree = new BlockTree(blocksDb, headersDb, blockInfosDb, MainNetSpecProvider.Instance, NullTxPool.Instance, syncConfig, LimboLogs.Instance); + loadedTree.FindHeader(lastBlock.Hash, BlockTreeLookupOptions.None); + } static object[] SourceOfBSearchTestCases = { diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs index 60a8ebfe103..06c4d0e7d49 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs @@ -348,7 +348,7 @@ public ProcessingTestContext IsDeletedAsInvalid() _processingTestContext._resetEvent.WaitOne(IgnoreWait); Assert.AreEqual(_processingTestContext._headBefore, _processingTestContext._blockTree.Head.Hash, "head"); _logger.Info($"Finished waiting for {_block.ToString(Block.Format.Short)} to be deleted"); - Assert.Null(_processingTestContext._blockTree.FindBlock(_block.Hash, false)); + Assert.Null(_processingTestContext._blockTree.FindBlock(_block.Hash, BlockTreeLookupOptions.None)); return _processingTestContext; } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/BlockDownloaderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/BlockDownloaderTests.cs index a24030ad0c7..7dd195d5f74 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/BlockDownloaderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/BlockDownloaderTests.cs @@ -74,7 +74,7 @@ public async Task BuildHeaderResponse(long startNumber, int numbe throw new TimeoutException(); } - BlockHeader startBlock = _blockTree.FindHeader(_testHeaderMapping[startNumber], false); + BlockHeader startBlock = _blockTree.FindHeader(_testHeaderMapping[startNumber], BlockTreeLookupOptions.None); BlockHeader[] headers = new BlockHeader[number]; headers[0] = startBlock; if (!justFirst) @@ -116,7 +116,7 @@ public async Task BuildBlocksResponse(Keccak[] blockHashes, Respons throw new TimeoutException(); } - BlockHeader startHeader = _blockTree.FindHeader(blockHashes[0], false); + BlockHeader startHeader = _blockTree.FindHeader(blockHashes[0], BlockTreeLookupOptions.None); if (startHeader == null) startHeader = Build.A.BlockHeader.WithHash(blockHashes[0]).TestObject; BlockHeader[] blockHeaders = new BlockHeader[blockHashes.Length]; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/FastBlocks/FastBlocksFeedTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/FastBlocks/FastBlocksFeedTests.cs index c44a247c934..f8063a41f0d 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/FastBlocks/FastBlocksFeedTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/FastBlocks/FastBlocksFeedTests.cs @@ -655,15 +655,15 @@ private void AssertTreeSynced(IBlockTree tree, bool bodiesSync = false, bool rec Keccak nextHash = tree.Head.Hash; for (int i = 0; i < tree.Head.Number; i++) { - BlockHeader header = _localBlockTree.FindHeader(nextHash); + BlockHeader header = _localBlockTree.FindHeader(nextHash, BlockTreeLookupOptions.None); Assert.NotNull(header, $"header {tree.Head.Number - i}"); if (bodiesSync) { - Block expectedBlock = _localBlockTree.FindBlock(nextHash, false); + Block expectedBlock = _localBlockTree.FindBlock(nextHash, BlockTreeLookupOptions.None); Assert.AreEqual(nextHash, expectedBlock?.Hash, $"hash difference {tree.Head.Number - i}"); if (expectedBlock != null) { - Block actualBlock = tree.FindBlock(expectedBlock.Hash, false); + Block actualBlock = tree.FindBlock(expectedBlock.Hash, BlockTreeLookupOptions.None); Rlp saved = Rlp.Encode(actualBlock); Rlp expected = Rlp.Encode(expectedBlock); Assert.AreEqual(expected, saved, $"body {tree.Head.Number - i}"); @@ -832,7 +832,7 @@ private void PrepareReceiptsResponse(ReceiptsSyncBatch receiptSyncBatch, Latency receiptSyncBatch.Response = new TxReceipt[receiptSyncBatch.Request.Length][]; for (int i = 0; i < receiptSyncBatch.Request.Length; i++) { - Block block = tree.FindBlock(receiptSyncBatch.Request[i], false); + Block block = tree.FindBlock(receiptSyncBatch.Request[i], BlockTreeLookupOptions.None); receiptSyncBatch.Response[i] = new TxReceipt[block.Transactions.Length]; for (int j = 0; j < block.Transactions.Length; j++) { @@ -861,7 +861,7 @@ private void PrepareBodiesResponse(BodiesSyncBatch bodiesSyncBatch, LatencySyncP for (int i = 0; i < Math.Min(maxResponseSize, requestSize); i++) { - Block block = tree.FindBlock(bodiesSyncBatch.Request[i], false); + Block block = tree.FindBlock(bodiesSyncBatch.Request[i], BlockTreeLookupOptions.None); bodiesSyncBatch.Response[i] = new BlockBody(block.Transactions, block.Ommers); } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/OldStyleFullSynchronizerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/OldStyleFullSynchronizerTests.cs index 5d2df4acd7d..33e8efc4b87 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/OldStyleFullSynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/OldStyleFullSynchronizerTests.cs @@ -199,7 +199,7 @@ public void Can_sync_on_split_of_length_1() Assert.AreEqual(miner1Tree.BestSuggestedHeader.Hash, _blockTree.BestSuggestedHeader.Hash, "client agrees with miner before split"); - Block splitBlock = Build.A.Block.WithParent(miner1Tree.FindParent(miner1Tree.Head)).WithDifficulty(miner1Tree.Head.Difficulty - 1).TestObject; + Block splitBlock = Build.A.Block.WithParent(miner1Tree.FindParent(miner1Tree.Head, BlockTreeLookupOptions.TotalDifficultyNotNeeded)).WithDifficulty(miner1Tree.Head.Difficulty - 1).TestObject; Block splitBlockChild = Build.A.Block.WithParent(splitBlock).TestObject; miner1Tree.SuggestBlock(splitBlock); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/SyncPeerMock.cs b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/SyncPeerMock.cs index 528165c5bd8..26502a71c03 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/SyncPeerMock.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Synchronization/SyncPeerMock.cs @@ -85,7 +85,7 @@ public Task GetBlocks(Keccak[] blockHashes, CancellationToken token BlockBody[] result = new BlockBody[blockHashes.Length]; for (int i = 0; i < blockHashes.Length; i++) { - Block block = _remoteTree.FindBlock(blockHashes[i], true); + Block block = _remoteTree.FindBlock(blockHashes[i], BlockTreeLookupOptions.RequireCanonical); result[i] = new BlockBody(block.Transactions, block.Ommers); } @@ -95,7 +95,7 @@ public Task GetBlocks(Keccak[] blockHashes, CancellationToken token public Task GetBlockHeaders(Keccak blockHash, int maxBlocks, int skip, CancellationToken token) { BlockHeader[] result = new BlockHeader[maxBlocks]; - long? firstNumber = _remoteTree.FindHeader(blockHash, true)?.Number; + long? firstNumber = _remoteTree.FindHeader(blockHash, BlockTreeLookupOptions.RequireCanonical)?.Number; if (!firstNumber.HasValue) { return Task.FromResult(result); diff --git a/src/Nethermind/Nethermind.Blockchain/BlockExtensions.cs b/src/Nethermind/Nethermind.Blockchain/BlockExtensions.cs index e2e3cff406e..8106eeb78a0 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockExtensions.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockExtensions.cs @@ -28,16 +28,20 @@ public static class BlockExtensions { public static Keccak CalculateReceiptRoot(this Block block, ISpecProvider specProvider, TxReceipt[] txReceipts) { - PatriciaTree receiptTree = txReceipts.Length > 0 ? new PatriciaTree(NullDb.Instance, Keccak.EmptyTreeHash, false) : null; + if (txReceipts.Length == 0) + { + return PatriciaTree.EmptyTreeHash; + } + + PatriciaTree receiptTree = new PatriciaTree(); for (int i = 0; i < txReceipts.Length; i++) { Rlp receiptRlp = Rlp.Encode(txReceipts[i], specProvider.GetSpec(block.Number).IsEip658Enabled ? RlpBehaviors.Eip658Receipts : RlpBehaviors.None); - receiptTree?.Set(Rlp.Encode(i).Bytes, receiptRlp); + receiptTree.Set(Rlp.Encode(i).Bytes, receiptRlp); } - receiptTree?.UpdateRootHash(); - Keccak receiptRoot = receiptTree?.RootHash ?? PatriciaTree.EmptyTreeHash; - return receiptRoot; + receiptTree.UpdateRootHash(); + return receiptTree.RootHash; } public static Keccak CalculateTxRoot(this Block block) @@ -60,7 +64,9 @@ public static Keccak CalculateTxRoot(this Block block) public static Keccak CalculateOmmersHash(this Block block) { - return Keccak.Compute(Rlp.Encode(block.Ommers)); + return block.Ommers.Length == 0 + ? Keccak.OfAnEmptySequenceRlp + : Keccak.Compute(Rlp.Encode(block.Ommers)); } } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs index 6946a9fa46c..ba59ba3f6e4 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs @@ -39,6 +39,15 @@ namespace Nethermind.Blockchain { + [Flags] + public enum BlockTreeLookupOptions + { + None = 0, + TotalDifficultyNotNeeded = 1, + RequireCanonical = 2, + All = 3 + } + [Todo(Improve.Refactor, "After the fast sync work there are some duplicated code parts for the 'by header' and 'by block' approaches.")] public class BlockTree : IBlockTree { @@ -54,7 +63,7 @@ public class BlockTree : IBlockTree private long _currentDbLoadBatchEnd; private ReaderWriterLockSlim _blockInfoLock = new ReaderWriterLockSlim(); - + private object _batchInsertLock = new object(); private readonly IDb _blockDb; @@ -126,7 +135,7 @@ public BlockTree( if (genesisLevel.BlockInfos[0].WasProcessed) { - BlockHeader genesisHeader = LoadHeader(genesisLevel.BlockInfos[0].BlockHash).Header; + BlockHeader genesisHeader = LoadHeader(genesisLevel.BlockInfos[0].BlockHash); Genesis = genesisHeader; LoadHeadBlock(); } @@ -173,7 +182,7 @@ private void LoadLowestInsertedHeader() ChainLevelInfo lowestInsertedLevel = null; while (left != right) { - if(_logger.IsTrace) _logger.Trace($"Finding lowest inserted header - L {left} | R {right}"); + if (_logger.IsTrace) _logger.Trace($"Finding lowest inserted header - L {left} | R {right}"); long index = left + (right - left) / 2 + 1; ChainLevelInfo level = LoadLevel(index, true); if (level == null) @@ -186,17 +195,17 @@ private void LoadLowestInsertedHeader() right = index - 1L; } } - + if (lowestInsertedLevel == null) { - if(_logger.IsTrace) _logger.Trace($"Lowest inserted header is null - L {left} | R {right}"); + if (_logger.IsTrace) _logger.Trace($"Lowest inserted header is null - L {left} | R {right}"); LowestInsertedHeader = null; } else { BlockInfo blockInfo = lowestInsertedLevel.BlockInfos[0]; LowestInsertedHeader = FindHeader(blockInfo.BlockHash); - if(_logger.IsDebug) _logger.Debug($"Lowest inserted header is {LowestInsertedHeader?.ToString(BlockHeader.Format.Short)} {right} - L {left} | R {right}"); + if (_logger.IsDebug) _logger.Debug($"Lowest inserted header is {LowestInsertedHeader?.ToString(BlockHeader.Format.Short)} {right} - L {left} | R {right}"); } } @@ -208,10 +217,10 @@ private void LoadLowestInsertedBody() Block lowestInsertedBlock = null; while (left != right) { - if(_logger.IsDebug) _logger.Debug($"Finding lowest inserted body - L {left} | R {right}"); + if (_logger.IsDebug) _logger.Debug($"Finding lowest inserted body - L {left} | R {right}"); long index = left + (right - left) / 2 + 1; ChainLevelInfo level = LoadLevel(index, true); - Block block = level == null ? null : FindBlock(level.BlockInfos[0].BlockHash, false); + Block block = level == null ? null : FindBlock(level.BlockInfos[0].BlockHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (block == null) { left = index; @@ -225,12 +234,12 @@ private void LoadLowestInsertedBody() if (lowestInsertedBlock == null) { - if(_logger.IsTrace) _logger.Trace($"Lowest inserted body is null - L {left} | R {right}"); + if (_logger.IsTrace) _logger.Trace($"Lowest inserted body is null - L {left} | R {right}"); LowestInsertedBody = null; } else { - if(_logger.IsDebug) _logger.Debug($"Lowest inserted body is {LowestInsertedBody?.ToString(Block.Format.Short)} {right} - L {left} | R {right}"); + if (_logger.IsDebug) _logger.Debug($"Lowest inserted body is {LowestInsertedBody?.ToString(Block.Format.Short)} {right} - L {left} | R {right}"); LowestInsertedBody = lowestInsertedBlock; } } @@ -261,7 +270,7 @@ public async Task LoadBlocksFromDb( { Head = startBlockNumber == 0 ? null : FindBlock(startBlockNumber.Value - 1)?.Header; } - + long blocksToLoad = Math.Min(FindNumberOfBlocksToLoadFromDb(), maxBlocksToLoad); if (blocksToLoad == 0) { @@ -311,10 +320,10 @@ public async Task LoadBlocksFromDb( throw new InvalidOperationException($"Expected at least one block at level {blockNumber}"); } - Block block = FindBlock(maxDifficultyBlock.BlockHash, false); + Block block = FindBlock(maxDifficultyBlock.BlockHash, BlockTreeLookupOptions.None); if (block == null) { - BlockHeader header = FindHeader(maxDifficultyBlock.BlockHash, false); + BlockHeader header = FindHeader(maxDifficultyBlock.BlockHash, BlockTreeLookupOptions.None); if (header == null) { _blockInfoDb.Delete(blockNumber); @@ -437,7 +446,7 @@ public AddBlockResult Insert(Block block) { throw new InvalidOperationException("Genesis block should not be inserted."); } - + using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, block); @@ -446,7 +455,7 @@ public AddBlockResult Insert(Block block) _blockDb.Set(block.Hash, newRlp); } - long expectedNumber = (LowestInsertedBody?.Number - 1 ?? LongConverter.FromString(_syncConfig.PivotNumber ?? "0")); + long expectedNumber = (LowestInsertedBody?.Number - 1 ?? LongConverter.FromString(_syncConfig.PivotNumber ?? "0")); if (block.Number != expectedNumber) { throw new InvalidOperationException($"Trying to insert out of order block {block.Number} when expected number was {expectedNumber}"); @@ -588,37 +597,39 @@ public AddBlockResult SuggestBlock(Block block, bool shouldProcess = true) return Suggest(block, block.Header, shouldProcess); } - public Block FindBlock(Keccak blockHash, bool mainChainOnly) + public Block FindBlock(Keccak blockHash, BlockTreeLookupOptions options) { - (Block block, BlockInfo _, ChainLevelInfo level) = Load(blockHash); - if (block == null) - { - return null; - } - - if (mainChainOnly) - { - bool isMain = level.HasBlockOnMainChain && level.BlockInfos[0].BlockHash.Equals(blockHash); - return isMain ? block : null; - } - - return block; + return Load(blockHash, options); } - public BlockHeader FindHeader(Keccak blockHash, bool mainChainOnly) + public BlockHeader FindHeader(Keccak blockHash, BlockTreeLookupOptions options) + { + return LoadHeader(blockHash, options); + } + + public BlockHeader FindHeader(long number) + { + Keccak hash = GetBlockHashOnMainOrOnlyHash(number); + return hash == null ? null : FindHeader(hash); + } + + public BlockHeader FindHeader(Keccak blockHash) { - (BlockHeader header, BlockInfo _, ChainLevelInfo level) = LoadHeader(blockHash); + BlockHeader header = _headerCache.Get(blockHash); if (header == null) { - return null; - } + byte[] data = _headerDb.Get(blockHash); + if (data == null) + { + return null; + } - if (mainChainOnly) - { - bool isMain = level.HasBlockOnMainChain && level.BlockInfos[0].BlockHash.Equals(blockHash); - return isMain ? header : null; + header = _headerDecoder.Decode(data.AsRlpContext(), RlpBehaviors.AllowExtraData); + _headerCache.Set(blockHash, header); } + BlockInfo blockInfo = LoadInfo(header.Number, header.Hash).Info; + header.TotalDifficulty = blockInfo.TotalDifficulty; return header; } @@ -627,7 +638,7 @@ public Block[] FindBlocks(Keccak blockHash, int numberOfBlocks, int skip, bool r if (blockHash == null) throw new ArgumentNullException(nameof(blockHash)); Block[] result = new Block[numberOfBlocks]; - Block startBlock = FindBlock(blockHash, true); + Block startBlock = FindBlock(blockHash, BlockTreeLookupOptions.RequireCanonical); if (startBlock == null) { return result; @@ -704,7 +715,7 @@ private Keccak GetBlockHashOnMainOrOnlyHash(long blockNumber) public Block FindBlock(long blockNumber) { Keccak hash = GetBlockHashOnMainOrOnlyHash(blockNumber); - return Load(hash).Block; + return Load(hash, BlockTreeLookupOptions.None); } public void DeleteInvalidBlock(Block invalidBlock) @@ -721,7 +732,7 @@ public void DeleteInvalidBlock(Block invalidBlock) }); BestSuggestedHeader = Head; - BestSuggestedBody = Head == null ? null : FindBlock(Head.Hash, false); + BestSuggestedBody = Head == null ? null : FindBlock(Head.Hash, BlockTreeLookupOptions.None); try { @@ -985,7 +996,7 @@ private void LoadHeadBlock() if (data != null) { BlockHeader headBlockHeader = data.Length == 32 - ? FindHeader(new Keccak(data), false) + ? FindHeader(new Keccak(data), BlockTreeLookupOptions.None) : Rlp.Decode(data.AsRlpContext(), RlpBehaviors.AllowExtraData); ChainLevelInfo level = LoadLevel(headBlockHeader.Number); @@ -998,7 +1009,7 @@ private void LoadHeadBlock() headBlockHeader.TotalDifficulty = level.BlockInfos[index.Value].TotalDifficulty; Head = BestSuggestedHeader = headBlockHeader; - BestSuggestedBody = FindBlock(headBlockHeader.Hash, false); + BestSuggestedBody = FindBlock(headBlockHeader.Hash, BlockTreeLookupOptions.None); } } @@ -1162,38 +1173,22 @@ private long LoadNumberOnly(Keccak blockHash) _headerCache.Set(blockHash, header); return header.Number; } - - public BlockHeader FindHeader(Keccak blockHash) - { - BlockHeader header = _headerCache.Get(blockHash); - if (header == null) - { - byte[] data = _headerDb.Get(blockHash); - if (data == null) - { - return null; - } - - header = _headerDecoder.Decode(data.AsRlpContext(), RlpBehaviors.AllowExtraData); - _headerCache.Set(blockHash, header); - } - - BlockInfo blockInfo = LoadInfo(header.Number, header.Hash).Info; - header.TotalDifficulty = blockInfo.TotalDifficulty; - return header; - } - - public BlockHeader FindHeader(long number) + + /// + /// To make cache useful even when we handle sync requests + /// + /// + /// + private bool ShouldCache(long number) { - Keccak hash = GetBlockHashOnMainOrOnlyHash(number); - return hash == null ? null : FindHeader(hash); + return number == 0L || Head == null || number > Head.Number - CacheSize && number <= Head.Number + 1; } - private (BlockHeader Header, BlockInfo BlockInfo, ChainLevelInfo Level) LoadHeader(Keccak blockHash) + private BlockHeader LoadHeader(Keccak blockHash, BlockTreeLookupOptions options = BlockTreeLookupOptions.None) { if (blockHash == null || blockHash == Keccak.Zero) { - return (null, null, null); + return null; } BlockHeader header = _headerCache.Get(blockHash); @@ -1202,58 +1197,61 @@ public BlockHeader FindHeader(long number) byte[] data = _headerDb.Get(blockHash); if (data == null) { - return (null, null, null); + return null; } header = _headerDecoder.Decode(data.AsRlpContext(), RlpBehaviors.AllowExtraData); - if (ShouldCache(header.Number)) - { - _headerCache.Set(blockHash, header); - } } - (BlockInfo blockInfo, ChainLevelInfo level) = LoadInfo(header.Number, header.Hash); - if (level == null || blockInfo == null) + bool totalDifficultyNeeded = (options & BlockTreeLookupOptions.TotalDifficultyNotNeeded) == BlockTreeLookupOptions.None; + bool requiresCanonical = (options & BlockTreeLookupOptions.RequireCanonical) == BlockTreeLookupOptions.RequireCanonical; + + if ((totalDifficultyNeeded && header.TotalDifficulty == null) || requiresCanonical) { - // TODO: this is here because storing block data is not transactional - // TODO: would be great to remove it, he? - SetTotalDifficulty(header); - blockInfo = new BlockInfo(header.Hash, header.TotalDifficulty.Value); - try + (BlockInfo blockInfo, ChainLevelInfo level) = LoadInfo(header.Number, header.Hash); + if (level == null || blockInfo == null) { - _blockInfoLock.EnterWriteLock(); - UpdateOrCreateLevel(header.Number, blockInfo); + // TODO: this is here because storing block data is not transactional + // TODO: would be great to remove it, he? + SetTotalDifficulty(header); + blockInfo = new BlockInfo(header.Hash, header.TotalDifficulty.Value); + try + { + _blockInfoLock.EnterWriteLock(); + UpdateOrCreateLevel(header.Number, blockInfo); + } + finally + { + _blockInfoLock.ExitWriteLock(); + } + + (_, level) = LoadInfo(header.Number, header.Hash); } - finally + else { - _blockInfoLock.ExitWriteLock(); + header.TotalDifficulty = blockInfo.TotalDifficulty; } - (blockInfo, level) = LoadInfo(header.Number, header.Hash); + if (requiresCanonical) + { + bool isMain = level.HasBlockOnMainChain && level.BlockInfos[0].BlockHash.Equals(blockHash); + header = isMain ? header : null; + } } - else + + if (header != null && ShouldCache(header.Number)) { - header.TotalDifficulty = blockInfo.TotalDifficulty; + _headerCache.Set(blockHash, header); } - return (header, blockInfo, level); - } - - /// - /// To make cache useful even when we handle sync requests - /// - /// - /// - private bool ShouldCache(long number) - { - return number == 0L || Head == null || number > Head.Number - CacheSize && number <= Head.Number + 1; + return header; } - private (Block Block, BlockInfo Info, ChainLevelInfo Level) Load(Keccak blockHash) + private Block Load(Keccak blockHash, BlockTreeLookupOptions options) { if (blockHash == null || blockHash == Keccak.Zero) { - return (null, null, null); + return null; } Block block = _blockCache.Get(blockHash); @@ -1262,42 +1260,55 @@ private bool ShouldCache(long number) byte[] data = _blockDb.Get(blockHash); if (data == null) { - return (null, null, null); + return null; } block = _blockDecoder.Decode(data.AsRlpContext(), RlpBehaviors.AllowExtraData); - if (ShouldCache(block.Number)) - { - _blockCache.Set(blockHash, block); - _headerCache.Set(blockHash, block.Header); - } } - (BlockInfo blockInfo, ChainLevelInfo level) = LoadInfo(block.Number, block.Hash); - if (level == null || blockInfo == null) + bool totalDifficultyNeeded = (options & BlockTreeLookupOptions.TotalDifficultyNotNeeded) == BlockTreeLookupOptions.None; + bool requiresCanonical = (options & BlockTreeLookupOptions.RequireCanonical) == BlockTreeLookupOptions.RequireCanonical; + + if ((totalDifficultyNeeded && block.TotalDifficulty == null) || requiresCanonical) { - // TODO: this is here because storing block data is not transactional - // TODO: would be great to remove it, he? - SetTotalDifficulty(block.Header); - blockInfo = new BlockInfo(block.Hash, block.TotalDifficulty.Value); - try + (BlockInfo blockInfo, ChainLevelInfo level) = LoadInfo(block.Number, block.Hash); + if (level == null || blockInfo == null) { - _blockInfoLock.EnterWriteLock(); - UpdateOrCreateLevel(block.Number, blockInfo); + // TODO: this is here because storing block data is not transactional + // TODO: would be great to remove it, he? + SetTotalDifficulty(block.Header); + blockInfo = new BlockInfo(block.Hash, block.TotalDifficulty.Value); + try + { + _blockInfoLock.EnterWriteLock(); + UpdateOrCreateLevel(block.Number, blockInfo); + } + finally + { + _blockInfoLock.ExitWriteLock(); + } + + (_, level) = LoadInfo(block.Number, block.Hash); } - finally + else { - _blockInfoLock.ExitWriteLock(); + block.Header.TotalDifficulty = blockInfo.TotalDifficulty; } - (blockInfo, level) = LoadInfo(block.Number, block.Hash); + if (requiresCanonical) + { + bool isMain = level.HasBlockOnMainChain && level.BlockInfos[0].BlockHash.Equals(blockHash); + block = isMain ? block : null; + } } - else + + if (block != null && ShouldCache(block.Number)) { - block.Header.TotalDifficulty = blockInfo.TotalDifficulty; + _blockCache.Set(blockHash, block); + _headerCache.Set(blockHash, block.Header); } - return (block, blockInfo, level); + return block; } private void SetTotalDifficulty(BlockHeader header) @@ -1313,7 +1324,7 @@ private void SetTotalDifficulty(BlockHeader header) } else { - BlockHeader parentHeader = this.FindParentHeader(header); + BlockHeader parentHeader = this.FindParentHeader(header, BlockTreeLookupOptions.None); if (parentHeader == null) { throw new InvalidOperationException($"An orphaned block on the chain {header}"); diff --git a/src/Nethermind/Nethermind.Blockchain/BlockchainProcessor.cs b/src/Nethermind/Nethermind.Blockchain/BlockchainProcessor.cs index 35f51e4051f..7d5f31a7916 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockchainProcessor.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockchainProcessor.cs @@ -204,7 +204,7 @@ private bool ResolveBlockRef(BlockRef blockRef) { if (blockRef.IsInDb) { - Block block = _blockTree.FindBlock(blockRef.BlockHash, false); + Block block = _blockTree.FindBlock(blockRef.BlockHash, BlockTreeLookupOptions.None); if (block == null) { return false; @@ -293,7 +293,7 @@ public Block Process(Block suggestedBlock, ProcessingOptions options, IBlockTrac break; } - branchingPoint = _blockTree.FindParentHeader(toBeProcessed.Header); + branchingPoint = _blockTree.FindParentHeader(toBeProcessed.Header, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (branchingPoint == null) { break; //failure here @@ -302,7 +302,7 @@ public Block Process(Block suggestedBlock, ProcessingOptions options, IBlockTrac bool isFastSyncTransition = _blockTree.Head == _blockTree.Genesis && toBeProcessed.Number > 1; if (!isFastSyncTransition) { - toBeProcessed = _blockTree.FindParent(toBeProcessed.Header); + toBeProcessed = _blockTree.FindParent(toBeProcessed.Header, BlockTreeLookupOptions.None); } else { @@ -406,7 +406,7 @@ public Block Process(Block suggestedBlock, ProcessingOptions options, IBlockTrac private bool RunSimpleChecksAheadOfProcessing(Block suggestedBlock, ProcessingOptions options) { /* a bit hacky way to get the invalid branch out of the processing loop */ - if (suggestedBlock.Number != 0 && _blockTree.FindParentHeader(suggestedBlock.Header) == null) + if (suggestedBlock.Number != 0 && !_blockTree.IsKnownBlock(suggestedBlock.Number - 1, suggestedBlock.ParentHash)) { if (_logger.IsDebug) _logger.Debug($"Skipping processing block {suggestedBlock.ToString(Block.Format.FullHashAndNumber)} with unknown parent"); return false; diff --git a/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs b/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs index 7f681cbdfdc..a7bbe8249ec 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockhashProvider.cs @@ -47,7 +47,7 @@ public Keccak GetBlockhash(BlockHeader currentBlock, in long number) bool isFastSyncSearch = false; - BlockHeader header = _blockTree.FindHeader(currentBlock.ParentHash); + BlockHeader header = _blockTree.FindHeader(currentBlock.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); for (var i = 0; i < _maxDepth; i++) { if (number == header.Number) @@ -55,7 +55,7 @@ public Keccak GetBlockhash(BlockHeader currentBlock, in long number) return header.Hash; } - header = _blockTree.FindHeader(header.ParentHash); + header = _blockTree.FindHeader(header.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (_blockTree.IsMainChain(header.Hash) && !isFastSyncSearch) { try diff --git a/src/Nethermind/Nethermind.Blockchain/DevBlockProducer.cs b/src/Nethermind/Nethermind.Blockchain/DevBlockProducer.cs index 5f2ece37440..981b3b4dde0 100644 --- a/src/Nethermind/Nethermind.Blockchain/DevBlockProducer.cs +++ b/src/Nethermind/Nethermind.Blockchain/DevBlockProducer.cs @@ -72,7 +72,7 @@ private Block PrepareBlock() BlockHeader parentHeader = _blockTree.Head; if (parentHeader == null) return null; - Block parent = _blockTree.FindBlock(parentHeader.Hash, false); + Block parent = _blockTree.FindBlock(parentHeader.Hash, BlockTreeLookupOptions.None); UInt256 timestamp = _timestamp.EpochSeconds; BlockHeader header = new BlockHeader( diff --git a/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs b/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs index 4546192cc56..1e5c8f324ef 100644 --- a/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs @@ -132,20 +132,18 @@ public interface IBlockTree Task LoadBlocksFromDb(CancellationToken cancellationToken, long? startBlockNumber, int batchSize = BlockTree.DbLoadBatchSize, int maxBlocksToLoad = int.MaxValue); - Block FindBlock(Keccak blockHash, bool mainChainOnly); + Block FindBlock(Keccak blockHash, BlockTreeLookupOptions options); - BlockHeader FindHeader(Keccak blockHash, bool mainChainOnly); - - BlockHeader FindHeader(Keccak blockHash); + BlockHeader FindHeader(Keccak blockHash, BlockTreeLookupOptions options); + Block FindBlock(long blockNumber); + BlockHeader FindHeader(long blockNumber); Block[] FindBlocks(Keccak blockHash, int numberOfBlocks, int skip, bool reverse); BlockHeader[] FindHeaders(Keccak hash, int numberOfBlocks, int skip, bool reverse); - Block FindBlock(long blockNumber); - void DeleteInvalidBlock(Block invalidBlock); event EventHandler NewBestSuggestedBlock; diff --git a/src/Nethermind/Nethermind.Blockchain/MinedBlockProducer.cs b/src/Nethermind/Nethermind.Blockchain/MinedBlockProducer.cs index 8d5dda1de3e..db2d10270f6 100644 --- a/src/Nethermind/Nethermind.Blockchain/MinedBlockProducer.cs +++ b/src/Nethermind/Nethermind.Blockchain/MinedBlockProducer.cs @@ -120,7 +120,7 @@ private Block PrepareBlock() return null; } - Block parent = _blockTree.FindBlock(parentHeader.Hash, false); + Block parent = _blockTree.FindBlock(parentHeader.Hash, BlockTreeLookupOptions.None); UInt256 timestamp = _timestamp.EpochSeconds; UInt256 difficulty = _difficultyCalculator.Calculate(parent.Difficulty, parent.Timestamp, _timestamp.EpochSeconds, parent.Number + 1, parent.Ommers.Length > 0); diff --git a/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs b/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs index f30341c790d..249d5c391d4 100644 --- a/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs @@ -74,19 +74,14 @@ public AddBlockResult SuggestHeader(BlockHeader header) throw new InvalidOperationException($"{nameof(ReadOnlyBlockTree)} does not expect {nameof(SuggestHeader)} calls"); } - public Block FindBlock(Keccak blockHash, bool mainChainOnly) + public Block FindBlock(Keccak blockHash, BlockTreeLookupOptions options) { - return _wrapped.FindBlock(blockHash, mainChainOnly); + return _wrapped.FindBlock(blockHash, options); } - public BlockHeader FindHeader(Keccak blockHash, bool mainChainOnly) + public BlockHeader FindHeader(Keccak blockHash, BlockTreeLookupOptions options) { - return _wrapped.FindHeader(blockHash, mainChainOnly); - } - - public BlockHeader FindHeader(Keccak blockHash) - { - return _wrapped.FindHeader(blockHash); + return _wrapped.FindHeader(blockHash, options); } public BlockHeader FindHeader(long blockNumber) diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/BlockDownloader.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/BlockDownloader.cs index c57c56f42ff..04ed3c89074 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/BlockDownloader.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/BlockDownloader.cs @@ -88,7 +88,7 @@ public async Task DownloadHeaders(PeerInfo bestPeer, int newBlocksToSkip, if (_logger.IsTrace) _logger.Trace($"Headers request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more."); var headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest); - BlockHeader startingPoint = headers[0] == null ? null : _blockTree.FindHeader(headers[0].Hash); + BlockHeader startingPoint = headers[0] == null ? null : _blockTree.FindHeader(headers[0].Hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (startingPoint == null) { ancestorLookupLevel += _syncBatchSize.Current; @@ -220,7 +220,14 @@ await bodiesTask.ContinueWith(t => Block[] blocks = new Block[bodies.Length]; for (int i = 0; i < bodies.Length; i++) { - blocks[i] = new Block(null, bodies[i].Transactions, bodies[i].Ommers); + BlockBody body = bodies[i]; + if (body == null) + { + // TODO: this is how it used to be... I do not want to touch it without extensive testing + throw new EthSynchronizationException($"{bestPeer} sent an empty body for {blocks[i].ToString(Block.Format.Short)}."); + } + + blocks[i] = new Block(null, body); } _sinceLastTimeout++; @@ -236,8 +243,8 @@ await bodiesTask.ContinueWith(t => if (blocks.Length > 0) { - BlockHeader parent = _blockTree.FindParentHeader(blocks[0].Header); - if (parent == null) + bool parentIsKnown = _blockTree.IsKnownBlock(blocks[0].Number - 1, blocks[0].ParentHash); + if (!parentIsKnown) { ancestorLookupLevel += _syncBatchSize.Current; currentNumber = currentNumber >= _syncBatchSize.Current ? (currentNumber - _syncBatchSize.Current) : 0L; diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/EthSyncPeerPool.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/EthSyncPeerPool.cs index 0d3f25c65db..b83f643e637 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/EthSyncPeerPool.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/EthSyncPeerPool.cs @@ -126,7 +126,7 @@ await RefreshPeerInfo(peerInfo, linkedSource.Token).ContinueWith(t => // cases when we want other nodes to resolve the impasse (check Goerli discussion on 5 out of 9 validators) if (peerInfo.TotalDifficulty == _blockTree.BestSuggestedHeader?.TotalDifficulty && peerInfo.HeadHash != _blockTree.BestSuggestedHeader?.Hash) { - Block block = _blockTree.FindBlock(_blockTree.BestSuggestedHeader.Hash, false); + Block block = _blockTree.FindBlock(_blockTree.BestSuggestedHeader.Hash, BlockTreeLookupOptions.None); if (block != null) // can be null if fast syncing headers only { peerInfo.SyncPeer.SendNewBlock(block); @@ -377,7 +377,7 @@ await firstToComplete.ContinueWith( peerInfo.HeadNumber = header.Number; peerInfo.HeadHash = header.Hash; - BlockHeader parent = _blockTree.FindHeader(header.ParentHash); + BlockHeader parent = _blockTree.FindHeader(header.ParentHash, BlockTreeLookupOptions.None); if (parent != null) { peerInfo.TotalDifficulty = (parent.TotalDifficulty ?? UInt256.Zero) + header.Difficulty; diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/FastBlocks/FastBlocksFeed.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/FastBlocks/FastBlocksFeed.cs index 57a693a230b..2f037443ce6 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/FastBlocks/FastBlocksFeed.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/FastBlocks/FastBlocksFeed.cs @@ -139,7 +139,7 @@ possibly continue in the next sync round */ case FastBlocksBatchType.Bodies: { Keccak hash = _lowestRequestedBodyHash; - BlockHeader header = _blockTree.FindHeader(hash); + BlockHeader header = _blockTree.FindHeader(hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (header == null) { throw new InvalidDataException($"Last header is null for {hash} at lowest inserted body: {_blockTree.LowestInsertedBody?.Number}"); @@ -152,7 +152,7 @@ possibly continue in the next sync round */ return null; } - header = _blockTree.FindParentHeader(header); + header = _blockTree.FindParentHeader(header, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (header == null) { throw new InvalidDataException($"Parent header is null for {hash} at lowest inserted body: {_blockTree.LowestInsertedBody?.Number}"); @@ -169,16 +169,42 @@ possibly continue in the next sync round */ { batch.Prioritized = true; } - - for (int i = requestSize - 1; i >= 0; i--) + + int collectedRequests = 0; + while (collectedRequests < requestSize) { - batch.Bodies.Headers[i] = header; - _lowestRequestedBodyHash = batch.Bodies.Request[i] = header.Hash; - header = _blockTree.FindHeader(header.ParentHash); - if (header == null) + int i = requestSize - collectedRequests - 1; +// while (header != null && !header.HasBody) +// { +// header = _blockTree.FindHeader(header.ParentHash); +// } + + if(header == null) { break; } + + batch.Bodies.Headers[i] = header; + collectedRequests++; + _lowestRequestedBodyHash = batch.Bodies.Request[i] = header.Hash; + + header = _blockTree.FindHeader(header.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); + } + + if (collectedRequests == 0) + { + return null; + } + + //only for the final one + if (collectedRequests < requestSize) + { + BlockHeader[] currentHeaders = batch.Bodies.Headers; + Keccak[] currentRequests = batch.Bodies.Request; + batch.Bodies.Request = new Keccak[collectedRequests]; + batch.Bodies.Headers = new BlockHeader[collectedRequests]; + Array.Copy(currentHeaders, requestSize - collectedRequests, batch.Bodies.Headers, 0, collectedRequests); + Array.Copy(currentRequests, requestSize - collectedRequests, batch.Bodies.Request, 0, collectedRequests); } break; @@ -199,7 +225,7 @@ possibly continue in the next sync round */ case FastBlocksBatchType.Receipts: { Keccak hash = _lowestRequestedReceiptsHash; - Block predecessorBlock = _blockTree.FindBlock(hash, false); + Block predecessorBlock = _blockTree.FindBlock(hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); Block block = predecessorBlock; if (block == null) { @@ -213,7 +239,7 @@ possibly continue in the next sync round */ return null; } - block = _blockTree.FindParent(predecessorBlock); + block = _blockTree.FindParent(predecessorBlock, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (block == null) { throw new InvalidDataException($"Parent block is null for {hash} at lowest inserted body: {_blockTree.LowestInsertedBody?.Number}"); @@ -249,7 +275,7 @@ possibly continue in the next sync round */ collectedRequests++; } - block = _blockTree.FindBlock(block.ParentHash, false); + block = _blockTree.FindBlock(block.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (block == null || block.IsGenesis) { break; diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncServer.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncServer.cs index 81319a15d1c..0b0f5516e0a 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncServer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncServer.cs @@ -30,10 +30,8 @@ public interface ISyncServer void AddNewBlock(Block block, Node node); TxReceipt[][] GetReceipts(Keccak[] blockHashes); Block Find(Keccak hash); - BlockHeader FindHeader(Keccak hash); - Block Find(long number); BlockHeader FindHeader(long number); - Block[] Find(Keccak hash, int numberOfBlocks, int skip, bool reverse); + Block[] FindBlocks(Keccak hash, int numberOfBlocks, int skip, bool reverse); BlockHeader[] FindHeaders(Keccak hash, int numberOfBlocks, int skip, bool reverse); byte[][] GetNodeData(Keccak[] keys); int GetPeerCount(); diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncProgressResolver.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncProgressResolver.cs index 2ef46a8ecc5..026c64c3629 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncProgressResolver.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncProgressResolver.cs @@ -72,7 +72,7 @@ when it causes a full sync vs node sync race at every block.*/ break; } - bestSuggested = _blockTree.FindHeader(bestSuggested.ParentHash); + bestSuggested = _blockTree.FindHeader(bestSuggested.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); } return bestFullState; diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncServer.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncServer.cs index ad56da441b8..c7512aedc6c 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncServer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncServer.cs @@ -72,7 +72,7 @@ public BlockHeader Head bool headIsGenesis = _blockTree.Head.Hash == _blockTree.Genesis.Hash; return headIsGenesis - ? _blockTree.FindHeader(new Keccak(_syncConfig.PivotHash ?? Keccak.Zero.ToString())) ?? _blockTree.Genesis + ? _blockTree.FindHeader(new Keccak(_syncConfig.PivotHash ?? Keccak.Zero.ToString()), BlockTreeLookupOptions.None) ?? _blockTree.Genesis : _blockTree.Head; } } @@ -218,17 +218,7 @@ public byte[][] GetNodeData(Keccak[] keys) public Block Find(Keccak hash) { - return _blockTree.FindBlock(hash, false); - } - - public BlockHeader FindHeader(Keccak hash) - { - return _blockTree.FindHeader(hash, false); - } - - public Block Find(long number) - { - return _blockTree.Head.Number >= number ? _blockTree.FindBlock(number) : null; + return _blockTree.FindBlock(hash, BlockTreeLookupOptions.None); } public BlockHeader FindHeader(long number) @@ -236,7 +226,7 @@ public BlockHeader FindHeader(long number) return _blockTree.FindHeader(number); } - public Block[] Find(Keccak hash, int numberOfBlocks, int skip, bool reverse) + public Block[] FindBlocks(Keccak hash, int numberOfBlocks, int skip, bool reverse) { return _blockTree.FindBlocks(hash, numberOfBlocks, skip, reverse); } diff --git a/src/Nethermind/Nethermind.Blockchain/Tracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracer.cs index 486073a8b41..d6af1c4e96f 100644 --- a/src/Nethermind/Nethermind.Blockchain/Tracer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Tracer.cs @@ -47,7 +47,7 @@ public Tracer(IBlockchainProcessor processor, IReceiptStorage receiptStorage, IB public GethLikeTxTrace Trace(Keccak blockHash, int txIndex) { - Block block = _blockTree.FindBlock(blockHash, false); + Block block = _blockTree.FindBlock(blockHash, BlockTreeLookupOptions.None); if (block == null) throw new InvalidOperationException("Only historical blocks"); if (txIndex > block.Transactions.Length - 1) throw new InvalidOperationException($"Block {blockHash} has only {block.Transactions.Length} transactions and the requested tx index was {txIndex}"); @@ -78,7 +78,7 @@ public GethLikeTxTrace Trace(long blockNumber, Transaction tx) { Block block = _blockTree.FindBlock(blockNumber); if (block == null) throw new InvalidOperationException("Only historical blocks"); - block.Transactions = new[] {tx}; + block.Body = new BlockBody(new[] {tx}, new BlockHeader[]{}); GethLikeBlockTracer blockTracer = new GethLikeBlockTracer(tx.Hash); _processor.Process(block, ProcessingOptions.ForceProcessing | ProcessingOptions.NoValidation | ProcessingOptions.WithRollback | ProcessingOptions.ReadOnlyChain, blockTracer); return blockTracer.BuildResult().SingleOrDefault(); @@ -86,7 +86,7 @@ public GethLikeTxTrace Trace(long blockNumber, Transaction tx) public GethLikeTxTrace[] TraceBlock(Keccak blockHash) { - Block block = _blockTree.FindBlock(blockHash, false); + Block block = _blockTree.FindBlock(blockHash, BlockTreeLookupOptions.None); return TraceBlock(block); } @@ -161,7 +161,7 @@ public ParityLikeTxTrace[] ParityTraceBlock(long blockNumber, ParityTraceTypes p public ParityLikeTxTrace[] ParityTraceBlock(Keccak blockHash, ParityTraceTypes parityTraceTypes) { - Block block = _blockTree.FindBlock(blockHash, false); + Block block = _blockTree.FindBlock(blockHash, BlockTreeLookupOptions.None); return ParityTraceBlock(block, parityTraceTypes); } @@ -185,7 +185,7 @@ private GethLikeTxTrace[] TraceBlock(Block block) if (block.Number != 0) { - BlockHeader parent = _blockTree.FindParentHeader(block.Header); + BlockHeader parent = _blockTree.FindParentHeader(block.Header, BlockTreeLookupOptions.None); if (!_blockTree.IsMainChain(parent.Hash)) throw new InvalidOperationException("Cannot trace orphaned blocks"); } @@ -200,7 +200,7 @@ private ParityLikeTxTrace[] ParityTraceBlock(Block block, ParityTraceTypes trace if (block.Number != 0) { - BlockHeader parent = _blockTree.FindParentHeader(block.Header); + BlockHeader parent = _blockTree.FindParentHeader(block.Header, BlockTreeLookupOptions.None); if (!_blockTree.IsMainChain(parent.Hash)) throw new InvalidOperationException("Cannot trace orphaned blocks"); } diff --git a/src/Nethermind/Nethermind.Blockchain/Validators/HeaderValidator.cs b/src/Nethermind/Nethermind.Blockchain/Validators/HeaderValidator.cs index 1934e31ea60..d3f5deee807 100644 --- a/src/Nethermind/Nethermind.Blockchain/Validators/HeaderValidator.cs +++ b/src/Nethermind/Nethermind.Blockchain/Validators/HeaderValidator.cs @@ -158,7 +158,7 @@ public bool Validate(BlockHeader header, BlockHeader parent, bool isOmmer = fals /// True if is valid, otherwise False public bool Validate(BlockHeader header, bool isOmmer = false) { - BlockHeader parent = _blockTree.FindHeader(header.ParentHash, false); + BlockHeader parent = _blockTree.FindHeader(header.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); return Validate(header, parent, isOmmer); } diff --git a/src/Nethermind/Nethermind.Blockchain/Validators/IBlockTreeExtensions.cs b/src/Nethermind/Nethermind.Blockchain/Validators/IBlockTreeExtensions.cs index 5d6083d9604..68b8f5cec30 100644 --- a/src/Nethermind/Nethermind.Blockchain/Validators/IBlockTreeExtensions.cs +++ b/src/Nethermind/Nethermind.Blockchain/Validators/IBlockTreeExtensions.cs @@ -23,34 +23,29 @@ namespace Nethermind.Blockchain.Validators // ReSharper disable once InconsistentNaming public static class IBlockTreeExtensions { - public static BlockHeader FindParentHeader(this IBlockTree tree, BlockHeader header) + public static BlockHeader FindParentHeader(this IBlockTree tree, BlockHeader header, BlockTreeLookupOptions options) { - return tree.FindHeader(header.ParentHash, false); + return tree.FindHeader(header.ParentHash, options); } - public static Block FindParent(this IBlockTree tree, Block block) + public static Block FindParent(this IBlockTree tree, Block block, BlockTreeLookupOptions options) { - return tree.FindBlock(block.Header.ParentHash, false); + return tree.FindBlock(block.Header.ParentHash, options); } - public static Block FindParent(this IBlockTree tree, BlockHeader blockHeader) + public static Block FindParent(this IBlockTree tree, BlockHeader blockHeader, BlockTreeLookupOptions options) { - return tree.FindBlock(blockHeader.ParentHash, false); - } - - public static Block RetrieveBestSuggestedBlock(this IBlockTree tree) - { - return tree.FindBlock(tree.BestSuggestedHeader.Hash, false); + return tree.FindBlock(blockHeader.ParentHash, options); } public static Block RetrieveHeadBlock(this IBlockTree tree) { - return tree.FindBlock(tree.Head.Hash, false); + return tree.FindBlock(tree.Head.Hash, BlockTreeLookupOptions.None); } public static Block RetrieveGenesisBlock(this IBlockTree tree) { - return tree.FindBlock(tree.Genesis.Hash, true); + return tree.FindBlock(tree.Genesis.Hash, BlockTreeLookupOptions.RequireCanonical); } } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Blockchain/Validators/OmmersValidator.cs b/src/Nethermind/Nethermind.Blockchain/Validators/OmmersValidator.cs index dfdf204fbf5..37ce2d52974 100644 --- a/src/Nethermind/Nethermind.Blockchain/Validators/OmmersValidator.cs +++ b/src/Nethermind/Nethermind.Blockchain/Validators/OmmersValidator.cs @@ -66,7 +66,7 @@ public bool Validate(BlockHeader header, BlockHeader[] ommers) return false; } - Block ancestor = _blockTree.FindBlock(header.ParentHash, false); + Block ancestor = _blockTree.FindBlock(header.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); for (int ancestorLevel = 0; ancestorLevel < 5; ancestorLevel++) { if (ancestor == null) @@ -80,7 +80,7 @@ public bool Validate(BlockHeader header, BlockHeader[] ommers) return false; } - ancestor = _blockTree.FindBlock(ancestor.Header.ParentHash, false); + ancestor = _blockTree.FindBlock(ancestor.Header.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); } } @@ -104,7 +104,7 @@ private bool IsKin(BlockHeader header, BlockHeader ommer, int relationshipLevel) return false; } - BlockHeader parent = _blockTree.FindHeader(header.ParentHash, false); + BlockHeader parent = _blockTree.FindHeader(header.ParentHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (parent == null) { return false; diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs index a4951d101ed..3029ed3091e 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueSealEngineTests.cs @@ -97,7 +97,7 @@ public async Task Can_sign_block() { Block block6 = CreateBlock(2, 6, _lastBlock); Block signed = await _clique.SealBlock(block6, CancellationToken.None); - bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(signed.ParentHash, false), signed.Header); + bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(signed.ParentHash, BlockTreeLookupOptions.None), signed.Header); bool validSeal = _sealValidator.ValidateSeal(signed.Header); Assert.True(validHeader); Assert.True(validSeal); diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs index be48614e2c6..88d80957274 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs @@ -82,7 +82,7 @@ public void Setup_chain() public void Test_real_block(string blockRlp) { Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp))); - bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(block.ParentHash, false), block.Header); + bool validHeader = _sealValidator.ValidateParams(_blockTree.FindHeader(block.ParentHash, BlockTreeLookupOptions.None), block.Header); bool validSeal = _sealValidator.ValidateSeal(block.Header); Assert.True(validHeader); Assert.True(validSeal); diff --git a/src/Nethermind/Nethermind.Clique/CliqueBlockProducer.cs b/src/Nethermind/Nethermind.Clique/CliqueBlockProducer.cs index 8666a9c10e5..865b0e41984 100644 --- a/src/Nethermind/Nethermind.Clique/CliqueBlockProducer.cs +++ b/src/Nethermind/Nethermind.Clique/CliqueBlockProducer.cs @@ -132,7 +132,7 @@ private void TimerOnElapsed(object sender, ElapsedEventArgs e) { if (_blockTree.Head.Timestamp + _config.BlockPeriod < _timestamp.EpochSeconds) { - _signalsQueue.Add(_blockTree.FindBlock(_blockTree.Head.Hash, false)); + _signalsQueue.Add(_blockTree.FindBlock(_blockTree.Head.Hash, BlockTreeLookupOptions.None)); } _timer.Enabled = true; @@ -148,7 +148,7 @@ private void TimerOnElapsed(object sender, ElapsedEventArgs e) { if(ReferenceEquals(scheduledBlock, _scheduledBlock)) { - BlockHeader parent = _blockTree.FindParentHeader(scheduledBlock.Header); + BlockHeader parent = _blockTree.FindParentHeader(scheduledBlock.Header, BlockTreeLookupOptions.TotalDifficultyNotNeeded); Address parentSigner = _snapshotManager.GetBlockSealer(parent); string parentTurnDescription = parent.IsInTurn() ? "IN TURN" : "OUT OF TURN"; @@ -324,7 +324,7 @@ private Block PrepareBlock(Block parentBlock) // Assemble the voting snapshot to check which votes make sense Snapshot snapshot = _snapshotManager.GetOrCreateSnapshot(number - 1, header.ParentHash); bool isEpochBlock = (ulong) number % 30000 == 0; - if (!isEpochBlock) + if (!isEpochBlock && _proposals.Any()) { // Gather all the proposals that make sense voting on List
addresses = new List
(); diff --git a/src/Nethermind/Nethermind.Clique/CliqueBridge.cs b/src/Nethermind/Nethermind.Clique/CliqueBridge.cs index ceed57471e3..7fc6b5d5976 100644 --- a/src/Nethermind/Nethermind.Clique/CliqueBridge.cs +++ b/src/Nethermind/Nethermind.Clique/CliqueBridge.cs @@ -69,7 +69,7 @@ public Snapshot GetSnapshot() public Snapshot GetSnapshot(Keccak hash) { - BlockHeader head = _blockTree.FindHeader(hash); + BlockHeader head = _blockTree.FindHeader(hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); return _snapshotManager.GetOrCreateSnapshot(head.Number, head.Hash); } @@ -93,26 +93,26 @@ public Address[] GetSigners() public Address[] GetSigners(long number) { - BlockHeader head = _blockTree.FindHeader(number); - return _snapshotManager.GetOrCreateSnapshot(head.Number, head.Hash).Signers.Select(s => s.Key).ToArray(); + BlockHeader header = _blockTree.FindHeader(number); + return _snapshotManager.GetOrCreateSnapshot(header.Number, header.Hash).Signers.Select(s => s.Key).ToArray(); } public string[] GetSignersAnnotated() { - BlockHeader head = _blockTree.Head; - return _snapshotManager.GetOrCreateSnapshot(head.Number, head.Hash).Signers.Select(s => string.Concat(s.Key, $" ({KnownAddresses.GetDescription(s.Key)})")).ToArray(); + BlockHeader header = _blockTree.Head; + return _snapshotManager.GetOrCreateSnapshot(header.Number, header.Hash).Signers.Select(s => string.Concat(s.Key, $" ({KnownAddresses.GetDescription(s.Key)})")).ToArray(); } public Address[] GetSigners(Keccak hash) { - BlockHeader head = _blockTree.FindHeader(hash); - return _snapshotManager.GetOrCreateSnapshot(head.Number, head.Hash).Signers.Select(s => s.Key).ToArray(); + BlockHeader header = _blockTree.FindHeader(hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); + return _snapshotManager.GetOrCreateSnapshot(header.Number, header.Hash).Signers.Select(s => s.Key).ToArray(); } public string[] GetSignersAnnotated(Keccak hash) { - BlockHeader head = _blockTree.FindHeader(hash); - return _snapshotManager.GetOrCreateSnapshot(head.Number, head.Hash).Signers.Select(s => string.Concat(s.Key, $" ({KnownAddresses.GetDescription(s.Key)})")).ToArray(); + BlockHeader header = _blockTree.FindHeader(hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); + return _snapshotManager.GetOrCreateSnapshot(header.Number, header.Hash).Signers.Select(s => string.Concat(s.Key, $" ({KnownAddresses.GetDescription(s.Key)})")).ToArray(); } } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Clique/SnapshotManager.cs b/src/Nethermind/Nethermind.Clique/SnapshotManager.cs index 7dc84bda191..5d286e89089 100644 --- a/src/Nethermind/Nethermind.Clique/SnapshotManager.cs +++ b/src/Nethermind/Nethermind.Clique/SnapshotManager.cs @@ -109,7 +109,7 @@ public Snapshot GetOrCreateSnapshot(long number, Keccak hash) if (snapshot != null) break; // If we're at an checkpoint block, make a snapshot if it's known - BlockHeader header = _blockTree.FindHeader(hash); + BlockHeader header = _blockTree.FindHeader(hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded); if (header == null) { throw new InvalidOperationException("Unknown ancestor"); diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs index caad53487b5..f3a46e2f476 100644 --- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs +++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs @@ -63,7 +63,7 @@ public BlockBuilder WithTimestamp(UInt256 timestamp) public BlockBuilder WithTransactions(params Transaction[] transactions) { - TestObjectInternal.Transactions = transactions; + TestObjectInternal.Body.Transactions = transactions; return this; } @@ -112,13 +112,13 @@ public BlockBuilder WithParent(Block block) public BlockBuilder WithOmmers(params Block[] ommers) { - TestObjectInternal.Ommers = ommers.Select(o => o.Header).ToArray(); + TestObjectInternal.Body.Ommers = ommers.Select(o => o.Header).ToArray(); return this; } public BlockBuilder WithOmmers(params BlockHeader[] ommers) { - TestObjectInternal.Ommers = ommers; + TestObjectInternal.Body.Ommers = ommers; return this; } diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs index e719f4faa46..f61425375a0 100644 --- a/src/Nethermind/Nethermind.Core/Block.cs +++ b/src/Nethermind/Nethermind.Core/Block.cs @@ -41,13 +41,19 @@ public enum Format private Block() { + Body = new BlockBody(); } + public Block(BlockHeader blockHeader, BlockBody body) + { + Header = blockHeader; + Body = body; + } + public Block(BlockHeader blockHeader, IEnumerable transactions, IEnumerable ommers) { Header = blockHeader; - Ommers = ommers.ToArray(); - Transactions = transactions.ToArray(); + Body = new BlockBody(transactions.ToArray(), ommers.ToArray()); } public Block(BlockHeader blockHeader, params BlockHeader[] ommers) @@ -57,9 +63,12 @@ public Block(BlockHeader blockHeader, params BlockHeader[] ommers) public bool IsGenesis => Header.IsGenesis; + public Transaction[] Transactions => Body?.Transactions; + + public BlockHeader[] Ommers => Body?.Ommers; + public BlockHeader Header { get; set; } - public Transaction[] Transactions { get; set; } - public BlockHeader[] Ommers { get; set; } + public BlockBody Body { get; set; } public Keccak Hash { @@ -179,13 +188,13 @@ public string ToString(string indent) builder.Append($"{Header.ToString(" ")}"); builder.AppendLine(" Ommers:"); - foreach (BlockHeader ommer in Ommers) + foreach (BlockHeader ommer in Body.Ommers) { builder.Append($"{ommer.ToString(" ")}"); } builder.AppendLine(" Transactions:"); - foreach (Transaction tx in Transactions) + foreach (Transaction tx in Body.Transactions) { builder.Append($"{tx.ToString(" ")}"); } @@ -216,20 +225,20 @@ public string ToString(Format format) case Format.HashNumberAndTx: if (Hash == null) { - return $"{Number} null, tx count: {Transactions.Length}"; + return $"{Number} null, tx count: {Body.Transactions.Length}"; } else { - return $"{Number} {TimestampDate:HH:mm:ss} ({Hash?.ToShortString()}), tx count: {Transactions.Length}"; + return $"{Number} {TimestampDate:HH:mm:ss} ({Hash?.ToShortString()}), tx count: {Body.Transactions.Length}"; } case Format.HashNumberDiffAndTx: if (Hash == null) { - return $"{Number} null, diff: {Difficulty}, tx count: {Transactions.Length}"; + return $"{Number} null, diff: {Difficulty}, tx count: {Body.Transactions.Length}"; } else { - return $"{Number} ({Hash?.ToShortString()}), diff: {Difficulty}, tx count: {Transactions.Length}"; + return $"{Number} ({Hash?.ToShortString()}), diff: {Difficulty}, tx count: {Body.Transactions.Length}"; } default: if (Hash == null) diff --git a/src/Nethermind/Nethermind.Core/BlockBody.cs b/src/Nethermind/Nethermind.Core/BlockBody.cs index 28bf43ecfda..f92d8255431 100644 --- a/src/Nethermind/Nethermind.Core/BlockBody.cs +++ b/src/Nethermind/Nethermind.Core/BlockBody.cs @@ -20,10 +20,10 @@ namespace Nethermind.Core { public class BlockBody { - public BlockBody(Block block) + public BlockBody() { - Transactions = block.Transactions; - Ommers = block.Ommers; + Transactions = new Transaction[0]; + Ommers = new BlockHeader[0]; } public BlockBody(Transaction[] transactions, BlockHeader[] ommers) @@ -32,7 +32,7 @@ public BlockBody(Transaction[] transactions, BlockHeader[] ommers) Ommers = ommers; } - public Transaction[] Transactions { get; } - public BlockHeader[] Ommers { get; } + public Transaction[] Transactions { get; set; } + public BlockHeader[] Ommers { get; set; } } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Core/BlockHeader.cs b/src/Nethermind/Nethermind.Core/BlockHeader.cs index 2332dfa9c13..870abbcd7e6 100644 --- a/src/Nethermind/Nethermind.Core/BlockHeader.cs +++ b/src/Nethermind/Nethermind.Core/BlockHeader.cs @@ -68,6 +68,8 @@ public BlockHeader(Keccak parentHash, Keccak ommersHash, Address beneficiary, UI public ulong Nonce { get; set; } public Keccak Hash { get; set; } public UInt256? TotalDifficulty { get; set; } + + public bool HasBody => OmmersHash != Keccak.OfAnEmptySequenceRlp || TxRoot != Keccak.EmptyTreeHash; public SealEngineType SealEngineType { get; set; } = SealEngineType.Ethash; private static ThreadLocal _rlpBuffer = new ThreadLocal(() => new byte[1024]); diff --git a/src/Nethermind/Nethermind.DataMarketplace.Test/ContractInteractionTest.cs b/src/Nethermind/Nethermind.DataMarketplace.Test/ContractInteractionTest.cs index 34877c16f02..a96d169227d 100644 --- a/src/Nethermind/Nethermind.DataMarketplace.Test/ContractInteractionTest.cs +++ b/src/Nethermind/Nethermind.DataMarketplace.Test/ContractInteractionTest.cs @@ -21,6 +21,7 @@ using System.Linq; using System.Numerics; using Nethermind.Abi; +using Nethermind.Blockchain; using Nethermind.Blockchain.Filters; using Nethermind.Blockchain.TxPools; using Nethermind.Core; @@ -138,7 +139,7 @@ public void NextBlockPlease(UInt256 timestamp) { _txIndex = 0; _headBlock = Build.A.Block.WithParent(Head).WithTimestamp(timestamp).TestObject; - _headBlock.Transactions = new Transaction[100]; + _headBlock.Body.Transactions = new Transaction[100]; _receiptsTracer.StartNewBlockTrace(_headBlock); } @@ -194,7 +195,7 @@ public void RecoverTxSender(Transaction tx, long blockNumber) throw new NotImplementedException(); } - public Block FindBlock(Keccak blockHash, bool mainChainOnly) + public Block FindBlock(Keccak blockHash, BlockTreeLookupOptions options) { throw new System.NotImplementedException(); } diff --git a/src/Nethermind/Nethermind.Db/RocksDbProvider.cs b/src/Nethermind/Nethermind.Db/RocksDbProvider.cs index 1ba4dba7142..fb4c2d7b42d 100644 --- a/src/Nethermind/Nethermind.Db/RocksDbProvider.cs +++ b/src/Nethermind/Nethermind.Db/RocksDbProvider.cs @@ -39,7 +39,7 @@ public RocksDbProvider(string basePath, IDbConfig dbConfig, ILogManager logManag if (useReceiptsDb) { - ReceiptsDb = new HeadersRocksDb(basePath, dbConfig, logManager); + ReceiptsDb = new ReceiptsRocksDb(basePath, dbConfig, logManager); } else { @@ -67,7 +67,7 @@ public RocksDbProvider(string basePath, IDbConfig dbConfig, ILogManager logManag public IDb ConfigsDb { get; } public IDb EthRequestsDb { get; } - public virtual void Dispose() + public void Dispose() { StateDb?.Dispose(); CodeDb?.Dispose(); diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockTracerTests.cs index 5706aac2332..2c0221b181f 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeBlockTracerTests.cs @@ -41,7 +41,7 @@ public void Starts_with_trace_set_to_null() public void Number_of_tx_traces_equals_number_of_txs_in_a_block() { Block block = Build.A.Block.TestObject; - block.Transactions = new Transaction[3]; + block.Body.Transactions = new Transaction[3]; GethLikeBlockTracer blockTracer = new GethLikeBlockTracer(); @@ -58,7 +58,7 @@ public void Number_of_tx_traces_equals_number_of_txs_in_a_block() public void Records_trace_properly() { Block block = Build.A.Block.TestObject; - block.Transactions = new Transaction[3]; + block.Body.Transactions = new Transaction[3]; GethLikeBlockTracer blockTracer = new GethLikeBlockTracer(); ((IBlockTracer) blockTracer).StartNewTxTrace(TestItem.KeccakA); @@ -80,7 +80,7 @@ public void Records_trace_properly() public void Throws_when_ending_without_starting() { Block block = Build.A.Block.TestObject; - block.Transactions = new Transaction[3]; + block.Body.Transactions = new Transaction[3]; block.Transactions[0] = Build.A.Transaction.TestObject; block.Transactions[1] = Build.A.Transaction.TestObject; block.Transactions[2] = Build.A.Transaction.TestObject; diff --git a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs index c650ce62c17..daeec0be2c7 100644 --- a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs +++ b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs @@ -98,17 +98,17 @@ public void Sign(Transaction tx) public BlockHeader BestSuggested => _blockTree.BestSuggestedHeader; public long BestKnown => _blockTree.BestKnownNumber; public bool IsSyncing => _blockTree.BestSuggestedHeader.Hash != _blockTree.Head.Hash; - public Block FindBlock(Keccak blockHash, bool mainChainOnly) => _blockTree.FindBlock(blockHash, mainChainOnly); + public Block FindBlock(Keccak blockHash, BlockTreeLookupOptions options) => _blockTree.FindBlock(blockHash, options); public Block FindBlock(long blockNumber) => _blockTree.FindBlock(blockNumber); - public Block RetrieveHeadBlock() => _blockTree.FindBlock(_blockTree.Head.Hash, false); - public Block RetrieveGenesisBlock() => _blockTree.FindBlock(_blockTree.Genesis.Hash, true); + public Block RetrieveHeadBlock() => _blockTree.FindBlock(_blockTree.Head.Hash, BlockTreeLookupOptions.None); + public Block RetrieveGenesisBlock() => _blockTree.FindBlock(_blockTree.Genesis.Hash, BlockTreeLookupOptions.RequireCanonical); public (TxReceipt Receipt, Transaction Transaction) GetTransaction(Keccak transactionHash) { TxReceipt txReceipt = _receiptStorage.Find(transactionHash); if (txReceipt?.BlockHash == null) return (null, null); - Block block = _blockTree.FindBlock(txReceipt.BlockHash, true); + Block block = _blockTree.FindBlock(txReceipt.BlockHash, BlockTreeLookupOptions.RequireCanonical); return (txReceipt, block.Transactions[txReceipt.Index]); } diff --git a/src/Nethermind/Nethermind.Facade/IBlockchainBridge.cs b/src/Nethermind/Nethermind.Facade/IBlockchainBridge.cs index 3c4a32dc295..a2c8e7bb479 100644 --- a/src/Nethermind/Nethermind.Facade/IBlockchainBridge.cs +++ b/src/Nethermind/Nethermind.Facade/IBlockchainBridge.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Numerics; +using Nethermind.Blockchain; using Nethermind.Blockchain.Filters; using Nethermind.Blockchain.TxPools; using Nethermind.Core; @@ -44,7 +45,7 @@ public interface IBlockchainBridge void RecoverTxSender(Transaction tx, long blockNumber); - Block FindBlock(Keccak blockHash, bool mainChainOnly); + Block FindBlock(Keccak blockHash, BlockTreeLookupOptions options); Block FindBlock(long blockNumber); Block RetrieveHeadBlock(); Block RetrieveGenesisBlock(); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/EthModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/EthModuleTests.cs index 03f64496617..94b0d360cfe 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/EthModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/EthModuleTests.cs @@ -17,6 +17,7 @@ */ using System; +using Nethermind.Blockchain; using Nethermind.Blockchain.Filters; using Nethermind.Config; using Nethermind.Core; @@ -158,7 +159,7 @@ public void Eth_get_filter_logs() public void Eth_get_block_by_hash() { IBlockchainBridge bridge = Substitute.For(); - bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); + bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); IEthModule module = new EthModule(NullLogManager.Instance, bridge); @@ -171,7 +172,7 @@ public void Eth_get_block_by_hash() public void Eth_get_block_by_number() { IBlockchainBridge bridge = Substitute.For(); - bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); + bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); bridge.RetrieveHeadBlock().Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); bridge.Head.Returns(Build.A.BlockHeader.TestObject); @@ -186,7 +187,7 @@ public void Eth_get_block_by_number() public void Eth_get_block_by_number_without_tx_details() { IBlockchainBridge bridge = Substitute.For(); - bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); + bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); bridge.RetrieveHeadBlock().Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); bridge.Head.Returns(Build.A.BlockHeader.TestObject); @@ -232,7 +233,7 @@ public void Eth_get_block_by_number_with_number_bad_number() public void Eth_get_block_by_number_empty_param() { IBlockchainBridge bridge = Substitute.For(); - bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); + bridge.FindBlock(Arg.Any(), Arg.Any()).Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); bridge.RetrieveHeadBlock().Returns(Build.A.Block.WithTotalDifficulty(0).WithTransactions(Build.A.Transaction.TestObject).TestObject); bridge.Head.Returns(Build.A.BlockHeader.TestObject); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.cs index 168db994b83..65c2449e67d 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.cs @@ -22,6 +22,7 @@ using System.Numerics; using System.Text; using System.Threading; +using Nethermind.Blockchain; using Nethermind.Blockchain.Filters; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -236,7 +237,7 @@ public ResultWrapper eth_getStorageAt(Address address, BigInteger positi try { _readerWriterLockSlim.EnterReadLock(); - var block = _blockchainBridge.FindBlock(blockHash, false); + var block = _blockchainBridge.FindBlock(blockHash, BlockTreeLookupOptions.None); if (block == null) { return ResultWrapper.Fail($"Cannot find block for hash: {blockHash}", ErrorType.NotFound, null); @@ -281,7 +282,7 @@ public ResultWrapper eth_getStorageAt(Address address, BigInteger positi try { _readerWriterLockSlim.EnterReadLock(); - var block = _blockchainBridge.FindBlock(blockHash, false); + var block = _blockchainBridge.FindBlock(blockHash, BlockTreeLookupOptions.None); if (block == null) { return ResultWrapper.Fail($"Cannot find block for hash: {blockHash}", ErrorType.NotFound, null); @@ -467,7 +468,7 @@ public ResultWrapper eth_getBlockByHash(Keccak blockHash, bool retu try { _readerWriterLockSlim.EnterReadLock(); - var block = _blockchainBridge.FindBlock(blockHash, false); + var block = _blockchainBridge.FindBlock(blockHash, BlockTreeLookupOptions.None); if (block != null && returnFullTransactionObjects) { _blockchainBridge.RecoverTxSenders(block); @@ -534,7 +535,7 @@ public ResultWrapper eth_getTransactionByBlockHashAndIndex(Ke try { _readerWriterLockSlim.EnterReadLock(); - var block = _blockchainBridge.FindBlock(blockHash, false); + var block = _blockchainBridge.FindBlock(blockHash, BlockTreeLookupOptions.None); if (block == null) { return ResultWrapper.Fail($"Cannot find block for hash: {blockHash}", ErrorType.NotFound); @@ -622,7 +623,7 @@ public ResultWrapper eth_getUncleByBlockHashAndIndex(Keccak blockHa { _readerWriterLockSlim.EnterReadLock(); Keccak blockHash = blockHashData; - var block = _blockchainBridge.FindBlock(blockHash, false); + var block = _blockchainBridge.FindBlock(blockHash, BlockTreeLookupOptions.None); if (block == null) { return ResultWrapper.Fail($"Cannot find block for hash: {blockHash}", ErrorType.NotFound); @@ -634,7 +635,7 @@ public ResultWrapper eth_getUncleByBlockHashAndIndex(Keccak blockHa } var ommerHeader = block.Ommers[(int) positionIndex]; - var ommer = _blockchainBridge.FindBlock(ommerHeader.Hash, false); + var ommer = _blockchainBridge.FindBlock(ommerHeader.Hash, BlockTreeLookupOptions.None); if (ommer == null) { return ResultWrapper.Fail($"Cannot find ommer for hash: {ommerHeader.Hash}", ErrorType.NotFound); @@ -671,7 +672,7 @@ public ResultWrapper eth_getUncleByBlockNumberAndIndex(BlockParamet } var ommerHeader = result.Data.Ommers[(int) positionIndex]; - var ommer = _blockchainBridge.FindBlock(ommerHeader.Hash, false); + var ommer = _blockchainBridge.FindBlock(ommerHeader.Hash, BlockTreeLookupOptions.None); if (ommer == null) { return ResultWrapper.Fail($"Cannot find ommer for hash: {ommerHeader.Hash}", ErrorType.NotFound); @@ -796,7 +797,7 @@ public ResultWrapper> eth_getWork() { if (blockParameter.Type == BlockParameterType.Pending) { - var headBlock = _blockchainBridge.FindBlock(_blockchainBridge.BestSuggested.Hash, false); + var headBlock = _blockchainBridge.FindBlock(_blockchainBridge.BestSuggested.Hash, BlockTreeLookupOptions.None); var count = headBlock.Ommers.Length; return ResultWrapper.Success(count); } @@ -814,7 +815,7 @@ public ResultWrapper> eth_getWork() { if (blockParameter.Type == BlockParameterType.Pending) { - var headBlock = _blockchainBridge.FindBlock(_blockchainBridge.BestSuggested.Hash, false); + var headBlock = _blockchainBridge.FindBlock(_blockchainBridge.BestSuggested.Hash, BlockTreeLookupOptions.None); var count = headBlock.Transactions.Length; return ResultWrapper.Success(count); } @@ -901,7 +902,7 @@ private ResultWrapper GetStorage(Address address, BigInteger index, Bloc switch (blockParameter.Type) { case BlockParameterType.Pending: - var pending = _blockchainBridge.FindBlock(_blockchainBridge.BestSuggested.Hash, false); + var pending = _blockchainBridge.FindBlock(_blockchainBridge.BestSuggested.Hash, BlockTreeLookupOptions.None); return ResultWrapper.Success(pending); // TODO: a pending block for sealEngine, work in progress case BlockParameterType.Latest: return ResultWrapper.Success(_blockchainBridge.RetrieveHeadBlock()); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/Eth62ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/Eth62ProtocolHandlerTests.cs index 29cb42470bb..ba87792bece 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/Eth62ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/Eth62ProtocolHandlerTests.cs @@ -80,7 +80,7 @@ public void Get_headers_when_blocks_are_missing() var session = Substitute.For(); var syncManager = Substitute.For(); var transactionPool = Substitute.For(); - syncManager.Find(null, Arg.Any(), Arg.Any(), Arg.Any()).Throws(new ArgumentNullException()); + syncManager.FindBlocks(null, Arg.Any(), Arg.Any(), Arg.Any()).Throws(new ArgumentNullException()); Block genesisBlock = Build.A.Block.Genesis.TestObject; syncManager.Head.Returns(genesisBlock.Header); syncManager.Genesis.Returns(genesisBlock.Header); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/BlockBodiesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/BlockBodiesMessage.cs index 5889a8bb68b..184070ae543 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/BlockBodiesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/BlockBodiesMessage.cs @@ -34,7 +34,7 @@ public BlockBodiesMessage(Block[] blocks) Bodies = new BlockBody[blocks.Length]; for (int i = 0; i < blocks.Length; i++) { - Bodies[i] = blocks[i] == null ? null : new BlockBody(blocks[i].Transactions, blocks[i].Ommers); + Bodies[i] = blocks[i] == null ? null : blocks[i].Body; } } diff --git a/src/Nethermind/Nethermind.PerfTest/Program.cs b/src/Nethermind/Nethermind.PerfTest/Program.cs index 10a929bf241..6ea01024000 100644 --- a/src/Nethermind/Nethermind.PerfTest/Program.cs +++ b/src/Nethermind/Nethermind.PerfTest/Program.cs @@ -238,19 +238,14 @@ public AddBlockResult SuggestHeader(BlockHeader header) return _blockTree.SuggestHeader(header); } - public Block FindBlock(Keccak blockHash, bool mainChainOnly) + public Block FindBlock(Keccak blockHash, BlockTreeLookupOptions option) { - return _blockTree.FindBlock(blockHash, mainChainOnly); + return _blockTree.FindBlock(blockHash, option); } - public BlockHeader FindHeader(Keccak blockHash, bool mainChainOnly) + public BlockHeader FindHeader(Keccak blockHash, BlockTreeLookupOptions options) { - return _blockTree.FindHeader(blockHash, mainChainOnly); - } - - public BlockHeader FindHeader(Keccak blockHash) - { - return _blockTree.FindHeader(blockHash); + return _blockTree.FindHeader(blockHash, options); } public BlockHeader FindHeader(long number) @@ -465,7 +460,7 @@ private static async Task RunRopstenBlocks() { if (!isStarted) { - blockchainProcessor.Process(blockTree.FindBlock(blockTree.Genesis.Hash, true), ProcessingOptions.None, NullBlockTracer.Instance); + blockchainProcessor.Process(blockTree.FindBlock(blockTree.Genesis.Hash, BlockTreeLookupOptions.RequireCanonical), ProcessingOptions.None, NullBlockTracer.Instance); stopwatch.Start(); blockchainProcessor.Start(); isStarted = true; diff --git a/src/Nethermind/Nethermind.PubSub.Kafka/Avro/AvroMapper.cs b/src/Nethermind/Nethermind.PubSub.Kafka/Avro/AvroMapper.cs index 3538e21a78e..75b6695e8be 100644 --- a/src/Nethermind/Nethermind.PubSub.Kafka/Avro/AvroMapper.cs +++ b/src/Nethermind/Nethermind.PubSub.Kafka/Avro/AvroMapper.cs @@ -89,7 +89,7 @@ public FullTransaction MapFullTransaction(Core.FullTransaction fullTransaction) return new FullTransaction { - minedAt = (long) _blockTree.FindBlock(receipt.BlockHash, false).Timestamp, + minedAt = (long) _blockTree.FindBlock(receipt.BlockHash, BlockTreeLookupOptions.None).Timestamp, blockNumber = (long) receipt.BlockNumber, receipt = new Receipt { diff --git a/src/Nethermind/merge.1 b/src/Nethermind/merge.1 deleted file mode 100644 index 46568d87ffc..00000000000 --- a/src/Nethermind/merge.1 +++ /dev/null @@ -1 +0,0 @@ -a: