public TransactionVerboseModel(NBitcoin.Transaction trx, Network network, NBitcoin.ChainedBlock block = null, ChainedBlock tip = null) : base(trx)
        {
            if (trx != null)
            {
                this.txid     = trx.GetHash().ToString();
                this.size     = trx.GetSerializedSize();
                this.version  = trx.Version;
                this.locktime = trx.LockTime;

                this.vin = trx.Inputs.Select(txin => new Vin(txin.PrevOut, txin.Sequence, txin.ScriptSig)).ToList();

                int n = 0;
                this.vout = trx.Outputs.Select(txout => new Vout(n++, txout, network)).ToList();

                if (block != null)
                {
                    blockhash = block.HashBlock.ToString();
                    time      = blocktime = Utils.DateTimeToUnixTime(block.Header.BlockTime);
                    if (tip != null)
                    {
                        confirmations = tip.Height - block.Height + 1;
                    }
                }
            }
        }
示例#2
0
		public bool TrySetTip(BlockHeader header, out ChainedBlock chainedHeader)
		{
			if (header == null) throw new ArgumentNullException("header");
			chainedHeader = null;
			var prev = GetBlock(header.HashPrevBlock);
			if(prev == null)
				return false;
			chainedHeader = new ChainedBlock(header, header.GetHash(), GetBlock(header.HashPrevBlock));
			SetTip(chainedHeader);
			return true;
		}
示例#3
0
        // (memory only) Sequencial id assigned to distinguish order in which blocks are received.
        //uint nSequenceId;
        public ChainedBlock(BlockHeader header,uint256 headerHash, ChainedBlock previous)
        {
            if(previous != null)
            {
                nHeight = previous.Height + 1;
            }
            this.pprev = previous;
            //this.nDataPos = pos;
            this.header = header;
            this.phashBlock = headerHash ?? header.GetHash();

            if(previous == null)
            {
                if(header.HashPrevBlock != 0)
                    throw new ArgumentException("Only the genesis block can have no previous block");
            }
            else
            {
                if(previous.HashBlock != header.HashPrevBlock)
                    throw new ArgumentException("The previous block has not the expected hash");
            }
        }
