diff --git a/chainntnfs/interface.go b/chainntnfs/interface.go index 798a2f427..342d268fd 100644 --- a/chainntnfs/interface.go +++ b/chainntnfs/interface.go @@ -203,6 +203,20 @@ type TxConfirmation struct { Block *wire.MsgBlock } +// TxUpdateInfo contains information about a transaction before it has reached +// its required number of confirmations. Transactions are registered for +// notification for a specific number of "required" confirmations, this struct +// will update the caller incrementally after each new block is found as long as +// the transaction is not yet fully regarded as confirmed. +type TxUpdateInfo struct { + // BlockHeight is the height of the block that contains the transaction. + BlockHeight uint32 + + // NumConfsLeft is the number of confirmations left for the transaction + // to be regarded as fully confirmed. + NumConfsLeft uint32 +} + // ConfirmationEvent encapsulates a confirmation notification. With this struct, // callers can be notified of: the instance the target txid reaches the targeted // number of confirmations, how many confirmations are left for the target txid @@ -229,11 +243,12 @@ type ConfirmationEvent struct { // Updates is a channel that will sent upon, at every incremental // confirmation, how many confirmations are left to declare the - // transaction as fully confirmed. + // transaction as fully confirmed, along with the height of the block + // that contains the transaction. // // NOTE: This channel must be buffered with the number of required // confirmations. - Updates chan uint32 + Updates chan TxUpdateInfo // NegativeConf is a channel that will be sent upon if the transaction // confirms, but is later reorged out of the chain. The integer sent @@ -262,7 +277,7 @@ func NewConfirmationEvent(numConfs uint32, cancel func()) *ConfirmationEvent { // the channel so we need to create a larger buffer to avoid // blocking the notifier. Confirmed: make(chan *TxConfirmation, 1), - Updates: make(chan uint32, numConfs), + Updates: make(chan TxUpdateInfo, numConfs), NegativeConf: make(chan int32, 1), Done: make(chan struct{}, 1), Cancel: cancel, diff --git a/chainntnfs/txnotifier.go b/chainntnfs/txnotifier.go index 9055d8567..57eee845c 100644 --- a/chainntnfs/txnotifier.go +++ b/chainntnfs/txnotifier.go @@ -947,8 +947,12 @@ func (n *TxNotifier) dispatchConfDetails( // We'll send a 0 value to the Updates channel, // indicating that the transaction/output script has already - // been confirmed. - err := n.notifyNumConfsLeft(ntfn, 0) + // been confirmed, and include the block height at which the + // transaction was included. + err := n.notifyNumConfsLeft(ntfn, TxUpdateInfo{ + NumConfsLeft: 0, + BlockHeight: details.BlockHeight, + }) if err != nil { return err } @@ -977,7 +981,10 @@ func (n *TxNotifier) dispatchConfDetails( // confirmations are left for the transaction/output script to // be confirmed. numConfsLeft := confHeight - n.currentHeight - err := n.notifyNumConfsLeft(ntfn, numConfsLeft) + err := n.notifyNumConfsLeft(ntfn, TxUpdateInfo{ + NumConfsLeft: numConfsLeft, + BlockHeight: details.BlockHeight, + }) if err != nil { return err } @@ -1731,7 +1738,10 @@ func (n *TxNotifier) NotifyHeight(height uint32) error { for confRequest := range confRequests { confSet := n.confNotifications[confRequest] for _, ntfn := range confSet.ntfns { - txConfHeight := confSet.details.BlockHeight + + // blockHeight is the height of the block which + // contains the transaction. + blockHeight := confSet.details.BlockHeight + txConfHeight := blockHeight + ntfn.NumConfirmations - 1 numConfsLeft := txConfHeight - height @@ -1744,7 +1754,10 @@ func (n *TxNotifier) NotifyHeight(height uint32) error { continue } - err := n.notifyNumConfsLeft(ntfn, numConfsLeft) + err := n.notifyNumConfsLeft(ntfn, TxUpdateInfo{ + NumConfsLeft: numConfsLeft, + BlockHeight: blockHeight, + }) if err != nil { return err } @@ -2113,25 +2126,28 @@ func (n *TxNotifier) TearDown() { } // notifyNumConfsLeft sends the number of confirmations left to the -// notification subscriber through the Event.Updates channel. +// notification subscriber through the Event.Updates channel, along with the +// block height in which the transaction was included. // // NOTE: must be used with the TxNotifier's lock held. -func (n *TxNotifier) notifyNumConfsLeft(ntfn *ConfNtfn, num uint32) error { +func (n *TxNotifier) notifyNumConfsLeft(ntfn *ConfNtfn, + info TxUpdateInfo) error { + // If the number left is no less than the recorded value, we can skip // sending it as it means this same value has already been sent before. - if num >= ntfn.numConfsLeft { + if info.NumConfsLeft >= ntfn.numConfsLeft { Log.Debugf("Skipped dispatched update (numConfsLeft=%v) for "+ - "request %v conf_id=%v", num, ntfn.ConfRequest, - ntfn.ConfID) + "request %v conf_id=%v", info.NumConfsLeft, + ntfn.ConfRequest, ntfn.ConfID) return nil } // Update the number of confirmations left to the notification. - ntfn.numConfsLeft = num + ntfn.numConfsLeft = info.NumConfsLeft select { - case ntfn.Event.Updates <- num: + case ntfn.Event.Updates <- info: case <-n.quit: return ErrTxNotifierExiting } diff --git a/chainntnfs/txnotifier_test.go b/chainntnfs/txnotifier_test.go index 1279330cf..1bd9f4f1c 100644 --- a/chainntnfs/txnotifier_test.go +++ b/chainntnfs/txnotifier_test.go @@ -271,13 +271,12 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) { // We should only receive one update for tx1 since it only requires // one confirmation and it already met it. select { - case numConfsLeft := <-ntfn1.Event.Updates: - const expected = 0 - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx1 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn1.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: 0, + BlockHeight: 11, } + require.Equal(t, expected, updDetails) default: t.Fatal("Expected confirmation update for tx1") } @@ -300,13 +299,12 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) { // We should only receive one update for tx2 since it only has one // confirmation so far and it requires two. select { - case numConfsLeft := <-ntfn2.Event.Updates: - const expected = 1 - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx2 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn2.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: 1, + BlockHeight: 11, } + require.Equal(t, expected, updDetails) default: t.Fatal("Expected confirmation update for tx2") } @@ -341,13 +339,12 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) { // We should only receive one update since the last at the new height, // indicating how many confirmations are still left. select { - case numConfsLeft := <-ntfn2.Event.Updates: - const expected = 0 - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx2 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn2.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: 0, + BlockHeight: 11, } + require.Equal(t, expected, updDetails) default: t.Fatal("Expected confirmation update for tx2") } @@ -411,13 +408,12 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) { err = n.UpdateConfDetails(ntfn1.HistoricalDispatch.ConfRequest, &txConf1) require.NoError(t, err, "unable to update conf details") select { - case numConfsLeft := <-ntfn1.Event.Updates: - const expected = 0 - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx1 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn1.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: 0, + BlockHeight: 9, } + require.Equal(t, expected, updDetails) default: t.Fatal("Expected confirmation update for tx1") } @@ -443,13 +439,12 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) { err = n.UpdateConfDetails(ntfn2.HistoricalDispatch.ConfRequest, &txConf2) require.NoError(t, err, "unable to update conf details") select { - case numConfsLeft := <-ntfn2.Event.Updates: - const expected = 1 - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx2 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn2.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: 1, + BlockHeight: 9, } + require.Equal(t, expected, updDetails) default: t.Fatal("Expected confirmation update for tx2") } @@ -485,13 +480,12 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) { // We should only receive one update for tx2 since the last one, // indicating how many confirmations are still left. select { - case numConfsLeft := <-ntfn2.Event.Updates: - const expected = 0 - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx2 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn2.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: 0, + BlockHeight: 9, } + require.Equal(t, expected, updDetails) default: t.Fatal("Expected confirmation update for tx2") } @@ -1490,13 +1484,12 @@ func TestTxNotifierConfReorg(t *testing.T) { // We should only receive one update for tx2 since it only requires // one confirmation and it already met it. select { - case numConfsLeft := <-ntfn2.Event.Updates: - const expected = 0 - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx2 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn2.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: 0, + BlockHeight: 12, } + require.Equal(t, expected, updDetails) default: t.Fatal("Expected confirmation update for tx2") } @@ -1520,15 +1513,14 @@ func TestTxNotifierConfReorg(t *testing.T) { // confirmations and it has already met them. for i := uint32(1); i <= 2; i++ { select { - case numConfsLeft := <-ntfn3.Event.Updates: - expected := tx3NumConfs - i - if numConfsLeft != expected { - t.Fatalf("Received incorrect confirmation update: tx3 "+ - "expected %d confirmations left, got %d", - expected, numConfsLeft) + case updDetails := <-ntfn3.Event.Updates: + expected := chainntnfs.TxUpdateInfo{ + NumConfsLeft: tx3NumConfs - i, + BlockHeight: 12, } + require.Equal(t, expected, updDetails) default: - t.Fatal("Expected confirmation update for tx2") + t.Fatal("Expected confirmation update for tx3") } }