spendnotifier.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package mock
  2. import (
  3. "sync"
  4. "github.com/btcsuite/btcd/wire"
  5. "github.com/lightningnetwork/lnd/chainntnfs"
  6. )
  7. // SpendNotifier extends the mock.ChainNotifier so that spend
  8. // notifications can be triggered and delivered to subscribers.
  9. type SpendNotifier struct {
  10. *ChainNotifier
  11. spendMap map[wire.OutPoint][]chan *chainntnfs.SpendDetail
  12. spends map[wire.OutPoint]*chainntnfs.SpendDetail
  13. mtx sync.Mutex
  14. }
  15. // MakeMockSpendNotifier creates a SpendNotifier.
  16. func MakeMockSpendNotifier() *SpendNotifier {
  17. return &SpendNotifier{
  18. ChainNotifier: &ChainNotifier{
  19. SpendChan: make(chan *chainntnfs.SpendDetail),
  20. EpochChan: make(chan *chainntnfs.BlockEpoch),
  21. ConfChan: make(chan *chainntnfs.TxConfirmation),
  22. },
  23. spendMap: make(map[wire.OutPoint][]chan *chainntnfs.SpendDetail),
  24. spends: make(map[wire.OutPoint]*chainntnfs.SpendDetail),
  25. }
  26. }
  27. // RegisterSpendNtfn registers a spend notification for a specified outpoint.
  28. func (s *SpendNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
  29. _ []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
  30. s.mtx.Lock()
  31. defer s.mtx.Unlock()
  32. spendChan := make(chan *chainntnfs.SpendDetail, 1)
  33. if detail, ok := s.spends[*outpoint]; ok {
  34. // Deliver spend immediately if details are already known.
  35. spendChan <- &chainntnfs.SpendDetail{
  36. SpentOutPoint: detail.SpentOutPoint,
  37. SpendingHeight: detail.SpendingHeight,
  38. SpendingTx: detail.SpendingTx,
  39. SpenderTxHash: detail.SpenderTxHash,
  40. SpenderInputIndex: detail.SpenderInputIndex,
  41. }
  42. } else {
  43. // Otherwise, queue the notification for delivery if the spend
  44. // is ever received.
  45. s.spendMap[*outpoint] = append(s.spendMap[*outpoint], spendChan)
  46. }
  47. return &chainntnfs.SpendEvent{
  48. Spend: spendChan,
  49. Cancel: func() {},
  50. }, nil
  51. }
  52. // Spend dispatches SpendDetails to all subscribers of the outpoint. The details
  53. // will includethe transaction and height provided by the caller.
  54. func (s *SpendNotifier) Spend(outpoint *wire.OutPoint, height int32,
  55. txn *wire.MsgTx) {
  56. s.mtx.Lock()
  57. defer s.mtx.Unlock()
  58. var inputIndex uint32
  59. for i, in := range txn.TxIn {
  60. if in.PreviousOutPoint == *outpoint {
  61. inputIndex = uint32(i)
  62. }
  63. }
  64. txnHash := txn.TxHash()
  65. details := &chainntnfs.SpendDetail{
  66. SpentOutPoint: outpoint,
  67. SpendingHeight: height,
  68. SpendingTx: txn,
  69. SpenderTxHash: &txnHash,
  70. SpenderInputIndex: inputIndex,
  71. }
  72. // Cache details in case of late registration.
  73. if _, ok := s.spends[*outpoint]; !ok {
  74. s.spends[*outpoint] = details
  75. }
  76. // Deliver any backlogged spend notifications.
  77. if spendChans, ok := s.spendMap[*outpoint]; ok {
  78. delete(s.spendMap, *outpoint)
  79. for _, spendChan := range spendChans {
  80. spendChan <- &chainntnfs.SpendDetail{
  81. SpentOutPoint: details.SpentOutPoint,
  82. SpendingHeight: details.SpendingHeight,
  83. SpendingTx: details.SpendingTx,
  84. SpenderTxHash: details.SpenderTxHash,
  85. SpenderInputIndex: details.SpenderInputIndex,
  86. }
  87. }
  88. }
  89. }