105 lines
2.9 KiB
Go
105 lines
2.9 KiB
Go
package mock
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
|
)
|
|
|
|
// SpendNotifier extends the mock.ChainNotifier so that spend
|
|
// notifications can be triggered and delivered to subscribers.
|
|
type SpendNotifier struct {
|
|
*ChainNotifier
|
|
spendMap map[wire.OutPoint][]chan *chainntnfs.SpendDetail
|
|
spends map[wire.OutPoint]*chainntnfs.SpendDetail
|
|
mtx sync.Mutex
|
|
}
|
|
|
|
// MakeMockSpendNotifier creates a SpendNotifier.
|
|
func MakeMockSpendNotifier() *SpendNotifier {
|
|
return &SpendNotifier{
|
|
ChainNotifier: &ChainNotifier{
|
|
SpendChan: make(chan *chainntnfs.SpendDetail),
|
|
EpochChan: make(chan *chainntnfs.BlockEpoch),
|
|
ConfChan: make(chan *chainntnfs.TxConfirmation),
|
|
},
|
|
spendMap: make(map[wire.OutPoint][]chan *chainntnfs.SpendDetail),
|
|
spends: make(map[wire.OutPoint]*chainntnfs.SpendDetail),
|
|
}
|
|
}
|
|
|
|
// RegisterSpendNtfn registers a spend notification for a specified outpoint.
|
|
func (s *SpendNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
|
_ []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
|
|
|
|
s.mtx.Lock()
|
|
defer s.mtx.Unlock()
|
|
|
|
spendChan := make(chan *chainntnfs.SpendDetail, 1)
|
|
if detail, ok := s.spends[*outpoint]; ok {
|
|
// Deliver spend immediately if details are already known.
|
|
spendChan <- &chainntnfs.SpendDetail{
|
|
SpentOutPoint: detail.SpentOutPoint,
|
|
SpendingHeight: detail.SpendingHeight,
|
|
SpendingTx: detail.SpendingTx,
|
|
SpenderTxHash: detail.SpenderTxHash,
|
|
SpenderInputIndex: detail.SpenderInputIndex,
|
|
}
|
|
} else {
|
|
// Otherwise, queue the notification for delivery if the spend
|
|
// is ever received.
|
|
s.spendMap[*outpoint] = append(s.spendMap[*outpoint], spendChan)
|
|
}
|
|
|
|
return &chainntnfs.SpendEvent{
|
|
Spend: spendChan,
|
|
Cancel: func() {},
|
|
}, nil
|
|
}
|
|
|
|
// Spend dispatches SpendDetails to all subscribers of the outpoint. The details
|
|
// will includethe transaction and height provided by the caller.
|
|
func (s *SpendNotifier) Spend(outpoint *wire.OutPoint, height int32,
|
|
txn *wire.MsgTx) {
|
|
|
|
s.mtx.Lock()
|
|
defer s.mtx.Unlock()
|
|
|
|
var inputIndex uint32
|
|
for i, in := range txn.TxIn {
|
|
if in.PreviousOutPoint == *outpoint {
|
|
inputIndex = uint32(i)
|
|
}
|
|
}
|
|
|
|
txnHash := txn.TxHash()
|
|
details := &chainntnfs.SpendDetail{
|
|
SpentOutPoint: outpoint,
|
|
SpendingHeight: height,
|
|
SpendingTx: txn,
|
|
SpenderTxHash: &txnHash,
|
|
SpenderInputIndex: inputIndex,
|
|
}
|
|
|
|
// Cache details in case of late registration.
|
|
if _, ok := s.spends[*outpoint]; !ok {
|
|
s.spends[*outpoint] = details
|
|
}
|
|
|
|
// Deliver any backlogged spend notifications.
|
|
if spendChans, ok := s.spendMap[*outpoint]; ok {
|
|
delete(s.spendMap, *outpoint)
|
|
for _, spendChan := range spendChans {
|
|
spendChan <- &chainntnfs.SpendDetail{
|
|
SpentOutPoint: details.SpentOutPoint,
|
|
SpendingHeight: details.SpendingHeight,
|
|
SpendingTx: details.SpendingTx,
|
|
SpenderTxHash: details.SpenderTxHash,
|
|
SpenderInputIndex: details.SpenderInputIndex,
|
|
}
|
|
}
|
|
}
|
|
}
|