public void correctly_finalizes_blocks_in_chain(int chainLength, long twoThirdsMajorityTransition, Address[] blockCreators, int notFinalizedExpectedCount) { _validatorStore.GetValidators(Arg.Any <long?>()).Returns(blockCreators); var blockTreeBuilder = Build.A.BlockTree(); HashSet <BlockHeader> finalizedBlocks = new HashSet <BlockHeader>(); var finalizationManager = new AuRaBlockFinalizationManager(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager, twoThirdsMajorityTransition); finalizationManager.BlocksFinalized += (sender, args) => { foreach (var block in args.FinalizedBlocks) { finalizedBlocks.Add(block); } }; blockTreeBuilder.OfChainLength(chainLength, 0, 0, blockCreators); var start = 0; for (int i = start; i < chainLength; i++) { var blockHash = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.BlockHash; var block = blockTreeBuilder.TestObject.FindBlock(blockHash, BlockTreeLookupOptions.None); _blockProcessor.BlockProcessed += Raise.EventWith(new BlockProcessedEventArgs(block, Array.Empty <TxReceipt>())); } var isBlockFinalized = Enumerable.Range(start, chainLength).Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.IsFinalized); var expected = Enumerable.Range(start, chainLength).Select(i => i < chainLength - notFinalizedExpectedCount); finalizedBlocks.Count.Should().Be(chainLength - notFinalizedExpectedCount); isBlockFinalized.Should().BeEquivalentTo(expected); }
public void correctly_de_finalizes_blocks_on_block_reprocessing(int chainLength, int rerun, int validatorCount, bool twoThirdsMajorityTransition) { Address[] blockCreators = TestItem.Addresses.Take(validatorCount).ToArray(); _validatorStore.GetValidators(Arg.Any <long?>()).Returns(blockCreators); var blockTreeBuilder = Build.A.BlockTree(); var finalizationManager = new AuRaBlockFinalizationManager( blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager, twoThirdsMajorityTransition ? 0 : long.MaxValue); blockTreeBuilder.OfChainLength(chainLength, 0, 0, blockCreators); FinalizeToLevel(chainLength, blockTreeBuilder.ChainLevelInfoRepository); List <Block> blocks = Enumerable.Range(1, rerun) .Select(i => blockTreeBuilder.TestObject.FindBlock(chainLength - i, BlockTreeLookupOptions.None)) .Reverse() .ToList(); _blockProcessor.BlocksProcessing += Raise.EventWith(new BlocksProcessingEventArgs(blocks)); int majority = (twoThirdsMajorityTransition ? (validatorCount - 1) * 2 / 3 : (validatorCount - 1) / 2) + 1; for (int i = 1; i < rerun + majority; i++) { blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(chainLength - i).MainChainBlock.IsFinalized.Should().BeFalse(); } blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(chainLength - rerun - majority - 1).MainChainBlock.IsFinalized.Should().BeTrue(); }
public void correctly_finalizes_blocks_in_chain() { var count = 10; var blockTreeBuilder = Build.A.BlockTree(); HashSet <BlockHeader> finalizedBlocks = new HashSet <BlockHeader>(); var finalizationManager = new AuRaBlockFinalizationManager(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _auraValidator, _logManager); finalizationManager.BlocksFinalized += (sender, args) => { foreach (var block in args.FinalizedBlocks) { finalizedBlocks.Add(block); } }; blockTreeBuilder.OfChainLength(count, 0, 0, TestItem.AddressA, TestItem.AddressB); var start = 0; for (int i = start; i < count; i++) { var blockHash = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.BlockHash; var block = blockTreeBuilder.TestObject.FindBlock(blockHash, BlockTreeLookupOptions.None); _blockProcessor.BlockProcessed += Raise.EventWith(new BlockProcessedEventArgs(block)); } var result = Enumerable.Range(start, count).Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.IsFinalized); var expected = Enumerable.Range(start, count).Select(i => i != count - 1); finalizedBlocks.Count.Should().Be(count - 1); result.Should().BeEquivalentTo(expected); }
private IBlockFinalizationManager InitFinalizationManager(IAuRaBlockProcessorExtension auRaBlockProcessorExtension) { AuRaBlockFinalizationManager finalizationManager = new AuRaBlockFinalizationManager(_context.BlockTree, _context.ChainLevelInfoRepository, _context.MainBlockProcessor, _context.ValidatorStore, new ValidSealerStrategy(), _context.LogManager); auRaBlockProcessorExtension.SetFinalizationManager(finalizationManager); return(finalizationManager); }
public void correctly_initializes_lastFinalizedBlock() { var blockTreeBuilder = Build.A.BlockTree().OfChainLength(3, 1, 1); FinalizeToLevel(1, blockTreeBuilder.ChainLevelInfoRepository); var finalizationManager = new AuRaBlockFinalizationManager(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); finalizationManager.LastFinalizedBlockLevel.Should().Be(1); }
public void correctly_finalizes_blocks_in_already_in_chain_on_initialize() { var count = 2; var blockTreeBuilder = Build.A.BlockTree().OfChainLength(count, 0, 0, TestItem.AddressA, TestItem.AddressB); var finalizationManager = new AuRaBlockFinalizationManager(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); IEnumerable <bool> result = Enumerable.Range(0, count).Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.IsFinalized); result.Should().BeEquivalentTo(new[] { true, false }); }
public long GetLastFinalizedBy_test(int chainLength, Address[] beneficiaries, int minForFinalization) { SetupValidators(beneficiaries, minForFinalization); var blockTreeBuilder = Build.A.BlockTree().OfChainLength(chainLength, 0, 0, beneficiaries); var blockTree = blockTreeBuilder.TestObject; var finalizationManager = new AuRaBlockFinalizationManager(blockTree, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); var result = finalizationManager.GetLastLevelFinalizedBy(blockTree.Head.Hash); return(result); }
public long?GetFinalizationLevel_tests(int chainLength, Address[] beneficiaries, int minForFinalization, long level) { SetupValidators(minForFinalization, beneficiaries); var blockTreeBuilder = Build.A.BlockTree().OfChainLength(chainLength, 0, 0, beneficiaries); var blockTree = blockTreeBuilder.TestObject; var finalizationManager = new AuRaBlockFinalizationManager(blockTree, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); var result = finalizationManager.GetFinalizationLevel(level); return(result); }
public long?GetFinalizedLevel_test(int chainLength, int levelToCheck, Address[] beneficiaries, int minForFinalization) { SetupValidators(beneficiaries, minForFinalization); _validSealerStrategy.IsValidSealer(Arg.Any <IList <Address> >(), Arg.Any <Address>(), Arg.Any <long>()).Returns(c => beneficiaries.GetItemRoundRobin(c.Arg <long>()) == c.Arg <Address>()); var blockTreeBuilder = Build.A.BlockTree().OfChainLength(chainLength, 0, 0, beneficiaries); var blockTree = blockTreeBuilder.TestObject; var finalizationManager = new AuRaBlockFinalizationManager(blockTree, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); var result = finalizationManager.GetFinalizedLevel(levelToCheck); return(result); }
public long?GetFinalizationLevel_when_before_pivot_and_not_synced(int minForFinalization, long bestKnownBlock, long level) { SetupValidators(minForFinalization); IBlockTree blockTree = Substitute.For <IBlockTree>(); blockTree.BestKnownNumber.Returns(bestKnownBlock); var finalizationManager = new AuRaBlockFinalizationManager( blockTree, Substitute.For <IChainLevelInfoRepository>(), _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); return(finalizationManager.GetFinalizationLevel(level)); }
public int[] correctly_finalizes_blocks_on_reorganisations(int validators, int chainLength) { _validatorStore.GetValidators(Arg.Any <long?>()).Returns(TestItem.Addresses.Take(validators).ToArray()); void ProcessBlock(BlockTreeBuilder blockTreeBuilder1, int level, int index) { var blockHash = blockTreeBuilder1.ChainLevelInfoRepository.LoadLevel(level).BlockInfos[index].BlockHash; var block = blockTreeBuilder1.TestObject.FindBlock(blockHash, BlockTreeLookupOptions.None); _blockProcessor.BlockProcessed += Raise.EventWith(new BlockProcessedEventArgs(block, Array.Empty <TxReceipt>())); } Block genesis = Build.A.Block.Genesis.TestObject; var blockTreeBuilder = Build.A.BlockTree(genesis); var finalizationManager = new AuRaBlockFinalizationManager(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager); blockTreeBuilder .OfChainLength(out Block headBlock, chainLength, 1, 0, TestItem.Addresses.Take(validators).ToArray()) .OfChainLength(out Block alternativeHeadBlock, chainLength, 0, splitFrom: 2, TestItem.Addresses.Skip(validators).Take(validators).ToArray()); for (int i = 0; i < chainLength - 1; i++) { ProcessBlock(blockTreeBuilder, i, 0); } for (int i = 1; i < chainLength - 1; i++) { ProcessBlock(blockTreeBuilder, i, 1); } ProcessBlock(blockTreeBuilder, chainLength - 1, 0); var finalizedBLocks = Enumerable.Range(0, chainLength) .Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).BlockInfos.Select((b, j) => b.IsFinalized ? j + 1 : 0).Sum()) .ToArray(); return(finalizedBLocks); }
private static async Task RunBenchmarkBlocks() { Rlp.RegisterDecoders(typeof(ParityTraceDecoder).Assembly); /* logging & instrumentation */ _logManager = new NLogManager("perfTest.logs.txt", null); _logger = _logManager.GetClassLogger(); if (_logger.IsInfo) { _logger.Info("Deleting state DBs"); } DeleteDb(FullStateDbPath); DeleteDb(FullCodeDbPath); DeleteDb(FullReceiptsDbPath); DeleteDb(FullPendingTxsDbPath); if (_logger.IsInfo) { _logger.Info("State DBs deleted"); } /* load spec */ ChainSpecLoader loader = new ChainSpecLoader(new EthereumJsonSerializer()); string path = Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"chainspec", "ropsten.json")); _logger.Info($"Loading ChainSpec from {path}"); ChainSpec chainSpec = loader.Load(File.ReadAllText(path)); _logger.Info($"ChainSpec loaded"); var specProvider = new ChainSpecBasedSpecProvider(chainSpec); IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); var dbProvider = new RocksDbProvider(DbBasePath, DbConfig.Default, _logManager, true, true); var stateDb = dbProvider.StateDb; var codeDb = dbProvider.CodeDb; var traceDb = dbProvider.TraceDb; var blocksDb = dbProvider.BlocksDb; var headersDb = dbProvider.HeadersDb; var blockInfosDb = dbProvider.BlockInfosDb; var receiptsDb = dbProvider.ReceiptsDb; /* state & storage */ var stateProvider = new StateProvider(stateDb, codeDb, _logManager); var storageProvider = new StorageProvider(stateDb, stateProvider, _logManager); var ethereumSigner = new EthereumEcdsa(specProvider, _logManager); var transactionPool = new TxPool( NullTxStorage.Instance, Timestamper.Default, ethereumSigner, specProvider, new TxPoolConfig(), stateProvider, _logManager); var blockInfoRepository = new ChainLevelInfoRepository(blockInfosDb); var blockTree = new UnprocessedBlockTreeWrapper(new BlockTree(blocksDb, headersDb, blockInfosDb, blockInfoRepository, specProvider, transactionPool, _logManager)); var receiptStorage = new InMemoryReceiptStorage(); IBlockDataRecoveryStep recoveryStep = new TxSignaturesRecoveryStep(ethereumSigner, transactionPool, _logManager); /* blockchain processing */ IList <IAdditionalBlockProcessor> blockProcessors = new List <IAdditionalBlockProcessor>(); var blockhashProvider = new BlockhashProvider(blockTree, LimboLogs.Instance); var virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, specProvider, _logManager); var processor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, _logManager); ISealValidator sealValidator; if (specProvider.ChainId == RopstenSpecProvider.Instance.ChainId) { var difficultyCalculator = new DifficultyCalculator(specProvider); sealValidator = new EthashSealValidator(_logManager, difficultyCalculator, new Ethash(_logManager)); } else if (chainSpec.SealEngineType == SealEngineType.Clique) { var snapshotManager = new SnapshotManager(CliqueConfig.Default, blocksDb, blockTree, ethereumSigner, _logManager); sealValidator = new CliqueSealValidator(CliqueConfig.Default, snapshotManager, _logManager); rewardCalculator = NoBlockRewards.Instance; recoveryStep = new CompositeDataRecoveryStep(recoveryStep, new AuthorRecoveryStep(snapshotManager)); } else if (chainSpec.SealEngineType == SealEngineType.AuRa) { var abiEncoder = new AbiEncoder(); var validatorProcessor = new AuRaAdditionalBlockProcessorFactory(dbProvider.StateDb, stateProvider, abiEncoder, processor, blockTree, receiptStorage, _logManager) .CreateValidatorProcessor(chainSpec.AuRa.Validators); sealValidator = new AuRaSealValidator(chainSpec.AuRa, new AuRaStepCalculator(chainSpec.AuRa.StepDuration, new Timestamper()), validatorProcessor, ethereumSigner, _logManager); rewardCalculator = new AuRaRewardCalculator(chainSpec.AuRa, abiEncoder, processor); blockProcessors.Add(validatorProcessor); } else { throw new NotSupportedException(); } /* store & validation */ var headerValidator = new HeaderValidator(blockTree, sealValidator, specProvider, _logManager); var ommersValidator = new OmmersValidator(blockTree, headerValidator, _logManager); var transactionValidator = new TxValidator(chainSpec.ChainId); var blockValidator = new BlockValidator(transactionValidator, headerValidator, ommersValidator, specProvider, _logManager); /* blockchain processing */ var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, processor, stateDb, codeDb, traceDb, stateProvider, storageProvider, transactionPool, receiptStorage, _logManager, blockProcessors); var blockchainProcessor = new BlockchainProcessor(blockTree, blockProcessor, recoveryStep, _logManager, true, false); if (chainSpec.SealEngineType == SealEngineType.AuRa) { stateProvider.CreateAccount(Address.Zero, UInt256.Zero); storageProvider.Commit(); stateProvider.Commit(Homestead.Instance); var finalizationManager = new AuRaBlockFinalizationManager(blockTree, blockInfoRepository, blockProcessor, blockProcessors.OfType <IAuRaValidator>().First(), _logManager); } foreach ((Address address, ChainSpecAllocation allocation) in chainSpec.Allocations) { stateProvider.CreateAccount(address, allocation.Balance); if (allocation.Code != null) { Keccak codeHash = stateProvider.UpdateCode(allocation.Code); stateProvider.UpdateCodeHash(address, codeHash, specProvider.GenesisSpec); } if (allocation.Constructor != null) { Transaction constructorTransaction = new Transaction(true) { SenderAddress = address, Init = allocation.Constructor, GasLimit = chainSpec.Genesis.GasLimit }; processor.Execute(constructorTransaction, chainSpec.Genesis.Header, NullTxTracer.Instance); } } _logger.Info($"Allocations configured, committing..."); stateProvider.Commit(specProvider.GenesisSpec); _logger.Info($"Finalizing genesis..."); chainSpec.Genesis.Header.StateRoot = stateProvider.StateRoot; chainSpec.Genesis.Header.Hash = BlockHeader.CalculateHash(chainSpec.Genesis.Header); if (chainSpec.Genesis.Hash != blockTree.Genesis.Hash) { throw new Exception("Unexpected genesis hash"); } _logger.Info($"Starting benchmark processor..."); /* start processing */ BigInteger totalGas = BigInteger.Zero; Stopwatch stopwatch = new Stopwatch(); Block currentHead; long maxMemory = 0; blockTree.NewHeadBlock += (sender, args) => { currentHead = args.Block; if (currentHead.Number == 0) { return; } maxMemory = Math.Max(maxMemory, GC.GetTotalMemory(false)); totalGas += currentHead.GasUsed; if ((BigInteger)args.Block.Number % 10000 == 9999) { stopwatch.Stop(); long ms = 1_000L * stopwatch.ElapsedTicks / Stopwatch.Frequency; BigInteger number = args.Block.Number + 1; _logger.Warn($"TOTAL after {number} (ms) : " + ms); _logger.Warn($"TOTAL after {number} blocks/s : {(decimal) currentHead.Number / (ms / 1000m),5}"); _logger.Warn($"TOTAL after {number} Mgas/s : {((decimal) totalGas / 1000000) / (ms / 1000m),5}"); _logger.Warn($"TOTAL after {number} max mem : {maxMemory}"); _logger.Warn($"TOTAL after {number} GC (0/1/2) : {GC.CollectionCount(0)}/{GC.CollectionCount(1)}/{GC.CollectionCount(2)}"); _logger.Warn($"Is server GC {number} : {System.Runtime.GCSettings.IsServerGC}"); _logger.Warn($"GC latency mode {number} : {System.Runtime.GCSettings.LatencyMode}"); _logger.Warn($"TOTAL after {number} blocks DB reads : {Store.Metrics.BlocksDbReads}"); _logger.Warn($"TOTAL after {number} blocks DB writes : {Store.Metrics.BlocksDbWrites}"); _logger.Warn($"TOTAL after {number} infos DB reads : {Store.Metrics.BlockInfosDbReads}"); _logger.Warn($"TOTAL after {number} infos DB writes : {Store.Metrics.BlockInfosDbWrites}"); _logger.Warn($"TOTAL after {number} state tree reads : {Store.Metrics.StateTreeReads}"); _logger.Warn($"TOTAL after {number} state tree writes : {Store.Metrics.StateTreeWrites}"); _logger.Warn($"TOTAL after {number} state DB reads : {Store.Metrics.StateDbReads}"); _logger.Warn($"TOTAL after {number} state DB writes : {Store.Metrics.StateDbWrites}"); _logger.Warn($"TOTAL after {number} storage tree reads : {Store.Metrics.StorageTreeReads}"); _logger.Warn($"TOTAL after {number} storage tree writes : {Store.Metrics.StorageTreeWrites}"); _logger.Warn($"TOTAL after {number} tree node hash : {Store.Metrics.TreeNodeHashCalculations}"); _logger.Warn($"TOTAL after {number} tree node RLP decode : {Store.Metrics.TreeNodeRlpDecodings}"); _logger.Warn($"TOTAL after {number} tree node RLP encode : {Store.Metrics.TreeNodeRlpEncodings}"); _logger.Warn($"TOTAL after {number} code DB reads : {Store.Metrics.CodeDbReads}"); _logger.Warn($"TOTAL after {number} code DB writes : {Store.Metrics.CodeDbWrites}"); _logger.Warn($"TOTAL after {number} receipts DB reads : {Store.Metrics.ReceiptsDbReads}"); _logger.Warn($"TOTAL after {number} receipts DB writes : {Store.Metrics.ReceiptsDbWrites}"); _logger.Warn($"TOTAL after {number} other DB reads : {Store.Metrics.OtherDbReads}"); _logger.Warn($"TOTAL after {number} other DB writes : {Store.Metrics.OtherDbWrites}"); _logger.Warn($"TOTAL after {number} EVM exceptions : {Evm.Metrics.EvmExceptions}"); _logger.Warn($"TOTAL after {number} SLOAD opcodes : {Evm.Metrics.SloadOpcode}"); _logger.Warn($"TOTAL after {number} SSTORE opcodes : {Evm.Metrics.SstoreOpcode}"); _logger.Warn($"TOTAL after {number} EXP opcodes : {Evm.Metrics.ModExpOpcode}"); _logger.Warn($"TOTAL after {number} BLOCKHASH opcodes : {Evm.Metrics.BlockhashOpcode}"); _logger.Warn($"TOTAL after {number} EVM calls : {Evm.Metrics.Calls}"); _logger.Warn($"TOTAL after {number} RIPEMD Precompiles : {Evm.Metrics.Ripemd160Precompile}"); _logger.Warn($"TOTAL after {number} SHA256 Precompiles : {Evm.Metrics.Sha256Precompile}"); // disk space stopwatch.Start(); } }; bool isStarted = false; TaskCompletionSource <object> completionSource = new TaskCompletionSource <object>(); blockTree.NewBestSuggestedBlock += (sender, args) => { if (!isStarted) { blockchainProcessor.Process(blockTree.FindBlock(blockTree.Genesis.Hash, BlockTreeLookupOptions.RequireCanonical), ProcessingOptions.None, NullBlockTracer.Instance); stopwatch.Start(); blockchainProcessor.Start(); isStarted = true; } if (args.Block.Number == BlocksToLoad) { completionSource.SetResult(null); } }; await Task.WhenAny(completionSource.Task, blockTree.LoadBlocksFromDb(CancellationToken.None, 0, 10000, BlocksToLoad)); await blockchainProcessor.StopAsync(true).ContinueWith( t => { if (t.IsFaulted) { _logger.Error("processing failed", t.Exception); _logger.Error("inner", t.Exception.InnerException); Console.ReadLine(); } _logger.Info("Block processing completed."); }); stopwatch.Stop(); Console.ReadLine(); }