/// <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); }
/// <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); }