示例#4
0
        // Stake Modifier (hash modifier of proof-of-stake):
        // The purpose of stake modifier is to prevent a txout (coin) owner from
        // computing future proof-of-stake generated by this txout at the time
        // of transaction confirmation. To meet kernel protocol, the txout
        // must hash with a future stake modifier to generate the proof.
        // Stake modifier consists of bits each of which is contributed from a
        // selected block of a given block group in the past.
        // The selection of a block is based on a hash of the block's proof-hash and
        // the previous stake modifier.
        // Stake modifier is recomputed at a fixed time interval instead of every
        // block. This is to make it difficult for an attacker to gain control of
        // additional bits in the stake modifier, even after generating a chain of
        // blocks.
        private static bool ComputeNextStakeModifier(StakeChain stakeChain, ChainBase chainIndex, ChainedBlock pindexPrev, out ulong nStakeModifier,
                                                     out bool fGeneratedStakeModifier)
        {
            nStakeModifier          = 0;
            fGeneratedStakeModifier = false;
            if (pindexPrev == null)
            {
                fGeneratedStakeModifier = true;
                return(true); // genesis block's modifier is 0
            }

            // First find current stake modifier and its generation block time
            // if it's not old enough, return the same stake modifier
            long nModifierTime = 0;

            if (!GetLastStakeModifier(stakeChain, pindexPrev, out nStakeModifier, out nModifierTime))
            {
                return(false); //error("ComputeNextStakeModifier: unable to get last modifier");
            }
            //LogPrint("stakemodifier", "ComputeNextStakeModifier: prev modifier=0x%016x time=%s\n", nStakeModifier, DateTimeStrFormat(nModifierTime));
            if (nModifierTime / ModifierInterval >= pindexPrev.Header.Time / ModifierInterval)
            {
                return(true);
            }

            // Sort candidate blocks by timestamp
            var  sortedByTimestamp       = new SortedDictionary <uint, uint256>();
            long nSelectionInterval      = GetStakeModifierSelectionInterval();
            long nSelectionIntervalStart = (pindexPrev.Header.Time / ModifierInterval) * ModifierInterval - nSelectionInterval;
            var  pindex = pindexPrev;

            while (pindex != null && pindex.Header.Time >= nSelectionIntervalStart)
            {
                sortedByTimestamp.Add(pindex.Header.Time, pindex.HashBlock);
                pindex = pindex.Previous;
            }
            int nHeightFirstCandidate = pindex?.Height + 1 ?? 0;

            // Select 64 blocks from candidate blocks to generate stake modifier
            ulong nStakeModifierNew      = 0;
            long  nSelectionIntervalStop = nSelectionIntervalStart;
            var   mapSelectedBlocks      = new Dictionary <uint256, ChainedBlock>();

            for (int nRound = 0; nRound < Math.Min(64, sortedByTimestamp.Count); nRound++)
            {
                // add an interval section to the current selection round
                nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection(nRound);

                // select a block from the candidates of current round
                if (!SelectBlockFromCandidates(stakeChain, pindexPrev, sortedByTimestamp, mapSelectedBlocks, nSelectionIntervalStop, nStakeModifier, out pindex))
                {
                    return(false); // error("ComputeNextStakeModifier: unable to select block at round %d", nRound);
                }
                // write the entropy bit of the selected block
                var blockStake = stakeChain.Get(pindex.HashBlock);
                nStakeModifierNew |= ((ulong)blockStake.GetStakeEntropyBit() << nRound);

                // add the selected block from candidates to selected list
                mapSelectedBlocks.Add(pindex.HashBlock, pindex);

                //LogPrint("stakemodifier", "ComputeNextStakeModifier: selected round %d stop=%s height=%d bit=%d\n", nRound, DateTimeStrFormat(nSelectionIntervalStop), pindex->nHeight, pindex->GetStakeEntropyBit());
            }

            //  // Print selection map for visualization of the selected blocks
            //  if (LogAcceptCategory("stakemodifier"))
            //  {
            //      string strSelectionMap = "";
            //      '-' indicates proof-of-work blocks not selected
            //      strSelectionMap.insert(0, pindexPrev->nHeight - nHeightFirstCandidate + 1, '-');
            //      pindex = pindexPrev;
            //      while (pindex && pindex->nHeight >= nHeightFirstCandidate)
            //      {
            //          // '=' indicates proof-of-stake blocks not selected
            //          if (pindex->IsProofOfStake())
            //              strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "=");
            //          pindex = pindex->pprev;
            //      }

            //      BOOST_FOREACH(const PAIRTYPE(uint256, const CBlockIndex*)& item, mapSelectedBlocks)
            //      {
            //          // 'S' indicates selected proof-of-stake blocks
            //          // 'W' indicates selected proof-of-work blocks
            //          strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake()? "S" : "W");
            //      }

            //      LogPrintf("ComputeNextStakeModifier: selection height [%d, %d] map %s\n", nHeightFirstCandidate, pindexPrev->nHeight, strSelectionMap);
            //  }

            //LogPrint("stakemodifier", "ComputeNextStakeModifier: new modifier=0x%016x time=%s\n", nStakeModifierNew, DateTimeStrFormat(pindexPrev->GetBlockTime()));

            nStakeModifier          = nStakeModifierNew;
            fGeneratedStakeModifier = true;
            return(true);
        }
        /// <summary>
        /// Gets the proof of work target for this entry in the chain.
        /// </summary>
        /// <param name="consensus">Consensus rules to use for this computation.</param>
        /// <returns>The target proof of work.</returns>
        public Target GetWorkRequired(Consensus consensus)
        {
            // Genesis block.
            if (this.Height == 0)
            {
                return(consensus.PowLimit);
            }

            Target       proofOfWorkLimit = consensus.PowLimit;
            ChainedBlock lastBlock        = this.Previous;
            var          height           = this.Height;

            if (lastBlock == null)
            {
                return(proofOfWorkLimit);
            }

            // Only change once per interval.
            if ((height) % consensus.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 (this.Header.BlockTime > (lastBlock.Header.BlockTime + TimeSpan.FromTicks(consensus.PowTargetSpacing.Ticks * 2)))
                    {
                        return(proofOfWorkLimit);
                    }

                    // Return the last non-special-min-difficulty-rules-block.
                    ChainedBlock chainedBlock = lastBlock;
                    while ((chainedBlock.Previous != null) && ((chainedBlock.Height % consensus.DifficultyAdjustmentInterval) != 0) && (chainedBlock.Header.Bits == proofOfWorkLimit))
                    {
                        chainedBlock = chainedBlock.Previous;
                    }

                    return(chainedBlock.Header.Bits);
                }

                return(lastBlock.Header.Bits);
            }

            long pastHeight = 0;

            if (consensus.LitecoinWorkCalculation)
            {
                long blocksToGoBack = consensus.DifficultyAdjustmentInterval - 1;
                if ((lastBlock.Height + 1) != consensus.DifficultyAdjustmentInterval)
                {
                    blocksToGoBack = consensus.DifficultyAdjustmentInterval;
                }

                pastHeight = lastBlock.Height - blocksToGoBack;
            }
            else
            {
                // Go back by what we want to be 14 days worth of blocks.
                pastHeight = lastBlock.Height - (consensus.DifficultyAdjustmentInterval - 1);
            }

            ChainedBlock firstChainedBlock = this.EnumerateToGenesis().FirstOrDefault(o => o.Height == pastHeight);

            if (firstChainedBlock == 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 - firstChainedBlock.Header.BlockTime;

            if (actualTimespan < TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks / 4))
            {
                actualTimespan = TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks / 4);
            }
            if (actualTimespan > TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks * 4))
            {
                actualTimespan = TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks * 4);
            }

            // Retarget.
            BigInteger newTarget = lastBlock.Header.Bits.ToBigInteger();

            newTarget = newTarget.Multiply(BigInteger.ValueOf((long)actualTimespan.TotalSeconds));
            newTarget = newTarget.Divide(BigInteger.ValueOf((long)consensus.PowTargetTimespan.TotalSeconds));

            var finalTarget = new Target(newTarget);

            if (finalTarget > proofOfWorkLimit)
            {
                finalTarget = proofOfWorkLimit;
            }

            return(finalTarget);
        }
