public BlockModel(Block block, ChainedHeader chainedHeader, ChainedHeader tip, Network network, int verbosity = 1)
        {
            this.Hash          = block.GetHash().ToString();
            this.Confirmations = tip.Height - chainedHeader.Height + 1;
            this.Size          = block.ToBytes().Length;
            this.Weight        = block.GetBlockWeight(network.Consensus);
            this.Height        = chainedHeader.Height;
            this.Version       = block.Header.Version;
            this.VersionHex    = block.Header.Version.ToString("x8");
            this.MerkleRoot    = block.Header.HashMerkleRoot.ToString();

            if (verbosity == 1)
            {
                this.Transactions = block.Transactions.Select(t => t.GetHash().ToString()).ToArray();
            }

            if (verbosity == 2)
            {
                this.Transactions = block.Transactions.Select(t => new TransactionVerboseModel(t, network)).ToArray();
            }

            this.Time                 = block.Header.BlockTime.ToUnixTimeSeconds();
            this.MedianTime           = chainedHeader.GetMedianTimePast().ToUnixTimeSeconds();
            this.Nonce                = block.Header.Nonce;
            this.Bits                 = block.Header.Bits.ToCompact().ToString("x8");
            this.Difficulty           = block.Header.Bits.Difficulty;
            this.ChainWork            = chainedHeader.ChainWork.ToString();
            this.NumberOfTransactions = block.Transactions.Count();
            this.PreviousBlockHash    = block.Header.HashPrevBlock.ToString();
            this.NextBlockHash        = chainedHeader.Next?.FirstOrDefault()?.HashBlock.ToString();
        }
        public ContextBlockInformation(ChainedHeader bestBlock, NBitcoin.Consensus consensus)
        {
            Guard.NotNull(bestBlock, nameof(bestBlock));

            this.Header         = bestBlock.Header;
            this.Height         = bestBlock.Height;
            this.MedianTimePast = bestBlock.GetMedianTimePast();
        }
示例#3
0
        /// <summary>
        /// Set time to consensus acceptable value.
        /// </summary>
        /// <param name="now">The expected date.</param>
        /// <param name="consensus">Consensus.</param>
        /// <param name="prev">Previous block.</param>
        public void UpdateTime(DateTimeOffset now, IConsensus consensus, ChainedHeader prev)
        {
            DateTimeOffset nOldTime = this.BlockTime;
            DateTimeOffset mtp      = prev.GetMedianTimePast() + TimeSpan.FromSeconds(1);
            DateTimeOffset nNewTime = mtp > now ? mtp : now;

            if (nOldTime < nNewTime)
            {
                this.BlockTime = nNewTime;
            }

            // Updating time can change work required on testnet.
            if (consensus.PowAllowMinDifficultyBlocks)
            {
                this.Bits = this.GetWorkRequired(consensus, prev);
            }
        }
示例#4
0
        /// <summary>
        /// Determines the state of a BIP from the cache and/or the chain header history and the corresponding version bits.
        /// </summary>
        /// <param name="indexPrev">The previous header of the chain header to determine the states for.</param>
        /// <param name="deployment">The deployment to check the state of.</param>
        /// <returns>The current state of the deployment.</returns>
        public ThresholdState GetState(ChainedHeader indexPrev, int deployment)
        {
            int            period      = this.consensus.MinerConfirmationWindow;
            int            threshold   = this.consensus.RuleChangeActivationThreshold;
            DateTimeOffset?timeStart   = this.consensus.BIP9Deployments[deployment]?.StartTime;
            DateTimeOffset?timeTimeout = this.consensus.BIP9Deployments[deployment]?.Timeout;

            // Check if this deployment is always active.
            if (timeStart == Utils.UnixTimeToDateTime(BIP9DeploymentsParameters.AlwaysActive))
            {
                return(ThresholdState.Active);
            }

            // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
            if (indexPrev != null)
            {
                indexPrev = indexPrev.GetAncestor(indexPrev.Height - ((indexPrev.Height + 1) % period));
            }

            // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known.
            var vToCompute = new List <ChainedHeader>();

            while (!this.ContainsKey(indexPrev?.HashBlock, deployment))
            {
                if (indexPrev.GetMedianTimePast() < timeStart)
                {
                    // Optimization: don't recompute down further, as we know every earlier block will be before the start time.
                    this.Set(indexPrev?.HashBlock, deployment, ThresholdState.Defined);
                    break;
                }

                vToCompute.Add(indexPrev);
                indexPrev = indexPrev.GetAncestor(indexPrev.Height - period);
            }

            // At this point, cache[pindexPrev] is known.
            this.Assert(this.ContainsKey(indexPrev?.HashBlock, deployment));
            ThresholdState state = this.Get(indexPrev?.HashBlock, deployment);

            // Now walk forward and compute the state of descendants of pindexPrev.
            while (vToCompute.Count != 0)
            {
                ThresholdState stateNext = state;
                indexPrev = vToCompute[vToCompute.Count - 1];
                vToCompute.RemoveAt(vToCompute.Count - 1);

                switch (state)
                {
                case ThresholdState.Defined:
                {
                    if (indexPrev.GetMedianTimePast() >= timeTimeout)
                    {
                        stateNext = ThresholdState.Failed;
                    }
                    else if (indexPrev.GetMedianTimePast() >= timeStart)
                    {
                        stateNext = ThresholdState.Started;
                    }

                    break;
                }

                case ThresholdState.Started:
                {
                    if (indexPrev.GetMedianTimePast() >= timeTimeout)
                    {
                        stateNext = ThresholdState.Failed;
                        break;
                    }

                    // Counts the "votes" in the confirmation window to determine
                    // whether the rule change activation threshold has been met.
                    ChainedHeader pindexCount = indexPrev;
                    int           count       = 0;
                    for (int i = 0; i < period; i++)
                    {
                        if (this.Condition(pindexCount, deployment))
                        {
                            count++;
                        }

                        pindexCount = pindexCount.Previous;
                    }

                    // If the threshold has been met then lock in the BIP activation.
                    if (count >= threshold)
                    {
                        stateNext = ThresholdState.LockedIn;
                    }

                    break;
                }

                case ThresholdState.LockedIn:
                {
                    // Always progresses into ACTIVE.
                    stateNext = ThresholdState.Active;
                    break;
                }

                case ThresholdState.Failed:
                case ThresholdState.Active:
                {
                    // Nothing happens, these are terminal states.
                    break;
                }
                }

                this.Set(indexPrev?.HashBlock, deployment, state = stateNext);
            }

            return(state);
        }