public async Task RunAsync(Func <RuleContext, Task> baseRunAsync, RuleContext context) { this.blockTxsProcessed.Clear(); this.receipts.Clear(); this.blockGasConsumed = 0; this.refundCounter = 1; Block block = context.ValidationContext.BlockToValidate; this.logger.LogDebug("Block to validate '{0}'", block.GetHash()); // Get a IStateRepositoryRoot we can alter without affecting the injected one which is used elsewhere. uint256 blockRoot = ((ISmartContractBlockHeader)context.ValidationContext.ChainedHeaderToValidate.Previous.Header).HashStateRoot; this.logger.LogDebug("Block hash state root '{0}'.", blockRoot); this.cachedResults = this.executionCache.GetExecutionResult(block.GetHash()); if (this.cachedResults == null) { // We have no cached results. Didn't come from our miner. We execute the contracts, so need to set up a new state repository. this.mutableStateRepository = this.stateRepositoryRoot.GetSnapshotTo(blockRoot.ToBytes()); } else { // We have already done all of this execution when mining so we will use those results. this.mutableStateRepository = this.cachedResults.MutatedStateRepository; foreach (Receipt receipt in this.cachedResults.Receipts) { // Block hash needs to be set for all. It was set during mining and can only be updated after. receipt.BlockHash = block.GetHash(); this.receipts.Add(receipt); } } // Always call into the base. When the base class calls back in, we will optionally perform execution based on whether this.cachedResults is set. await baseRunAsync(context); var blockHeader = (ISmartContractBlockHeader)block.Header; var mutableStateRepositoryRoot = new uint256(this.mutableStateRepository.Root); uint256 blockHeaderHashStateRoot = blockHeader.HashStateRoot; this.logger.LogDebug("Compare state roots '{0}' and '{1}'", mutableStateRepositoryRoot, blockHeaderHashStateRoot); if (mutableStateRepositoryRoot != blockHeaderHashStateRoot) { SmartContractConsensusErrors.UnequalStateRoots.Throw(); } this.ValidateAndStoreReceipts(blockHeader.ReceiptRoot); this.ValidateLogsBloom(blockHeader.LogsBloom); // Push to underlying database this.mutableStateRepository.Commit(); // Update the globally injected state so all services receive the updates. this.stateRepositoryRoot.SyncToRoot(this.mutableStateRepository.Root); }
/// <inheritdoc/> public override BlockTemplate Build(ChainedHeader chainTip, Script scriptPubKeyIn) { GetSenderResult getSenderResult = this.senderRetriever.GetAddressFromScript(scriptPubKeyIn); this.coinbaseAddress = (getSenderResult.Success) ? getSenderResult.Sender : uint160.Zero; this.stateSnapshot = this.stateRoot.GetSnapshotTo(((ISmartContractBlockHeader)this.ConsensusManager.Tip.Header).HashStateRoot.ToBytes()); this.refundOutputs.Clear(); this.receipts.Clear(); this.blockGasConsumed = 0; base.OnBuild(chainTip, scriptPubKeyIn); this.coinbase.Outputs.AddRange(this.refundOutputs); // Cache the results. We don't need to execute these again when validating. var cacheModel = new BlockExecutionResultModel(this.stateSnapshot, this.receipts); this.executionCache.StoreExecutionResult(this.BlockTemplate.Block.GetHash(), cacheModel); return(this.BlockTemplate); }