示例#6
0
        public static Target GetNextTargetRequired(StakeChain stakeChain, ChainedBlock indexLast, 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));
        }
示例#7
0
        // Purple kernel protocol
        // coinstake must meet hash target according to the protocol:
        // kernel (input 0) must meet the formula
        //     hash(nStakeModifier + txPrev.block.nTime + txPrev.nTime + txPrev.vout.hash + txPrev.vout.n + nTime) < bnTarget * nWeight
        // this ensures that the chance of getting a coinstake is proportional to the
        // amount of coins one owns.
        // The reason this hash is chosen is the following:
        //   nStakeModifier: scrambles computation to make it very difficult to precompute
        //                   future proof-of-stake
        //   txPrev.block.nTime: prevent nodes from guessing a good timestamp to
        //                       generate transaction for future advantage,
        //                       obsolete since v3
        //   txPrev.nTime: slightly scrambles computation
        //   txPrev.vout.hash: hash of txPrev, to reduce the chance of nodes
        //                     generating coinstake at the same time
        //   txPrev.vout.n: output number of txPrev, to reduce the chance of nodes
        //                  generating coinstake at the same time
        //   nTime: current timestamp
        //   block/tx hash should not be used here as they can be generated in vast
        //   quantities so as to generate blocks faster, degrading the system back into
        //   a proof-of-work situation.
        //
        private static bool CheckStakeKernelHashV2(ChainedBlock pindexPrev, uint nBits, uint nTimeBlockFrom, BlockStake prevBlockStake,
                                                   Transaction txPrev, OutPoint prevout, uint nTimeTx, out uint256 hashProofOfStake, out uint256 targetProofOfStake, bool fPrintProofOfStake)
        {
            targetProofOfStake = null; hashProofOfStake = null;

            if (nTimeTx < txPrev.Time) // Transaction timestamp violation
            {
                return(false);         //error("CheckStakeKernelHash() : nTime violation");
            }
            // Base target
            var bnTarget = new Target(nBits).ToBigInteger();

            // Weighted target
            var nValueIn = txPrev.Outputs[prevout.N].Value.Satoshi;
            var bnWeight = BigInteger.ValueOf(nValueIn);

            bnTarget = bnTarget.Multiply(bnWeight);

            // todo: investigate this issue, is the convertion to uint256 similar to the c++ implementation
            //targetProofOfStake = Target.ToUInt256(bnTarget);

            var     nStakeModifier       = prevBlockStake.StakeModifier;   //pindexPrev.Header.BlockStake.StakeModifier;
            uint256 bnStakeModifierV2    = prevBlockStake.StakeModifierV2; //pindexPrev.Header.BlockStake.StakeModifierV2;
            int     nStakeModifierHeight = pindexPrev.Height;
            var     nStakeModifierTime   = pindexPrev.Header.Time;

            // Calculate hash
            using (var ms = new MemoryStream())
            {
                var serializer = new BitcoinStream(ms, true);
                if (IsProtocolV3((int)nTimeTx))
                {
                    serializer.ReadWrite(bnStakeModifierV2);
                }
                else
                {
                    serializer.ReadWrite(nStakeModifier);
                    serializer.ReadWrite(nTimeBlockFrom);
                }

                serializer.ReadWrite(txPrev.Time);
                serializer.ReadWrite(prevout.Hash);
                serializer.ReadWrite(prevout.N);
                serializer.ReadWrite(nTimeTx);

                hashProofOfStake = Hashes.Hash256(ms.ToArray());
            }

            if (fPrintProofOfStake)
            {
                //LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from timestamp=%s\n",
                //    nStakeModifier, nStakeModifierHeight,
                //    DateTimeStrFormat(nStakeModifierTime),

                //    DateTimeStrFormat(nTimeBlockFrom));

                //LogPrintf("CheckStakeKernelHash() : check modifier=0x%016x nTimeBlockFrom=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
                //    nStakeModifier,
                //    nTimeBlockFrom, txPrev.nTime, prevout.n, nTimeTx,
                //    hashProofOfStake.ToString());
            }

            // Now check if proof-of-stake hash meets target protocol
            var hashProofOfStakeTarget = new BigInteger(hashProofOfStake.ToBytes(false));

            if (hashProofOfStakeTarget.CompareTo(bnTarget) > 0)
            {
                return(false);
            }


            //  if (fDebug && !fPrintProofOfStake)
            //  {
            //        LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from timestamp=%s\n",
            //        nStakeModifier, nStakeModifierHeight,
            //        DateTimeStrFormat(nStakeModifierTime),

            //        DateTimeStrFormat(nTimeBlockFrom));

            //        LogPrintf("CheckStakeKernelHash() : pass modifier=0x%016x nTimeBlockFrom=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
            //        nStakeModifier,
            //        nTimeBlockFrom, txPrev.nTime, prevout.n, nTimeTx,
            //        hashProofOfStake.ToString());
            //  }

            return(true);
        }
示例#8
0
 public bool Contains(ChainedBlock blockIndex)
 {
     if(StartHeight <= blockIndex.Height && blockIndex.Height <= Height)
     {
         return vChain[blockIndex.Height - StartHeight] == blockIndex;
     }
     else
         return false;
 }
