/// <summary>
        /// Calculates the priority of a transaction based upon transaction size and priority inputs.
        /// </summary>
        /// <param name="trx">Memory pool transaction.</param>
        /// <param name="dPriorityInputs">Priority weighting of inputs.</param>
        /// <param name="nTxSize">Transaction size, 0 will compute.</param>
        /// <returns>Priority value.</returns>
        private double ComputePriority(Transaction trx, double dPriorityInputs, int nTxSize = 0)
        {
            nTxSize = MempoolValidator.CalculateModifiedSize(nTxSize, trx, this.mempoolValidator.ConsensusOptions);
            if (nTxSize == 0)
            {
                return(0.0);
            }

            return(dPriorityInputs / nTxSize);
        }
        /// <summary>
        /// Add an orphan transaction to the orphan pool.
        /// </summary>
        /// <param name="nodeId">Node id of the source node.</param>
        /// <param name="tx">The transaction to add.</param>
        /// <returns>Whether the orphan transaction was added.</returns>
        public bool AddOrphanTx(ulong nodeId, Transaction tx)
        {
            lock (this.lockObject)
            {
                uint256 hash = tx.GetHash();
                if (this.mapOrphanTransactions.ContainsKey(hash))
                {
                    this.logger.LogTrace("(-)[DUP_ORPH]:false");
                    return(false);
                }

                // Ignore big transactions, to avoid a
                // send-big-orphans memory exhaustion attack. If a peer has a legitimate
                // large transaction with a missing parent then we assume
                // it will rebroadcast it later, after the parent transaction(s)
                // have been mined or received.
                // 100 orphans, each of which is at most 99,999 bytes big is
                // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
                int sz = MempoolValidator.GetTransactionWeight(tx, this.Validator.ConsensusOptions);
                if (sz >= this.chain.Network.Consensus.Options.MaxStandardTxWeight)
                {
                    this.logger.LogInformation("ignoring large orphan tx (size: {0}, hash: {1})", sz, hash);
                    this.logger.LogTrace("(-)[LARGE_ORPH]:false");
                    return(false);
                }

                var orphan = new OrphanTx
                {
                    Tx         = tx,
                    NodeId     = nodeId,
                    TimeExpire = this.dateTimeProvider.GetTime() + OrphanTxExpireTime
                };

                if (this.mapOrphanTransactions.TryAdd(hash, orphan))
                {
                    foreach (TxIn txin in tx.Inputs)
                    {
                        List <OrphanTx> prv = this.mapOrphanTransactionsByPrev.TryGet(txin.PrevOut);
                        if (prv == null)
                        {
                            prv = new List <OrphanTx>();
                            this.mapOrphanTransactionsByPrev.Add(txin.PrevOut, prv);
                        }
                        prv.Add(orphan);
                    }
                }

                int orphanSize = this.mapOrphanTransactions.Count;
                this.logger.LogInformation("stored orphan tx {0} (mapsz {1} outsz {2})", hash, orphanSize, this.mapOrphanTransactionsByPrev.Count);
                this.Validator.PerformanceCounter.SetMempoolOrphanSize(orphanSize);
            }

            return(true);
        }
 public MempoolBehavior(
     MempoolValidator validator,
     MempoolManager manager,
     MempoolOrphans orphans,
     IConnectionManager connectionManager,
     ChainState chainState,
     Signals.Signals signals,
     ILoggerFactory loggerFactory)
     : this(validator, manager, orphans, connectionManager, chainState, signals, loggerFactory.CreateLogger(typeof(MempoolBehavior).FullName))
 {
 }
