diff --git a/blockmanager.go b/blockmanager.go index 8f48199c..3a119bc0 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -1215,11 +1215,11 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // connected block from the transaction pool. Secondly, remove any // transactions which are now double spends as a result of these // new transactions. Finally, remove any transaction that is - // no longer an orphan. Note that removing a transaction from - // pool also removes any transactions which depend on it, - // recursively. + // no longer an orphan. Transactions which depend on a confirmed + // transaction are NOT removed recursively because they are still + // valid. for _, tx := range block.Transactions()[1:] { - b.server.txMemPool.RemoveTransaction(tx) + b.server.txMemPool.RemoveTransaction(tx, false) b.server.txMemPool.RemoveDoubleSpends(tx) b.server.txMemPool.RemoveOrphan(tx.Sha()) b.server.txMemPool.ProcessOrphans(tx.Sha()) @@ -1261,7 +1261,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // Remove the transaction and all transactions // that depend on it if it wasn't accepted into // the transaction pool. - b.server.txMemPool.RemoveTransaction(tx) + b.server.txMemPool.RemoveTransaction(tx, true) } } diff --git a/mempool.go b/mempool.go index 12e12b39..4112801a 100644 --- a/mempool.go +++ b/mempool.go @@ -398,13 +398,15 @@ func (mp *txMemPool) HaveTransaction(hash *wire.ShaHash) bool { // RemoveTransaction. See the comment for RemoveTransaction for more details. // // This function MUST be called with the mempool lock held (for writes). -func (mp *txMemPool) removeTransaction(tx *btcutil.Tx) { - // Remove any transactions which rely on this one. +func (mp *txMemPool) removeTransaction(tx *btcutil.Tx, removeRedeemers bool) { txHash := tx.Sha() - for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ { - outpoint := wire.NewOutPoint(txHash, i) - if txRedeemer, exists := mp.outpoints[*outpoint]; exists { - mp.removeTransaction(txRedeemer) + if removeRedeemers { + // Remove any transactions which rely on this one. + for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ { + outpoint := wire.NewOutPoint(txHash, i) + if txRedeemer, exists := mp.outpoints[*outpoint]; exists { + mp.removeTransaction(txRedeemer, true) + } } } @@ -466,16 +468,18 @@ func (mp *txMemPool) removeScriptFromAddrIndex(pkScript []byte, tx *btcutil.Tx) return nil } -// RemoveTransaction removes the passed transaction and any transactions which -// depend on it from the memory pool. +// RemoveTransaction removes the passed transaction from the mempool. If +// removeRedeemers flag is set, any transactions that redeem outputs from the +// removed transaction will also be removed recursively from the mempool, as +// they would otherwise become orphan. // // This function is safe for concurrent access. -func (mp *txMemPool) RemoveTransaction(tx *btcutil.Tx) { +func (mp *txMemPool) RemoveTransaction(tx *btcutil.Tx, removeRedeemers bool) { // Protect concurrent access. mp.Lock() defer mp.Unlock() - mp.removeTransaction(tx) + mp.removeTransaction(tx, removeRedeemers) } // RemoveDoubleSpends removes all transactions which spend outputs spent by the @@ -493,7 +497,7 @@ func (mp *txMemPool) RemoveDoubleSpends(tx *btcutil.Tx) { for _, txIn := range tx.MsgTx().TxIn { if txRedeemer, ok := mp.outpoints[txIn.PreviousOutPoint]; ok { if !txRedeemer.Sha().IsEqual(tx.Sha()) { - mp.removeTransaction(txRedeemer) + mp.removeTransaction(txRedeemer, true) } } }