示例#9
0
        // ppcoin: total coin age spent in transaction, in the unit of coin-days.
        // Only those coins meeting minimum age requirement counts. As those
        // transactions not in main chain are not currently indexed so we
        // might not find out about their coin age. Older transactions are
        // guaranteed to be in main chain by sync-checkpoint. This rule is
        // introduced to help nodes establish a consistent view of the coin
        // age (trust score) of competing branches.
        public static bool GetCoinAge(INBitcoinBlockRepository blockStore, ITransactionRepository trasnactionStore, IBlockTransactionMapStore mapStore,
                                      Transaction trx, ChainedBlock pindexPrev, out ulong nCoinAge)
        {
            BigInteger bnCentSecond = BigInteger.Zero;  // coin age in the unit of cent-seconds

            nCoinAge = 0;

            if (trx.IsCoinBase)
            {
                return(true);
            }

            foreach (var txin in trx.Inputs)
            {
                // First try finding the previous transaction in database
                Transaction txPrev = trasnactionStore.Get(txin.PrevOut.Hash);
                if (txPrev == null)
                {
                    continue;  // previous transaction not in main chain
                }
                if (trx.Time < txPrev.Time)
                {
                    return(false);  // Transaction timestamp violation
                }
                if (IsProtocolV3((int)trx.Time))
                {
                    int nSpendDepth = 0;
                    if (IsConfirmedInNPrevBlocks(blockStore, txPrev, pindexPrev, StakeMinConfirmations - 1, ref nSpendDepth))
                    {
                        //LogPrint("coinage", "coin age skip nSpendDepth=%d\n", nSpendDepth + 1);
                        continue; // only count coins meeting min confirmations requirement
                    }
                }
                else
                {
                    // Read block header
                    var block = blockStore.GetBlock(txPrev.GetHash());
                    if (block == null)
                    {
                        return(false); // unable to read block of previous transaction
                    }
                    if (block.Header.Time + StakeMinAge > trx.Time)
                    {
                        continue; // only count coins meeting min age requirement
                    }
                }

                long nValueIn   = txPrev.Outputs[txin.PrevOut.N].Value;
                var  multiplier = BigInteger.ValueOf((trx.Time - txPrev.Time) / CENT);
                bnCentSecond = bnCentSecond.Add(BigInteger.ValueOf(nValueIn).Multiply(multiplier));
                //bnCentSecond += new BigInteger(nValueIn) * (trx.Time - txPrev.Time) / CENT;


                //LogPrint("coinage", "coin age nValueIn=%d nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString());
            }

            BigInteger bnCoinDay = bnCentSecond.Multiply(BigInteger.ValueOf(CENT / COIN / (24 * 60 * 60)));

            //BigInteger bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);

            //LogPrint("coinage", "coin age bnCoinDay=%s\n", bnCoinDay.ToString());
            nCoinAge = new Target(bnCoinDay).ToCompact();

            return(true);
        }
示例#10
0
 public bool Contains(ChainedBlock blockIndex)
 {
     return(GetBlock(blockIndex.Height) != null);
 }
示例#11
0
		/// <summary>
		/// Force a new tip for the chain
		/// </summary>
		/// <param name="pindex"></param>
		/// <returns>forking point</returns>
		public override ChainedBlock SetTip(ChainedBlock block)
		{
			using(@lock.LockWrite())
			{
				return SetTipNoLock(block);
			}
		}
示例#12
0
文件: Block.cs 项目: crowar/NBitcoin
		/// <summary>
		/// Set time to consensus acceptable value
		/// </summary>
		/// <param name="network">Network</param>
		/// <param name="prev">previous block</param>
		public void UpdateTime(Network network, ChainedBlock prev)
		{
			var nOldTime = this.BlockTime;
			var mtp = prev.GetMedianTimePast() + TimeSpan.FromSeconds(1);
			var now = DateTimeOffset.UtcNow;
			var nNewTime = mtp > now ? mtp : now;

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

			// Updating time can change work required on testnet:
			if(network.Consensus.PowAllowMinDifficultyBlocks)
				Bits = GetWorkRequired(network, prev);
		}
示例#13
0
文件: Block.cs 项目: crowar/NBitcoin
		public Target GetWorkRequired(Network network, ChainedBlock prev)
		{
			return new ChainedBlock(this, null, prev).GetWorkRequired(network);
		}
