chainntfs: add checks for previously confirmed transactions and spends
Without these checks, “zombie” notification requests that would never be dispatched could be registered. This would occur if notification requests were made for events (transaction confirmation and output spent) that had already been recorded on the blockchain.
This commit is contained in:
1 parent
e39dc9eec1
commit
909c3f8df9
2 files changed
+199
No files matched your search
@@ -2,6 +2,7 @@ package btcdnotify
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -436,6 +437,7 @@ type spendNotification struct {
|
||||
// outpoint has been detected, the details of the spending event will be sent
|
||||
// across the 'Spend' channel.
|
||||
func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint) (*chainntnfs.SpendEvent, error) {
|
||||
|
||||
if err := b.chainConn.NotifySpent([]*wire.OutPoint{outpoint}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -447,6 +449,33 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint) (*chainntnfs.S
|
||||
|
||||
b.notificationRegistry <- ntfn
|
||||
|
||||
// The following conditional checks to ensure that when a spend notification
|
||||
// is registered, the output hasn't already been spent. If the output
|
||||
// is no longer in the UTXO set, the chain will be rescanned from the point
|
||||
// where the output was added. The rescan will dispatch the notification.
|
||||
txout, err := b.chainConn.GetTxOut(&outpoint.Hash, outpoint.Index, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if txout == nil {
|
||||
transaction, err := b.chainConn.GetRawTransactionVerbose(&outpoint.Hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blockhash, err := wire.NewShaHashFromStr(transaction.BlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ops := []*wire.OutPoint{outpoint}
|
||||
if err := b.chainConn.Rescan(blockhash, nil, ops); err != nil {
|
||||
chainntnfs.Log.Errorf("Rescan for spend notification txout failed: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &chainntnfs.SpendEvent{ntfn.spendChan}, nil
|
||||
}
|
||||
|
||||
@@ -477,6 +506,19 @@ func (b *BtcdNotifier) RegisterConfirmationsNtfn(txid *wire.ShaHash,
|
||||
|
||||
b.notificationRegistry <- ntfn
|
||||
|
||||
// The following conditional checks transaction confirmation notification
|
||||
// requests so that if the transaction has already been included in a block
|
||||
// with the requested number of confirmations, the notification will be
|
||||
// dispatched immediately.
|
||||
tx, err := b.chainConn.GetRawTransactionVerbose(txid)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "No information") {
|
||||
return nil, err
|
||||
}
|
||||
} else if uint32(tx.Confirmations) > numConfs {
|
||||
ntfn.finConf <- int32(tx.Confirmations)
|
||||
}
|
||||
|
||||
return &chainntnfs.ConfirmationEvent{
|
||||
Confirmed: ntfn.finConf,
|
||||
NegativeConf: ntfn.negativeConf,
|
||||
|
||||
Reference in new issue
Block a user