chainntnfs: notify BlockHeight in Updates event

Enhance the ConfirmationEvent's Updates channel by including the
BlockHeight alongside NumConfsLeft.

Signed-off-by: Nishant Bansal <nishant.bansal.282003@gmail.com>
This commit is contained in:
Nishant Bansal
2025-09-11 18:25:49 +05:30
parent aa9c3272e3
commit 7bc6331402
3 changed files with 87 additions and 64 deletions

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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")
}
}