示例#14
0
        /// <summary>
        /// Change tip of the chain
        /// </summary>
        /// <param name="pindex"></param>
        /// <returns>forking point</returns>
        internal ChainedBlock SetTip(ChainedBlock pindex)
        {
            int backtrackCount = 0;
            foreach(var remove in vChain.Resize(pindex.Height + 1 - StartHeight))
            {
                index.Remove(remove.HashBlock);
                offchainIndex.AddOrReplace(remove.HashBlock, remove);
                backtrackCount++;
            }

            while(pindex != null && vChain[pindex.Height - StartHeight] != pindex)
            {
                var old = vChain[pindex.Height - StartHeight];
                if(old != null)
                {
                    index.Remove(old.HashBlock);
                    offchainIndex.AddOrReplace(old.HashBlock, old);
                    backtrackCount++;
                }
                vChain[pindex.Height - StartHeight] = pindex;
                index.AddOrReplace(pindex.HashBlock, pindex);
                pindex = pindex.Previous;
            }

            if(backtrackCount != 0)
                Changes.WriteNext(new ChainChange()
                {
                    Add = false,
                    HeightOrBackstep = (uint)(backtrackCount)
                });

            for(int i = pindex.Height + 1 ; i <= Tip.Height ; i++)
            {
                var block = vChain[i - StartHeight];
                Changes.WriteNext(new ChainChange()
                {
                    Add = true,
                    BlockHeader = block.Header,
                    HeightOrBackstep = (uint)block.Height
                });
            }

            return pindex;
        }
示例#15
0
        public ChainedBlock GetOrAdd(BlockHeader header)
        {
            AssertInitialized();
            var headerHash = header.GetHash();
            ChainedBlock pindex = GetBlock(headerHash, true);
            if(pindex != null)
                return pindex;
            ChainedBlock previous = GetBlock(header.HashPrevBlock, true);
            if(previous == null)
            {
                return null;
            }

            pindex = new ChainedBlock(header, headerHash, previous);
            if(previous.HashBlock == Tip.HashBlock)
            {
                var change = new ChainChange()
                {
                    Add = true,
                    BlockHeader = pindex.Header,
                    HeightOrBackstep = (uint)pindex.Height
                };
                ProcessAndRecord(change, pindex.HashBlock);
            }
            else
            {
                if(pindex.Height <= Tip.Height)
                {
                    offchainIndex.Add(pindex.HashBlock, pindex);
                }
                else
                {
                    var fork = FindFork(pindex.EnumerateToGenesis().Select(c => c.HashBlock));
                    var change = new ChainChange()
                    {
                        Add = false,
                        HeightOrBackstep = (uint)(Tip.Height - fork.Height)
                    };
                    ProcessAndRecord(change, null);

                    foreach(var block in pindex.EnumerateToGenesis().TakeWhile(s => s != fork).Reverse())
                    {
                        change = new ChainChange()
                        {
                            Add = true,
                            BlockHeader = block.Header,
                            HeightOrBackstep = (uint)block.Height
                        };
                        ProcessAndRecord(change, block.HashBlock);
                    }
                }
            }
            return pindex;
        }
示例#16
0
 public IEnumerable<ChainedBlock> EnumerateAfter(ChainedBlock block)
 {
     for(int i = block.Height + 1 ; i < vChain.Count ; i++)
     {
         yield return vChain[i - StartHeight];
     }
 }
示例#17
0
		public IEnumerable<ChainedBlock> EnumerateToTip(ChainedBlock block)
		{
			if(block == null)
				throw new ArgumentNullException("block");
			return EnumerateToTip(block.HashBlock);
		}
示例#18
0
        public bool Contains(uint256 hash, bool includeBranch = false)
        {
            ChainedBlock pindex = GetBlock(hash, includeBranch);

            return(pindex != null);
        }
示例#19
0
		/// <summary>
		/// Force a new tip for the chain
		/// </summary>
		/// <param name="pindex"></param>
		/// <returns>forking point</returns>
		public abstract ChainedBlock SetTip(ChainedBlock pindex);
示例#20
0
        public Target GetWorkRequired(Network network, int height)
        {
            if (IsPartial)
            {
                throw new InvalidOperationException("You can't calculate work on partial chain");
            }
            var nProofOfWorkLimit = new Target(network.ProofOfWorkLimit);
            var pindexLast        = height == 0 ? null : GetBlock(height - 1);

            // Genesis block
            if (pindexLast == null)
            {
                return(nProofOfWorkLimit);
            }

            // Only change once per interval
            if ((height) % nInterval != 0)
            {
                if (network == Network.TestNet)
                {
                    // 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 (DateTimeOffset.UtcNow > pindexLast.Header.BlockTime + TimeSpan.FromTicks(nTargetSpacing.Ticks * 2))
                    {
                        return(nProofOfWorkLimit);
                    }
                    else
                    {
                        // Return the last non-special-min-difficulty-rules-block
                        ChainedBlock pindex = pindexLast;
                        while (pindex.Previous != null && (pindex.Height % nInterval) != 0 && pindex.Header.Bits == nProofOfWorkLimit)
                        {
                            pindex = pindex.Previous;
                        }
                        return(pindex.Header.Bits);
                    }
                }
                return(pindexLast.Header.Bits);
            }

            // Go back by what we want to be 14 days worth of blocks
            var          pastHeight  = pindexLast.Height - nInterval + 1;
            ChainedBlock pindexFirst = GetBlock((int)pastHeight);

            assert(pindexFirst);

            // Limit adjustment step
            var nActualTimespan = pindexLast.Header.BlockTime - pindexFirst.Header.BlockTime;

            if (nActualTimespan < TimeSpan.FromTicks(nTargetTimespan.Ticks / 4))
            {
                nActualTimespan = TimeSpan.FromTicks(nTargetTimespan.Ticks / 4);
            }
            if (nActualTimespan > TimeSpan.FromTicks(nTargetTimespan.Ticks * 4))
            {
                nActualTimespan = TimeSpan.FromTicks(nTargetTimespan.Ticks * 4);
            }

            // Retarget
            var bnNew = pindexLast.Header.Bits.ToBigInteger();

            bnNew *= (ulong)nActualTimespan.TotalSeconds;
            bnNew /= (ulong)nTargetTimespan.TotalSeconds;
            var newTarget = new Target(bnNew);

            if (newTarget > nProofOfWorkLimit)
            {
                newTarget = nProofOfWorkLimit;
            }

            return(newTarget);
        }
