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