Beispiel #4
0
        /// <summary>
        /// Add an orphan transaction to the orphan pool.
        /// </summary>
        /// <param name="nodeId">Node id of the source node.</param>
        /// <param name="tx">The transaction to add.</param>
        /// <returns>Whether the orphan transaction was added.</returns>
        public Task <bool> AddOrphanTx(ulong nodeId, Transaction tx)
        {
            return(this.MempoolLock.WriteAsync(() =>
            {
                uint256 hash = tx.GetHash();
                if (this.mapOrphanTransactions.ContainsKey(hash))
                {
                    return false;
                }

                // Ignore big transactions, to avoid a
                // send-big-orphans memory exhaustion attack. If a peer has a legitimate
                // large transaction with a missing parent then we assume
                // it will rebroadcast it later, after the parent transaction(s)
                // have been mined or received.
                // 100 orphans, each of which is at most 99,999 bytes big is
                // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
                int sz = MempoolValidator.GetTransactionWeight(tx, this.Validator.ConsensusOptions);
                if (sz >= this.consensusValidator.ConsensusOptions.MaxStandardTxWeight)
                {
                    this.mempoolLogger.LogInformation($"ignoring large orphan tx (size: {sz}, hash: {hash})");
                    return false;
                }

                var orphan = new OrphanTx
                {
                    Tx = tx,
                    NodeId = nodeId,
                    TimeExpire = this.dateTimeProvider.GetTime() + OrphanTxExpireTime
                };
                if (this.mapOrphanTransactions.TryAdd(hash, orphan))
                {
                    foreach (var txin in tx.Inputs)
                    {
                        List <OrphanTx> prv = this.mapOrphanTransactionsByPrev.TryGet(txin.PrevOut);
                        if (prv == null)
                        {
                            prv = new List <OrphanTx>();
                            this.mapOrphanTransactionsByPrev.Add(txin.PrevOut, prv);
                        }
                        prv.Add(orphan);
                    }
                }

                int orphanSize = this.mapOrphanTransactions.Count;
                this.mempoolLogger.LogInformation($"stored orphan tx {hash} (mapsz {orphanSize} outsz {this.mapOrphanTransactionsByPrev.Count})");
                this.Validator.PerformanceCounter.SetMempoolOrphanSize(orphanSize);

                return true;
            }));
        }
Beispiel #5
0
 public MempoolManager(
     MempoolScheduler mempoolScheduler,
     TxMempool memPool,
     MempoolValidator validator,
     MempoolOrphans orphans,
     IDateTimeProvider dateTimeProvider,
     NodeSettings nodeArgs,
     IMempoolPersistence mempoolPersistence,
     ILoggerFactory loggerFactory)
 {
     this.MempoolScheduler   = mempoolScheduler;
     this.memPool            = memPool;
     this.DateTimeProvider   = dateTimeProvider;
     this.NodeArgs           = nodeArgs;
     this.Orphans            = orphans;
     this.Validator          = validator;
     this.mempoolPersistence = mempoolPersistence;
     this.mempoolLogger      = loggerFactory.CreateLogger(this.GetType().FullName);
 }
        public MempoolBehavior(
            MempoolValidator validator,
            MempoolManager manager,
            MempoolOrphans orphans,
            IConnectionManager connectionManager,
            ChainState chainState,
            Signals.Signals signals,
            ILogger logger)
        {
            this.validator         = validator;
            this.manager           = manager;
            this.orphans           = orphans;
            this.connectionManager = connectionManager;
            this.chainState        = chainState;
            this.signals           = signals;
            this.logger            = logger;

            this.inventoryTxToSend    = new Dictionary <uint256, uint256>();
            this.filterInventoryKnown = new Dictionary <uint256, uint256>();
        }
Beispiel #7
0
        /// <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, ConsensusOptions 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.consensusOptions  = consensusOptions;

            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;
        }
 public MempoolCoinView(CoinView inner, TxMempool memPool, AsyncLock mempoolScheduler, MempoolValidator mempoolValidator)
 {
     this.Inner            = inner;
     this.memPool          = memPool;
     this.mempoolScheduler = mempoolScheduler;
     this.mempoolValidator = mempoolValidator;
     this.Set = new UnspentOutputSet();
 }