示例#21
0
		private IEnumerable<ChainedBlock> EnumerateThisToFork(ChainedBlock block)
		{
			if(_Tip == null)
				yield break;
			var tip = _Tip;
			while(true)
			{
				if(object.ReferenceEquals(null, block) || object.ReferenceEquals(null, tip))
					throw new InvalidOperationException("No fork found between the two chains");
				if(tip.Height > block.Height)
				{
					yield return tip;
					tip = tip.Previous;
				}
				else if(tip.Height < block.Height)
				{
					block = block.Previous;
				}
				else if(tip.Height == block.Height)
				{
					if(tip.HashBlock == block.HashBlock)
						break;
					yield return tip;
					block = block.Previous;
					tip = tip.Previous;
				}
			}
		}
示例#22
0
        /// <summary>
        /// Whether the chain contains a chained block header with the given hash.
        /// </summary>
        /// <param name="hash">The hash to search for.</param>
        /// <returns>Whether the chain contains the chained block header.</returns>
        public bool Contains(uint256 hash)
        {
            ChainedBlock block = this.GetBlock(hash);

            return(block != null);
        }
示例#23
0
文件: Block.cs 项目: rtddrt/NBitcoin
 public Target GetWorkRequired(Consensus consensus, ChainedBlock prev)
 {
     return(new ChainedBlock(this, null, prev).GetWorkRequired(consensus));
 }
示例#24
0
 /// <summary>
 /// Force a new tip for the chain.
 /// </summary>
 /// <param name="chainedBlock">New tip for the chain.</param>
 /// <returns>Forking point.</returns>
 public abstract ChainedBlock SetTip(ChainedBlock chainedBlock);
示例#25
0
 // miner's coin stake reward
 public static long GetProofOfStakeReward(ChainedBlock pindexPrev, ulong nCoinAge, long nFees)
 {
     return(1 * BlockValidator.COIN + nFees);
 }
        public bool Evaluate(ChainedBlock block)
        {
            var nBlockTime = block.Previous == null?Utils.UnixTimeToDateTime(0) : block.Previous.GetMedianTimePast();

            return(this.MinHeight < block.Height && this.MinTime < nBlockTime);
        }
示例#27
0
        private static bool IsConfirmedInNPrevBlocks(INBitcoinBlockRepository blockStore, Transaction txPrev, ChainedBlock pindexFrom, int maxDepth, ref int actualDepth)
        {
            // note: this method can be optimized by ensuring that blockstore keeps
            // in memory at least maxDepth blocks twards genesis

            var hashPrev = txPrev.GetHash();

            for (var pindex = pindexFrom; pindex != null && pindexFrom.Height - pindex.Height < maxDepth; pindex = pindex.Previous)
            {
                var block = blockStore.GetBlock(pindex.HashBlock);
                if (block == null)
                {
                    return(false);
                }
                if (block.Transactions.Any(b => b.GetHash() == hashPrev)) //pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
                {
                    actualDepth = pindexFrom.Height - pindex.Height;
                    return(true);
                }
            }

            return(false);
        }
示例#28
0
 public Target GetWorkRequired(Network network, ChainedBlock prev)
 {
     return(new ChainedBlock(this, null, prev).GetWorkRequired(network));
 }
示例#29
0
        // select a block from the candidate blocks in vSortedByTimestamp, excluding
        // already selected blocks in vSelectedBlocks, and with timestamp up to
        // nSelectionIntervalStop.
        private static bool SelectBlockFromCandidates(StakeChain stakeChain, ChainedBlock chainIndex, SortedDictionary <uint, uint256> sortedByTimestamp,
                                                      Dictionary <uint256, ChainedBlock> mapSelectedBlocks,
                                                      long nSelectionIntervalStop, ulong nStakeModifierPrev, out ChainedBlock pindexSelected)
        {
            bool    fSelected = false;
            uint256 hashBest  = 0;

            pindexSelected = null;

            foreach (var item in sortedByTimestamp)
            {
                var pindex = chainIndex.FindAncestorOrSelf(item.Value);
                if (pindex == null)
                {
                    return(false); // error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString());
                }
                if (fSelected && pindex.Header.Time > nSelectionIntervalStop)
                {
                    break;
                }

                if (mapSelectedBlocks.Keys.Any(key => key == pindex.HashBlock))
                {
                    continue;
                }

                var blockStake = stakeChain.Get(pindex.HashBlock);

                // compute the selection hash by hashing its proof-hash and the
                // previous proof-of-stake modifier
                uint256 hashSelection;
                using (var ms = new MemoryStream())
                {
                    var serializer = new BitcoinStream(ms, true);
                    serializer.ReadWrite(blockStake.HashProof);
                    serializer.ReadWrite(nStakeModifierPrev);

                    hashSelection = Hashes.Hash256(ms.ToArray());
                }

                // the selection hash is divided by 2**32 so that proof-of-stake block
                // is always favored over proof-of-work block. this is to preserve
                // the energy efficiency property
                if (blockStake.IsProofOfStake())
                {
                    hashSelection >>= 32;
                }

                if (fSelected && hashSelection < hashBest)
                {
                    hashBest       = hashSelection;
                    pindexSelected = pindex;
                }
                else if (!fSelected)
                {
                    fSelected      = true;
                    hashBest       = hashSelection;
                    pindexSelected = pindex;
                }
            }

            //LogPrint("stakemodifier", "SelectBlockFromCandidates: selection hash=%s\n", hashBest.ToString());
            return(fSelected);
        }
