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(suggestedBlocks[0]); } _logger.Info($"Processing {suggestedBlocks.Last().ToString(Block.Format.Short)}"); while (true) { bool notYet = false; for (int i = 0; i < suggestedBlocks.Count; i++) { BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks)); Block suggestedBlock = suggestedBlocks[i]; Keccak hash = suggestedBlock.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(suggestedBlock); } notYet = true; break; } } if (notYet) { Thread.Sleep(20); } else { BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(suggestedBlocks.Last(), Array.Empty <TxReceipt>())); return(suggestedBlocks.ToArray()); } } }
// 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; int 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}. Block: {suggestedBlocks[i]}"); } } _witnessCollector.Reset(); (Block processedBlock, TxReceipt[] 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(); Keccak?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; } }