private TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, IBlockTracer blockTracer) { _receiptsTracer.SetOtherTracer(blockTracer); _receiptsTracer.StartNewBlockTrace(block); for (int i = 0; i < block.Transactions.Length; i++) { Transaction currentTx = block.Transactions[i]; if ((processingOptions & ProcessingOptions.DoNotVerifyNonce) != 0) { currentTx.Nonce = _stateProvider.GetNonce(currentTx.SenderAddress); } _receiptsTracer.StartNewTxTrace(currentTx.Hash); _transactionProcessor.Execute(currentTx, block.Header, _receiptsTracer); _receiptsTracer.EndTxTrace(); TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(i, currentTx, _receiptsTracer.TxReceipts[i])); } return(_receiptsTracer.TxReceipts); }
public Block[] Process(Keccak branchStateRoot, Block[] suggestedBlocks, ProcessingOptions options, IBlockTracer blockTracer) { if (_logger.IsTrace) { _logger.Trace($"Processing block {suggestedBlocks[0].Number} from state root: {branchStateRoot}"); } if (suggestedBlocks.Length == 0) { return(Array.Empty <Block>()); } int stateSnapshot = _stateDb.TakeSnapshot(); int codeSnapshot = _codeDb.TakeSnapshot(); if (stateSnapshot != -1 || codeSnapshot != -1) { if (_logger.IsError) { _logger.Error($"Uncommitted state ({stateSnapshot}, {codeSnapshot}) when processing from a branch root {branchStateRoot} starting with block {suggestedBlocks[0].ToString(Block.Format.Short)}"); } } Keccak snapshotStateRoot = _stateProvider.StateRoot; if (branchStateRoot != null && _stateProvider.StateRoot != branchStateRoot) { /* discarding the other branch data - chain reorganization */ Metrics.Reorganizations++; _storageProvider.Reset(); _stateProvider.Reset(); _stateProvider.StateRoot = branchStateRoot; } var processedBlocks = new Block[suggestedBlocks.Length]; try { for (int i = 0; i < suggestedBlocks.Length; i++) { processedBlocks[i] = ProcessOne(suggestedBlocks[i], options, blockTracer); if (_logger.IsTrace) { _logger.Trace($"Committing trees - state root {_stateProvider.StateRoot}"); } _stateProvider.CommitTree(); _storageProvider.CommitTrees(); } if ((options & ProcessingOptions.ReadOnlyChain) != 0) { Restore(stateSnapshot, codeSnapshot, snapshotStateRoot); } else { _stateDb.Commit(); _codeDb.Commit(); } return(processedBlocks); } catch (InvalidBlockException) { Restore(stateSnapshot, codeSnapshot, snapshotStateRoot); throw; } }
public void SetOtherTracer(IBlockTracer blockTracer) { _otherTracer = blockTracer; }
public Block[] Process(Keccak branchStateRoot, Block[] suggestedBlocks, ProcessingOptions processingOptions, IBlockTracer blockTracer) { _logger.Info($"Processing {suggestedBlocks.Last().ToString(Block.Format.Short)}"); while (true) { bool notYet = false; for (int i = 0; i < suggestedBlocks.Length; i++) { Keccak hash = suggestedBlocks[i].Hash; if (!_allowed.Contains(hash)) { if (_allowedToFail.Contains(hash)) { _allowedToFail.Remove(hash); BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last())); throw new InvalidBlockException(hash); } notYet = true; break; } } if (notYet) { Thread.Sleep(20); } else { BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last())); return(suggestedBlocks); } } }
private TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, IBlockTracer blockTracer) { _receiptsTracer.SetOtherTracer(blockTracer); _receiptsTracer.StartNewBlockTrace(block); for (int i = 0; i < block.Transactions.Length; i++) { if (_logger.IsTrace) { _logger.Trace($"Processing transaction {i}"); } Transaction currentTx = block.Transactions[i]; _receiptsTracer.StartNewTxTrace(currentTx.Hash); _transactionProcessor.Execute(currentTx, block.Header, _receiptsTracer); _receiptsTracer.EndTxTrace(); if ((processingOptions & ProcessingOptions.ReadOnlyChain) == 0) { TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(_receiptsTracer.TxReceipts[i])); } } return(_receiptsTracer.TxReceipts); }
public Block Process(Block suggestedBlock, ProcessingOptions options, IBlockTracer blockTracer) { if (!RunSimpleChecksAheadOfProcessing(suggestedBlock, options)) { return(null); } UInt256 totalDifficulty = suggestedBlock.TotalDifficulty ?? 0; if (_logger.IsTrace) { _logger.Trace($"Total difficulty of block {suggestedBlock.ToString(Block.Format.Short)} is {totalDifficulty}"); } UInt256 totalTransactions = suggestedBlock.TotalTransactions ?? 0; if (_logger.IsTrace) { _logger.Trace($"Total transactions of block {suggestedBlock.ToString(Block.Format.Short)} is {totalTransactions}"); } Block[] processedBlocks = null; if (_blockTree.Head == null || totalDifficulty > _blockTree.Head.TotalDifficulty || (options & ProcessingOptions.ForceProcessing) != 0) { List <Block> blocksToBeAddedToMain = new List <Block>(); Block toBeProcessed = suggestedBlock; do { blocksToBeAddedToMain.Add(toBeProcessed); toBeProcessed = toBeProcessed.Number == 0 ? null : _blockTree.FindParent(toBeProcessed); if (toBeProcessed == null) { break; } } while (!_blockTree.IsMainChain(toBeProcessed.Hash)); BlockHeader branchingPoint = toBeProcessed?.Header; if (branchingPoint != null && branchingPoint.Hash != _blockTree.Head?.Hash) { if (_logger.IsTrace) { _logger.Trace($"Head block was: {_blockTree.Head?.ToString(BlockHeader.Format.Short)}"); } if (_logger.IsTrace) { _logger.Trace($"Branching from: {branchingPoint.ToString(BlockHeader.Format.Short)}"); } } else { if (_logger.IsTrace) { _logger.Trace(branchingPoint == null ? "Setting as genesis block" : $"Adding on top of {branchingPoint.ToString(BlockHeader.Format.Short)}"); } } Keccak stateRoot = branchingPoint?.StateRoot; if (_logger.IsTrace) { _logger.Trace($"State root lookup: {stateRoot}"); } List <Block> blocksToProcess = new List <Block>(); Block[] blocks; if ((options & ProcessingOptions.ForceProcessing) != 0) { blocksToBeAddedToMain.Clear(); blocks = new Block[1]; blocks[0] = suggestedBlock; } else { foreach (Block block in blocksToBeAddedToMain) { if (block.Hash != null && _blockTree.WasProcessed(block.Number, block.Hash)) { stateRoot = block.Header.StateRoot; if (_logger.IsTrace) { _logger.Trace($"State root lookup: {stateRoot}"); } break; } blocksToProcess.Add(block); } blocks = new Block[blocksToProcess.Count]; for (int i = 0; i < blocksToProcess.Count; i++) { blocks[blocks.Length - i - 1] = blocksToProcess[i]; } } if (_logger.IsTrace) { _logger.Trace($"Processing {blocks.Length} blocks from state root {stateRoot}"); } for (int i = 0; i < blocks.Length; i++) { /* this can happen if the block was loaded as an ancestor and did not go through the recovery queue */ _recoveryStep.RecoverData(blocks[i]); } try { processedBlocks = _blockProcessor.Process(stateRoot, blocks, options, blockTracer); } catch (InvalidBlockException ex) { for (int i = 0; i < blocks.Length; i++) { if (blocks[i].Hash == ex.InvalidBlockHash) { _blockTree.DeleteInvalidBlock(blocks[i]); if (_logger.IsDebug) { _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)} because of {blocks[i].ToString(Block.Format.FullHashAndNumber)} is invalid"); } return(null); } } } if ((options & ProcessingOptions.ReadOnlyChain) == 0) { _blockTree.UpdateMainChain(blocksToBeAddedToMain.ToArray()); } } else { if (_logger.IsDebug) { _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)}, Head = {_blockTree.Head?.ToString(BlockHeader.Format.Short)}, total diff = {totalDifficulty}, head total diff = {_blockTree.Head?.TotalDifficulty}"); } } Block lastProcessed = null; if (processedBlocks != null && processedBlocks.Length > 0) { lastProcessed = processedBlocks[processedBlocks.Length - 1]; if (_logger.IsTrace) { _logger.Trace($"Setting total on last processed to {lastProcessed.ToString(Block.Format.Short)}"); } lastProcessed.TotalDifficulty = suggestedBlock.TotalDifficulty; lastProcessed.TotalTransactions = suggestedBlock.TotalTransactions; } else { if (_logger.IsDebug) { _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)}, last processed is null: {lastProcessed == null}, processedBlocks.Length: {processedBlocks?.Length}"); } } return(lastProcessed); }
private void RunProcessingLoop() { _stats.Start(); if (_logger.IsDebug) { _logger.Debug($"Starting block processor - {_blockQueue.Count} blocks waiting in the queue."); } if (IsEmpty) { ProcessingQueueEmpty?.Invoke(this, EventArgs.Empty); } foreach (BlockRef blockRef in _blockQueue.GetConsumingEnumerable(_loopCancellationSource.Token)) { if (blockRef.IsInDb || blockRef.Block == null) { throw new InvalidOperationException("Processing loop expects only resolved blocks"); } Block block = blockRef.Block; if (_logger.IsTrace) { _logger.Trace($"Processing block {block.ToString(Block.Format.Short)})."); } IBlockTracer tracer = GetDefaultTracer(); try { Block processedBlock = Process(block, blockRef.ProcessingOptions, tracer); if (processedBlock == null) { if (_logger.IsTrace) { _logger.Trace($"Failed / skipped processing {block.ToString(Block.Format.Full)}"); } } else { if (_logger.IsTrace) { _logger.Trace($"Processed block {block.ToString(Block.Format.Full)}"); } _stats.UpdateStats(block, _recoveryQueue.Count, _blockQueue.Count); } if (_logger.IsTrace) { _logger.Trace($"Now {_blockQueue.Count} blocks waiting in the queue."); } if (IsEmpty) { ProcessingQueueEmpty?.Invoke(this, EventArgs.Empty); } } finally { LogDiagnosticTrace(tracer); } } if (_logger.IsInfo) { _logger.Info("Block processor queue stopped."); } }
// TODO: move to branch processor public Block[] Process(Keccak newBranchStateRoot, List <Block> suggestedBlocks, ProcessingOptions options, IBlockTracer blockTracer) { if (suggestedBlocks.Count == 0) { return(Array.Empty <Block>()); } BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks)); /* We need to save the snapshot state root before reorganization in case the new branch has invalid blocks. * In case of invalid blocks on the new branch we will discard the entire branch and come back to * the previous head state.*/ Keccak previousBranchStateRoot = CreateCheckpoint(); InitBranch(newBranchStateRoot); bool readOnly = (options & ProcessingOptions.ReadOnlyChain) != 0; var blocksCount = suggestedBlocks.Count; Block[] processedBlocks = new Block[blocksCount]; try { for (int i = 0; i < blocksCount; i++) { if (blocksCount > 64 && i % 8 == 0) { if (_logger.IsInfo) { _logger.Info($"Processing part of a long blocks branch {i}/{blocksCount}"); } } _witnessCollector.Reset(); var(processedBlock, receipts) = ProcessOne(suggestedBlocks[i], options, blockTracer); processedBlocks[i] = processedBlock; // be cautious here as AuRa depends on processing PreCommitBlock(newBranchStateRoot, suggestedBlocks[i].Number); if (!readOnly) { _witnessCollector.Persist(processedBlock.Hash !); BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(processedBlock, receipts)); } // CommitBranch in parts if we have long running branch bool isFirstInBatch = i == 0; bool isLastInBatch = i == blocksCount - 1; bool isNotAtTheEdge = !isFirstInBatch && !isLastInBatch; bool isCommitPoint = i % MaxUncommittedBlocks == 0 && isNotAtTheEdge; if (isCommitPoint && readOnly == false) { if (_logger.IsInfo) { _logger.Info($"Commit part of a long blocks branch {i}/{blocksCount}"); } CommitBranch(); previousBranchStateRoot = CreateCheckpoint(); var newStateRoot = suggestedBlocks[i].StateRoot; InitBranch(newStateRoot, false); } } if (readOnly) { RestoreBranch(previousBranchStateRoot); } else { // TODO: move to branch processor CommitBranch(); } return(processedBlocks); } catch (Exception ex) // try to restore for all cost { _logger.Trace($"Encountered exception {ex} while processing blocks."); RestoreBranch(previousBranchStateRoot); throw; } }
public static void LogDiagnosticTrace( IBlockTracer blockTracer, Keccak blockHash, ILogger logger) {
public void Add(IBlockTracer tracer) { _childTracers.Add(tracer); IsTracingRewards |= tracer.IsTracingRewards; }
// TODO: block processor pipeline private (Block Block, TxReceipt[] Receipts) ProcessOne(Block suggestedBlock, ProcessingOptions options, IBlockTracer blockTracer) { if (_logger.IsTrace) { _logger.Trace($"Processing block {suggestedBlock.ToString(Block.Format.Short)} ({options})"); } ApplyDaoTransition(suggestedBlock); Block block = PrepareBlockForProcessing(suggestedBlock); TxReceipt[] receipts = ProcessBlock(block, blockTracer, options); ValidateProcessedBlock(suggestedBlock, options, block, receipts); if ((options & ProcessingOptions.StoreReceipts) != 0) { StoreTxReceipts(block, receipts); } return(block, receipts); }
public void Remove(IBlockTracer tracer) { _childTracers.Remove(tracer); IsTracingRewards = _childTracers.Any(t => t.IsTracingRewards); }
private Block ProcessOne(Block suggestedBlock, ProcessingOptions options, IBlockTracer blockTracer) { if (_syncConfig.ValidateTree) { if (_logger.IsWarn) { _logger.Warn("Collecting trie stats:"); } TrieStats stats = _stateProvider.CollectStats(); if (stats.MissingNodes > 0) { if (_logger.IsError) { _logger.Error(stats.ToString()); } } else { if (_logger.IsWarn) { _logger.Warn(stats.ToString()); } } } if (suggestedBlock.IsGenesis) { return(suggestedBlock); } if (_specProvider.DaoBlockNumber.HasValue && _specProvider.DaoBlockNumber.Value == suggestedBlock.Header.Number) { if (_logger.IsInfo) { _logger.Info("Applying DAO transition"); } ApplyDaoTransition(); } Block block = PrepareBlockForProcessing(suggestedBlock); var receipts = ProcessTransactions(block, options, blockTracer); SetReceiptsRootAndBloom(block, receipts); ApplyMinerRewards(block, blockTracer); _stateProvider.Commit(_specProvider.GetSpec(block.Number)); block.Header.StateRoot = _stateProvider.StateRoot; block.Header.Hash = BlockHeader.CalculateHash(block.Header); if ((options & ProcessingOptions.NoValidation) == 0 && !_blockValidator.ValidateProcessedBlock(block, receipts, suggestedBlock)) { if (_logger.IsError) { _logger.Error($"Processed block is not valid {suggestedBlock.ToString(Block.Format.FullHashAndNumber)}"); } throw new InvalidBlockException(suggestedBlock.Hash); } if ((options & ProcessingOptions.StoreReceipts) != 0) { StoreTxReceipts(block, receipts); } if ((options & ProcessingOptions.StoreTraces) != 0) { StoreTraces(blockTracer as ParityLikeBlockTracer); } BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(block)); return(block); }
public Block Process(Block suggestedBlock, ProcessingOptions options, IBlockTracer tracer) { if (!RunSimpleChecksAheadOfProcessing(suggestedBlock, options)) { return(null); } UInt256 totalDifficulty = suggestedBlock.TotalDifficulty ?? 0; if (_logger.IsTrace) { _logger.Trace($"Total difficulty of block {suggestedBlock.ToString(Block.Format.Short)} is {totalDifficulty}"); } Block[] processedBlocks = null; bool shouldProcess = suggestedBlock.IsGenesis || totalDifficulty > (_blockTree.Head?.TotalDifficulty ?? 0) // so above is better and more correct but creates an impression of the node staying behind on stats page // so we are okay to process slightly more // and below is less correct but potentially reporting well // || totalDifficulty >= (_blockTree.Head?.TotalDifficulty ?? 0) || (options & ProcessingOptions.ForceProcessing) == ProcessingOptions.ForceProcessing; if (!shouldProcess) { if (_logger.IsDebug) { _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)}, Head = {_blockTree.Head?.Header?.ToString(BlockHeader.Format.Short)}, total diff = {totalDifficulty}, head total diff = {_blockTree.Head?.TotalDifficulty}"); } return(null); } ProcessingBranch processingBranch = PrepareProcessingBranch(suggestedBlock, options); PrepareBlocksToProcess(suggestedBlock, options, processingBranch); try { processedBlocks = _blockProcessor.Process(processingBranch.Root, processingBranch.BlocksToProcess, options, tracer); } catch (InvalidBlockException ex) { for (int i = 0; i < processingBranch.BlocksToProcess.Count; i++) { if (processingBranch.BlocksToProcess[i].Hash == ex.InvalidBlockHash) { _blockTree.DeleteInvalidBlock(processingBranch.BlocksToProcess[i]); if (_logger.IsDebug) { _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)} because of {processingBranch.BlocksToProcess[i].ToString(Block.Format.FullHashAndNumber)} is invalid"); } return(null); } } } if ((options & (ProcessingOptions.ReadOnlyChain | ProcessingOptions.DoNotUpdateHead)) == 0) { _blockTree.UpdateMainChain(processingBranch.Blocks.ToArray(), true); } Block lastProcessed = null; if (processedBlocks != null && processedBlocks.Length > 0) { lastProcessed = processedBlocks[^ 1];
public Block[] Process(Keccak newBranchStateRoot, List <Block> suggestedBlocks, ProcessingOptions options, IBlockTracer blockTracer) { if (suggestedBlocks.Count == 0) { return(Array.Empty <Block>()); } /* We need to save the snapshot state root before reorganization in case the new branch has invalid blocks. * In case of invalid blocks on the new branch we will discard the entire branch and come back to * the previous head state.*/ Keccak previousBranchStateRoot = CreateCheckpoint(); InitBranch(newBranchStateRoot); bool readOnly = (options & ProcessingOptions.ReadOnlyChain) != 0; Block[] processedBlocks = new Block[suggestedBlocks.Count]; try { for (int i = 0; i < suggestedBlocks.Count; i++) { processedBlocks[i] = ProcessOne(suggestedBlocks[i], options, blockTracer); // be cautious here as AuRa depends on processing PreCommitBlock(newBranchStateRoot); // only needed if we plan to read state root? if (!readOnly) { BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(processedBlocks[i])); } } if (readOnly) { RestoreBranch(previousBranchStateRoot); } else { CommitBranch(); } return(processedBlocks); } catch (Exception) // try to restore for all cost { RestoreBranch(previousBranchStateRoot); throw; } }
public static CancellationBlockTracer WithCancellation(this IBlockTracer txTracer, CancellationToken cancellationToken) => new CancellationBlockTracer(txTracer, cancellationToken);
private void RunProcessingLoop() { _stats.Start(); if (_logger.IsDebug) { _logger.Debug($"Starting block processor - {_blockQueue.Count} blocks waiting in the queue."); } if (_blockQueue.Count == 0) { ProcessingQueueEmpty?.Invoke(this, EventArgs.Empty); } foreach (BlockRef blockRef in _blockQueue.GetConsumingEnumerable(_loopCancellationSource.Token)) { if (blockRef.IsInDb || blockRef.Block == null) { throw new InvalidOperationException("Processing loop expects only resolved blocks"); } Block block = blockRef.Block; if (_logger.IsTrace) { _logger.Trace($"Processing block {block.ToString(Block.Format.Short)})."); } IBlockTracer tracer = NullBlockTracer.Instance; if ((blockRef.ProcessingOptions & ProcessingOptions.StoreTraces) != 0) { tracer = new ParityLikeBlockTracer(ParityTraceTypes.Trace | ParityTraceTypes.StateDiff); } Block processedBlock = Process(block, blockRef.ProcessingOptions, tracer); if (processedBlock == null) { if (_logger.IsTrace) { _logger.Trace($"Failed / skipped processing {block.ToString(Block.Format.Full)}"); } } else { if (_logger.IsTrace) { _logger.Trace($"Processed block {block.ToString(Block.Format.Full)}"); } _stats.UpdateStats(block, _recoveryQueue.Count, _blockQueue.Count); } if (_logger.IsTrace) { _logger.Trace($"Now {_blockQueue.Count} blocks waiting in the queue."); } if (_blockQueue.Count == 0) { ProcessingQueueEmpty?.Invoke(this, EventArgs.Empty); } } if (_logger.IsTrace) { _logger.Trace($"Return"); } }
private (Block Block, TxReceipt[] Receipts) ProcessOne(Block suggestedBlock, ProcessingOptions options, IBlockTracer blockTracer) { ApplyDaoTransition(suggestedBlock); Block block = PrepareBlockForProcessing(suggestedBlock); TxReceipt[] receipts = ProcessBlock(block, blockTracer, options); ValidateProcessedBlock(suggestedBlock, options, block, receipts); if ((options & ProcessingOptions.StoreReceipts) != 0) { StoreTxReceipts(block, receipts); } return(block, receipts); }
public Block[] Process(Keccak newBranchStateRoot, List <Block> suggestedBlocks, ProcessingOptions processingOptions, IBlockTracer blockTracer) { if (blockTracer != NullBlockTracer.Instance) { // this is for block reruns on failure for diag tracing throw new InvalidBlockException(Keccak.Zero); } _logger.Info($"Processing {suggestedBlocks.Last().ToString(Block.Format.Short)}"); while (true) { bool notYet = false; for (int i = 0; i < suggestedBlocks.Count; i++) { Keccak hash = suggestedBlocks[i].Hash; if (!_allowed.Contains(hash)) { if (_allowedToFail.Contains(hash)) { _allowedToFail.Remove(hash); BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty <TxReceipt>())); throw new InvalidBlockException(hash); } notYet = true; break; } } if (notYet) { Thread.Sleep(20); } else { BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty <TxReceipt>())); return(suggestedBlocks.ToArray()); } } }
public Block[] Process(Keccak newBranchStateRoot, List <Block> suggestedBlocks, ProcessingOptions processingOptions, IBlockTracer blockTracer) { return(suggestedBlocks.ToArray()); }