示例#30
0
 /// <summary>
 /// Force a new tip for the chain
 /// </summary>
 /// <param name="pindex"></param>
 /// <returns>forking point</returns>
 public abstract ChainedBlock SetTip(ChainedBlock pindex);
示例#31
0
        public Target GetWorkRequired(Consensus consensus)
        {
            AssertHasHeader();
            // Genesis block
            if (Height == 0)
            {
                return(consensus.PowLimit);
            }
            var nProofOfWorkLimit = consensus.PowLimit;
            var pindexLast        = this.Previous;
            var height            = Height;

            if (pindexLast == null)
            {
                return(nProofOfWorkLimit);
            }

            // Only change once per interval
            if ((height) % consensus.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 (this.Header.BlockTime > pindexLast.Header.BlockTime + TimeSpan.FromTicks(consensus.PowTargetSpacing.Ticks * 2))
                    {
                        return(nProofOfWorkLimit);
                    }
                    else
                    {
                        // Return the last non-special-min-difficulty-rules-block
                        ChainedBlock pindex = pindexLast;
                        while (pindex.Previous != null && (pindex.Height % consensus.DifficultyAdjustmentInterval) != 0 && pindex.Header.Bits == nProofOfWorkLimit)
                        {
                            pindex = pindex.Previous;
                        }
                        return(pindex.Header.Bits);
                    }
                }
                return(pindexLast.Header.Bits);
            }

            long pastHeight = 0;

            if (consensus.LitecoinWorkCalculation)
            {
                long blockstogoback = consensus.DifficultyAdjustmentInterval - 1;
                if ((pindexLast.Height + 1) != consensus.DifficultyAdjustmentInterval)
                {
                    blockstogoback = consensus.DifficultyAdjustmentInterval;
                }
                pastHeight = pindexLast.Height - blockstogoback;
            }
            else
            {
                // Go back by what we want to be 14 days worth of blocks
                pastHeight = pindexLast.Height - (consensus.DifficultyAdjustmentInterval - 1);
            }
            ChainedBlock pindexFirst = this.EnumerateToGenesis().FirstOrDefault(o => o.Height == pastHeight);

            assert(pindexFirst);
            if (consensus.PowNoRetargeting)
            {
                return(pindexLast.Header.Bits);
            }

            // Limit adjustment step
            var nActualTimespan = pindexLast.Header.BlockTime - pindexFirst.Header.BlockTime;

            if (nActualTimespan < TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks / 4))
            {
                nActualTimespan = TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks / 4);
            }
            if (nActualTimespan > TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks * 4))
            {
                nActualTimespan = TimeSpan.FromTicks(consensus.PowTargetTimespan.Ticks * 4);
            }

            // Retarget
            var bnNew = pindexLast.Header.Bits.ToBigInteger();

            bnNew = bnNew.Multiply(BigInteger.ValueOf((long)nActualTimespan.TotalSeconds));
            bnNew = bnNew.Divide(BigInteger.ValueOf((long)consensus.PowTargetTimespan.TotalSeconds));
            var newTarget = new Target(bnNew);

            if (newTarget > nProofOfWorkLimit)
            {
                newTarget = nProofOfWorkLimit;
            }

            return(newTarget);
        }
示例#32
0
        public bool Contains(uint256 hash)
        {
            ChainedBlock pindex = GetBlock(hash);

            return(pindex != null);
        }
示例#33
0
		public bool Evaluate(ChainedBlock block)
		{
			var nBlockTime = block.Previous == null ? Utils.UnixTimeToDateTime(0) : block.Previous.GetMedianTimePast();
			return this.MinHeight < block.Height && this.MinTime < nBlockTime;
		}
示例#34
0
文件: Block.cs 项目: rtddrt/NBitcoin
 /// <summary>
 /// Set time to consensus acceptable value
 /// </summary>
 /// <param name="network">Network</param>
 /// <param name="prev">previous block</param>
 public void UpdateTime(Network network, ChainedBlock prev)
 {
     UpdateTime(DateTimeOffset.UtcNow, network, prev);
 }
示例#35
0
		public virtual IEnumerable<ChainedBlock> EnumerateAfter(ChainedBlock block)
		{
			int i = block.Height + 1;
			var prev = block;
			while(true)
			{
				var b = GetBlock(i);
				if(b == null || b.Previous != prev)
					yield break;
				yield return b;
				i++;
				prev = b;
			}
		}
