Exemplo n.º 1
0
        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);
        }