public Target GetWorkRequired(ChainedHeader chainedHeaderToValidate, XRCConsensus consensus) { // Genesis block. if (chainedHeaderToValidate.Height == 0) { return(consensus.PowLimit2); } var XRCConsensusProtocol = (XRCConsensusProtocol)consensus.ConsensusFactory.Protocol; //hard fork if (chainedHeaderToValidate.Height == XRCConsensusProtocol.PowLimit2Height + 1) { return(consensus.PowLimit); } //hard fork 2 - DigiShield + X11 if (chainedHeaderToValidate.Height > XRCConsensusProtocol.PowDigiShieldX11Height) { return(GetWorkRequiredDigiShield(chainedHeaderToValidate, consensus)); } Target proofOfWorkLimit; // Hard fork to higher difficulty if (chainedHeaderToValidate.Height > XRCConsensusProtocol.PowLimit2Height) { proofOfWorkLimit = consensus.PowLimit; } else { proofOfWorkLimit = consensus.PowLimit2; } ChainedHeader lastBlock = chainedHeaderToValidate.Previous; int height = chainedHeaderToValidate.Height; if (lastBlock == null) { return(proofOfWorkLimit); } long difficultyAdjustmentInterval = GetDifficultyAdjustmentInterval(consensus); // Only change once per interval. if ((height) % difficultyAdjustmentInterval != 0) { if (consensus.PowAllowMinDifficultyBlocks) { // Special difficulty rule for testnet: // If the new block's timestamp is more than 2* 10 minutes // then allow mining of a min-difficulty block. if (chainedHeaderToValidate.Header.BlockTime > (lastBlock.Header.BlockTime + TimeSpan.FromTicks(consensus.TargetSpacing.Ticks * 2))) { return(proofOfWorkLimit); } // Return the last non-special-min-difficulty-rules-block. ChainedHeader chainedHeader = lastBlock; while ((chainedHeader.Previous != null) && ((chainedHeader.Height % difficultyAdjustmentInterval) != 0) && (chainedHeader.Header.Bits == proofOfWorkLimit)) { chainedHeader = chainedHeader.Previous; } return(chainedHeader.Header.Bits); } return(lastBlock.Header.Bits); } // Go back by what we want to be 14 days worth of blocks. long pastHeight = lastBlock.Height - (difficultyAdjustmentInterval - 1); ChainedHeader firstChainedHeader = chainedHeaderToValidate.GetAncestor((int)pastHeight); if (firstChainedHeader == null) { throw new NotSupportedException("Can only calculate work of a full chain"); } if (consensus.PowNoRetargeting) { return(lastBlock.Header.Bits); } // Limit adjustment step. TimeSpan actualTimespan = lastBlock.Header.BlockTime - firstChainedHeader.Header.BlockTime; if (actualTimespan < TimeSpan.FromTicks(consensus.TargetTimespan.Ticks / 4)) { actualTimespan = TimeSpan.FromTicks(consensus.TargetTimespan.Ticks / 4); } if (actualTimespan > TimeSpan.FromTicks(consensus.TargetTimespan.Ticks * 4)) { actualTimespan = TimeSpan.FromTicks(consensus.TargetTimespan.Ticks * 4); } // Retarget. BigInteger newTarget = lastBlock.Header.Bits.ToBigInteger(); newTarget = newTarget.Multiply(BigInteger.ValueOf((long)actualTimespan.TotalSeconds)); newTarget = newTarget.Divide(BigInteger.ValueOf((long)consensus.TargetTimespan.TotalSeconds)); var finalTarget = new Target(newTarget); if (finalTarget > proofOfWorkLimit) { finalTarget = proofOfWorkLimit; } return(finalTarget); }
public Target GetWorkRequiredDigiShield(ChainedHeader chainedHeaderToValidate, XRCConsensus consensus) { var nAveragingInterval = 10 * 5; // block var multiAlgoTargetSpacingV4 = 10 * 60; // seconds var nAveragingTargetTimespanV4 = nAveragingInterval * multiAlgoTargetSpacingV4; var nMaxAdjustDownV4 = 16; var nMaxAdjustUpV4 = 8; var nMinActualTimespanV4 = TimeSpan.FromSeconds(nAveragingTargetTimespanV4 * (100 - nMaxAdjustUpV4) / 100); var nMaxActualTimespanV4 = TimeSpan.FromSeconds(nAveragingTargetTimespanV4 * (100 + nMaxAdjustDownV4) / 100); var height = chainedHeaderToValidate.Height; Target proofOfWorkLimit = consensus.PowLimit2; ChainedHeader lastBlock = chainedHeaderToValidate.Previous; ChainedHeader firstBlock = chainedHeaderToValidate.GetAncestor(height - nAveragingInterval); var XRCConsensusProtocol = (XRCConsensusProtocol)consensus.ConsensusFactory.Protocol; if (((height - XRCConsensusProtocol.PowDigiShieldX11Height) <= (nAveragingInterval + this.MedianTimeSpan)) && (consensus.CoinType == (int)XRCCoinType.CoinTypes.XRCMain)) { return(new Target(new uint256("000000000001a61a000000000000000000000000000000000000000000000000"))); } // Limit adjustment step // Use medians to prevent time-warp attacks TimeSpan nActualTimespan = GetAverageTimePast(lastBlock) - GetAverageTimePast(firstBlock); nActualTimespan = TimeSpan.FromSeconds(nAveragingTargetTimespanV4 + (nActualTimespan.TotalSeconds - nAveragingTargetTimespanV4) / 4); if (nActualTimespan < nMinActualTimespanV4) { nActualTimespan = nMinActualTimespanV4; } if (nActualTimespan > nMaxActualTimespanV4) { nActualTimespan = nMaxActualTimespanV4; } // Retarget. BigInteger newTarget = lastBlock.Header.Bits.ToBigInteger(); newTarget = newTarget.Multiply(BigInteger.ValueOf((long)nActualTimespan.TotalSeconds)); newTarget = newTarget.Divide(BigInteger.ValueOf((long)nAveragingTargetTimespanV4)); var finalTarget = new Target(newTarget); if (finalTarget > proofOfWorkLimit) { finalTarget = proofOfWorkLimit; } return(finalTarget); }