/// <inheritdoc/>
        public ChainedHeader GetLastPowPosChainedBlock(IStakeChain stakeChain, ChainedHeader startChainedHeader, bool proofOfStake)
        {
            Guard.Assert(startChainedHeader != null);

            BlockStake blockStake = stakeChain.Get(startChainedHeader.HashBlock);

            while ((startChainedHeader.Previous != null) && (blockStake.IsProofOfStake() != proofOfStake))
            {
                startChainedHeader = startChainedHeader.Previous;
                blockStake         = stakeChain.Get(startChainedHeader.HashBlock);
            }

            return(startChainedHeader);
        }
        /// <inheritdoc />
        public ChainedHeader GetLastPowPosChainedBlock(IStakeChain stakeChain, ChainedHeader startChainedHeader,
                                                       bool proofOfStake)
        {
            Guard.NotNull(stakeChain, nameof(stakeChain));
            Guard.Assert(startChainedHeader != null);

            var blockStake = stakeChain.Get(startChainedHeader.HashBlock);

            while (startChainedHeader.Previous != null && blockStake.IsProofOfStake() != proofOfStake)
            {
                startChainedHeader = startChainedHeader.Previous;
                blockStake         = stakeChain.Get(startChainedHeader.HashBlock);
            }

            return(startChainedHeader);
        }
Exemple #3
0
        /// <inheritdoc/>
        public ChainedHeader GetLastPowPosChainedBlock(IStakeChain stakeChain, ChainedHeader startChainedHeader, bool proofOfStake)
        {
            Guard.Assert(startChainedHeader != null);

            this.logger.LogTrace("({0}:'{1}',{2}:{3})", nameof(startChainedHeader), startChainedHeader, nameof(proofOfStake), proofOfStake);

            BlockStake blockStake = stakeChain.Get(startChainedHeader.HashBlock);

            while ((startChainedHeader.Previous != null) && (blockStake.IsProofOfStake() != proofOfStake))
            {
                startChainedHeader = startChainedHeader.Previous;
                blockStake         = stakeChain.Get(startChainedHeader.HashBlock);
            }

            this.logger.LogTrace("(-)':{0}'", startChainedHeader);
            return(startChainedHeader);
        }
        /// <inheritdoc/>
        public Target GetNextTargetRequired(IStakeChain stakeChain, ChainedHeader chainTip, IConsensus consensus, bool proofOfStake)
        {
            Guard.NotNull(stakeChain, nameof(stakeChain));

            // If the chain uses a PosPowRatchet, we branch away here, 4 blocks after it has activated. A safe delta of 4
            // is used, so that when we iterate over blocks backwards, we'll never hit non-Ratchet blocks.
            if (consensus.Options is X1ConsensusOptions options &&
                options.IsPosPowRatchetActiveAtHeight(chainTip.Height - 4))
            {
                bool isChainTipProofOfStake = stakeChain.Get(chainTip.HashBlock).IsProofOfStake();
                if (isChainTipProofOfStake && chainTip.Height % 2 != 0 || !isChainTipProofOfStake && chainTip.Height % 2 == 0)
                {
                    throw new InvalidOperationException("Misconfiguration: When the ratchet is active for a height, the convention that PoS block heights are even numbers, must be met.");
                }

                return(options.GetNextTargetRequired(chainTip, isChainTipProofOfStake, consensus, proofOfStake));
            }


            // Genesis block.
            if (chainTip == null)
            {
                this.logger.LogTrace("(-)[GENESIS]:'{0}'", consensus.PowLimit);
                return(consensus.PowLimit);
            }

            // Find the last two blocks that correspond to the mining algo
            // (i.e if this is a POS block we need to find the last two POS blocks).
            BigInteger targetLimit = proofOfStake
                ? consensus.ProofOfStakeLimitV2
                : consensus.PowLimit.ToBigInteger();

            // First block.
            ChainedHeader lastPowPosBlock = this.GetLastPowPosChainedBlock(stakeChain, chainTip, proofOfStake);

            if (lastPowPosBlock.Previous == null)
            {
                var res = new Target(targetLimit);
                this.logger.LogTrace("(-)[FIRST_BLOCK]:'{0}'", res);
                return(res);
            }

            // Second block.
            ChainedHeader prevLastPowPosBlock = this.GetLastPowPosChainedBlock(stakeChain, lastPowPosBlock.Previous, proofOfStake);

            if (prevLastPowPosBlock.Previous == null)
            {
                var res = new Target(targetLimit);
                this.logger.LogTrace("(-)[SECOND_BLOCK]:'{0}'", res);
                return(res);
            }

            // This is used in tests to allow quickly mining blocks.
            if (!proofOfStake && consensus.PowNoRetargeting)
            {
                this.logger.LogTrace("(-)[NO_POW_RETARGET]:'{0}'", lastPowPosBlock.Header.Bits);
                return(lastPowPosBlock.Header.Bits);
            }

            if (proofOfStake && consensus.PosNoRetargeting)
            {
                this.logger.LogTrace("(-)[NO_POS_RETARGET]:'{0}'", lastPowPosBlock.Header.Bits);
                return(lastPowPosBlock.Header.Bits);
            }

            Target finalTarget = this.CalculateRetarget(lastPowPosBlock.Header.Time, lastPowPosBlock.Header.Bits, prevLastPowPosBlock.Header.Time, targetLimit);

            return(finalTarget);
        }