|
6 | 6 | "time" |
7 | 7 |
|
8 | 8 | "github.com/btcsuite/btcd/btcec/v2" |
| 9 | + "github.com/btcsuite/btcd/chaincfg/chainhash" |
9 | 10 | "github.com/btcsuite/btcd/wire" |
| 11 | + "github.com/lightningnetwork/lnd/chainntnfs" |
10 | 12 | "github.com/lightningnetwork/lnd/fn" |
11 | 13 | "github.com/lightningnetwork/lnd/lnwire" |
12 | 14 | ) |
@@ -80,6 +82,28 @@ type DaemonAdapters interface { |
80 | 82 |
|
81 | 83 | // BroadcastTransaction broadcasts a transaction with the target label. |
82 | 84 | BroadcastTransaction(*wire.MsgTx, string) error |
| 85 | + |
| 86 | + // RegisterConfirmationsNtfn registers an intent to be notified once |
| 87 | + // txid reaches numConfs confirmations. We also pass in the pkScript as |
| 88 | + // the default light client instead needs to match on scripts created |
| 89 | + // in the block. If a nil txid is passed in, then not only should we |
| 90 | + // match on the script, but we should also dispatch once the |
| 91 | + // transaction containing the script reaches numConfs confirmations. |
| 92 | + // This can be useful in instances where we only know the script in |
| 93 | + // advance, but not the transaction containing it. |
| 94 | + // |
| 95 | + // TODO(roasbeef): could abstract further? |
| 96 | + RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte, |
| 97 | + numConfs, heightHint uint32, |
| 98 | + opts ...chainntnfs.NotifierOption, |
| 99 | + ) (*chainntnfs.ConfirmationEvent, error) |
| 100 | + |
| 101 | + // RegisterSpendNtfn registers an intent to be notified once the target |
| 102 | + // outpoint is successfully spent within a transaction. The script that |
| 103 | + // the outpoint creates must also be specified. This allows this |
| 104 | + // interface to be implemented by BIP 158-like filtering. |
| 105 | + RegisterSpendNtfn(outpoint *wire.OutPoint, pkScript []byte, |
| 106 | + heightHint uint32) (*chainntnfs.SpendEvent, error) |
83 | 107 | } |
84 | 108 |
|
85 | 109 | // stateQuery is used by outside callers to query the internal state of the |
@@ -285,6 +309,78 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error { |
285 | 309 | } |
286 | 310 |
|
287 | 311 | return nil |
| 312 | + |
| 313 | + // The state machine has requested a new event to be sent once a |
| 314 | + // transaction spending a specified outpoint has confirmed. |
| 315 | + case *RegisterSpend[Event]: |
| 316 | + spendEvent, err := s.daemon.RegisterSpendNtfn( |
| 317 | + &daemonEvent.OutPoint, daemonEvent.PkScript, |
| 318 | + daemonEvent.HeightHint, |
| 319 | + ) |
| 320 | + if err != nil { |
| 321 | + return fmt.Errorf("unable to register spend: %w", err) |
| 322 | + } |
| 323 | + |
| 324 | + s.wg.Add(1) |
| 325 | + go func() { |
| 326 | + defer s.wg.Done() |
| 327 | + for { |
| 328 | + select { |
| 329 | + case <-spendEvent.Spend: |
| 330 | + // If there's a post-send event, then |
| 331 | + // we'll send that into the current |
| 332 | + // state now. |
| 333 | + postSpend := daemonEvent.PostSpendEvent |
| 334 | + postSpend.WhenSome(func(e Event) { |
| 335 | + s.SendEvent(e) |
| 336 | + }) |
| 337 | + |
| 338 | + return |
| 339 | + |
| 340 | + case <-s.quit: |
| 341 | + return |
| 342 | + } |
| 343 | + } |
| 344 | + }() |
| 345 | + |
| 346 | + return nil |
| 347 | + |
| 348 | + // The state machine has requested a new event to be sent once a |
| 349 | + // specified txid+pkScript pair has confirmed. |
| 350 | + case *RegisterConf[Event]: |
| 351 | + numConfs := daemonEvent.NumConfs.UnwrapOr(1) |
| 352 | + confEvent, err := s.daemon.RegisterConfirmationsNtfn( |
| 353 | + &daemonEvent.Txid, daemonEvent.PkScript, |
| 354 | + numConfs, daemonEvent.HeightHint, |
| 355 | + ) |
| 356 | + if err != nil { |
| 357 | + return fmt.Errorf("unable to register conf: %w", err) |
| 358 | + } |
| 359 | + |
| 360 | + s.wg.Add(1) |
| 361 | + go func() { |
| 362 | + defer s.wg.Done() |
| 363 | + for { |
| 364 | + select { |
| 365 | + case <-confEvent.Confirmed: |
| 366 | + // If there's a post-conf event, then |
| 367 | + // we'll send that into the current |
| 368 | + // state now. |
| 369 | + // |
| 370 | + // TODO(roasbeef): refactor to |
| 371 | + // dispatchAfterRecv w/ above |
| 372 | + postConf := daemonEvent.PostConfEvent |
| 373 | + postConf.WhenSome(func(e Event) { |
| 374 | + s.SendEvent(e) |
| 375 | + }) |
| 376 | + |
| 377 | + return |
| 378 | + |
| 379 | + case <-s.quit: |
| 380 | + return |
| 381 | + } |
| 382 | + } |
| 383 | + }() |
288 | 384 | } |
289 | 385 |
|
290 | 386 | return fmt.Errorf("unknown daemon event: %T", event) |
|
0 commit comments