private static ISealEngine ConfigureSealEngine(TransactionStore transactionStore, EthereumSigner ethereumSigner, InitParams initParams) { var blockMiningTime = TimeSpan.FromMilliseconds(initParams.FakeMiningDelay ?? 12000); // var sealEngine = new EthashSealEngine(new Ethash()); var sealEngine = new FakeSealEngine(blockMiningTime, false); sealEngine.IsMining = initParams.IsMining ?? false; if (sealEngine.IsMining) { var transactionDelay = TimeSpan.FromMilliseconds((initParams.FakeMiningDelay ?? 12000) / 4); TestTransactionsGenerator testTransactionsGenerator = new TestTransactionsGenerator(transactionStore, ethereumSigner, transactionDelay, _logManager); // stateProvider.CreateAccount(testTransactionsGenerator.SenderAddress, 1000.Ether()); // stateProvider.Commit(specProvider.GenesisSpec); testTransactionsGenerator.Start(); } return(sealEngine); }
private static void InitBlockchain(ChainSpec chainSpec, bool isMining, int miningDelay) { /* spec */ var blockMiningTime = TimeSpan.FromMilliseconds(miningDelay); var transactionDelay = TimeSpan.FromMilliseconds(miningDelay / 4); var specProvider = RopstenSpecProvider.Instance; var difficultyCalculator = new DifficultyCalculator(specProvider); // var sealEngine = new EthashSealEngine(new Ethash()); var sealEngine = new FakeSealEngine(blockMiningTime, false); /* sync */ var transactionStore = new TransactionStore(); var blockTree = new BlockTree(RopstenSpecProvider.Instance, ChainLogger); /* validation */ var headerValidator = new HeaderValidator(difficultyCalculator, blockTree, sealEngine, specProvider, ChainLogger); var ommersValidator = new OmmersValidator(blockTree, headerValidator, ChainLogger); var txValidator = new TransactionValidator(new SignatureValidator(ChainId.Ropsten)); var blockValidator = new BlockValidator(txValidator, headerValidator, ommersValidator, specProvider, ChainLogger); /* state */ var dbProvider = new DbProvider(StateLogger); var codeDb = new InMemoryDb(); var stateDb = new InMemoryDb(); var stateTree = new StateTree(stateDb); var stateProvider = new StateProvider(stateTree, StateLogger, codeDb); var storageProvider = new StorageProvider(dbProvider, stateProvider, StateLogger); var storageDbProvider = new DbProvider(StateLogger); /* blockchain */ var ethereumSigner = new EthereumSigner(specProvider, ChainLogger); /* blockchain processing */ var blockhashProvider = new BlockhashProvider(blockTree); var virtualMachine = new VirtualMachine(specProvider, stateProvider, storageProvider, blockhashProvider, EvmLogger); var transactionProcessor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, ethereumSigner, ChainLogger); var rewardCalculator = new RewardCalculator(specProvider); var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, transactionProcessor, storageDbProvider, stateProvider, storageProvider, transactionStore, ChainLogger); _blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ChainLogger); /* genesis */ foreach (KeyValuePair <Address, BigInteger> allocation in chainSpec.Allocations) { stateProvider.CreateAccount(allocation.Key, allocation.Value); } stateProvider.Commit(specProvider.GenesisSpec); var testTransactionsGenerator = new TestTransactionsGenerator(transactionStore, ethereumSigner, transactionDelay, ChainLogger); stateProvider.CreateAccount(testTransactionsGenerator.SenderAddress, 1000.Ether()); stateProvider.Commit(specProvider.GenesisSpec); if (isMining) { testTransactionsGenerator.Start(); } Block genesis = chainSpec.Genesis; genesis.Header.StateRoot = stateProvider.StateRoot; genesis.Header.RecomputeHash(); // we are adding test transactions account so the state root will change (not an actual ropsten at the moment) // var expectedGenesisHash = "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"; // if (chainSpec.Genesis.Hash != new Keccak(expectedGenesisHash)) // { // throw new Exception($"Unexpected genesis hash for Ropsten, expected {expectedGenesisHash}, but was {chainSpec.Genesis.Hash}"); // } /* start test processing */ sealEngine.IsMining = isMining; _blockchainProcessor.Start(); blockTree.AddBlock(genesis); _syncManager = new SynchronizationManager( blockTree, blockValidator, headerValidator, transactionStore, txValidator, NetworkLogger); _syncManager.Start(); }
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 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 */ FakeSealEngine sealEngine = new FakeSealEngine(miningDelay); sealEngine.CanSeal = true; RopstenSpecProvider specProvider = RopstenSpecProvider.Instance; /* store & validation */ EthereumSigner ethereumSigner = new EthereumSigner(specProvider, logManager); MemDb receiptsDb = new MemDb(); MemDb traceDb = new MemDb(); TransactionPool transactionPool = new TransactionPool(new NullTransactionStorage(), new PendingTransactionThresholdValidator(), new Timestamp(), ethereumSigner, logManager); IReceiptStorage receiptStorage = new PersistentReceiptStorage(receiptsDb, specProvider); BlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), specProvider, transactionPool, logManager); Timestamp timestamp = new Timestamp(); DifficultyCalculator difficultyCalculator = new DifficultyCalculator(specProvider); HeaderValidator headerValidator = new HeaderValidator(blockTree, sealEngine, specProvider, logManager); OmmersValidator ommersValidator = new OmmersValidator(blockTree, headerValidator, logManager); TransactionValidator transactionValidator = new TransactionValidator(new SignatureValidator(ChainId.Ropsten)); BlockValidator blockValidator = new BlockValidator(transactionValidator, headerValidator, ommersValidator, specProvider, logManager); /* state & storage */ StateDb codeDb = new StateDb(); StateDb stateDb = new StateDb(); StateTree stateTree = new StateTree(stateDb); StateProvider stateProvider = new StateProvider(stateTree, codeDb, logManager); StorageProvider storageProvider = new StorageProvider(stateDb, stateProvider, logManager); TestTransactionsGenerator generator = new TestTransactionsGenerator(transactionPool, ethereumSigner, TimeSpan.FromMilliseconds(5 * timeMultiplier), NullLogManager.Instance); generator.Start(); /* blockchain processing */ BlockhashProvider blockhashProvider = new BlockhashProvider(blockTree); 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, transactionPool, receiptStorage, logManager); BlockchainProcessor blockchainProcessor = new BlockchainProcessor(blockTree, blockProcessor, new TxSignaturesRecoveryStep(ethereumSigner, NullTransactionPool.Instance), logManager, false, false); /* load ChainSpec and init */ ChainSpecLoader loader = new ChainSpecLoader(new UnforgivingJsonSerializer()); 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, transactionPool, blockchainProcessor, sealEngine, blockTree, timestamp, NullLogManager.Instance); minedBlockProducer.Start(); ManualResetEvent manualResetEvent = new ManualResetEvent(false); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 6) { manualResetEvent.Set(); } }; manualResetEvent.WaitOne(miningDelay * 12 * timeMultiplier); await minedBlockProducer.StopAsync(); int previousCount = 0; int totalTx = 0; for (int i = 0; i < 6; i++) { Block block = blockTree.FindBlock(new UInt256(i)); logger.Info($"Block {i} with {block.Transactions.Length} txs"); ManualResetEvent blockProcessedEvent = new ManualResetEvent(false); blockchainProcessor.ProcessingQueueEmpty += (sender, args) => blockProcessedEvent.Set(); blockchainProcessor.SuggestBlock(block.Hash, ProcessingOptions.ForceProcessing | ProcessingOptions.StoreReceipts | ProcessingOptions.ReadOnlyChain); blockProcessedEvent.WaitOne(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 async Task Test() { TimeSpan miningDelay = TimeSpan.FromMilliseconds(50); /* logging & instrumentation */ var logger = new OneLoggerLogManager(new SimpleConsoleLogger(true)); /* spec */ var sealEngine = new FakeSealEngine(miningDelay); sealEngine.IsMining = true; 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 codeDb = new MemDb(); var stateDb = new MemDb(); var stateTree = new StateTree(stateDb); var stateProvider = new StateProvider(stateTree, codeDb, logger); var storageDbProvider = new MemDbProvider(logger); var storageProvider = new StorageProvider(storageDbProvider, 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, storageDbProvider, stateProvider, storageProvider, transactionStore, logger); var blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ethereumSigner, logger, new PerfService(NullLogManager.Instance)); /* 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, UInt256> 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(); ManualResetEvent manualResetEvent = new ManualResetEvent(false); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 6) { manualResetEvent.Set(); } }; manualResetEvent.WaitOne(miningDelay * 12); await blockchainProcessor.StopAsync(true).ContinueWith( t => { if (t.IsFaulted) { throw t.Exception; } Assert.GreaterOrEqual((int)blockTree.Head.Number, 6); }); }