/// <summary>
        /// Constructs a transaction memory pool entry.
        /// </summary>
        /// <param name="transaction">Transaction for the entry.</param>
        /// <param name="nFee">Fee for the transaction in the entry in the memory pool.</param>
        /// <param name="nTime">The local time when entering the memory pool.</param>
        /// <param name="entryPriority">Priority when entering the memory pool.</param>
        /// <param name="entryHeight">The chain height when entering the mempool.</param>
        /// <param name="inChainInputValue">The sum of all txin values that are already in blockchain.</param>
        /// <param name="spendsCoinbase">Whether the transaction spends a coinbase.</param>
        /// <param name="nSigOpsCost">The total signature operations cost.</param>
        /// <param name="lp">Tthe lock points that track the height and time at which tx was final.</param>
        /// <param name="consensusOptions">Proof of work consensus options used to compute transaction weight and modified size.</param>
        public TxMempoolEntry(Transaction transaction, Money nFee,
                              long nTime, double entryPriority, int entryHeight,
                              Money inChainInputValue, bool spendsCoinbase,
                              long nSigOpsCost, LockPoints lp, PowConsensusOptions consensusOptions)
        {
            this.Transaction       = transaction;
            this.TransactionHash   = transaction.GetHash();
            this.Fee               = nFee;
            this.Time              = nTime;
            this.entryPriority     = entryPriority;
            this.EntryHeight       = entryHeight;
            this.InChainInputValue = inChainInputValue;
            this.SpendsCoinbase    = spendsCoinbase;
            this.SigOpCost         = nSigOpsCost;
            this.LockPoints        = lp;

            this.TxWeight = MempoolValidator.GetTransactionWeight(transaction, consensusOptions);
            this.nModSize = MempoolValidator.CalculateModifiedSize(this.Transaction.GetSerializedSize(), this.Transaction, consensusOptions);

            this.nUsageSize = transaction.GetSerializedSize(); // RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(Transaction);

            this.CountWithDescendants   = 1;
            this.SizeWithDescendants    = this.GetTxSize();
            this.ModFeesWithDescendants = this.Fee;
            Money nValueIn = transaction.TotalOut + this.Fee;

            Guard.Assert(this.InChainInputValue <= nValueIn);

            this.feeDelta = 0;

            this.CountWithAncestors     = 1;
            this.SizeWithAncestors      = this.GetTxSize();
            this.ModFeesWithAncestors   = this.Fee;
            this.SigOpCostWithAncestors = this.SigOpCost;
        }
 /// <summary>
 /// Update the <see cref="LockPoints"/> after a reorg.
 /// </summary>
 /// <param name="lp">New lockpoints.</param>
 public void UpdateLockPoints(LockPoints lp)
 {
     this.LockPoints = lp;
 }
Example #3
0
        // Check if transaction will be BIP 68 final in the next block to be created.
        // Simulates calling SequenceLocks() with data from the tip of the current active chain.
        // Optionally stores in LockPoints the resulting height and time calculated and the hash
        // of the block needed for calculation or skips the calculation and uses the LockPoints
        // passed in for evaluation.
        // The LockPoints should not be considered valid if CheckSequenceLocks returns false.
        // See consensus/consensus.h for flag definitions.
        public static bool CheckSequenceLocks(ChainedBlock tip, MempoolValidationContext context, Transaction.LockTimeFlags flags, LockPoints lp = null,
                                              bool useExistingLockPoints = false)
        {
            var dummyBlock = new Block {
                Header = { HashPrevBlock = tip.HashBlock }
            };
            ChainedBlock index = new ChainedBlock(dummyBlock.Header, dummyBlock.GetHash(), tip);

            // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
            // height based locks because when SequenceLocks() is called within
            // ConnectBlock(), the height of the block *being*
            // evaluated is what is used.
            // Thus if we want to know if a transaction can be part of the
            // *next* block, we need to use one more than chainActive.Height()

            SequenceLock lockPair;

            if (useExistingLockPoints)
            {
                Guard.Assert(lp != null);
                lockPair = new SequenceLock(lp.Height, lp.Time);
            }
            else
            {
                // pcoinsTip contains the UTXO set for chainActive.Tip()
                List <int> prevheights = new List <int>();
                foreach (var txin in context.Transaction.Inputs)
                {
                    var coins = context.View.GetCoins(txin.PrevOut.Hash);
                    if (coins == null)
                    {
                        return(false);
                    }

                    if (coins.Height == TxMempool.MempoolHeight)
                    {
                        // Assume all mempool transaction confirm in the next block
                        prevheights.Add(tip.Height + 1);
                    }
                    else
                    {
                        prevheights.Add((int)coins.Height);
                    }
                }
                lockPair = context.Transaction.CalculateSequenceLocks(prevheights.ToArray(), index, flags);

                if (lp != null)
                {
                    lp.Height = lockPair.MinHeight;
                    lp.Time   = lockPair.MinTime.ToUnixTimeMilliseconds();
                    // Also store the hash of the block with the highest height of
                    // all the blocks which have sequence locked prevouts.
                    // This hash needs to still be on the chain
                    // for these LockPoint calculations to be valid
                    // Note: It is impossible to correctly calculate a maxInputBlock
                    // if any of the sequence locked inputs depend on unconfirmed txs,
                    // except in the special case where the relative lock time/height
                    // is 0, which is equivalent to no sequence lock. Since we assume
                    // input height of tip+1 for mempool txs and test the resulting
                    // lockPair from CalculateSequenceLocks against tip+1.  We know
                    // EvaluateSequenceLocks will fail if there was a non-zero sequence
                    // lock on a mempool input, so we can use the return value of
                    // CheckSequenceLocks to indicate the LockPoints validity
                    int maxInputHeight = 0;
                    foreach (var height in prevheights)
                    {
                        // Can ignore mempool inputs since we'll fail if they had non-zero locks
                        if (height != tip.Height + 1)
                        {
                            maxInputHeight = Math.Max(maxInputHeight, height);
                        }
                    }

                    lp.MaxInputBlock = tip.GetAncestor(maxInputHeight);
                }
            }

            return(lockPair.Evaluate(index));
        }