public void Can_suggest_terminal_block_correctly() { // every block has difficulty 1000000, block 9 TD: 10000000 TestSpecProvider specProvider = new(London.Instance); specProvider.TerminalTotalDifficulty = (UInt256)9999900; BlockTreeBuilder treeBuilder = Build.A.BlockTree().OfChainLength(10); BlockTree tree = new( treeBuilder.BlocksDb, treeBuilder.HeadersDb, treeBuilder.BlockInfoDb, treeBuilder.MetadataDb, treeBuilder.ChainLevelInfoRepository, specProvider, NullBloomStorage.Instance, new SyncConfig(), LimboLogs.Instance); PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, LimboLogs.Instance); Block?block8 = tree.FindBlock(8, BlockTreeLookupOptions.None); Assert.False(block8 !.IsTerminalBlock(specProvider)); Assert.AreEqual(9, tree.BestKnownNumber); Assert.AreEqual(9, tree.BestSuggestedBody !.Number); Assert.AreEqual(9, tree.Head !.Number); Assert.True(tree.Head.IsTerminalBlock(specProvider)); }
public void RunMigration(int?migratedBlockNumber) { int chainLength = 10; IConfigProvider configProvider = Substitute.For <IConfigProvider>(); BlockTreeBuilder blockTreeBuilder = Core.Test.Builders.Build.A.BlockTree().OfChainLength(chainLength); InMemoryReceiptStorage inMemoryReceiptStorage = new() { MigratedBlockNumber = migratedBlockNumber != null ? 0 : long.MaxValue }; InMemoryReceiptStorage outMemoryReceiptStorage = new() { MigratedBlockNumber = migratedBlockNumber != null ? 0 : long.MaxValue }; NethermindApi context = new() { ConfigProvider = configProvider, EthereumJsonSerializer = new EthereumJsonSerializer(), LogManager = LimboLogs.Instance, ReceiptStorage = new TestReceiptStorage(inMemoryReceiptStorage, outMemoryReceiptStorage), DbProvider = Substitute.For <IDbProvider>(), BlockTree = blockTreeBuilder.TestObject, Synchronizer = Substitute.For <ISynchronizer>(), ChainLevelInfoRepository = blockTreeBuilder.ChainLevelInfoRepository, SyncModeSelector = Substitute.For <ISyncModeSelector>() }; configProvider.GetConfig <IInitConfig>().StoreReceipts.Returns(true); configProvider.GetConfig <IInitConfig>().ReceiptsMigration.Returns(true); context.SyncModeSelector.Current.Returns(SyncMode.WaitingForBlock); int txIndex = 0; for (int i = 1; i < chainLength; i++) { Block block = context.BlockTree.FindBlock(i); inMemoryReceiptStorage.Insert(block, new[] { Core.Test.Builders.Build.A.Receipt.WithTransactionHash(TestItem.Keccaks[txIndex++]).TestObject, Core.Test.Builders.Build.A.Receipt.WithTransactionHash(TestItem.Keccaks[txIndex++]).TestObject }); } ManualResetEvent guard = new(false); Keccak lastTransaction = TestItem.Keccaks[txIndex - 1]; context.DbProvider.ReceiptsDb.When(x => x.Remove(lastTransaction.Bytes)).Do(c => guard.Set()); ReceiptMigration migration = new(context); if (migratedBlockNumber.HasValue) { migration.Run(migratedBlockNumber.Value); } else { migration.Run(); } guard.WaitOne(TimeSpan.FromSeconds(1)); int txCount = ((migratedBlockNumber ?? chainLength) - 1 - 1) * 2; context.DbProvider.ReceiptsDb.Received(Quantity.Exactly(txCount)).Remove(Arg.Any <byte[]>()); outMemoryReceiptStorage.Count.Should().Be(txCount); } private class TestReceiptStorage : IReceiptStorage {
public void Can_call_by_hash() { StateProvider stateProvider = CreateInitialState(null); Keccak root = stateProvider.StateRoot; Block block = Build.A.Block.WithParent(_blockTree.Head).WithStateRoot(root).TestObject; BlockTreeBuilder.AddBlock(_blockTree, block); // would need to setup state root somehow... TransactionForRpc tx = new TransactionForRpc { From = TestItem.AddressA, To = TestItem.AddressB, GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 }; _proofModule.proof_call(tx, new BlockParameter(block.Hash)); EthereumJsonSerializer serializer = new EthereumJsonSerializer(); string response = RpcTest.TestSerializedRequest(_proofModule, "proof_call", $"{serializer.Serialize(tx)}", $"{block.Hash}"); Assert.True(response.Contains("\"result\"")); }
public void correctly_finalizes_blocks_in_chain(int chainLength, long twoThirdsMajorityTransition, Address[] blockCreators, int notFinalizedExpectedCount) { _validatorStore.GetValidators(Arg.Any <long?>()).Returns(blockCreators); BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree(); HashSet <BlockHeader> finalizedBlocks = new(); AuRaBlockFinalizationManager finalizationManager = new(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager, twoThirdsMajorityTransition); finalizationManager.BlocksFinalized += (sender, args) => { foreach (BlockHeader block in args.FinalizedBlocks) { finalizedBlocks.Add(block); } }; blockTreeBuilder.OfChainLength(chainLength, 0, 0, blockCreators); int start = 0; for (int i = start; i < chainLength; i++) { Keccak blockHash = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.BlockHash; Block? block = blockTreeBuilder.TestObject.FindBlock(blockHash, BlockTreeLookupOptions.None); _blockProcessor.BlockProcessed += Raise.EventWith(new BlockProcessedEventArgs(block, Array.Empty <TxReceipt>())); } IEnumerable <bool> isBlockFinalized = Enumerable.Range(start, chainLength).Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.IsFinalized); IEnumerable <bool> expected = Enumerable.Range(start, chainLength).Select(i => i < chainLength - notFinalizedExpectedCount); finalizedBlocks.Count.Should().Be(chainLength - notFinalizedExpectedCount); isBlockFinalized.Should().BeEquivalentTo(expected); }
public async Task Can_resync_if_missed_a_block() { _remoteBlockTree = Build.A.BlockTree(_genesisBlock).OfChainLength(QueueBasedSyncManager.MaxBatchSize).TestObject; ISynchronizationPeer peer = new SynchronizationPeerMock(_remoteBlockTree); SemaphoreSlim semaphore = new SemaphoreSlim(0); _manager.SyncEvent += (sender, args) => { if (args.SyncStatus == SyncStatus.Completed || args.SyncStatus == SyncStatus.Failed) { semaphore.Release(1); } }; _manager.Start(); Task addPeerTask = _manager.AddPeer(peer); Task firstToComplete = await Task.WhenAny(addPeerTask, Task.Delay(_standardTimeoutUnit)); Assert.AreSame(addPeerTask, firstToComplete); BlockTreeBuilder.ExtendTree(_remoteBlockTree, QueueBasedSyncManager.MaxBatchSize * 2); _manager.AddNewBlock(_remoteBlockTree.RetrieveHeadBlock(), peer.NodeId); semaphore.Wait(_standardTimeoutUnit); semaphore.Wait(_standardTimeoutUnit); Assert.AreEqual(QueueBasedSyncManager.MaxBatchSize * 2 - 1, (int)_blockTree.BestSuggested.Number); }
private (BlockTree notSyncedTree, BlockTree syncedTree) BuildBlockTrees( int notSyncedTreeSize, int syncedTreeSize) { Block genesisBlock = Build.A.Block.WithNumber(0).TestObject; TestSpecProvider specProvider = new(London.Instance); specProvider.TerminalTotalDifficulty = 0; ; BlockTreeBuilder treeBuilder = Build.A.BlockTree(genesisBlock, specProvider).OfChainLength(notSyncedTreeSize); BlockTree notSyncedTree = new( treeBuilder.BlocksDb, treeBuilder.HeadersDb, treeBuilder.BlockInfoDb, treeBuilder.MetadataDb, treeBuilder.ChainLevelInfoRepository, MainnetSpecProvider.Instance, NullBloomStorage.Instance, new SyncConfig(), LimboLogs.Instance); BlockTreeBuilder syncedTreeBuilder = Build.A.BlockTree(genesisBlock, specProvider).OfChainLength(syncedTreeSize); BlockTree syncedTree = new( syncedTreeBuilder.BlocksDb, syncedTreeBuilder.HeadersDb, syncedTreeBuilder.BlockInfoDb, syncedTreeBuilder.MetadataDb, syncedTreeBuilder.ChainLevelInfoRepository, specProvider, NullBloomStorage.Instance, new SyncConfig(), LimboLogs.Instance); return(notSyncedTree, syncedTree); }
public void correctly_de_finalizes_blocks_on_block_reprocessing(int chainLength, int rerun, int validatorCount, bool twoThirdsMajorityTransition) { Address[] blockCreators = TestItem.Addresses.Take(validatorCount).ToArray(); _validatorStore.GetValidators(Arg.Any <long?>()).Returns(blockCreators); BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree(); AuRaBlockFinalizationManager finalizationManager = new( blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager, twoThirdsMajorityTransition ? 0 : long.MaxValue); blockTreeBuilder.OfChainLength(chainLength, 0, 0, blockCreators); FinalizeToLevel(chainLength, blockTreeBuilder.ChainLevelInfoRepository); List <Block> blocks = Enumerable.Range(1, rerun) .Select(i => blockTreeBuilder.TestObject.FindBlock(chainLength - i, BlockTreeLookupOptions.None)) .Reverse() .ToList(); _blockProcessor.BlocksProcessing += Raise.EventWith(new BlocksProcessingEventArgs(blocks)); int majority = (twoThirdsMajorityTransition ? (validatorCount - 1) * 2 / 3 : (validatorCount - 1) / 2) + 1; for (int i = 1; i < rerun + majority; i++) { blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(chainLength - i).MainChainBlock.IsFinalized.Should().BeFalse(); } blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(chainLength - rerun - majority - 1).MainChainBlock.IsFinalized.Should().BeTrue(); }
public void Suggest_terminal_block_with_lower_number_and_lower_total_difficulty() { TestSpecProvider specProvider = new(London.Instance); specProvider.TerminalTotalDifficulty = (UInt256)9999900; BlockTreeBuilder treeBuilder = Build.A.BlockTree().OfChainLength(10); BlockTree tree = new( treeBuilder.BlocksDb, treeBuilder.HeadersDb, treeBuilder.BlockInfoDb, treeBuilder.MetadataDb, treeBuilder.ChainLevelInfoRepository, specProvider, NullBloomStorage.Instance, new SyncConfig(), LimboLogs.Instance); PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, LimboLogs.Instance); Block?block7 = tree.FindBlock(7, BlockTreeLookupOptions.None); Block newTerminalBlock = Build.A.Block .WithHeader(Build.A.BlockHeader.WithParent(block7 !.Header).TestObject) .WithParent(block7 !) .WithTotalDifficulty((UInt256)9999950) .WithNumber(block7 !.Number + 1).WithDifficulty(1999950).TestObject; // current Head TD: 10000000, block7 TD: 8000000, TTD 9999900, newTerminalBlock 9999950 tree.SuggestBlock(newTerminalBlock); Assert.True(newTerminalBlock.IsTerminalBlock(specProvider)); Assert.AreEqual(9, tree.BestKnownNumber); Assert.AreEqual(9, tree.BestSuggestedBody !.Number); Assert.AreEqual(9, tree.Head !.Number); Assert.True(tree.Head.IsTerminalBlock(specProvider)); }
public void Can_resync_if_missed_a_block() { _remoteBlockTree = Build.A.BlockTree(_genesisBlock).OfChainLength(SyncBatchSize.Max).TestObject; ISyncPeer peer = new SyncPeerMock(_remoteBlockTree); SemaphoreSlim semaphore = new SemaphoreSlim(0); _synchronizer.SyncEvent += (sender, args) => { if (args.SyncEvent == SyncEvent.Completed || args.SyncEvent == SyncEvent.Failed) { semaphore.Release(1); } }; _pool.Start(); _synchronizer.Start(); _pool.AddPeer(peer); BlockTreeBuilder.ExtendTree(_remoteBlockTree, SyncBatchSize.Max * 2); _syncServer.AddNewBlock(_remoteBlockTree.RetrieveHeadBlock(), peer); semaphore.Wait(_standardTimeoutUnit); semaphore.Wait(_standardTimeoutUnit); Assert.AreEqual(SyncBatchSize.Max * 2 - 1, (int)_blockTree.BestSuggestedHeader.Number); }
public void Can_call_by_hash_canonical() { Block lastHead = _blockTree.Head; Block block = Build.A.Block.WithParent(lastHead).TestObject; Block newBlockOnMain = Build.A.Block.WithParent(lastHead).WithDifficulty(block.Difficulty + 1).TestObject; BlockTreeBuilder.AddBlock(_blockTree, block); BlockTreeBuilder.AddBlock(_blockTree, newBlockOnMain); // would need to setup state root somehow... TransactionForRpc tx = new TransactionForRpc { From = TestItem.AddressA, To = TestItem.AddressB, GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 }; EthereumJsonSerializer serializer = new EthereumJsonSerializer(); string response = RpcTest.TestSerializedRequest(_proofModule, "proof_call", $"{serializer.Serialize(tx)}", $"{{\"blockHash\" : \"{block.Hash}\", \"requireCanonical\" : true}}"); Assert.True(response.Contains("-32000")); response = RpcTest.TestSerializedRequest(_proofModule, "proof_call", $"{serializer.Serialize(tx)}", $"{{\"blockHash\" : \"{TestItem.KeccakG}\", \"requireCanonical\" : true}}"); Assert.True(response.Contains("-32001")); }
public void correctly_initializes_lastFinalizedBlock() { BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree().OfChainLength(3, 1, 1); FinalizeToLevel(1, blockTreeBuilder.ChainLevelInfoRepository); AuRaBlockFinalizationManager finalizationManager = new(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); finalizationManager.LastFinalizedBlockLevel.Should().Be(1); }
public void correctly_finalizes_blocks_in_already_in_chain_on_initialize() { int count = 2; BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree().OfChainLength(count, 0, 0, TestItem.AddressA, TestItem.AddressB); AuRaBlockFinalizationManager finalizationManager = new(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); IEnumerable <bool> result = Enumerable.Range(0, count).Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.IsFinalized); result.Should().BeEquivalentTo(new[] { true, false }); }
public long?GetFinalizationLevel_tests(int chainLength, Address[] beneficiaries, int minForFinalization, long level) { SetupValidators(minForFinalization, beneficiaries); BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree().OfChainLength(chainLength, 0, 0, beneficiaries); BlockTree blockTree = blockTreeBuilder.TestObject; AuRaBlockFinalizationManager finalizationManager = new(blockTree, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); long?result = finalizationManager.GetFinalizationLevel(level); return(result); }
public void Cannot_change_best_suggested_to_terminal_block_after_merge_block() { // every block has difficulty 1000000, block 9 TD: 10000000 TestSpecProvider specProvider = new(London.Instance); specProvider.TerminalTotalDifficulty = (UInt256)9999900; BlockTreeBuilder treeBuilder = Build.A.BlockTree().OfChainLength(10); BlockTree tree = new( treeBuilder.BlocksDb, treeBuilder.HeadersDb, treeBuilder.BlockInfoDb, treeBuilder.MetadataDb, treeBuilder.ChainLevelInfoRepository, specProvider, NullBloomStorage.Instance, new SyncConfig(), LimboLogs.Instance); PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, LimboLogs.Instance); Block?block8 = tree.FindBlock(8, BlockTreeLookupOptions.None); Assert.False(block8 !.Header.IsTerminalBlock(specProvider)); Assert.AreEqual(9, tree.BestKnownNumber); Assert.AreEqual(9, tree.BestSuggestedBody !.Number); Assert.AreEqual(9, tree.Head !.Number); Assert.True(tree.Head.IsTerminalBlock(specProvider)); Block firstPoSBlock = Build.A.Block .WithHeader(Build.A.BlockHeader.WithParent(tree.Head !.Header).TestObject) .WithParent(tree.Head.Header) .WithDifficulty(0) .WithNumber(tree.Head !.Number + 1).TestObject; tree.SuggestBlock(firstPoSBlock); tree.UpdateMainChain(new[] { firstPoSBlock }, true, true); // simulating fcU Assert.AreEqual(10, tree.BestKnownNumber); Assert.AreEqual(10, tree.BestSuggestedBody !.Number); Block newTerminalBlock = Build.A.Block .WithHeader(Build.A.BlockHeader.WithParent(block8 !.Header).TestObject) .WithParent(block8 !) .WithTotalDifficulty((UInt256)10000001) .WithNumber(block8 !.Number + 1).WithDifficulty(2000001).TestObject; Assert.True(newTerminalBlock.IsTerminalBlock(specProvider)); tree.SuggestBlock(newTerminalBlock); Assert.AreEqual(10, tree.BestKnownNumber); Assert.AreEqual(10, tree.BestSuggestedBody !.Number); }
public async Task Can_resync_if_missed_a_block() { _remoteBlockTree = Build.A.BlockTree(_genesisBlock).OfChainLength(SynchronizationManager.BatchSize).TestObject; ISynchronizationPeer peer = new SynchronizationPeerMock(_remoteBlockTree); ManualResetEvent resetEvent = new ManualResetEvent(false); _manager.SyncEvent += (sender, args) => { resetEvent.Set(); }; Task addPeerTask = _manager.AddPeer(peer); Task firstToComplete = await Task.WhenAny(addPeerTask, Task.Delay(2000)); Assert.AreSame(addPeerTask, firstToComplete); _manager.Start(); resetEvent.WaitOne(TimeSpan.FromMilliseconds(2000)); BlockTreeBuilder.ExtendTree(_remoteBlockTree, SynchronizationManager.BatchSize * 2); _manager.AddNewBlock(_remoteBlockTree.RetrieveHeadBlock(), peer.NodeId); Assert.AreEqual(SynchronizationManager.BatchSize * 2 - 1, (int)_blockTree.BestSuggested.Number); }
private CallResultWithProof TestCallWithCode(byte[] code, Address from = null) { StateProvider stateProvider = CreateInitialState(code); Keccak root = stateProvider.StateRoot; Block block = Build.A.Block.WithParent(_blockTree.Head).WithStateRoot(root).WithBeneficiary(TestItem.AddressD).TestObject; BlockTreeBuilder.AddBlock(_blockTree, block); Block blockOnTop = Build.A.Block.WithParent(block).WithStateRoot(root).WithBeneficiary(TestItem.AddressD).TestObject; BlockTreeBuilder.AddBlock(_blockTree, blockOnTop); // would need to setup state root somehow... TransactionForRpc tx = new TransactionForRpc { From = from, To = TestItem.AddressB, GasPrice = _useNonZeroGasPrice ? 10.GWei() : 0 }; CallResultWithProof callResultWithProof = _proofModule.proof_call(tx, new BlockParameter(blockOnTop.Number)).Data; Assert.Greater(callResultWithProof.Accounts.Length, 0); foreach (AccountProof accountProof in callResultWithProof.Accounts) { ProofVerifier.Verify(accountProof.Proof, block.StateRoot); foreach (StorageProof storageProof in accountProof.StorageProofs) { ProofVerifier.Verify(storageProof.Proof, accountProof.StorageRoot); } } EthereumJsonSerializer serializer = new EthereumJsonSerializer(); string response = RpcTest.TestSerializedRequest(_proofModule, "proof_call", $"{serializer.Serialize(tx)}", $"{blockOnTop.Number}"); Assert.True(response.Contains("\"result\"")); return(callResultWithProof); }
public void Can_build_correct_block_tree() { Block genesisBlock = Build.A.Block.WithNumber(0).TestObject; TestSpecProvider specProvider = new(London.Instance); specProvider.TerminalTotalDifficulty = 0; BlockTreeBuilder treeBuilder = Build.A.BlockTree(genesisBlock, specProvider).OfChainLength(10); BlockTree tree = new( treeBuilder.BlocksDb, treeBuilder.HeadersDb, treeBuilder.BlockInfoDb, treeBuilder.MetadataDb, treeBuilder.ChainLevelInfoRepository, MainnetSpecProvider.Instance, NullBloomStorage.Instance, new SyncConfig(), LimboLogs.Instance); Assert.AreEqual(9, tree.BestKnownNumber); Assert.AreEqual(9, tree.BestSuggestedBody !.Number); Assert.AreEqual(9, tree.Head !.Number); }
public int[] correctly_finalizes_blocks_on_reorganisations(int validators, int chainLength) { _validatorStore.GetValidators(Arg.Any <long?>()).Returns(TestItem.Addresses.Take(validators).ToArray()); void ProcessBlock(BlockTreeBuilder blockTreeBuilder1, int level, int index) { Keccak blockHash = blockTreeBuilder1.ChainLevelInfoRepository.LoadLevel(level).BlockInfos[index].BlockHash; Block? block = blockTreeBuilder1.TestObject.FindBlock(blockHash, BlockTreeLookupOptions.None); _blockProcessor.BlockProcessed += Raise.EventWith(new BlockProcessedEventArgs(block, Array.Empty <TxReceipt>())); } Block genesis = Build.A.Block.Genesis.TestObject; BlockTreeBuilder blockTreeBuilder = Build.A.BlockTree(genesis); AuRaBlockFinalizationManager finalizationManager = new(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); blockTreeBuilder .OfChainLength(out Block headBlock, chainLength, 1, 0, TestItem.Addresses.Take(validators).ToArray()) .OfChainLength(out Block alternativeHeadBlock, chainLength, 0, splitFrom: 2, TestItem.Addresses.Skip(validators).Take(validators).ToArray()); for (int i = 0; i < chainLength - 1; i++) { ProcessBlock(blockTreeBuilder, i, 0); } for (int i = 1; i < chainLength - 1; i++) { ProcessBlock(blockTreeBuilder, i, 1); } ProcessBlock(blockTreeBuilder, chainLength - 1, 0); int[] finalizedBLocks = Enumerable.Range(0, chainLength) .Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).BlockInfos.Select((b, j) => b.IsFinalized ? j + 1 : 0).Sum()) .ToArray(); return(finalizedBLocks); }
private void TestCallWithStorageAndCode(byte[] code, UInt256 gasPrice, Address from = null) { StateProvider stateProvider = CreateInitialState(code); StorageProvider storageProvider = new StorageProvider(new TrieStore(_dbProvider.StateDb, LimboLogs.Instance), stateProvider, LimboLogs.Instance); for (int i = 0; i < 10000; i++) { storageProvider.Set(new StorageCell(TestItem.AddressB, (UInt256)i), i.ToBigEndianByteArray()); } storageProvider.Commit(); storageProvider.CommitTrees(0); stateProvider.Commit(MainnetSpecProvider.Instance.GenesisSpec, null); stateProvider.CommitTree(0); Keccak root = stateProvider.StateRoot; Block block = Build.A.Block.WithParent(_blockTree.Head).WithStateRoot(root).TestObject; BlockTreeBuilder.AddBlock(_blockTree, block); Block blockOnTop = Build.A.Block.WithParent(block).WithStateRoot(root).TestObject; BlockTreeBuilder.AddBlock(_blockTree, blockOnTop); // would need to setup state root somehow... TransactionForRpc tx = new TransactionForRpc { // we are testing system transaction here when From is null From = from, To = TestItem.AddressB, GasPrice = gasPrice, Nonce = 1000 }; CallResultWithProof callResultWithProof = _proofModule.proof_call(tx, new BlockParameter(blockOnTop.Number)).Data; Assert.Greater(callResultWithProof.Accounts.Length, 0); // just the keys for debugging Span <byte> span = stackalloc byte[32]; new UInt256(0).ToBigEndian(span); Keccak k0 = Keccak.Compute(span); // just the keys for debugging new UInt256(1).ToBigEndian(span); Keccak k1 = Keccak.Compute(span); // just the keys for debugging new UInt256(2).ToBigEndian(span); Keccak k2 = Keccak.Compute(span); foreach (AccountProof accountProof in callResultWithProof.Accounts) { // this is here for diagnostics - so you can read what happens in the test // generally the account here should be consistent with the values inside the proof // the exception will be thrown if the account did not exist before the call Account account; try { account = new AccountDecoder().Decode(new RlpStream(ProofVerifier.Verify(accountProof.Proof, block.StateRoot))); } catch (Exception) { // ignored } foreach (StorageProof storageProof in accountProof.StorageProofs) { // we read the values here just to allow easier debugging so you can confirm that the value is same as the one in the proof and in the trie byte[] value = ProofVerifier.Verify(storageProof.Proof, accountProof.StorageRoot); } } EthereumJsonSerializer serializer = new EthereumJsonSerializer(); string response = RpcTest.TestSerializedRequest(_proofModule, "proof_call", $"{serializer.Serialize(tx)}", $"{blockOnTop.Number}"); Assert.True(response.Contains("\"result\"")); }