コード例 #1
0
 public PosTestBlockAssembler(IConsensusLoop consensusLoop,
                              Network network,
                              MempoolSchedulerLock mempoolLock,
                              ITxMempool mempool,
                              IDateTimeProvider dateTimeProvider,
                              StakeChain stakeChain,
                              IStakeValidator stakeValidator,
                              ChainedBlock chainTip,
                              ILoggerFactory loggerFactory,
                              AssemblerOptions options = null) :
     base(consensusLoop, network, mempoolLock, mempool, dateTimeProvider, stakeChain, stakeValidator, chainTip, loggerFactory, options)
 {
     base.pblock = this.pblocktemplate.Block;
 }
コード例 #2
0
 public PosBlockAssembler(
     ConsensusLoop consensusLoop,
     Network network,
     ConcurrentChain chain,
     MempoolAsyncLock mempoolLock,
     TxMempool mempool,
     IDateTimeProvider dateTimeProvider,
     StakeChain stakeChain,
     ILogger logger,
     AssemblerOptions options = null)
     : base(consensusLoop, network, chain, mempoolLock, mempool, dateTimeProvider, logger, options)
 {
     this.stakeChain = stakeChain;
 }
コード例 #3
0
        /// <summary>
        /// Initialize a new instance of <see cref="ConsensusLoop"/>.
        /// </summary>
        /// <param name="asyncLoopFactory">The async loop we need to wait upon before we can shut down this feature.</param>
        /// <param name="validator">The validation logic for the consensus rules.</param>
        /// <param name="nodeLifetime">Contain information about the life time of the node, its used on startup and shutdown.</param>
        /// <param name="chain">A chain of headers all the way to genesis.</param>
        /// <param name="utxoSet">The consensus db, containing all unspent UTXO in the chain.</param>
        /// <param name="puller">A puller that can pull blocks from peers on demand.</param>
        /// <param name="nodeDeployments">Contain information about deployment and activation of features in the chain.</param>
        /// <param name="loggerFactory">A factory to provide logger instances.</param>
        /// <param name="chainState">Holds state related to the block chain.</param>
        /// <param name="connectionManager">Connection manager of all the currently connected peers.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="signals">A signaler that used to signal messages between features.</param>
        /// <param name="checkpoints">Provider of block header hash checkpoints.</param>
        /// <param name="settings">Consensus settings for the full node.</param>
        /// <param name="stakeChain">Information holding POS data chained.</param>
        public ConsensusLoop(
            IAsyncLoopFactory asyncLoopFactory,
            PowConsensusValidator validator,
            INodeLifetime nodeLifetime,
            ConcurrentChain chain,
            CoinView utxoSet,
            LookaheadBlockPuller puller,
            NodeDeployments nodeDeployments,
            ILoggerFactory loggerFactory,
            ChainState chainState,
            IConnectionManager connectionManager,
            IDateTimeProvider dateTimeProvider,
            Signals.Signals signals,
            ICheckpoints checkpoints,
            ConsensusSettings settings,
            StakeChain stakeChain = null)
        {
            Guard.NotNull(asyncLoopFactory, nameof(asyncLoopFactory));
            Guard.NotNull(validator, nameof(validator));
            Guard.NotNull(nodeLifetime, nameof(nodeLifetime));
            Guard.NotNull(chain, nameof(chain));
            Guard.NotNull(utxoSet, nameof(utxoSet));
            Guard.NotNull(puller, nameof(puller));
            Guard.NotNull(nodeDeployments, nameof(nodeDeployments));
            Guard.NotNull(connectionManager, nameof(connectionManager));
            Guard.NotNull(chainState, nameof(chainState));
            Guard.NotNull(signals, nameof(signals));
            Guard.NotNull(settings, nameof(settings));

            this.consensusLock = new AsyncLock();

            this.logger = loggerFactory.CreateLogger(this.GetType().FullName);

            this.asyncLoopFactory  = asyncLoopFactory;
            this.Validator         = validator;
            this.nodeLifetime      = nodeLifetime;
            this.chainState        = chainState;
            this.connectionManager = connectionManager;
            this.signals           = signals;
            this.Chain             = chain;
            this.UTXOSet           = utxoSet;
            this.Puller            = puller;
            this.NodeDeployments   = nodeDeployments;
            this.checkpoints       = checkpoints;
            this.dateTimeProvider  = dateTimeProvider;
            this.settings          = settings;

            // chain of stake info can be null if POS is not enabled
            this.StakeChain = stakeChain;
        }
