|
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 | ) |
@@ -83,6 +85,28 @@ type DaemonAdapters interface { |
83 | 85 |
|
84 | 86 | // DisableChannel disables the target channel. |
85 | 87 | DisableChannel(wire.OutPoint) error |
| 88 | + |
| 89 | + // RegisterConfirmationsNtfn registers an intent to be notified once |
| 90 | + // txid reaches numConfs confirmations. We also pass in the pkScript as |
| 91 | + // the default light client instead needs to match on scripts created |
| 92 | + // in the block. If a nil txid is passed in, then not only should we |
| 93 | + // match on the script, but we should also dispatch once the |
| 94 | + // transaction containing the script reaches numConfs confirmations. |
| 95 | + // This can be useful in instances where we only know the script in |
| 96 | + // advance, but not the transaction containing it. |
| 97 | + // |
| 98 | + // TODO(roasbeef): could abstract further? |
| 99 | + RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte, |
| 100 | + numConfs, heightHint uint32, |
| 101 | + opts ...chainntnfs.NotifierOption, |
| 102 | + ) (*chainntnfs.ConfirmationEvent, error) |
| 103 | + |
| 104 | + // RegisterSpendNtfn registers an intent to be notified once the target |
| 105 | + // outpoint is successfully spent within a transaction. The script that |
| 106 | + // the outpoint creates must also be specified. This allows this |
| 107 | + // interface to be implemented by BIP 158-like filtering. |
| 108 | + RegisterSpendNtfn(outpoint *wire.OutPoint, pkScript []byte, |
| 109 | + heightHint uint32) (*chainntnfs.SpendEvent, error) |
86 | 110 | } |
87 | 111 |
|
88 | 112 | // stateQuery is used by outside callers to query the internal state of the |
@@ -298,6 +322,78 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error { |
298 | 322 | } |
299 | 323 |
|
300 | 324 | return nil |
| 325 | + |
| 326 | + // The state machine has requested a new event to be sent once a |
| 327 | + // transaction spending a specified outpoint has confirmed. |
| 328 | + case *RegisterSpend[Event]: |
| 329 | + spendEvent, err := s.daemon.RegisterSpendNtfn( |
| 330 | + &daemonEvent.OutPoint, daemonEvent.PkScript, |
| 331 | + daemonEvent.HeightHint, |
| 332 | + ) |
| 333 | + if err != nil { |
| 334 | + return fmt.Errorf("unable to register spend: %w", err) |
| 335 | + } |
| 336 | + |
| 337 | + s.wg.Add(1) |
| 338 | + go func() { |
| 339 | + defer s.wg.Done() |
| 340 | + for { |
| 341 | + select { |
| 342 | + case <-spendEvent.Spend: |
| 343 | + // If there's a post-send event, then |
| 344 | + // we'll send that into the current |
| 345 | + // state now. |
| 346 | + postSpend := daemonEvent.PostSpendEvent |
| 347 | + postSpend.WhenSome(func(e Event) { |
| 348 | + s.SendEvent(e) |
| 349 | + }) |
| 350 | + |
| 351 | + return |
| 352 | + |
| 353 | + case <-s.quit: |
| 354 | + return |
| 355 | + } |
| 356 | + } |
| 357 | + }() |
| 358 | + |
| 359 | + return nil |
| 360 | + |
| 361 | + // The state machine has requested a new event to be sent once a |
| 362 | + // specified txid+pkScript pair has confirmed. |
| 363 | + case *RegisterConf[Event]: |
| 364 | + numConfs := daemonEvent.NumConfs.UnwrapOr(1) |
| 365 | + confEvent, err := s.daemon.RegisterConfirmationsNtfn( |
| 366 | + &daemonEvent.Txid, daemonEvent.PkScript, |
| 367 | + numConfs, daemonEvent.HeightHint, |
| 368 | + ) |
| 369 | + if err != nil { |
| 370 | + return fmt.Errorf("unable to register conf: %w", err) |
| 371 | + } |
| 372 | + |
| 373 | + s.wg.Add(1) |
| 374 | + go func() { |
| 375 | + defer s.wg.Done() |
| 376 | + for { |
| 377 | + select { |
| 378 | + case <-confEvent.Confirmed: |
| 379 | + // If there's a post-conf event, then |
| 380 | + // we'll send that into the current |
| 381 | + // state now. |
| 382 | + // |
| 383 | + // TODO(roasbeef): refactor to |
| 384 | + // dispatchAfterRecv w/ above |
| 385 | + postConf := daemonEvent.PostConfEvent |
| 386 | + postConf.WhenSome(func(e Event) { |
| 387 | + s.SendEvent(e) |
| 388 | + }) |
| 389 | + |
| 390 | + return |
| 391 | + |
| 392 | + case <-s.quit: |
| 393 | + return |
| 394 | + } |
| 395 | + } |
| 396 | + }() |
301 | 397 | } |
302 | 398 |
|
303 | 399 | return fmt.Errorf("unknown daemon event: %T", event) |
|
0 commit comments