diff --git a/chainntnfs/txconfnotifier.go b/chainntnfs/txconfnotifier.go index 4eeea84d..17471957 100644 --- a/chainntnfs/txconfnotifier.go +++ b/chainntnfs/txconfnotifier.go @@ -57,6 +57,11 @@ type TxConfNotifier struct { // The coinbase maturity period is a reasonable value to use. reorgSafetyLimit uint32 + // reorgDepth is the depth of a chain organization that this system is being + // informed of. This is incremented as long as a sequence of blocks are + // disconnected without being interrupted by a new block. + reorgDepth uint32 + // confNotifications is an index of notification requests by transaction // hash. confNotifications map[chainhash.Hash][]*ConfNtfn @@ -142,6 +147,7 @@ func (tcn *TxConfNotifier) ConnectTip(blockHash *chainhash.Hash, tcn.currentHeight, blockHeight) } tcn.currentHeight++ + tcn.reorgDepth = 0 // Record any newly confirmed transactions in ntfnsByConfirmHeight so that // notifications get dispatched when the tx gets sufficient confirmations. @@ -204,9 +210,26 @@ func (tcn *TxConfNotifier) DisconnectTip(blockHeight uint32) error { tcn.currentHeight, blockHeight) } tcn.currentHeight-- + tcn.reorgDepth++ for _, txHash := range tcn.confTxsByInitialHeight[blockHeight] { for _, ntfn := range tcn.confNotifications[*txHash] { + // If notification has been dispatched with sufficient + // confirmations, notify of the reversal. + if ntfn.dispatched { + select { + case <-ntfn.Event.Confirmed: + // Drain confirmation notification instead of sending + // negative conf if the receiver has not processed it yet. + // This ensures sends to the Confirmed channel are always + // non-blocking. + default: + ntfn.Event.NegativeConf <- int32(tcn.reorgDepth) + } + ntfn.dispatched = false + continue + } + confHeight := blockHeight + ntfn.NumConfirmations - 1 ntfnSet, exists := tcn.ntfnsByConfirmHeight[confHeight] if !exists { diff --git a/chainntnfs/txconfnotifier_test.go b/chainntnfs/txconfnotifier_test.go index 3b2ec5a6..d60b5227 100644 --- a/chainntnfs/txconfnotifier_test.go +++ b/chainntnfs/txconfnotifier_test.go @@ -276,6 +276,16 @@ func TestTxConfChainReorg(t *testing.T) { t.Fatalf("Failed to connect block: %v", err) } + select { + case reorgDepth := <-ntfn2.Event.NegativeConf: + if reorgDepth != 1 { + t.Fatalf("Incorrect value for negative conf notification: "+ + "expected %d, got %d", 1, reorgDepth) + } + default: + t.Fatalf("Expected negative conf notification for tx1") + } + select { case txConf := <-ntfn1.Event.Confirmed: t.Fatalf("Received unexpected confirmation for tx1: %v", txConf)