Пример #1
0
        /// <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]");
        }