/// <summary> /// Checks and computes stake. /// </summary> /// <param name="context">Context that contains variety of information regarding blocks validation and execution.</param> /// <exception cref="ConsensusErrors.PrevStakeNull">Thrown if previous stake is not found.</exception> /// <exception cref="ConsensusErrors.SetStakeEntropyBitFailed">Thrown if failed to set stake entropy bit.</exception> private void CheckAndComputeStake(RuleContext context) { ChainedHeader chainedHeader = context.ValidationContext.ChainedHeaderToValidate; Block block = context.ValidationContext.BlockToValidate; var posRuleContext = context as PosRuleContext; if (posRuleContext.BlockStake == null) { posRuleContext.BlockStake = BlockStake.Load(context.ValidationContext.BlockToValidate); } BlockStake blockStake = posRuleContext.BlockStake; // Verify hash target and signature of coinstake tx. if (BlockStake.IsProofOfStake(block)) { ChainedHeader prevChainedHeader = chainedHeader.Previous; BlockStake prevBlockStake = this.stakeChain.Get(prevChainedHeader.HashBlock); if (prevBlockStake == null) { ConsensusErrors.PrevStakeNull.Throw(); } // Only do proof of stake validation for blocks that are after the assumevalid block or after the last checkpoint. if (!context.SkipValidation) { this.stakeValidator.CheckProofOfStake(posRuleContext, prevChainedHeader, prevBlockStake, block.Transactions[1], chainedHeader.Header.Bits.ToCompact()); } else { this.Logger.LogTrace("POS validation skipped for block at height {0}.", chainedHeader.Height); } } // PoW is checked in CheckBlock(). if (BlockStake.IsProofOfWork(block)) { posRuleContext.HashProofOfStake = chainedHeader.Header.GetPoWHash(); } // Compute stake entropy bit for stake modifier. if (!blockStake.SetStakeEntropyBit(blockStake.GetStakeEntropyBit())) { this.Logger.LogTrace("(-)[STAKE_ENTROPY_BIT_FAIL]"); ConsensusErrors.SetStakeEntropyBitFailed.Throw(); } // Record proof hash value. blockStake.HashProof = posRuleContext.HashProofOfStake; int lastCheckpointHeight = this.Parent.Checkpoints.GetLastCheckpointHeight(); if (chainedHeader.Height > lastCheckpointHeight) { // Compute stake modifier. ChainedHeader prevChainedHeader = chainedHeader.Previous; BlockStake blockStakePrev = prevChainedHeader == null ? null : this.stakeChain.Get(prevChainedHeader.HashBlock); blockStake.StakeModifierV2 = this.stakeValidator.ComputeStakeModifierV2(prevChainedHeader, blockStakePrev?.StakeModifierV2, blockStake.IsProofOfWork() ? chainedHeader.HashBlock : blockStake.PrevoutStake.Hash); } else if (chainedHeader.Height == lastCheckpointHeight) { // Copy checkpointed stake modifier. CheckpointInfo checkpoint = this.Parent.Checkpoints.GetCheckpoint(lastCheckpointHeight); blockStake.StakeModifierV2 = checkpoint.StakeModifierV2; this.Logger.LogTrace("Last checkpoint stake modifier V2 loaded: '{0}'.", blockStake.StakeModifierV2); } else { this.Logger.LogTrace("POS stake modifier computation skipped for block at height {0} because it is not above last checkpoint block height {1}.", chainedHeader.Height, lastCheckpointHeight); } }
public void CheckAndComputeStake(ContextInformation context) { this.logger.LogTrace("()"); ChainedBlock chainedBlock = context.BlockResult.ChainedBlock; Block block = context.BlockResult.Block; BlockStake blockStake = context.Stake.BlockStake; int lastCheckpointHeight = this.checkpoints.GetLastCheckpointHeight(); // Verify hash target and signature of coinstake tx. if (BlockStake.IsProofOfStake(block)) { ChainedBlock prevChainedBlock = chainedBlock.Previous; BlockStake prevBlockStake = this.stakeChain.Get(prevChainedBlock.HashBlock); if (prevBlockStake == null) { ConsensusErrors.PrevStakeNull.Throw(); } // Only do proof of stake validation for blocks after last checkpoint. if (chainedBlock.Height > lastCheckpointHeight) { this.stakeValidator.CheckProofOfStake(context, prevChainedBlock, prevBlockStake, block.Transactions[1], chainedBlock.Header.Bits.ToCompact()); } else { this.logger.LogTrace("POS validation skipped for block at height {0} because it is not above last checkpoint block height {1}.", chainedBlock.Height, lastCheckpointHeight); } } // PoW is checked in CheckBlock(). if (BlockStake.IsProofOfWork(block)) { context.Stake.HashProofOfStake = chainedBlock.Header.GetPoWHash(); } // Compute stake entropy bit for stake modifier. if (!blockStake.SetStakeEntropyBit(blockStake.GetStakeEntropyBit())) { this.logger.LogTrace("(-)[STAKE_ENTROPY_BIT_FAIL]"); ConsensusErrors.SetStakeEntropyBitFailed.Throw(); } // Record proof hash value. blockStake.HashProof = context.Stake.HashProofOfStake; if (chainedBlock.Height > lastCheckpointHeight) { // Compute stake modifier. ChainedBlock prevChainedBlock = chainedBlock.Previous; BlockStake blockStakePrev = prevChainedBlock == null ? null : this.stakeChain.Get(prevChainedBlock.HashBlock); blockStake.StakeModifierV2 = this.stakeValidator.ComputeStakeModifierV2(prevChainedBlock, blockStakePrev, blockStake.IsProofOfWork() ? chainedBlock.HashBlock : blockStake.PrevoutStake.Hash); } else if (chainedBlock.Height == lastCheckpointHeight) { // Copy checkpointed stake modifier. CheckpointInfo checkpoint = this.checkpoints.GetCheckpoint(lastCheckpointHeight); blockStake.StakeModifierV2 = checkpoint.StakeModifierV2; this.logger.LogTrace("Last checkpoint stake modifier V2 loaded: '{0}'.", blockStake.StakeModifierV2); } else { this.logger.LogTrace("POS stake modifier computation skipped for block at height {0} because it is not above last checkpoint block height {1}.", chainedBlock.Height, lastCheckpointHeight); } this.logger.LogTrace("(-)[OK]"); }