private Task <bool> ProduceNewBlock(BlockHeader parent, CancellationToken token) { _stateProvider.StateRoot = parent.StateRoot; Block block = PrepareBlock(parent); if (PreparedBlockCanBeMined(block)) { Block processedBlock = ProcessPreparedBlock(block); if (processedBlock == null) { if (Logger.IsError) { Logger.Error("Block prepared by block producer was rejected by processor."); } Metrics.FailedBlockSeals++; } else { return(SealBlock(processedBlock, parent, token).ContinueWith((Func <Task <Block>, bool>)(t => { if (t.IsCompletedSuccessfully) { if (t.Result != null) { if (Logger.IsInfo) { Logger.Info($"Sealed block {t.Result.ToString(Block.Format.HashNumberDiffAndTx)}"); } BlockTree.SuggestBlock(t.Result); Metrics.BlocksSealed++; _lastProducedBlock = DateTime.UtcNow; return true; } else { if (Logger.IsInfo) { Logger.Info($"Failed to seal block {processedBlock.ToString(Block.Format.HashNumberDiffAndTx)} (null seal)"); } Metrics.FailedBlockSeals++; } } else if (t.IsFaulted) { if (Logger.IsError) { Logger.Error("Mining failed", t.Exception); } Metrics.FailedBlockSeals++; } else if (t.IsCanceled) { if (Logger.IsInfo) { Logger.Info($"Sealing block {processedBlock.Number} cancelled"); } Metrics.FailedBlockSeals++; } return false; }), token)); } } return(Task.FromResult(false)); }
protected async Task RunTest(LegacyBlockchainTest test, Stopwatch stopwatch = null) { TestContext.Write($"Running {test.Name} at {DateTime.UtcNow:HH:mm:ss.ffffff}"); Assert.IsNull(test.LoadFailure, "test data loading failure"); ISnapshotableDb stateDb = new StateDb(); ISnapshotableDb codeDb = new StateDb(); ISpecProvider specProvider; if (test.NetworkAfterTransition != null) { specProvider = new CustomSpecProvider( (0, Frontier.Instance), (1, test.Network), (test.TransitionBlockNumber, test.NetworkAfterTransition)); } else { specProvider = new CustomSpecProvider( (0, Frontier.Instance), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier (1, test.Network)); } if (specProvider.GenesisSpec != Frontier.Instance) { Assert.Fail("Expected genesis spec to be Frontier for blockchain tests"); } DifficultyCalculator.Wrapped = new DifficultyCalculator(specProvider); IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); IEthereumEcdsa ecdsa = new EthereumEcdsa(specProvider, _logManager); IStateProvider stateProvider = new StateProvider(stateDb, codeDb, _logManager); ITxPool transactionPool = new TxPool(NullTxStorage.Instance, new Timestamper(), ecdsa, specProvider, new TxPoolConfig(), stateProvider, _logManager); IReceiptStorage receiptStorage = NullReceiptStorage.Instance; var blockInfoDb = new MemDb(); IBlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), specProvider, transactionPool, NullBloomStorage.Instance, _logManager); IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, _logManager); ITxValidator txValidator = new TxValidator(ChainId.MainNet); IHeaderValidator headerValidator = new HeaderValidator(blockTree, Sealer, specProvider, _logManager); IOmmersValidator ommersValidator = new OmmersValidator(blockTree, headerValidator, _logManager); IBlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, ommersValidator, specProvider, _logManager); IStorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, _logManager); IVirtualMachine virtualMachine = new VirtualMachine( stateProvider, storageProvider, blockhashProvider, specProvider, _logManager); IBlockProcessor blockProcessor = new BlockProcessor( specProvider, blockValidator, rewardCalculator, new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, _logManager), stateDb, codeDb, stateProvider, storageProvider, transactionPool, receiptStorage, _logManager); IBlockchainProcessor blockchainProcessor = new BlockchainProcessor( blockTree, blockProcessor, new TxSignaturesRecoveryStep(ecdsa, NullTxPool.Instance, _logManager), _logManager, false); InitializeTestState(test, stateProvider, storageProvider, specProvider); List <(Block Block, string ExpectedException)> correctRlp = new List <(Block, string)>(); for (int i = 0; i < test.Blocks.Length; i++) { try { TestBlockJson testBlockJson = test.Blocks[i]; var rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream(); Block suggestedBlock = Rlp.Decode <Block>(rlpContext); suggestedBlock.Header.SealEngineType = test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None; Assert.AreEqual(new Keccak(testBlockJson.BlockHeader.Hash), suggestedBlock.Header.Hash, "hash of the block"); for (int ommerIndex = 0; ommerIndex < suggestedBlock.Ommers.Length; ommerIndex++) { Assert.AreEqual(new Keccak(testBlockJson.UncleHeaders[ommerIndex].Hash), suggestedBlock.Ommers[ommerIndex].Hash, "hash of the ommer"); } correctRlp.Add((suggestedBlock, testBlockJson.ExpectedException)); } catch (Exception) { _logger?.Info($"Invalid RLP ({i})"); } } if (correctRlp.Count == 0) { Assert.AreEqual(new Keccak(test.GenesisBlockHeader.Hash), test.LastBlockHash); return; } if (test.GenesisRlp == null) { test.GenesisRlp = Rlp.Encode(new Block(JsonToBlockchainTest.Convert(test.GenesisBlockHeader))); } Block genesisBlock = Rlp.Decode <Block>(test.GenesisRlp.Bytes); Assert.AreEqual(new Keccak(test.GenesisBlockHeader.Hash), genesisBlock.Header.Hash, "genesis header hash"); ManualResetEvent genesisProcessed = new ManualResetEvent(false); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 0) { Assert.AreEqual(genesisBlock.Header.StateRoot, stateProvider.StateRoot, "genesis state root"); genesisProcessed.Set(); } }; blockchainProcessor.Start(); blockTree.SuggestBlock(genesisBlock); genesisProcessed.WaitOne(); for (int i = 0; i < correctRlp.Count; i++) { stopwatch?.Start(); try { if (correctRlp[i].ExpectedException != null) { _logger.Info($"Expecting block exception: {correctRlp[i].ExpectedException}"); } if (correctRlp[i].Block.Hash == null) { throw new Exception($"null hash in {test.Name} block {i}"); } // TODO: mimic the actual behaviour where block goes through validating sync manager? if (!test.SealEngineUsed || blockValidator.ValidateSuggestedBlock(correctRlp[i].Block)) { blockTree.SuggestBlock(correctRlp[i].Block); } else { Console.WriteLine("Invalid block"); } } catch (InvalidBlockException) { } catch (Exception ex) { _logger?.Info(ex.ToString()); } } await blockchainProcessor.StopAsync(true); stopwatch?.Stop(); List <string> differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), storageProvider, stateProvider); // if (differences.Any()) // { // BlockTrace blockTrace = blockchainProcessor.TraceBlock(blockTree.BestSuggested.Hash); // _logger.Info(new UnforgivingJsonSerializer().Serialize(blockTrace, true)); // } Assert.Zero(differences.Count, "differences"); }
public SyncingContext BlockIsKnown() { Assert.True(BlockTree.IsKnownBlock(_blockHeader.Number, _blockHeader.Hash)); return(this); }
protected async Task RunTest(BlockchainTest test, Stopwatch stopwatch = null) { LoggingTraceListener traceListener = new LoggingTraceListener(); // TODO: not supported in .NET Core, need to replace? // Debug.Listeners.Clear(); // Debug.Listeners.Add(traceListener); IDbProvider dbProvider = new MemDbProvider(_logManager); StateTree stateTree = new StateTree(dbProvider.GetOrCreateStateDb()); ISpecProvider specProvider; if (test.NetworkAfterTransition != null) { specProvider = new CustomSpecProvider( (0, Frontier.Instance), (1, test.Network), (test.TransitionBlockNumber, test.NetworkAfterTransition)); } else { specProvider = new CustomSpecProvider( (0, Frontier.Instance), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier (1, test.Network)); } if (specProvider.GenesisSpec != Frontier.Instance) { Assert.Fail("Expected genesis spec to be Frontier for blockchain tests"); } IDifficultyCalculator difficultyCalculator = new DifficultyCalculator(specProvider); IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); IBlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), new MemDb(), specProvider, _logManager); IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree); ISignatureValidator signatureValidator = new SignatureValidator(ChainId.MainNet); ITransactionValidator transactionValidator = new TransactionValidator(signatureValidator); IHeaderValidator headerValidator = new HeaderValidator(difficultyCalculator, blockTree, SealEngine, specProvider, _logManager); IOmmersValidator ommersValidator = new OmmersValidator(blockTree, headerValidator, _logManager); IBlockValidator blockValidator = new BlockValidator(transactionValidator, headerValidator, ommersValidator, specProvider, _logManager); IStateProvider stateProvider = new StateProvider(stateTree, dbProvider.GetOrCreateCodeDb(), _logManager); IStorageProvider storageProvider = new StorageProvider(dbProvider, stateProvider, _logManager); IVirtualMachine virtualMachine = new VirtualMachine( stateProvider, storageProvider, blockhashProvider, _logManager); ISealEngine sealEngine = new EthashSealEngine(new Ethash(_logManager), _logManager); ITransactionStore transactionStore = new TransactionStore(); IEthereumSigner signer = new EthereumSigner(specProvider, _logManager); IBlockProcessor blockProcessor = new BlockProcessor( specProvider, blockValidator, rewardCalculator, new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, NullTracer.Instance, _logManager), dbProvider, stateProvider, storageProvider, transactionStore, _logManager); IBlockchainProcessor blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, signer, _logManager); InitializeTestState(test, stateProvider, storageProvider, specProvider); List <(Block Block, string ExpectedException)> correctRlpsBlocks = new List <(Block, string)>(); for (int i = 0; i < test.Blocks.Length; i++) { try { TestBlockJson testBlockJson = test.Blocks[i]; var rlpContext = Hex.ToBytes(testBlockJson.Rlp).AsRlpContext(); Block suggestedBlock = Rlp.Decode <Block>(rlpContext); Assert.AreEqual(new Keccak(testBlockJson.BlockHeader.Hash), suggestedBlock.Header.Hash, "hash of the block"); for (int ommerIndex = 0; ommerIndex < suggestedBlock.Ommers.Length; ommerIndex++) { Assert.AreEqual(new Keccak(testBlockJson.UncleHeaders[ommerIndex].Hash), suggestedBlock.Ommers[ommerIndex].Hash, "hash of the ommer"); } correctRlpsBlocks.Add((suggestedBlock, testBlockJson.ExpectedException)); } catch (Exception e) { _logger?.Info($"Invalid RLP ({i})"); } } if (correctRlpsBlocks.Count == 0) { Assert.AreEqual(new Keccak(test.GenesisBlockHeader.Hash), test.LastBlockHash); return; } if (test.GenesisRlp == null) { test.GenesisRlp = Rlp.Encode(new Block(Convert(test.GenesisBlockHeader))); } Block genesisBlock = Rlp.Decode <Block>(test.GenesisRlp.Bytes); Assert.AreEqual(new Keccak(test.GenesisBlockHeader.Hash), genesisBlock.Header.Hash, "genesis header hash"); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 0) { Assert.AreEqual(genesisBlock.Header.StateRoot, stateTree.RootHash, "genesis state root"); } }; blockchainProcessor.Start(); blockTree.SuggestBlock(genesisBlock); for (int i = 0; i < correctRlpsBlocks.Count; i++) { stopwatch?.Start(); try { if (correctRlpsBlocks[i].ExpectedException != null) { _logger.Info($"Expecting block exception: {correctRlpsBlocks[i].ExpectedException}"); } if (correctRlpsBlocks[i].Block.Hash == null) { throw new Exception($"null hash in {test.Name} block {i}"); } // TODO: mimic the actual behaviour where block goes through validating sync manager? if (blockValidator.ValidateSuggestedBlock(correctRlpsBlocks[i].Block)) { blockTree.SuggestBlock(correctRlpsBlocks[i].Block); } else { Console.WriteLine("Invalid block"); } } catch (InvalidBlockException ex) { } catch (Exception ex) { _logger?.Info(ex.ToString()); } } await blockchainProcessor.StopAsync(true); stopwatch?.Stop(); RunAssertions(test, blockTree.RetrieveHeadBlock(), storageProvider, stateProvider); }
public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = false) { if (_logger.IsInfo) { _logger.Info($"CREATING NODE {privateKey.Address}"); } _logManagers[privateKey] = LimboLogs.Instance; // _logManagers[privateKey] = new OneLoggerLogManager(new ConsoleAsyncLogger(LogLevel.Debug, $"{privateKey.Address} ")); var nodeLogManager = _logManagers[privateKey]; AutoResetEvent newHeadBlockEvent = new AutoResetEvent(false); _blockEvents.Add(privateKey, newHeadBlockEvent); MemDb blocksDb = new MemDb(); MemDb headersDb = new MemDb(); MemDb blockInfoDb = new MemDb(); TxPool txPool = new TxPool(new InMemoryTxStorage(), _timestamp, _ethereumEcdsa, GoerliSpecProvider.Instance, new TxPoolConfig(), _logManager); _pools[privateKey] = txPool; BlockTree blockTree = new BlockTree(blocksDb, headersDb, blockInfoDb, GoerliSpecProvider.Instance, txPool, nodeLogManager); blockTree.NewHeadBlock += (sender, args) => { _blockEvents[privateKey].Set(); }; BlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, LimboLogs.Instance); _blockTrees.Add(privateKey, blockTree); IBasicWallet wallet = new BasicWallet(privateKey); SnapshotManager snapshotManager = new SnapshotManager(_cliqueConfig, blocksDb, blockTree, _ethereumEcdsa, nodeLogManager); _snapshotManager[privateKey] = snapshotManager; CliqueSealer cliqueSealer = new CliqueSealer(wallet, _cliqueConfig, snapshotManager, privateKey.Address, nodeLogManager); ISnapshotableDb stateDb = new StateDb(); ISnapshotableDb codeDb = new StateDb(); IDb traceDb = new MemDb(); StateProvider stateProvider = new StateProvider(stateDb, codeDb, nodeLogManager); stateProvider.CreateAccount(TestItem.PrivateKeyD.Address, 100.Ether()); stateProvider.Commit(GoerliSpecProvider.Instance.GenesisSpec); _genesis.StateRoot = _genesis3Validators.StateRoot = stateProvider.StateRoot; _genesis.Hash = BlockHeader.CalculateHash(_genesis.Header); _genesis3Validators.Hash = BlockHeader.CalculateHash(_genesis3Validators.Header); StorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, nodeLogManager); TransactionProcessor transactionProcessor = new TransactionProcessor(GoerliSpecProvider.Instance, stateProvider, storageProvider, new VirtualMachine(stateProvider, storageProvider, blockhashProvider, nodeLogManager), nodeLogManager); BlockProcessor blockProcessor = new BlockProcessor(GoerliSpecProvider.Instance, TestBlockValidator.AlwaysValid, NoBlockRewards.Instance, transactionProcessor, stateDb, codeDb, traceDb, stateProvider, storageProvider, txPool, NullReceiptStorage.Instance, nodeLogManager); BlockchainProcessor processor = new BlockchainProcessor(blockTree, blockProcessor, new AuthorRecoveryStep(snapshotManager), nodeLogManager, false, false); processor.Start(); StateProvider minerStateProvider = new StateProvider(stateDb, codeDb, nodeLogManager); StorageProvider minerStorageProvider = new StorageProvider(stateDb, minerStateProvider, nodeLogManager); VirtualMachine minerVirtualMachine = new VirtualMachine(minerStateProvider, minerStorageProvider, blockhashProvider, nodeLogManager); TransactionProcessor minerTransactionProcessor = new TransactionProcessor(GoerliSpecProvider.Instance, minerStateProvider, minerStorageProvider, minerVirtualMachine, nodeLogManager); BlockProcessor minerBlockProcessor = new BlockProcessor(GoerliSpecProvider.Instance, TestBlockValidator.AlwaysValid, NoBlockRewards.Instance, minerTransactionProcessor, stateDb, codeDb, traceDb, minerStateProvider, minerStorageProvider, txPool, NullReceiptStorage.Instance, nodeLogManager); BlockchainProcessor minerProcessor = new BlockchainProcessor(blockTree, minerBlockProcessor, new AuthorRecoveryStep(snapshotManager), nodeLogManager, false, false); if (withGenesisAlreadyProcessed) { ProcessGenesis(privateKey); } CliqueBlockProducer blockProducer = new CliqueBlockProducer(txPool, minerProcessor, blockTree, _timestamp, new CryptoRandom(), minerStateProvider, snapshotManager, cliqueSealer, privateKey.Address, _cliqueConfig, nodeLogManager); blockProducer.Start(); _producers.Add(privateKey, blockProducer); return(this); }
public async Task Can_process_mined_blocks() { int timeMultiplier = 1; // for debugging TimeSpan miningDelay = TimeSpan.FromMilliseconds(50 * timeMultiplier); /* logging & instrumentation */ // OneLoggerLogManager logger = new OneLoggerLogManager(new SimpleConsoleLogger(true)); ILogManager logManager = NullLogManager.Instance; ILogger logger = logManager.GetClassLogger(); /* spec */ FakeSealer sealer = new FakeSealer(miningDelay); RopstenSpecProvider specProvider = RopstenSpecProvider.Instance; /* store & validation */ EthereumEcdsa ethereumEcdsa = new EthereumEcdsa(specProvider, logManager); MemDb receiptsDb = new MemDb(); MemDb traceDb = new MemDb(); TxPool txPool = new TxPool(new NullTransactionStorage(), new PendingTransactionThresholdValidator(), new Timestamp(), ethereumEcdsa, specProvider, logManager); IReceiptStorage receiptStorage = new PersistentReceiptStorage(receiptsDb, specProvider); BlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), new MemDb(), specProvider, txPool, logManager); Timestamp timestamp = new Timestamp(); DifficultyCalculator difficultyCalculator = new DifficultyCalculator(specProvider); HeaderValidator headerValidator = new HeaderValidator(blockTree, sealer, specProvider, logManager); OmmersValidator ommersValidator = new OmmersValidator(blockTree, headerValidator, logManager); TxValidator txValidator = new TxValidator(ChainId.Ropsten); BlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, ommersValidator, specProvider, logManager); /* state & storage */ StateDb codeDb = new StateDb(); StateDb stateDb = new StateDb(); StateProvider stateProvider = new StateProvider(stateDb, codeDb, logManager); StorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, logManager); TestTransactionsGenerator generator = new TestTransactionsGenerator(txPool, ethereumEcdsa, TimeSpan.FromMilliseconds(5 * timeMultiplier), NullLogManager.Instance); generator.Start(); /* blockchain processing */ BlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, LimboLogs.Instance); VirtualMachine virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, logManager); TransactionProcessor processor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, logManager); RewardCalculator rewardCalculator = new RewardCalculator(specProvider); BlockProcessor blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, processor, stateDb, codeDb, traceDb, stateProvider, storageProvider, txPool, receiptStorage, new SyncConfig(), logManager); BlockchainProcessor blockchainProcessor = new BlockchainProcessor(blockTree, blockProcessor, new TxSignaturesRecoveryStep(ethereumEcdsa, NullTxPool.Instance, LimboLogs.Instance), logManager, false, false); /* load ChainSpec and init */ ChainSpecLoader loader = new ChainSpecLoader(new EthereumJsonSerializer()); string path = "chainspec.json"; logManager.GetClassLogger().Info($"Loading ChainSpec from {path}"); ChainSpec chainSpec = loader.Load(File.ReadAllBytes(path)); foreach (var allocation in chainSpec.Allocations) { stateProvider.CreateAccount(allocation.Key, allocation.Value); } stateProvider.Commit(specProvider.GenesisSpec); chainSpec.Genesis.Header.StateRoot = stateProvider.StateRoot; // TODO: shall it be HeaderSpec and not BlockHeader? chainSpec.Genesis.Header.Hash = BlockHeader.CalculateHash(chainSpec.Genesis.Header); if (chainSpec.Genesis.Hash != new Keccak("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d")) { throw new Exception("Unexpected genesis hash"); } /* start processing */ blockTree.SuggestBlock(chainSpec.Genesis); blockchainProcessor.Start(); MinedBlockProducer minedBlockProducer = new MinedBlockProducer(difficultyCalculator, txPool, blockchainProcessor, sealer, blockTree, timestamp, NullLogManager.Instance); minedBlockProducer.Start(); ManualResetEventSlim manualResetEvent = new ManualResetEventSlim(false); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 6) { manualResetEvent.Set(); } }; manualResetEvent.Wait(miningDelay * 12 * timeMultiplier); await minedBlockProducer.StopAsync(); int previousCount = 0; int totalTx = 0; for (int i = 0; i < 6; i++) { Block block = blockTree.FindBlock(i); logger.Info($"Block {i} with {block.Transactions.Length} txs"); ManualResetEventSlim blockProcessedEvent = new ManualResetEventSlim(false); blockchainProcessor.ProcessingQueueEmpty += (sender, args) => blockProcessedEvent.Set(); blockchainProcessor.SuggestBlock(block, ProcessingOptions.ForceProcessing | ProcessingOptions.StoreReceipts | ProcessingOptions.ReadOnlyChain); blockProcessedEvent.Wait(1000); Tracer tracer = new Tracer(blockchainProcessor, receiptStorage, blockTree, new MemDb()); int currentCount = receiptsDb.Keys.Count; logger.Info($"Current count of receipts {currentCount}"); logger.Info($"Previous count of receipts {previousCount}"); if (block.Transactions.Length > 0) { GethLikeTxTrace trace = tracer.Trace(block.Transactions[0].Hash); Assert.AreSame(GethLikeTxTrace.QuickFail, trace); Assert.AreNotEqual(previousCount, currentCount, $"receipts at block {i}"); totalTx += block.Transactions.Length; } previousCount = currentCount; } Assert.AreNotEqual(0, totalTx, "no tx in blocks"); }
public void Initialize() { Rlp.RegisterDecoders(typeof(ParityTraceDecoder).Assembly); _ethSerializer = new EthereumJsonSerializer(); ISpecProvider specProvider = MainNetSpecProvider.Instance; IEthereumEcdsa ethereumEcdsa = new EthereumEcdsa(specProvider, LimboLogs.Instance); ITxStorage txStorage = new InMemoryTxStorage(); ISnapshotableDb stateDb = new StateDb(); ISnapshotableDb codeDb = new StateDb(); IStateReader stateReader = new StateReader(stateDb, codeDb, LimboLogs.Instance); IStateProvider stateProvider = new StateProvider(stateDb, codeDb, LimboLogs.Instance); stateProvider.CreateAccount(TestItem.AddressA, 1000.Ether()); stateProvider.CreateAccount(TestItem.AddressB, 1000.Ether()); stateProvider.CreateAccount(TestItem.AddressC, 1000.Ether()); byte[] code = Bytes.FromHexString("0xabcd"); Keccak codeHash = Keccak.Compute(code); stateProvider.UpdateCode(code); stateProvider.UpdateCodeHash(TestItem.AddressA, codeHash, specProvider.GenesisSpec); IStorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, LimboLogs.Instance); storageProvider.Set(new StorageAddress(TestItem.AddressA, UInt256.One), Bytes.FromHexString("0xabcdef")); storageProvider.Commit(); stateProvider.Commit(specProvider.GenesisSpec); ITxPool txPool = new TxPool(txStorage, Timestamper.Default, ethereumEcdsa, specProvider, new TxPoolConfig(), stateProvider, LimboLogs.Instance); IDb blockDb = new MemDb(); IDb headerDb = new MemDb(); IDb blockInfoDb = new MemDb(); IDb traceDb = new MemDb(); IBlockTree blockTree = new BlockTree(blockDb, headerDb, blockInfoDb, new ChainLevelInfoRepository(blockDb), specProvider, txPool, LimboLogs.Instance); IReceiptStorage receiptStorage = new InMemoryReceiptStorage(); VirtualMachine virtualMachine = new VirtualMachine(stateProvider, storageProvider, new BlockhashProvider(blockTree, LimboLogs.Instance), specProvider, LimboLogs.Instance); TransactionProcessor txProcessor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, LimboLogs.Instance); IBlockProcessor blockProcessor = new BlockProcessor(specProvider, AlwaysValidBlockValidator.Instance, new RewardCalculator(specProvider), txProcessor, stateDb, codeDb, traceDb, stateProvider, storageProvider, txPool, receiptStorage, LimboLogs.Instance); IFilterStore filterStore = new FilterStore(); IFilterManager filterManager = new FilterManager(filterStore, blockProcessor, txPool, LimboLogs.Instance); _blockchainBridge = new BlockchainBridge(stateReader, stateProvider, storageProvider, blockTree, txPool, receiptStorage, filterStore, filterManager, NullWallet.Instance, txProcessor, ethereumEcdsa); BlockchainProcessor blockchainProcessor = new BlockchainProcessor(blockTree, blockProcessor, new TxSignaturesRecoveryStep(ethereumEcdsa, txPool, LimboLogs.Instance), LimboLogs.Instance, true, true); blockchainProcessor.Start(); ManualResetEventSlim resetEvent = new ManualResetEventSlim(false); blockTree.NewHeadBlock += (s, e) => { if (e.Block.Number == 9) { resetEvent.Set(); } }; Block genesis = Build.A.Block.Genesis.WithStateRoot(new Keccak("0x1ef7300d8961797263939a3d29bbba4ccf1702fabf02d8ad7a20b454edb6fd2f")).TestObject; blockTree.SuggestBlock(genesis); Block previousBlock = genesis; for (int i = 1; i < 10; i++) { Block block = Build.A.Block.WithNumber(i).WithParent(previousBlock).WithStateRoot(new Keccak("0x1ef7300d8961797263939a3d29bbba4ccf1702fabf02d8ad7a20b454edb6fd2f")).TestObject; blockTree.SuggestBlock(block); previousBlock = block; } resetEvent.Wait(); _ethModule = new EthModule(LimboLogs.Instance, _blockchainBridge); _blockTree = blockTree; }
public void Setup() { IDbProvider memDbProvider = TestMemDbProvider.Init(); TrieStore trieStore = new TrieStore(new MemDb(), LimboLogs.Instance); StateProvider stateProvider = new StateProvider(trieStore, memDbProvider.CodeDb, LimboLogs.Instance); StorageProvider storageProvider = new StorageProvider(trieStore, stateProvider, LimboLogs.Instance); ChainLevelInfoRepository chainLevelInfoRepository = new ChainLevelInfoRepository(memDbProvider); ISpecProvider specProvider = MainnetSpecProvider.Instance; IBloomStorage bloomStorage = NullBloomStorage.Instance; EthereumEcdsa ecdsa = new EthereumEcdsa(1, LimboLogs.Instance); ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(specProvider, _blockTree); _blockTree = new BlockTree( memDbProvider, chainLevelInfoRepository, specProvider, bloomStorage, new SyncConfig(), LimboLogs.Instance); TxPool.TxPool txPool = new TxPool.TxPool( NullTxStorage.Instance, ecdsa, new ChainHeadInfoProvider(specProvider, _blockTree, stateProvider), new TxPoolConfig(), new TxValidator(specProvider.ChainId), LimboLogs.Instance, transactionComparerProvider.GetDefaultComparer()); BlockhashProvider blockhashProvider = new BlockhashProvider(_blockTree, LimboLogs.Instance); VirtualMachine virtualMachine = new VirtualMachine( stateProvider, storageProvider, blockhashProvider, specProvider, LimboLogs.Instance); TransactionProcessor transactionProcessor = new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, LimboLogs.Instance); BlockProcessor blockProcessor = new BlockProcessor( MainnetSpecProvider.Instance, Always.Valid, new RewardCalculator(specProvider), transactionProcessor, stateProvider, storageProvider, txPool, NullReceiptStorage.Instance, new WitnessCollector(memDbProvider.StateDb, LimboLogs.Instance), LimboLogs.Instance); _blockchainProcessor = new BlockchainProcessor( _blockTree, blockProcessor, new RecoverSignatures( ecdsa, txPool, specProvider, LimboLogs.Instance), LimboLogs.Instance, BlockchainProcessor.Options.Default); }
private void OnBlockProduced(object?sender, BlockEventArgs e) { BlockTree.SuggestBlock(e.Block, BlockTreeSuggestOptions.ForceDontSetAsMain); BlockchainProcessor.Process(e.Block !, GetProcessingOptions(), NullBlockTracer.Instance); BlockTree.UpdateMainChain(new[] { e.Block ! }, true);
public async Task Merge_Happy_path(long pivot, long headNumber, int options, int threshold, long insertedBeaconBlocks) { BlockTreeTests.BlockTreeTestScenario.ScenarioBuilder blockTrees = BlockTreeTests.BlockTreeTestScenario .GoesLikeThis() .WithBlockTrees(4, (int)headNumber + 1) .InsertBeaconPivot(pivot) .InsertHeaders(4, pivot - 1) .InsertBeaconBlocks(pivot + 1, insertedBeaconBlocks, BlockTreeTests.BlockTreeTestScenario.ScenarioBuilder.TotalDifficultyMode.Null); BlockTree notSyncedTree = blockTrees.NotSyncedTree; BlockTree syncedTree = blockTrees.SyncedTree; Context ctx = new(notSyncedTree); DownloaderOptions downloaderOptions = (DownloaderOptions)options; bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts; InMemoryReceiptStorage receiptStorage = new(); MemDb metadataDb = blockTrees.NotSyncedTreeBuilder.MetadataDb; PoSSwitcher posSwitcher = new(new MergeConfig() { Enabled = true, TerminalTotalDifficulty = "0" }, new SyncConfig(), metadataDb, notSyncedTree, RopstenSpecProvider.Instance, LimboLogs.Instance); BeaconPivot beaconPivot = new(new SyncConfig(), metadataDb, notSyncedTree, LimboLogs.Instance); beaconPivot.EnsurePivot(blockTrees.SyncedTree.FindHeader(pivot, BlockTreeLookupOptions.None)); beaconPivot.ProcessDestination = blockTrees.SyncedTree.FindHeader(pivot, BlockTreeLookupOptions.None); MergeBlockDownloader downloader = new( posSwitcher, beaconPivot, ctx.Feed, ctx.PeerPool, notSyncedTree, Always.Valid, Always.Valid, NullSyncReport.Instance, receiptStorage, RopstenSpecProvider.Instance, CreateMergePeerChoiceStrategy(posSwitcher, beaconPivot), new ChainLevelHelper(notSyncedTree, beaconPivot, new SyncConfig(), LimboLogs.Instance), Substitute.For <ISyncProgressResolver>(), LimboLogs.Instance); Response responseOptions = Response.AllCorrect; if (withReceipts) { responseOptions |= Response.WithTransactions; } SyncPeerMock syncPeer = new(syncedTree, withReceipts, responseOptions, 16000000); PeerInfo peerInfo = new(syncPeer); await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None); ctx.BlockTree.BestSuggestedHeader.Number.Should().Be(Math.Max(0, insertedBeaconBlocks)); ctx.BlockTree.BestKnownNumber.Should().Be(Math.Max(0, insertedBeaconBlocks)); int receiptCount = 0; for (int i = (int)Math.Max(0, headNumber - threshold); i < peerInfo.HeadNumber; i++) { if (i % 3 == 0) { receiptCount += 2; } } receiptStorage.Count.Should().Be(withReceipts ? receiptCount : 0); beaconPivot.ProcessDestination?.Number.Should().Be(insertedBeaconBlocks); }
protected override UInt256 CalculateDifficulty(BlockHeader parent, UInt256 timestamp) { Block parentBlock = BlockTree.FindBlock(parent.Hash, BlockTreeLookupOptions.None); return(_difficultyCalculator.Calculate(parent.Difficulty, parent.Timestamp, timestamp, parent.Number + 1, parentBlock.Ommers.Length > 0)); }
public async Task Can_load_from_DB_when_there_is_an_invalid_block_in_DB_and_a_valid_branch() { MemDb blocksDb = new MemDb(); MemDb blockInfosDb = new MemDb(); MemDb headersDb = new MemDb(); BlockTree tree1 = new BlockTree(blocksDb, headersDb, blockInfosDb, MainNetSpecProvider.Instance, NullTxPool.Instance, LimboLogs.Instance); Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; Block block2B = Build.A.Block.WithNumber(2).WithDifficulty(1).WithParent(block1B).TestObject; Block block3B = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2B).TestObject; tree1.SuggestBlock(block0); tree1.SuggestBlock(block1); tree1.SuggestBlock(block2); tree1.SuggestBlock(block3); tree1.SuggestBlock(block1B); tree1.SuggestBlock(block2B); tree1.SuggestBlock(block3B); tree1.UpdateMainChain(block0); BlockTree tree2 = new BlockTree(blocksDb, headersDb, blockInfosDb, MainNetSpecProvider.Instance, NullTxPool.Instance, LimboLogs.Instance); CancellationTokenSource tokenSource = new CancellationTokenSource(); #pragma warning disable 4014 Task.Delay(_dbLoadTimeout).ContinueWith(t => tokenSource.Cancel()); #pragma warning restore 4014 tree2.NewBestSuggestedBlock += (sender, args) => { if (args.Block.Hash == block1.Hash) { tree2.DeleteInvalidBlock(args.Block); } else { tree2.UpdateMainChain(args.Block); } }; await tree2.LoadBlocksFromDb(tokenSource.Token, startBlockNumber : null, batchSize : 1); /* note the block tree historically loads one less block than it could */ Assert.AreEqual(3L, tree2.BestKnownNumber, "best known"); Assert.AreEqual(block2B.Hash, tree2.Head.Hash, "head"); Assert.AreEqual(block2B.Hash, tree2.BestSuggested.Hash, "suggested"); Assert.IsNull(blocksDb.Get(block1.Hash), "block 1"); Assert.IsNull(blocksDb.Get(block2.Hash), "block 2"); Assert.IsNull(blocksDb.Get(block3.Hash), "block 3"); Assert.NotNull(blockInfosDb.Get(1), "level 1"); Assert.NotNull(blockInfosDb.Get(2), "level 2"); Assert.NotNull(blockInfosDb.Get(3), "level 3"); }
private static void AddToMain(BlockTree blockTree, Block block0) { blockTree.SuggestBlock(block0); blockTree.UpdateMainChain(new[] { block0 }); }
public async Task Can_load_from_DB_when_there_is_only_an_invalid_chain_in_DB() { MemDb blocksDb = new MemDb(); MemDb blockInfosDb = new MemDb(); MemDb headersDb = new MemDb(); BlockTree tree1 = new BlockTree( blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance); Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; tree1.SuggestBlock(block0); tree1.SuggestBlock(block1); tree1.SuggestBlock(block2); tree1.SuggestBlock(block3); tree1.UpdateMainChain(block0); BlockTree tree2 = new BlockTree( blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance); CancellationTokenSource tokenSource = new CancellationTokenSource(); #pragma warning disable 4014 Task.Delay(_dbLoadTimeout).ContinueWith(t => tokenSource.Cancel()); #pragma warning restore 4014 tree2.NewBestSuggestedBlock += (sender, args) => { if (args.Block.Hash == block1.Hash) { tree2.DeleteInvalidBlock(args.Block); } else { tree2.UpdateMainChain(args.Block); } }; DbBlocksLoader loader = new DbBlocksLoader(tree2, LimboNoErrorLogger.Instance, null, 1); await tree2.Accept(loader, tokenSource.Token); /* note the block tree historically loads one less block than it could */ Assert.AreEqual(0L, tree2.BestKnownNumber, "best known"); Assert.AreEqual(block0.Hash, tree2.Head.Hash, "head"); Assert.AreEqual(block0.Hash, tree2.BestSuggestedHeader.Hash, "suggested"); Assert.IsNull(blocksDb.Get(block1.Hash), "block 1"); Assert.IsNull(blocksDb.Get(block2.Hash), "block 2"); Assert.IsNull(blocksDb.Get(block3.Hash), "block 3"); Assert.IsNull(blockInfosDb.Get(1), "level 1"); Assert.IsNull(blockInfosDb.Get(2), "level 2"); Assert.IsNull(blockInfosDb.Get(3), "level 3"); }
// It takes dotCover to run it quite long, increased timeouts public async Task Can_process_mined_blocks() { int timeMultiplier = 1; // for debugging TimeSpan miningDelay = TimeSpan.FromMilliseconds(200 * timeMultiplier); /* logging & instrumentation */ // OneLoggerLogManager logger = new OneLoggerLogManager(new SimpleConsoleLogger(true)); ILogManager logManager = LimboLogs.Instance; ILogger logger = logManager.GetClassLogger(); /* spec */ FakeSealer sealer = new FakeSealer(miningDelay); RopstenSpecProvider specProvider = RopstenSpecProvider.Instance; /* state & storage */ StateDb codeDb = new StateDb(); StateDb stateDb = new StateDb(); StateProvider stateProvider = new StateProvider(stateDb, codeDb, logManager); StorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, logManager); StateReader stateReader = new StateReader(stateDb, codeDb, logManager); /* store & validation */ EthereumEcdsa ecdsa = new EthereumEcdsa(specProvider.ChainId, logManager); MemColumnsDb <ReceiptsColumns> receiptsDb = new MemColumnsDb <ReceiptsColumns>(); TxPool.TxPool txPool = new TxPool.TxPool(NullTxStorage.Instance, Timestamper.Default, ecdsa, specProvider, new TxPoolConfig(), stateProvider, logManager); IReceiptStorage receiptStorage = new PersistentReceiptStorage(receiptsDb, specProvider, new ReceiptsRecovery()); var blockInfoDb = new MemDb(); BlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), specProvider, txPool, NullBloomStorage.Instance, logManager); ITimestamper timestamper = Timestamper.Default; DifficultyCalculator difficultyCalculator = new DifficultyCalculator(specProvider); HeaderValidator headerValidator = new HeaderValidator(blockTree, sealer, specProvider, logManager); OmmersValidator ommersValidator = new OmmersValidator(blockTree, headerValidator, logManager); TxValidator txValidator = new TxValidator(ChainId.Ropsten); BlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, ommersValidator, specProvider, logManager); TestTransactionsGenerator generator = new TestTransactionsGenerator(txPool, ecdsa, TimeSpan.FromMilliseconds(50 * timeMultiplier), LimboLogs.Instance); generator.Start(); /* blockchain processing */ BlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, LimboLogs.Instance); VirtualMachine virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, specProvider, logManager); TransactionProcessor processor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, logManager); RewardCalculator rewardCalculator = new RewardCalculator(specProvider); BlockProcessor blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, processor, stateDb, codeDb, stateProvider, storageProvider, txPool, receiptStorage, logManager); BlockchainProcessor blockchainProcessor = new BlockchainProcessor(blockTree, blockProcessor, new TxSignaturesRecoveryStep(ecdsa, NullTxPool.Instance, LimboLogs.Instance), logManager, BlockchainProcessor.Options.NoReceipts); /* load ChainSpec and init */ ChainSpecLoader loader = new ChainSpecLoader(new EthereumJsonSerializer()); string path = "chainspec.json"; logManager.GetClassLogger().Info($"Loading ChainSpec from {path}"); ChainSpec chainSpec = loader.Load(File.ReadAllText(path)); foreach (var allocation in chainSpec.Allocations) { stateProvider.CreateAccount(allocation.Key, allocation.Value.Balance); if (allocation.Value.Code != null) { Keccak codeHash = stateProvider.UpdateCode(allocation.Value.Code); stateProvider.UpdateCodeHash(allocation.Key, codeHash, specProvider.GenesisSpec); } } stateProvider.Commit(specProvider.GenesisSpec); chainSpec.Genesis.Header.StateRoot = stateProvider.StateRoot; chainSpec.Genesis.Header.Hash = chainSpec.Genesis.Header.CalculateHash(); if (chainSpec.Genesis.Hash != new Keccak("0xafbc3c327d2d18ff2b843e89226ef288fcee379542f854f982e4cfb85916d126")) { throw new Exception("Unexpected genesis hash"); } /* start processing */ blockTree.SuggestBlock(chainSpec.Genesis); blockchainProcessor.Start(); var transactionSelector = new TxPoolTxSource(txPool, stateReader, logManager); MinedBlockProducer minedBlockProducer = new MinedBlockProducer(transactionSelector, blockchainProcessor, sealer, blockTree, blockchainProcessor, stateProvider, timestamper, LimboLogs.Instance, difficultyCalculator); minedBlockProducer.Start(); ManualResetEventSlim manualResetEvent = new ManualResetEventSlim(false); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 6) { manualResetEvent.Set(); } }; manualResetEvent.Wait(miningDelay * 100); await minedBlockProducer.StopAsync(); int previousCount = 0; int totalTx = 0; for (int i = 0; i < 6; i++) { Block block = blockTree.FindBlock(i, BlockTreeLookupOptions.None); Assert.That(block, Is.Not.Null, $"Block {i} not produced"); logger.Info($"Block {i} with {block.Transactions.Length} txs"); ManualResetEventSlim blockProcessedEvent = new ManualResetEventSlim(false); blockchainProcessor.ProcessingQueueEmpty += (sender, args) => blockProcessedEvent.Set(); blockchainProcessor.Enqueue(block, ProcessingOptions.ForceProcessing | ProcessingOptions.StoreReceipts | ProcessingOptions.ReadOnlyChain); blockProcessedEvent.Wait(miningDelay); GethStyleTracer gethStyleTracer = new GethStyleTracer(blockchainProcessor, receiptStorage, blockTree); int currentCount = receiptsDb.Keys.Count; logger.Info($"Current count of receipts {currentCount}"); logger.Info($"Previous count of receipts {previousCount}"); if (block.Transactions.Length > 0) { Assert.AreNotEqual(previousCount, currentCount, $"receipts at block {i}"); totalTx += block.Transactions.Length; } previousCount = currentCount; } Assert.AreNotEqual(0, totalTx, "no tx in blocks"); }
public void Test() { ISpecProvider specProvider = MainnetSpecProvider.Instance; DbProvider dbProvider = new DbProvider(DbModeHint.Mem); dbProvider.RegisterDb(DbNames.BlockInfos, new MemDb()); dbProvider.RegisterDb(DbNames.Blocks, new MemDb()); dbProvider.RegisterDb(DbNames.Headers, new MemDb()); dbProvider.RegisterDb(DbNames.State, new MemDb()); dbProvider.RegisterDb(DbNames.Code, new MemDb()); BlockTree blockTree = new BlockTree( dbProvider, new ChainLevelInfoRepository(dbProvider), specProvider, NullBloomStorage.Instance, LimboLogs.Instance); TrieStore trieStore = new TrieStore( dbProvider.RegisteredDbs[DbNames.State], NoPruning.Instance, Archive.Instance, LimboLogs.Instance); StateProvider stateProvider = new StateProvider( trieStore, dbProvider.RegisteredDbs[DbNames.Code], LimboLogs.Instance); StorageProvider storageProvider = new StorageProvider(trieStore, stateProvider, LimboLogs.Instance); BlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, LimboLogs.Instance); VirtualMachine virtualMachine = new VirtualMachine( stateProvider, storageProvider, blockhashProvider, specProvider, LimboLogs.Instance); TransactionProcessor txProcessor = new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, LimboLogs.Instance); BlockProcessor blockProcessor = new BlockProcessor( specProvider, Always.Valid, NoBlockRewards.Instance, txProcessor, stateProvider, storageProvider, NullTxPool.Instance, NullReceiptStorage.Instance, NullWitnessCollector.Instance, LimboLogs.Instance); BlockchainProcessor blockchainProcessor = new BlockchainProcessor( blockTree, blockProcessor, NullRecoveryStep.Instance, LimboLogs.Instance, BlockchainProcessor.Options.Default); BuildBlocksWhenRequested trigger = new BuildBlocksWhenRequested(); var timestamper = new ManualTimestamper(); DevBlockProducer devBlockProducer = new DevBlockProducer( EmptyTxSource.Instance, blockchainProcessor, stateProvider, blockTree, blockchainProcessor, trigger, timestamper, specProvider, new MiningConfig { Enabled = true }, LimboLogs.Instance); blockchainProcessor.Start(); devBlockProducer.Start(); AutoResetEvent autoResetEvent = new AutoResetEvent(false); blockTree.NewHeadBlock += (s, e) => autoResetEvent.Set(); blockTree.SuggestBlock(Build.A.Block.Genesis.TestObject); autoResetEvent.WaitOne(1000).Should().BeTrue("genesis"); trigger.BuildBlock(); autoResetEvent.WaitOne(1000).Should().BeTrue("1"); blockTree.Head.Number.Should().Be(1); }
private void SelectToolboxToolStripMenuItem_Click(object sender, EventArgs e) { BlockTree.Focus(); // CTRL + {SPACE} = Focus blockTree }
protected override IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer, ITransactionComparerProvider transactionComparerProvider) { MiningConfig miningConfig = new() { MinGasPrice = UInt256.One }; BlockProducerEnvFactory blockProducerEnvFactory = new( DbProvider, BlockTree, ReadOnlyTrieStore, SpecProvider, BlockValidator, NoBlockRewards.Instance, ReceiptStorage, BlockPreprocessorStep, TxPool, transactionComparerProvider, miningConfig, LogManager) { TransactionsExecutorFactory = new MevBlockProducerTransactionsExecutorFactory(SpecProvider, LogManager) }; Eth2BlockProducer CreateEth2BlockProducer(IBlockProductionTrigger blockProductionTrigger, ITxSource?txSource = null) => new Eth2TestBlockProducerFactory(GasLimitCalculator, txSource).Create( blockProducerEnvFactory, BlockTree, blockProductionTrigger, SpecProvider, Signer, Timestamper, miningConfig, LogManager); MevBlockProducer.MevBlockProducerInfo CreateProducer(int bundleLimit = 0, ITxSource?additionalTxSource = null) { bool BundleLimitTriggerCondition(BlockProductionEventArgs e) { BlockHeader?parent = BlockTree.GetProducedBlockParent(e.ParentHeader); if (parent is not null) { IEnumerable <MevBundle> bundles = BundlePool.GetBundles(parent, Timestamper); return(bundles.Count() >= bundleLimit); } return(false); } IManualBlockProductionTrigger manualTrigger = new BuildBlocksWhenRequested(); IBlockProductionTrigger trigger = manualTrigger; if (bundleLimit != 0) { trigger = new TriggerWithCondition(manualTrigger, BundleLimitTriggerCondition); } IBlockProducer producer = CreateEth2BlockProducer(trigger, additionalTxSource); return(new MevBlockProducer.MevBlockProducerInfo(producer, manualTrigger, new BeneficiaryTracer())); } int megabundleProducerCount = _relayAddresses.Any() ? 1 : 0; List <MevBlockProducer.MevBlockProducerInfo> blockProducers = new(_maxMergedBundles + megabundleProducerCount + 1); // Add non-mev block MevBlockProducer.MevBlockProducerInfo standardProducer = CreateProducer(); blockProducers.Add(standardProducer); // Try blocks with all bundle numbers <= maxMergedBundles for (int bundleLimit = 1; bundleLimit <= _maxMergedBundles; bundleLimit++) { BundleSelector bundleSelector = new(BundlePool, bundleLimit); BundleTxSource bundleTxSource = new(bundleSelector, Timestamper); MevBlockProducer.MevBlockProducerInfo bundleProducer = CreateProducer(bundleLimit, bundleTxSource); blockProducers.Add(bundleProducer); } if (megabundleProducerCount > 0) { MegabundleSelector megabundleSelector = new(BundlePool); BundleTxSource megabundleTxSource = new(megabundleSelector, Timestamper); MevBlockProducer.MevBlockProducerInfo bundleProducer = CreateProducer(0, megabundleTxSource); blockProducers.Add(bundleProducer); } return(new MevBlockProducer(BlockProductionTrigger, LogManager, blockProducers.ToArray())); }
public static void UpdateMainChain(this BlockTree blockTree, Block block) { blockTree.UpdateMainChain(new [] { block }); }
private Task ProduceNewBlock(BlockHeader parent, CancellationToken token) { lock (_newBlockLock) { _stateProvider.StateRoot = parent.StateRoot; Block block = PrepareBlock(parent); if (!PreparedBlockCanBeMined(block)) { return(Task.CompletedTask); } Block processedBlock = Processor.Process(block, ProcessingOptions.ProducingBlock, NullBlockTracer.Instance); if (processedBlock == null) { if (Logger.IsError) { Logger.Error("Block prepared by block producer was rejected by processor."); } } else { _sealer.SealBlock(processedBlock, token).ContinueWith(t => { if (t.IsCompletedSuccessfully) { if (t.Result != null) { if (Logger.IsInfo) { Logger.Info($"Sealed block {t.Result.ToString(Block.Format.HashNumberDiffAndTx)}"); } BlockTree.SuggestBlock(t.Result); } else { if (Logger.IsInfo) { Logger.Info($"Failed to seal block {processedBlock.ToString(Block.Format.HashNumberDiffAndTx)} (null seal)"); } } } else if (t.IsFaulted) { if (Logger.IsError) { Logger.Error("Mining failed", t.Exception); } } else if (t.IsCanceled) { if (Logger.IsInfo) { Logger.Info($"Sealing block {processedBlock.Number} cancelled"); } } }, token); } return(Task.CompletedTask); } }
private SyncTestContext CreateSyncManager(int index) { Rlp.RegisterDecoders(typeof(ParityTraceDecoder).Assembly); var logManager = NoErrorLimboLogs.Instance; ConsoleAsyncLogger logger = new ConsoleAsyncLogger(LogLevel.Debug, "PEER " + index + " "); // var logManager = new OneLoggerLogManager(logger); var specProvider = new SingleReleaseSpecProvider(ConstantinopleFix.Instance, MainNetSpecProvider.Instance.ChainId); MemDb traceDb = new MemDb(); MemDb blockDb = new MemDb(); MemDb headerDb = new MemDb(); MemDb blockInfoDb = new MemDb(); StateDb codeDb = new StateDb(); StateDb stateDb = new StateDb(); var stateProvider = new StateProvider(stateDb, codeDb, logManager); stateProvider.CreateAccount(TestItem.AddressA, 10000.Ether()); stateProvider.Commit(specProvider.GenesisSpec); stateProvider.CommitTree(); stateDb.Commit(); var storageProvider = new StorageProvider(stateDb, stateProvider, logManager); var receiptStorage = new InMemoryReceiptStorage(); var ecdsa = new EthereumEcdsa(specProvider, logManager); var txPool = new TxPool(new InMemoryTxStorage(), new Timestamper(), ecdsa, specProvider, new TxPoolConfig(), stateProvider, logManager); var tree = new BlockTree(blockDb, headerDb, blockInfoDb, specProvider, txPool, logManager); var blockhashProvider = new BlockhashProvider(tree, LimboLogs.Instance); var virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, specProvider, logManager); var sealValidator = TestSealValidator.AlwaysValid; var headerValidator = new HeaderValidator(tree, sealValidator, specProvider, logManager); var txValidator = TestTxValidator.AlwaysValid; var ommersValidator = new OmmersValidator(tree, headerValidator, logManager); var blockValidator = new BlockValidator(txValidator, headerValidator, ommersValidator, specProvider, logManager); // var blockValidator = TestBlockValidator.AlwaysValid; SyncConfig syncConfig = new SyncConfig(); syncConfig.FastSync = _synchronizerType == SynchronizerType.Fast; var rewardCalculator = new RewardCalculator(specProvider); var txProcessor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, logManager); var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, txProcessor, stateDb, codeDb, traceDb, stateProvider, storageProvider, txPool, receiptStorage, logManager); var step = new TxSignaturesRecoveryStep(ecdsa, txPool, logManager); var processor = new BlockchainProcessor(tree, blockProcessor, step, logManager, true, true); var nodeStatsManager = new NodeStatsManager(new StatsConfig(), logManager); var syncPeerPool = new EthSyncPeerPool(tree, nodeStatsManager, syncConfig, 25, logManager); StateProvider devState = new StateProvider(stateDb, codeDb, logManager); StorageProvider devStorage = new StorageProvider(stateDb, devState, logManager); var devEvm = new VirtualMachine(devState, devStorage, blockhashProvider, specProvider, logManager); var devTxProcessor = new TransactionProcessor(specProvider, devState, devStorage, devEvm, logManager); var devBlockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, devTxProcessor, stateDb, codeDb, traceDb, devState, devStorage, txPool, receiptStorage, logManager); var devChainProcessor = new BlockchainProcessor(tree, devBlockProcessor, step, logManager, false, false); var producer = new DevBlockProducer(txPool, devChainProcessor, tree, new Timestamper(), logManager); NodeDataFeed feed = new NodeDataFeed(codeDb, stateDb, logManager); NodeDataDownloader downloader = new NodeDataDownloader(syncPeerPool, feed, logManager); Synchronizer synchronizer = new Synchronizer( MainNetSpecProvider.Instance, tree, NullReceiptStorage.Instance, blockValidator, sealValidator, syncPeerPool, syncConfig, downloader, NullSyncReport.Instance, logManager); var syncServer = new SyncServer(stateDb, codeDb, tree, receiptStorage, TestSealValidator.AlwaysValid, syncPeerPool, synchronizer, syncConfig, logManager); ManualResetEventSlim waitEvent = new ManualResetEventSlim(); tree.NewHeadBlock += (s, e) => waitEvent.Set(); if (index == 0) { _genesis = Build.A.Block.Genesis.WithStateRoot(stateProvider.StateRoot).TestObject; producer.Start(); } syncPeerPool.Start(); synchronizer.Start(); processor.Start(); tree.SuggestBlock(_genesis); if (!waitEvent.Wait(1000)) { throw new Exception("No genesis"); } SyncTestContext context = new SyncTestContext(); context.Ecdsa = ecdsa; context.BlockchainProcessor = processor; context.PeerPool = syncPeerPool; context.StateProvider = stateProvider; context.Synchronizer = synchronizer; context.SyncServer = syncServer; context.Tree = tree; context.BlockProducer = producer; context.TxPool = txPool; context.Logger = logger; return(context); }
private async Task InitBlockchain() { ChainSpec chainSpec = LoadChainSpec(_initConfig.ChainSpecPath); /* spec */ // TODO: rebuild to use chainspec ISpecProvider specProvider; if (chainSpec.ChainId == RopstenSpecProvider.Instance.ChainId) { specProvider = RopstenSpecProvider.Instance; } else if (chainSpec.ChainId == MainNetSpecProvider.Instance.ChainId) { specProvider = MainNetSpecProvider.Instance; } else { throw new NotSupportedException($"Not yet tested, not yet supported ChainId {chainSpec.ChainId}"); } var ethereumSigner = new EthereumSigner( specProvider, _logManager); var transactionStore = new TransactionStore(); var sealEngine = ConfigureSealEngine( transactionStore, ethereumSigner); /* sync */ IDbConfig dbConfig = _configProvider.GetConfig <IDbConfig>(); foreach (PropertyInfo propertyInfo in typeof(IDbConfig).GetProperties()) { _logger.Info($"DB {propertyInfo.Name}: {propertyInfo.GetValue(dbConfig)}"); } var blocksDb = new DbOnTheRocks( Path.Combine(_dbBasePath, DbOnTheRocks.BlocksDbPath), dbConfig); var blockInfosDb = new DbOnTheRocks( Path.Combine(_dbBasePath, DbOnTheRocks.BlockInfosDbPath), dbConfig); var receiptsDb = new DbOnTheRocks( Path.Combine(_dbBasePath, DbOnTheRocks.ReceiptsDbPath), dbConfig); /* blockchain */ _blockTree = new BlockTree( blocksDb, blockInfosDb, receiptsDb, specProvider, _logManager); var difficultyCalculator = new DifficultyCalculator( specProvider); /* validation */ var headerValidator = new HeaderValidator( difficultyCalculator, _blockTree, sealEngine, specProvider, _logManager); var ommersValidator = new OmmersValidator( _blockTree, headerValidator, _logManager); var txValidator = new TransactionValidator( new SignatureValidator(specProvider.ChainId)); var blockValidator = new BlockValidator( txValidator, headerValidator, ommersValidator, specProvider, _logManager); /* state */ var dbProvider = new RocksDbProvider( _dbBasePath, _logManager, dbConfig); var stateDb = dbProvider.GetOrCreateStateDb(); var stateTree = new StateTree(stateDb); var stateProvider = new StateProvider( stateTree, dbProvider.GetOrCreateCodeDb(), _logManager); var storageProvider = new StorageProvider( dbProvider, stateProvider, _logManager); /* blockchain processing */ var blockhashProvider = new BlockhashProvider( _blockTree); var virtualMachine = new VirtualMachine( stateProvider, storageProvider, blockhashProvider, _logManager); var transactionProcessor = new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, _tracer, _logManager); var rewardCalculator = new RewardCalculator( specProvider); var blockProcessor = new BlockProcessor( specProvider, blockValidator, rewardCalculator, transactionProcessor, dbProvider, stateProvider, storageProvider, transactionStore, _logManager); _blockchainProcessor = new BlockchainProcessor( _blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ethereumSigner, _logManager, _perfService); // create shared objects between discovery and peer manager _nodeFactory = new NodeFactory(); _nodeStatsProvider = new NodeStatsProvider(_configProvider.GetConfig <IStatsConfig>(), _nodeFactory, _logManager); var jsonSerializer = new JsonSerializer( _logManager); var encrypter = new AesEncrypter( _configProvider, _logManager); _keyStore = new FileKeyStore( _configProvider, jsonSerializer, encrypter, _cryptoRandom, _logManager); //creating blockchain bridge BlockchainBridge = new BlockchainBridge( ethereumSigner, stateProvider, _keyStore, _blockTree, stateDb, transactionStore); EthereumSigner = ethereumSigner; _blockchainProcessor.Start(); LoadGenesisBlock(chainSpec, string.IsNullOrWhiteSpace(_initConfig.GenesisHash) ? null : new Keccak(_initConfig.GenesisHash), _blockTree, stateProvider, specProvider); #pragma warning disable 4014 LoadBlocksFromDb(); #pragma warning restore 4014 await InitializeNetwork( transactionStore, blockValidator, headerValidator, txValidator); }
protected async Task <EthereumTestResult> RunTest(BlockchainTest test, Stopwatch?stopwatch = null) { TestContext.Write($"Running {test.Name} at {DateTime.UtcNow:HH:mm:ss.ffffff}"); Assert.IsNull(test.LoadFailure, "test data loading failure"); IDb stateDb = new MemDb(); IDb codeDb = new MemDb(); ISpecProvider specProvider; if (test.NetworkAfterTransition != null) { specProvider = new CustomSpecProvider(1, (0, Frontier.Instance), (1, test.Network), (test.TransitionBlockNumber, test.NetworkAfterTransition)); } else { specProvider = new CustomSpecProvider(1, (0, Frontier.Instance), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier (1, test.Network)); } if (specProvider.GenesisSpec != Frontier.Instance) { Assert.Fail("Expected genesis spec to be Frontier for blockchain tests"); } bool isNetworkAfterTransitionLondon = test.NetworkAfterTransition == London.Instance; HeaderDecoder.Eip1559TransitionBlock = isNetworkAfterTransitionLondon ? test.TransitionBlockNumber : long.MaxValue; DifficultyCalculator.Wrapped = new EthashDifficultyCalculator(specProvider); IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); IEthereumEcdsa ecdsa = new EthereumEcdsa(specProvider.ChainId, _logManager); TrieStore trieStore = new(stateDb, _logManager); IStateProvider stateProvider = new StateProvider(trieStore, codeDb, _logManager); MemDb blockInfoDb = new MemDb(); IBlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), specProvider, NullBloomStorage.Instance, _logManager); ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(specProvider, blockTree); IStateReader stateReader = new StateReader(trieStore, codeDb, _logManager); IChainHeadInfoProvider chainHeadInfoProvider = new ChainHeadInfoProvider(specProvider, blockTree, stateReader); ITxPool transactionPool = new TxPool(ecdsa, chainHeadInfoProvider, new TxPoolConfig(), new TxValidator(specProvider.ChainId), _logManager, transactionComparerProvider.GetDefaultComparer()); IReceiptStorage receiptStorage = NullReceiptStorage.Instance; IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, _logManager); ITxValidator txValidator = new TxValidator(ChainId.Mainnet); IHeaderValidator headerValidator = new HeaderValidator(blockTree, Sealer, specProvider, _logManager); IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager); IBlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, unclesValidator, specProvider, _logManager); IStorageProvider storageProvider = new StorageProvider(trieStore, stateProvider, _logManager); IVirtualMachine virtualMachine = new VirtualMachine( blockhashProvider, specProvider, _logManager); IBlockProcessor blockProcessor = new BlockProcessor( specProvider, blockValidator, rewardCalculator, new BlockProcessor.BlockValidationTransactionsExecutor( new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, _logManager), stateProvider), stateProvider, storageProvider, receiptStorage, NullWitnessCollector.Instance, _logManager); IBlockchainProcessor blockchainProcessor = new BlockchainProcessor( blockTree, blockProcessor, new RecoverSignatures(ecdsa, NullTxPool.Instance, specProvider, _logManager), _logManager, BlockchainProcessor.Options.NoReceipts); InitializeTestState(test, stateProvider, storageProvider, specProvider); List <(Block Block, string ExpectedException)> correctRlp = new(); for (int i = 0; i < test.Blocks.Length; i++) { try { TestBlockJson testBlockJson = test.Blocks[i]; var rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream(); Block suggestedBlock = Rlp.Decode <Block>(rlpContext); suggestedBlock.Header.SealEngineType = test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None; Assert.AreEqual(new Keccak(testBlockJson.BlockHeader.Hash), suggestedBlock.Header.Hash, "hash of the block"); for (int uncleIndex = 0; uncleIndex < suggestedBlock.Uncles.Length; uncleIndex++) { Assert.AreEqual(new Keccak(testBlockJson.UncleHeaders[uncleIndex].Hash), suggestedBlock.Uncles[uncleIndex].Hash, "hash of the uncle"); } correctRlp.Add((suggestedBlock, testBlockJson.ExpectedException)); } catch (Exception) { _logger?.Info($"Invalid RLP ({i})"); } } if (correctRlp.Count == 0) { EthereumTestResult result; if (test.GenesisBlockHeader is null) { result = new EthereumTestResult(test.Name, "Genesis block header missing in the test spec."); } else if (!new Keccak(test.GenesisBlockHeader.Hash).Equals(test.LastBlockHash)) { result = new EthereumTestResult(test.Name, "Genesis hash mismatch"); } else { result = new EthereumTestResult(test.Name, null, true); } return(result); } if (test.GenesisRlp == null) { test.GenesisRlp = Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader))); } Block genesisBlock = Rlp.Decode <Block>(test.GenesisRlp.Bytes); Assert.AreEqual(new Keccak(test.GenesisBlockHeader.Hash), genesisBlock.Header.Hash, "genesis header hash"); ManualResetEvent genesisProcessed = new(false); blockTree.NewHeadBlock += (_, args) => { if (args.Block.Number == 0) { Assert.AreEqual(genesisBlock.Header.StateRoot, stateProvider.StateRoot, "genesis state root"); genesisProcessed.Set(); } }; blockchainProcessor.Start(); blockTree.SuggestBlock(genesisBlock); genesisProcessed.WaitOne(); for (int i = 0; i < correctRlp.Count; i++) { stopwatch?.Start(); try { if (correctRlp[i].ExpectedException != null) { _logger.Info($"Expecting block exception: {correctRlp[i].ExpectedException}"); } if (correctRlp[i].Block.Hash == null) { throw new Exception($"null hash in {test.Name} block {i}"); } // TODO: mimic the actual behaviour where block goes through validating sync manager? if (!test.SealEngineUsed || blockValidator.ValidateSuggestedBlock(correctRlp[i].Block)) { blockTree.SuggestBlock(correctRlp[i].Block); } else { Console.WriteLine("Invalid block"); } } catch (InvalidBlockException) { } catch (Exception ex) { _logger?.Info(ex.ToString()); } } await blockchainProcessor.StopAsync(true); stopwatch?.Stop(); List <string> differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), storageProvider, stateProvider); // if (differences.Any()) // { // BlockTrace blockTrace = blockchainProcessor.TraceBlock(blockTree.BestSuggested.Hash); // _logger.Info(new UnforgivingJsonSerializer().Serialize(blockTrace, true)); // } Assert.Zero(differences.Count, "differences"); return(new EthereumTestResult ( test.Name, null, differences.Count == 0 )); }
public void Initialize() { var logger = LimboLogs.Instance; var specProvider = MainNetSpecProvider.Instance; var ethereumEcdsa = new EthereumEcdsa(specProvider, logger); var txStorage = new InMemoryTxStorage(); var txPool = new TxPool.TxPool(txStorage, Timestamper.Default, ethereumEcdsa, specProvider, new TxPoolConfig(), new StateProvider(new StateDb(), new MemDb(), LimboLogs.Instance), LimboLogs.Instance); IDb blockDb = new MemDb(); IDb headerDb = new MemDb(); IDb blockInfoDb = new MemDb(); IBlockTree blockTree = new BlockTree(blockDb, headerDb, blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), specProvider, txPool, NullBloomStorage.Instance, LimboLogs.Instance); IReceiptStorage receiptStorage = new InMemoryReceiptStorage(); _parityModule = new ParityModule(new EthereumEcdsa(specProvider, logger), txPool, blockTree, receiptStorage, logger); var blockNumber = 2; var pendingTransaction = Build.A.Transaction.Signed(ethereumEcdsa, TestItem.PrivateKeyD, blockNumber) .WithSenderAddress(Address.FromNumber((UInt256)blockNumber)).TestObject; pendingTransaction.Signature.V = 37; txPool.AddTransaction(pendingTransaction, blockNumber, TxHandlingOptions.None); blockNumber = 1; var transaction = Build.A.Transaction.Signed(ethereumEcdsa, TestItem.PrivateKeyD, blockNumber) .WithSenderAddress(Address.FromNumber((UInt256)blockNumber)) .WithNonce(100).TestObject; transaction.Signature.V = 37; txPool.AddTransaction(transaction, blockNumber, TxHandlingOptions.None); Block genesis = Build.A.Block.Genesis .WithStateRoot(new Keccak("0x1ef7300d8961797263939a3d29bbba4ccf1702fabf02d8ad7a20b454edb6fd2f")) .TestObject; blockTree.SuggestBlock(genesis); blockTree.UpdateMainChain(new[] { genesis }, true); Block previousBlock = genesis; Block block = Build.A.Block.WithNumber(blockNumber).WithParent(previousBlock) .WithStateRoot(new Keccak("0x1ef7300d8961797263939a3d29bbba4ccf1702fabf02d8ad7a20b454edb6fd2f")) .WithTransactions(transaction) .TestObject; blockTree.SuggestBlock(block); blockTree.UpdateMainChain(new[] { block }, true); var logEntries = new[] { Build.A.LogEntry.TestObject }; receiptStorage.Add(new TxReceipt() { Bloom = new Bloom(logEntries), Index = 1, Recipient = TestItem.AddressA, Sender = TestItem.AddressB, BlockHash = TestItem.KeccakA, BlockNumber = 1, ContractAddress = TestItem.AddressC, GasUsed = 1000, TxHash = transaction.Hash, StatusCode = 0, GasUsedTotal = 2000, Logs = logEntries }, true); }
public override void OnBlockProcessingStart(Block block, ProcessingOptions options = ProcessingOptions.None) { if (block.IsGenesis) { return; } var isProducingBlock = options.IsProducingBlock(); var isProcessingBlock = !isProducingBlock; var isInitBlock = InitBlockNumber == block.Number; var notConsecutiveBlock = block.Number - 1 > _lastProcessedBlockNumber || _lastProcessedBlockNumber == 0; var shouldLoadValidators = Validators == null || notConsecutiveBlock || isProducingBlock; var mainChainProcessing = !ForSealing && isProcessingBlock; if (shouldLoadValidators) { Validators = isInitBlock || notConsecutiveBlock ? LoadValidatorsFromContract(BlockTree.FindParentHeader(block.Header, BlockTreeLookupOptions.None)) : ValidatorStore.GetValidators(); if (mainChainProcessing) { if (_logger.IsInfo) { _logger.Info($"{(isInitBlock ? "Initial" : "Current")} contract validators ({Validators.Length}): [{string.Join<Address>(", ", Validators)}]."); } } } if (isInitBlock) { if (mainChainProcessing) { ValidatorStore.SetValidators(InitBlockNumber, Validators); } InitiateChange(block, Validators.ToArray(), isProcessingBlock, true); } else { if (mainChainProcessing && notConsecutiveBlock) { bool loadedValidatorsAreSameInStore = (ValidatorStore.GetValidators()?.SequenceEqual(Validators) == true); if (!loadedValidatorsAreSameInStore) { ValidatorStore.SetValidators(_blockFinalizationManager.GetLastLevelFinalizedBy(block.ParentHash), Validators); } } if (isProcessingBlock) { bool reorganisationHappened = block.Number <= _lastProcessedBlockNumber; if (reorganisationHappened) { var reorganisationToBlockBeforePendingValidatorsInitChange = block.Number <= CurrentPendingValidators?.BlockNumber; SetPendingValidators(reorganisationToBlockBeforePendingValidatorsInitChange ? null : LoadPendingValidators(), reorganisationToBlockBeforePendingValidatorsInitChange); } else if (block.Number > _lastProcessedBlockNumber + 1) // blocks skipped, like fast sync { SetPendingValidators(TryGetInitChangeFromPastBlocks(block.ParentHash), true); } } else { // if we are not processing blocks we are not on consecutive blocks. // We need to initialize pending validators from db on each block being produced. SetPendingValidators(LoadPendingValidators()); } } base.OnBlockProcessingStart(block, options); FinalizePendingValidatorsIfNeeded(block.Header, isProcessingBlock); _lastProcessedBlockNumber = block.Number; }
public async Task Build_some_chain() { /* logging & instrumentation */ var logger = new OneLoggerLogManager(new SimpleConsoleLogger()); /* spec */ var blockMiningTime = TimeSpan.FromMilliseconds(500); var sealEngine = new FakeSealEngine(blockMiningTime); var specProvider = RopstenSpecProvider.Instance; /* store & validation */ var blockTree = new BlockTree(new MemDb(), new MemDb(), new MemDb(), specProvider, logger); var difficultyCalculator = new DifficultyCalculator(specProvider); var headerValidator = new HeaderValidator(difficultyCalculator, blockTree, sealEngine, specProvider, logger); var ommersValidator = new OmmersValidator(blockTree, headerValidator, logger); var transactionValidator = new TransactionValidator(new SignatureValidator(ChainId.Ropsten)); var blockValidator = new BlockValidator(transactionValidator, headerValidator, ommersValidator, specProvider, logger); /* state & storage */ var dbProvider = new MemDbProvider(logger); var stateTree = new StateTree(dbProvider.GetOrCreateStateDb()); var stateProvider = new StateProvider(stateTree, dbProvider.GetOrCreateCodeDb(), logger); var storageProvider = new StorageProvider(dbProvider, stateProvider, logger); /* blockchain processing */ var ethereumSigner = new EthereumSigner(specProvider, logger); var transactionStore = new TransactionStore(); var blockhashProvider = new BlockhashProvider(blockTree); var virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, logger); var processor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, NullTracer.Instance, logger); var rewardCalculator = new RewardCalculator(specProvider); var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, processor, dbProvider, stateProvider, storageProvider, transactionStore, logger); var blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ethereumSigner, logger); /* load ChainSpec and init */ ChainSpecLoader loader = new ChainSpecLoader(new UnforgivingJsonSerializer()); string path = Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\Chains", "ropsten.json")); logger.GetClassLogger().Info($"Loading ChainSpec from {path}"); ChainSpec chainSpec = loader.Load(File.ReadAllBytes(path)); foreach (KeyValuePair <Address, BigInteger> allocation in chainSpec.Allocations) { stateProvider.CreateAccount(allocation.Key, allocation.Value); } stateProvider.Commit(specProvider.GenesisSpec); chainSpec.Genesis.Header.StateRoot = stateProvider.StateRoot; // TODO: shall it be HeaderSpec and not BlockHeader? chainSpec.Genesis.Header.Hash = BlockHeader.CalculateHash(chainSpec.Genesis.Header); if (chainSpec.Genesis.Hash != new Keccak("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d")) { throw new Exception("Unexpected genesis hash"); } /* start processing */ sealEngine.IsMining = true; var testTransactionsGenerator = new TestTransactionsGenerator(transactionStore, ethereumSigner, blockMiningTime, logger); testTransactionsGenerator.Start(); blockchainProcessor.Start(); blockTree.SuggestBlock(chainSpec.Genesis); BigInteger roughlyNumberOfBlocks = 6; Thread.Sleep(blockMiningTime * (int)roughlyNumberOfBlocks); await blockchainProcessor.StopAsync(false); Assert.GreaterOrEqual(blockTree.Head.Number, roughlyNumberOfBlocks - 2, "number of blocks"); Assert.GreaterOrEqual(blockTree.Head.TotalTransactions, roughlyNumberOfBlocks - 2, "number of transactions"); }
public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = false) { AutoResetEvent newHeadBlockEvent = new AutoResetEvent(false); _blockEvents.Add(privateKey, newHeadBlockEvent); MemDb blocksDb = new MemDb(); MemDb blockInfoDb = new MemDb(); TransactionPool transactionPool = new TransactionPool(new InMemoryTransactionStorage(), new PendingTransactionThresholdValidator(), _timestamp, _ethereumSigner, GoerliSpecProvider.Instance, NullLogManager.Instance); _pools[privateKey] = transactionPool; BlockTree blockTree = new BlockTree(blocksDb, blockInfoDb, GoerliSpecProvider.Instance, transactionPool, NullLogManager.Instance); blockTree.NewHeadBlock += (sender, args) => { _blockEvents[privateKey].Set(); }; BlockhashProvider blockhashProvider = new BlockhashProvider(blockTree); _blockTrees.Add(privateKey, blockTree); EthereumSigner ethereumSigner = new EthereumSigner(GoerliSpecProvider.Instance, NullLogManager.Instance); CliqueSealEngine cliqueSealEngine = new CliqueSealEngine(_cliqueConfig, ethereumSigner, privateKey, new MemDb(), blockTree, NullLogManager.Instance); cliqueSealEngine.CanSeal = true; ISnapshotableDb stateDb = new StateDb(); ISnapshotableDb codeDb = new StateDb(); IDb traceDb = new MemDb(); StateProvider stateProvider = new StateProvider(new StateTree(stateDb), codeDb, NullLogManager.Instance); stateProvider.CreateAccount(TestObject.PrivateKeyD.Address, 100.Ether()); stateProvider.Commit(GoerliSpecProvider.Instance.GenesisSpec); _genesis.StateRoot = _genesis3Validators.StateRoot = stateProvider.StateRoot; _genesis.Hash = BlockHeader.CalculateHash(_genesis.Header); _genesis3Validators.Hash = BlockHeader.CalculateHash(_genesis3Validators.Header); StorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, NullLogManager.Instance); TransactionProcessor transactionProcessor = new TransactionProcessor(GoerliSpecProvider.Instance, stateProvider, storageProvider, new VirtualMachine(stateProvider, storageProvider, blockhashProvider, NullLogManager.Instance), NullLogManager.Instance); BlockProcessor blockProcessor = new BlockProcessor(GoerliSpecProvider.Instance, TestBlockValidator.AlwaysValid, new NoBlockRewards(), transactionProcessor, stateDb, codeDb, traceDb, stateProvider, storageProvider, transactionPool, NullReceiptStorage.Instance, NullLogManager.Instance); BlockchainProcessor processor = new BlockchainProcessor(blockTree, blockProcessor, new AuthorRecoveryStep(cliqueSealEngine), NullLogManager.Instance, false, false); processor.Start(); StateProvider minerStateProvider = new StateProvider(new StateTree(stateDb), codeDb, NullLogManager.Instance); StorageProvider minerStorageProvider = new StorageProvider(stateDb, minerStateProvider, NullLogManager.Instance); VirtualMachine minerVirtualMachine = new VirtualMachine(minerStateProvider, minerStorageProvider, blockhashProvider, NullLogManager.Instance); TransactionProcessor minerTransactionProcessor = new TransactionProcessor(GoerliSpecProvider.Instance, minerStateProvider, minerStorageProvider, minerVirtualMachine, NullLogManager.Instance); BlockProcessor minerBlockProcessor = new BlockProcessor(GoerliSpecProvider.Instance, TestBlockValidator.AlwaysValid, new NoBlockRewards(), minerTransactionProcessor, stateDb, codeDb, traceDb, minerStateProvider, minerStorageProvider, transactionPool, NullReceiptStorage.Instance, NullLogManager.Instance); BlockchainProcessor minerProcessor = new BlockchainProcessor(blockTree, minerBlockProcessor, new AuthorRecoveryStep(cliqueSealEngine), NullLogManager.Instance, false, false); if (withGenesisAlreadyProcessed) { ProcessGenesis(privateKey); } CliqueBlockProducer blockProducer = new CliqueBlockProducer(transactionPool, minerProcessor, blockTree, minerStateProvider, _timestamp, new CryptoRandom(), cliqueSealEngine, _cliqueConfig, privateKey.Address, NullLogManager.Instance); blockProducer.Start(); _producers.Add(privateKey, blockProducer); return(this); }
public async Task Can_load_from_DB_when_there_is_an_invalid_block_in_DB_and_a_valid_branch() { MemDb blocksDb = new MemDb(); MemDb blockInfosDb = new MemDb(); MemDb headersDb = new MemDb(); BlockTree tree1 = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullTxPool.Instance, NullBloomStorage.Instance, LimboLogs.Instance); Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; Block block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject; Block block2B = Build.A.Block.WithNumber(2).WithDifficulty(1).WithParent(block1B).TestObject; Block block3B = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2B).TestObject; tree1.SuggestBlock(block0); tree1.SuggestBlock(block1); // invalid block tree1.SuggestBlock(block2); // invalid branch tree1.SuggestBlock(block3); // invalid branch tree1.SuggestBlock(block1B); tree1.SuggestBlock(block2B); tree1.SuggestBlock(block3B); // expected to be head tree1.UpdateMainChain(block0); BlockTree tree2 = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullTxPool.Instance, NullBloomStorage.Instance, LimboLogs.Instance); CancellationTokenSource tokenSource = new CancellationTokenSource(); #pragma warning disable 4014 Task.Delay(_dbLoadTimeout).ContinueWith(t => tokenSource.Cancel()); #pragma warning restore 4014 tree2.NewBestSuggestedBlock += (sender, args) => { if (args.Block.Hash == block1.Hash) { tree2.DeleteInvalidBlock(args.Block); } else { tree2.UpdateMainChain(args.Block); } }; DbBlocksLoader loader = new DbBlocksLoader(tree2, LimboNoErrorLogger.Instance, null, 1); await tree2.Accept(loader, tokenSource.Token); Assert.AreEqual(3L, tree2.BestKnownNumber, "best known"); tree2.Head.Header.Should().BeEquivalentTo(block3B.Header, options => { return(options.Excluding(t => t.MaybeParent)); }); tree2.BestSuggestedHeader.Should().BeEquivalentTo(block3B.Header, options => { return(options.Excluding(t => t.MaybeParent)); }); Assert.IsNull(blocksDb.Get(block1.Hash), "block 1"); Assert.IsNull(blocksDb.Get(block2.Hash), "block 2"); Assert.IsNull(blocksDb.Get(block3.Hash), "block 3"); Assert.NotNull(blockInfosDb.Get(1), "level 1"); Assert.NotNull(blockInfosDb.Get(2), "level 2"); Assert.NotNull(blockInfosDb.Get(3), "level 3"); }
private void MineBlock(BlockTree tree, Block block) { tree.SuggestBlock(block); tree.UpdateMainChain(block); }
public void GlobalSetup() { ISnapshotableDb codeDb = new StateDb(); ISnapshotableDb stateDb = new StateDb(); IDb blockInfoDb = new MemDb(10, 5); ISpecProvider specProvider = MainNetSpecProvider.Instance; IReleaseSpec spec = MainNetSpecProvider.Instance.GenesisSpec; StateProvider stateProvider = new StateProvider(stateDb, codeDb, LimboLogs.Instance); stateProvider.CreateAccount(Address.Zero, 1000.Ether()); stateProvider.Commit(spec); StorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, LimboLogs.Instance); StateReader stateReader = new StateReader(stateDb, codeDb, LimboLogs.Instance); ChainLevelInfoRepository chainLevelInfoRepository = new ChainLevelInfoRepository(blockInfoDb); BlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), blockInfoDb, chainLevelInfoRepository, specProvider, NullTxPool.Instance, NullBloomStorage.Instance, LimboLogs.Instance); _blockhashProvider = new BlockhashProvider(blockTree, LimboLogs.Instance); _virtualMachine = new VirtualMachine(stateProvider, storageProvider, _blockhashProvider, specProvider, LimboLogs.Instance); Block genesisBlock = Build.A.Block.Genesis.TestObject; blockTree.SuggestBlock(genesisBlock); Block block1 = Build.A.Block.WithParent(genesisBlock).WithNumber(1).TestObject; blockTree.SuggestBlock(block1); TransactionProcessor transactionProcessor = new TransactionProcessor(MainNetSpecProvider.Instance, stateProvider, storageProvider, _virtualMachine, LimboLogs.Instance); BlockProcessor blockProcessor = new BlockProcessor(specProvider, AlwaysValidBlockValidator.Instance, new RewardCalculator(specProvider), transactionProcessor, stateDb, codeDb, stateProvider, storageProvider, NullTxPool.Instance, NullReceiptStorage.Instance, LimboLogs.Instance); BlockchainProcessor blockchainProcessor = new BlockchainProcessor( blockTree, blockProcessor, new TxSignaturesRecoveryStep(new EthereumEcdsa(specProvider, LimboLogs.Instance), NullTxPool.Instance, LimboLogs.Instance), LimboLogs.Instance, false); blockchainProcessor.Process(genesisBlock, ProcessingOptions.None, NullBlockTracer.Instance); blockchainProcessor.Process(block1, ProcessingOptions.None, NullBlockTracer.Instance); IBloomStorage bloomStorage = new BloomStorage(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); BlockchainBridge bridge = new BlockchainBridge( stateReader, stateProvider, storageProvider, blockTree, NullTxPool.Instance, NullReceiptStorage.Instance, NullFilterStore.Instance, NullFilterManager.Instance, new DevWallet(new WalletConfig(), LimboLogs.Instance), transactionProcessor, new EthereumEcdsa(MainNetSpecProvider.Instance, LimboLogs.Instance), bloomStorage, new ReceiptsRecovery()); _ethModule = new EthModule(new JsonRpcConfig(), LimboLogs.Instance, bridge); }