コード例 #4
0
 public PosBlockAssembler(
     ConsensusLoop consensusLoop,
     Network network,
     MempoolSchedulerLock mempoolLock,
     TxMempool mempool,
     IDateTimeProvider dateTimeProvider,
     StakeChain stakeChain,
     ChainedBlock chainTip,
     ILoggerFactory loggerFactory,
     AssemblerOptions options = null)
     : base(consensusLoop, network, mempoolLock, mempool, dateTimeProvider, chainTip, loggerFactory, options)
 {
     this.logger     = loggerFactory.CreateLogger(this.GetType().FullName);
     this.stakeChain = stakeChain;
 }
コード例 #5
0
        public static ChainedBlock GetLastBlockIndex(StakeChain stakeChain, ChainedBlock index, bool proofOfStake)
        {
            if (index == null)
            {
                throw new ArgumentNullException(nameof(index));
            }
            var blockStake = stakeChain.Get(index.HashBlock);

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

            return(index);
        }
コード例 #6
0
        /// <inheritdoc />
        /// <param name="stakeValidator">Provides functionality for checking validity of PoS blocks.</param>
        /// <param name="checkpoints">Provider of block header hash checkpoints.</param>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="stakeChain">Database of stake related data for the current blockchain.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public PosConsensusValidator(
            StakeValidator stakeValidator,
            ICheckpoints checkpoints,
            Network network,
            StakeChain stakeChain,
            IDateTimeProvider dateTimeProvider,
            ILoggerFactory loggerFactory)
            : base(network, checkpoints, dateTimeProvider, loggerFactory)
        {
            Guard.NotNull(network.Consensus.Option <PosConsensusOptions>(), nameof(network.Consensus.Options));

            this.logger           = loggerFactory.CreateLogger(this.GetType().FullName);
            this.StakeValidator   = stakeValidator;
            this.stakeChain       = stakeChain;
            this.consensusOptions = network.Consensus.Option <PosConsensusOptions>();
        }
コード例 #7
0
        /// <summary>
        /// Gets the last block in the chain that was generated using
        /// PoS if <paramref name="proofOfStake"/> is <c>true</c> or PoW if <paramref name="proofOfStake"/> is <c>false</c>.
        /// </summary>
        /// <param name="stakeChain">Database of stake related data for the current blockchain.</param>
        /// <param name="startChainedBlock">Block that we start from. Only blocks before that one will be checked.</param>
        /// <param name="proofOfStake">Specifies what kind of block we are looking for: <c>true</c> for PoS or <c>false</c> for PoW.</param>
        /// <returns>Last block in the chain that satisfies provided requirements.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="startChainedBlock"/> is <c>null</c>.</exception>
        public ChainedBlock GetLastPowPosChainedBlock(StakeChain stakeChain, ChainedBlock startChainedBlock, bool proofOfStake)
        {
            Guard.Assert(startChainedBlock != null);

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

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

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

            this.logger.LogTrace("(-)':{0}'", startChainedBlock);
            return(startChainedBlock);
        }
コード例 #8
0
 public PosAssemblerFactory(
     ConsensusLoop consensusLoop,
     Network network,
     MempoolAsyncLock mempoolScheduler,
     TxMempool mempool,
     IDateTimeProvider dateTimeProvider,
     ILoggerFactory loggerFactory,
     StakeChain stakeChain = null)
 {
     this.consensusLoop    = consensusLoop;
     this.network          = network;
     this.mempoolScheduler = mempoolScheduler;
     this.mempool          = mempool;
     this.dateTimeProvider = dateTimeProvider;
     this.stakeChain       = stakeChain;
     this.loggerFactory    = loggerFactory;
     this.logger           = loggerFactory.CreateLogger(this.GetType().FullName);
 }
コード例 #9
0
        public static ChainedBlock GetLastBlockIndex(StakeChain stakeChain, ChainedBlock index, bool proofOfStake)
        {
            if (index == null)
            {
                throw new ArgumentNullException(nameof(index));
            }

            clogger.LogTrace("({0}:'{1}',{2}:{3})", nameof(index), index, nameof(proofOfStake), proofOfStake);

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

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

            clogger.LogTrace("(-)':{0}'", index);
            return(index);
        }
