예제 #1
0
        /// <summary>
        ///     Constructs a memory pool feature.
        /// </summary>
        /// <param name="connectionManager">Connection manager for managing node connections.</param>
        /// <param name="mempoolSignaled">Observes block signal notifications from signals.</param>
        /// <param name="blocksDisconnectedSignaled">Observes reorged headers signal notifications from signals.</param>
        /// <param name="mempoolBehavior">Memory pool node behavior for managing attached node messages.</param>
        /// <param name="mempoolManager">Memory pool manager for managing external access to memory pool.</param>
        /// <param name="loggerFactory">Logger factory for creating instance logger.</param>
        public MempoolFeature(
            IConnectionManager connectionManager,
            MempoolSignaled mempoolSignaled,
            BlocksDisconnectedSignaled blocksDisconnectedSignaled,
            MempoolBehavior mempoolBehavior,
            MempoolManager mempoolManager,
            ILoggerFactory loggerFactory,
            INodeStats nodeStats)
        {
            this.connectionManager          = connectionManager;
            this.mempoolSignaled            = mempoolSignaled;
            this.blocksDisconnectedSignaled = blocksDisconnectedSignaled;
            this.mempoolBehavior            = mempoolBehavior;
            this.mempoolManager             = mempoolManager;
            this.logger = loggerFactory.CreateLogger(GetType().FullName);

            nodeStats.RegisterStats(AddComponentStats, StatsType.Component, GetType().Name);
        }
예제 #2
0
        /// <summary>
        ///     Processes orphan transactions.
        ///     Executed when receive a new transaction through MempoolBehavior.
        /// </summary>
        /// <param name="behavior">Memory pool behavior that received new transaction.</param>
        /// <param name="tx">The new transaction received.</param>
        public async Task ProcessesOrphansAsync(MempoolBehavior behavior, Transaction tx)
        {
            var workQueue  = new Queue <OutPoint>();
            var eraseQueue = new List <uint256>();

            var trxHash = tx.GetHash();

            for (var index = 0; index < tx.Outputs.Count; index++)
            {
                workQueue.Enqueue(new OutPoint(trxHash, index));
            }

            // Recursively process any orphan transactions that depended on this one
            var setMisbehaving = new List <ulong>();

            while (workQueue.Any())
            {
                List <OrphanTx> itByPrev = null;
                lock (this.lockObject)
                {
                    var prevOrphans = this.mapOrphanTransactionsByPrev.TryGet(workQueue.Dequeue());

                    if (prevOrphans != null)
                    {
                        // Create a copy of the list so we can manage it outside of the lock.
                        itByPrev = prevOrphans.ToList();
                    }
                }

                if (itByPrev == null)
                {
                    continue;
                }

                foreach (var mi in itByPrev)
                {
                    var orphanTx   = mi.Tx;
                    var orphanHash = orphanTx.GetHash();
                    var fromPeer   = mi.NodeId;

                    if (setMisbehaving.Contains(fromPeer))
                    {
                        continue;
                    }

                    // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
                    // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
                    // anyone relaying LegitTxX banned)
                    var stateDummy = new MempoolValidationState(true);
                    if (await this.Validator.AcceptToMemoryPool(stateDummy, orphanTx))
                    {
                        this.logger.LogInformation("accepted orphan tx {0}", orphanHash);

                        behavior.RelayTransaction(orphanTx.GetHash());

                        this.signals.Publish(new TransactionReceived(orphanTx));

                        for (var index = 0; index < orphanTx.Outputs.Count; index++)
                        {
                            workQueue.Enqueue(new OutPoint(orphanHash, index));
                        }

                        eraseQueue.Add(orphanHash);
                    }
                    else if (!stateDummy.MissingInputs)
                    {
                        var nDos = 0;

                        if (stateDummy.IsInvalid && nDos > 0)
                        {
                            // Punish peer that gave us an invalid orphan tx
                            //Misbehaving(fromPeer, nDos);
                            setMisbehaving.Add(fromPeer);
                            this.logger.LogInformation("invalid orphan tx {0}", orphanHash);
                        }

                        // Has inputs but not accepted to mempool
                        // Probably non-standard or insufficient fee/priority
                        this.logger.LogInformation("removed orphan tx {0}", orphanHash);
                        eraseQueue.Add(orphanHash);
                        if (!orphanTx.HasWitness && !stateDummy.CorruptionPossible)
                        {
                            // Do not use rejection cache for witness transactions or
                            // witness-stripped transactions, as they can have been malleated.
                            // See https://github.com/bitcoin/bitcoin/issues/8279 for details.

                            AddToRecentRejects(orphanHash);
                        }
                    }

                    // TODO: implement sanity checks.
                    //this.memPool.Check(new MempoolCoinView(this.coinView, this.memPool, this.MempoolLock, this.Validator));
                }
            }

            if (eraseQueue.Count > 0)
            {
                lock (this.lockObject)
                {
                    foreach (var hash in eraseQueue)
                    {
                        EraseOrphanTxLock(hash);
                    }
                }
            }
        }