示例#36
0
文件: Block.cs 项目: rtddrt/NBitcoin
 /// <summary>
 /// Set time to consensus acceptable value
 /// </summary>
 /// <param name="consensus">Consensus</param>
 /// <param name="prev">previous block</param>
 public void UpdateTime(Consensus consensus, ChainedBlock prev)
 {
     UpdateTime(DateTimeOffset.UtcNow, consensus, prev);
 }
示例#37
0
		public bool Contains(ChainedBlock blockIndex)
		{
			if(blockIndex == null)
				throw new ArgumentNullException("blockIndex");
			return GetBlock(blockIndex.Height) != null;
		}
        public IEnumerable<ChainBlockHeader> GetChainChangesUntilFork(ChainedBlock currentTip, bool forkIncluded, CancellationToken cancellation = default(CancellationToken))
        {
            var oldTip = currentTip;
            var table = Configuration.GetChainTable();
            List<ChainBlockHeader> blocks = new List<ChainBlockHeader>();
            foreach(var chainPart in
                ExecuteBalanceQuery(table, new TableQuery(), new[] { 1, 2, 10 })
            .Concat(table.ExecuteQuery(new TableQuery()).Skip(2))
            .Select(e => new ChainPartEntry(e)))
            {
                cancellation.ThrowIfCancellationRequested();

                int height = chainPart.ChainOffset + chainPart.BlockHeaders.Count - 1;
                foreach(var block in chainPart.BlockHeaders.Reverse<BlockHeader>())
                {
                    if(currentTip == null && oldTip != null)
                        throw new InvalidOperationException("No fork found, the chain stored in azure is probably different from the one of the provided input");
                    if(oldTip == null || height > currentTip.Height)
                        yield return CreateChainChange(height, block);
                    else
                    {
                        if(height < currentTip.Height)
                            currentTip = currentTip.FindAncestorOrSelf(height);
                        var chainChange = CreateChainChange(height, block);
                        if(chainChange.BlockId == currentTip.HashBlock)
                        {
                            if(forkIncluded)
                                yield return chainChange;
                            yield break;
                        }
                        yield return chainChange;
                        currentTip = currentTip.Previous;
                    }
                    height--;
                }
            }
        }
示例#39
0
		private ChainedBlock SetTipNoLock(ChainedBlock block)
		{
			int height = Tip == null ? -1 : Tip.Height;
			foreach(var orphaned in EnumerateThisToFork(block))
			{
				_BlocksById.Remove(orphaned.HashBlock);
				_BlocksByHeight.Remove(orphaned.Height);
				height--;
			}
			var fork = GetBlockNoLock(height);
			foreach(var newBlock in block.EnumerateToGenesis()
				.TakeWhile(c => c != Tip))
			{
				_BlocksById.AddOrReplace(newBlock.HashBlock, newBlock);
				_BlocksByHeight.AddOrReplace(newBlock.Height, newBlock);
			}
			_Tip = block;
			return fork;
		}
示例#40
0
        public Chain CreateSubChain(ChainedBlock from,
            bool fromIncluded,
            ChainedBlock to,
            bool toIncluded,
            ObjectStream<ChainChange> output = null)
        {
            if(output == null)
                output = new StreamObjectStream<ChainChange>();

            var blocks
                =
                to.EnumerateToGenesis()
                .Skip(toIncluded ? 0 : 1)
                .TakeWhile(c => c.HashBlock != from.HashBlock);
            if(fromIncluded)
                blocks = blocks.Concat(new ChainedBlock[] { from });

            var array = blocks.Reverse().ToArray();
            foreach(var b in array)
            {
                output.WriteNext(new ChainChange()
                {
                    Add = true,
                    BlockHeader = b.Header,
                    HeightOrBackstep = (uint)b.Height
                });
            }
            return new Chain(output);
        }
示例#41
0
文件: Block.cs 项目: rtddrt/NBitcoin
 /// <summary>
 /// Set time to consensus acceptable value
 /// </summary>
 /// <param name="now">The expected date</param>
 /// <param name="network">Network</param>
 /// <param name="prev">previous block</param>
 public void UpdateTime(DateTimeOffset now, Network network, ChainedBlock prev)
 {
     UpdateTime(now, network.Consensus, prev);
 }
示例#42
0
文件: Block.cs 项目: ywzqhl/NBitcoin
		/// <summary>
		/// Set time to consensus acceptable value
		/// </summary>
		/// <param name="network">Network</param>
		/// <param name="prev">previous block</param>
		public void UpdateTime(Network network, ChainedBlock prev)
		{
			UpdateTime(DateTimeOffset.UtcNow, network, prev);
		}
示例#43
0
文件: Block.cs 项目: rtddrt/NBitcoin
 public Target GetWorkRequired(Network network, ChainedBlock prev)
 {
     return(GetWorkRequired(network.Consensus, prev));
 }
示例#44
0
 public Target GetWorkRequired(Consensus consensus, ChainedBlock prev)
 {
     return(new ChainedBlock(this, this.GetHash(consensus.NetworkOptions), prev).GetWorkRequired(consensus));
 }