コード例 #10
0
        public PosMinting(
            ConsensusLoop consensusLoop,
            ConcurrentChain chain,
            Network network,
            IConnectionManager connection,
            IDateTimeProvider dateTimeProvider,
            AssemblerFactory blockAssemblerFactory,
            BlockRepository blockRepository,
            ChainState chainState,
            Signals.Signals signals, INodeLifetime nodeLifetime,
            NodeSettings settings,
            CoinView coinView,
            StakeChain stakeChain,
            IWalletManager wallet,
            IAsyncLoopFactory asyncLoopFactory,
            ILoggerFactory loggerFactory)
        {
            this.consensusLoop         = consensusLoop;
            this.chain                 = chain;
            this.network               = network;
            this.connection            = connection;
            this.dateTimeProvider      = dateTimeProvider;
            this.blockAssemblerFactory = blockAssemblerFactory;
            this.blockRepository       = blockRepository;
            this.chainState            = chainState;
            this.signals               = signals;
            this.nodeLifetime          = nodeLifetime;
            this.settings              = settings;
            this.coinView              = coinView;
            this.stakeChain            = stakeChain;
            this.asyncLoopFactory      = asyncLoopFactory;
            this.wallet                = wallet as WalletManager;
            this.logger                = loggerFactory.CreateLogger(this.GetType().FullName);

            this.minerSleep = 500;                                                                          // GetArg("-minersleep", 500);
            this.lastCoinStakeSearchTime = Utils.DateTimeToUnixTime(this.dateTimeProvider.GetTimeOffset()); // startup timestamp
            this.reserveBalance          = 0;                                                               // TOOD:settings.ReserveBalance
            this.minimumInputValue       = 0;

            this.posConsensusValidator = consensusLoop.Validator as PosConsensusValidator;
        }
コード例 #11
0
 /// <summary>
 /// Initializes an instance of the object.
 /// </summary>
 public PosConsensusRules(Network network, ILoggerFactory loggerFactory, IDateTimeProvider dateTimeProvider, ConcurrentChain chain, NodeDeployments nodeDeployments, ConsensusSettings consensusSettings, ICheckpoints checkpoints, StakeChain stakeChain, IStakeValidator stakeValidator)
     : base(network, loggerFactory, dateTimeProvider, chain, nodeDeployments, consensusSettings, checkpoints)
 {
     this.StakeChain     = stakeChain;
     this.StakeValidator = stakeValidator;
 }
コード例 #12
0
        public static Target GetNextTargetRequired(StakeChain stakeChain, ChainedBlock indexLast, NBitcoin.Consensus consensus, bool proofOfStake)
        {
            // Genesis block
            if (indexLast == null)
            {
                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)
            var targetLimit = proofOfStake
                                ? GetProofOfStakeLimit(consensus, indexLast.Height)
                                : consensus.PowLimit.ToBigInteger();

            // first block
            var pindexPrev = GetLastBlockIndex(stakeChain, indexLast, proofOfStake);

            if (pindexPrev.Previous == null)
            {
                return(new Target(targetLimit));
            }

            // second block
            var pindexPrevPrev = GetLastBlockIndex(stakeChain, pindexPrev.Previous, proofOfStake);

            if (pindexPrevPrev.Previous == null)
            {
                return(new Target(targetLimit));
            }


            int targetSpacing = GetTargetSpacing(indexLast.Height);
            int actualSpacing = (int)(pindexPrev.Header.Time - pindexPrevPrev.Header.Time);

            if (IsProtocolV1RetargetingFixed(indexLast.Height))
            {
                if (actualSpacing < 0)
                {
                    actualSpacing = targetSpacing;
                }
            }
            if (IsProtocolV3((int)indexLast.Header.Time))
            {
                if (actualSpacing > targetSpacing * 10)
                {
                    actualSpacing = targetSpacing * 10;
                }
            }

            // target change every block
            // retarget with exponential moving toward target spacing
            var targetTimespan = 16 * 60;             // 16 mins
            var target         = pindexPrev.Header.Bits.ToBigInteger();

            int interval = targetTimespan / targetSpacing;

            target = target.Multiply(BigInteger.ValueOf(((interval - 1) * targetSpacing + actualSpacing + actualSpacing)));
            target = target.Divide(BigInteger.ValueOf(((interval + 1) * targetSpacing)));

            if (target.CompareTo(BigInteger.Zero) <= 0 || target.CompareTo(targetLimit) >= 1)
            {
                //if (target <= 0 || target > targetLimit)
                target = targetLimit;
            }

            return(new Target(target));
        }
コード例 #13
0
        public ConsensusLoop(PowConsensusValidator validator, ConcurrentChain chain, CoinView utxoSet, LookaheadBlockPuller puller, NodeDeployments nodeDeployments, StakeChain stakeChain = null)
        {
            Guard.NotNull(validator, nameof(validator));
            Guard.NotNull(chain, nameof(chain));
            Guard.NotNull(utxoSet, nameof(utxoSet));
            Guard.NotNull(puller, nameof(puller));
            Guard.NotNull(nodeDeployments, nameof(nodeDeployments));

            this.Validator       = validator;
            this.Chain           = chain;
            this.UTXOSet         = utxoSet;
            this.Puller          = puller;
            this.NodeDeployments = nodeDeployments;

            // chain of stake info can be null if POS is not enabled
            this.StakeChain = stakeChain;
        }
コード例 #14
0
        /// <summary>
        /// Calculates the difficulty target for the next block.
        /// </summary>
        /// <param name="stakeChain">Database of stake related data for the current blockchain.</param>
        /// <param name="chainedBlock">Block header for which to calculate the target difficulty.</param>
        /// <param name="consensus">Consensus rules for the current network.</param>
        /// <param name="proofOfStake"><c>true</c> for calculation of PoS difficulty target, <c>false</c> for calculation of PoW difficulty target.</param>
        /// <returns>The difficulty target for the next block after <paramref name="chainedBlock"/>.</returns>
        /// <remarks>
        /// The calculation of the next target is based on the last target value and the block time (aka spacing) of <paramref name="chainedBlock"/>
        /// (i.e. difference in time stamp of this block and its immediate predecessor). The target changes every block and it is adjusted
        /// down (i.e. towards harder to reach, or more difficult) if the time to mine last block was lower than the target block time.
        /// And it is adjusted up if it took longer than the target block time. The adjustments are done in a way the target is moving towards
        /// the target spacing exponentially, so even a big change in the mining power on the network will be fixed by retargeting relatively quickly.
        /// <para>
        /// Over <see cref="RetargetIntervalMinutes"/> minutes there are certain number (say <c>N</c>) of blocks expected to be mined if the target block time
        /// of <see cref="TargetSpacingSeconds"/> was reached every time. Then the next target is calculated as follows:</para>
        /// <code>
        /// NewTarget = PrevTarget * ((N - 1) * TargetSpacingSeconds + 2 * LastBlockTime) / ((N + 1) * TargetSpacingSeconds)
        /// </code>
        /// <para>
        /// Which basically says that the block time of the last block is counted twice instead of two optimal block times.
        /// And the <c>N</c> determines how strongly will the deviation of the last block time affect the difficulty.
        /// </para>
        /// </remarks>
        public static Target GetNextTargetRequired(StakeChain stakeChain, ChainedBlock chainedBlock, NBitcoin.Consensus consensus, bool proofOfStake)
        {
            clogger.LogTrace("({0}:'{1}',{2}:{3})", nameof(chainedBlock), chainedBlock, nameof(proofOfStake), proofOfStake);

            // Genesis block.
            if (chainedBlock == null)
            {
                clogger.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.
            ChainedBlock pindexPrev = GetLastBlockIndex(stakeChain, chainedBlock, proofOfStake);

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

            // Second block.
            ChainedBlock pindexPrevPrev = GetLastBlockIndex(stakeChain, pindexPrev.Previous, proofOfStake);

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

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

            int targetSpacing = TargetSpacingSeconds;
            int actualSpacing = (int)(pindexPrev.Header.Time - pindexPrevPrev.Header.Time);

            if (actualSpacing < 0)
            {
                actualSpacing = targetSpacing;
            }

            if (actualSpacing > targetSpacing * 10)
            {
                actualSpacing = targetSpacing * 10;
            }

            int targetTimespan = RetargetIntervalMinutes * 60;
            int interval       = targetTimespan / targetSpacing;

            BigInteger target = pindexPrev.Header.Bits.ToBigInteger();

            long multiplyBy = (interval - 1) * targetSpacing + actualSpacing + actualSpacing;

            target = target.Multiply(BigInteger.ValueOf(multiplyBy));

            long divideBy = (interval + 1) * targetSpacing;

            target = target.Divide(BigInteger.ValueOf(divideBy));

            clogger.LogTrace("The next target difficulty will be {0} times higher (easier to satisfy) than the previous target.", (double)multiplyBy / (double)divideBy);

            if ((target.CompareTo(BigInteger.Zero) <= 0) || (target.CompareTo(targetLimit) >= 1))
            {
                target = targetLimit;
            }

            var finalTarget = new Target(target);

            clogger.LogTrace("(-):'{0}'", finalTarget);
            return(finalTarget);
        }