Skip to content

Commit 8988141

Browse files
authored
Merge pull request #9726 from Roasbeef/protofsm-full-block-conf
protofsm: add option to allow conf resp to return full block
2 parents a893077 + 3f03752 commit 8988141

File tree

3 files changed

+82
-17
lines changed

3 files changed

+82
-17
lines changed

protofsm/daemon_events.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ type RegisterConf[Event any] struct {
116116
// transaction needs to dispatch an event.
117117
NumConfs fn.Option[uint32]
118118

119+
// FullBlock is a boolean that indicates whether we want the full block
120+
// in the returned response. This is useful if callers want to create an
121+
// SPV proof for the transaction post conf.
122+
FullBlock bool
123+
119124
// PostConfMapper is a special conf mapper, that if present, will be
120125
// used to map the protofsm confirmation event to a custom event.
121126
PostConfMapper fn.Option[ConfMapper[Event]]

protofsm/state_machine.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,10 +510,15 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(ctx context.Context,
510510
s.log.DebugS(ctx, "Registering conf",
511511
"txid", daemonEvent.Txid)
512512

513+
var opts []chainntnfs.NotifierOption
514+
if daemonEvent.FullBlock {
515+
opts = append(opts, chainntnfs.WithIncludeBlock())
516+
}
517+
513518
numConfs := daemonEvent.NumConfs.UnwrapOr(1)
514519
confEvent, err := s.cfg.Daemon.RegisterConfirmationsNtfn(
515520
&daemonEvent.Txid, daemonEvent.PkScript,
516-
numConfs, daemonEvent.HeightHint,
521+
numConfs, daemonEvent.HeightHint, opts...,
517522
)
518523
if err != nil {
519524
return fmt.Errorf("unable to register conf: %w", err)

protofsm/state_machine_test.go

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (c *confDetailsEvent) dummy() {
4949
}
5050

5151
type registerConf struct {
52+
fullBlock bool
5253
}
5354

5455
func (r *registerConf) dummy() {
@@ -173,6 +174,7 @@ func (d *dummyStateStart) ProcessEvent(event dummyEvents, env *dummyEnv,
173174
Txid: chainhash.Hash{1},
174175
PkScript: []byte{0x01},
175176
HeightHint: 100,
177+
FullBlock: newEvent.fullBlock,
176178
PostConfMapper: fn.Some[ConfMapper[dummyEvents]](
177179
confMapper,
178180
),
@@ -383,7 +385,8 @@ func (d *dummyAdapters) RegisterConfirmationsNtfn(txid *chainhash.Hash,
383385
opts ...chainntnfs.NotifierOption,
384386
) (*chainntnfs.ConfirmationEvent, error) {
385387

386-
args := d.Called(txid, pkScript, numConfs)
388+
// Pass opts as the last argument to the mock call checker.
389+
args := d.Called(txid, pkScript, numConfs, heightHint, opts)
387390

388391
err := args.Error(0)
389392

@@ -589,11 +592,12 @@ func TestStateMachineDaemonEvents(t *testing.T) {
589592
env.AssertExpectations(t)
590593
}
591594

592-
// TestStateMachineConfMapper tests that the state machine is able to properly
593-
// map the confirmation event into a custom event that can be used to trigger a
594-
// state transition.
595-
func TestStateMachineConfMapper(t *testing.T) {
596-
t.Parallel()
595+
// testStateMachineConfMapperImpl is a helper function that encapsulates the
596+
// core logic for testing the confirmation mapping functionality of the state
597+
// machine. It takes a boolean flag `fullBlock` to determine whether to test the
598+
// scenario where full block details are requested in the confirmation
599+
// notification.
600+
func testStateMachineConfMapperImpl(t *testing.T, fullBlock bool) {
597601
ctx := context.Background()
598602

599603
// Create the state machine.
@@ -614,35 +618,69 @@ func TestStateMachineConfMapper(t *testing.T) {
614618
stateMachine.Start(ctx)
615619
defer stateMachine.Stop()
616620

617-
// Expect the RegisterConfirmationsNtfn call when we send the event.
618-
// We use NumConfs=1 as the default.
619-
adapters.On(
620-
"RegisterConfirmationsNtfn", &chainhash.Hash{1}, []byte{0x01},
621-
uint32(1),
622-
).Return(nil)
621+
// Define the expected arguments for the mock call.
622+
expectedTxid := &chainhash.Hash{1}
623+
expectedPkScript := []byte{0x01}
624+
expectedNumConfs := uint32(1)
625+
expectedHeightHint := uint32(100)
626+
627+
// Set up the mock expectation based on the FullBlock flag. We use
628+
// mock.MatchedBy to assert the options passed.
629+
if fullBlock {
630+
// Expect WithIncludeBlock() option when FullBlock is true.
631+
adapters.On(
632+
"RegisterConfirmationsNtfn",
633+
expectedTxid, expectedPkScript,
634+
expectedNumConfs, expectedHeightHint,
635+
mock.MatchedBy(
636+
func(opts []chainntnfs.NotifierOption) bool {
637+
// Check if exactly one option is passed
638+
// and it's the correct type. Unless we
639+
// use reflect, we can introspect into
640+
// the private fields.
641+
return len(opts) == 1
642+
},
643+
),
644+
).Return(nil)
645+
} else {
646+
// Expect no options when FullBlock is false.
647+
adapters.On(
648+
"RegisterConfirmationsNtfn",
649+
expectedTxid, expectedPkScript,
650+
expectedNumConfs, expectedHeightHint,
651+
mock.MatchedBy(func(opts []chainntnfs.NotifierOption) bool { //nolint:ll
652+
return len(opts) == 0
653+
}),
654+
).Return(nil)
655+
}
656+
657+
// Create the registerConf event with the specified FullBlock value.
658+
regConfEvent := &registerConf{
659+
fullBlock: fullBlock,
660+
}
623661

624662
// Send the event that triggers RegisterConf emission.
625-
stateMachine.SendEvent(ctx, &registerConf{})
663+
stateMachine.SendEvent(ctx, regConfEvent)
626664

627665
// We should transition back to the starting state initially.
628666
expectedStates := []State[dummyEvents, *dummyEnv]{
629667
&dummyStateStart{}, &dummyStateStart{},
630668
}
631669
assertStateTransitions(t, stateSub, expectedStates)
632670

633-
// Assert the registration call was made.
671+
// Assert the registration call was made with the correct arguments
672+
// (including options).
634673
adapters.AssertExpectations(t)
635674

636675
// Now, simulate the confirmation event coming back from the notifier.
637-
// Populate it with some data to be mapped.
638676
simulatedConf := &chainntnfs.TxConfirmation{
639677
BlockHash: &chainhash.Hash{2},
640678
BlockHeight: 123,
641679
}
642680
adapters.confChan <- simulatedConf
643681

644682
// This should trigger the mapper and send the confDetailsEvent,
645-
// transitioning us to the final state.
683+
// transitioning us to the confirmed state.
646684
expectedStates = []State[dummyEvents, *dummyEnv]{&dummyStateConfirmed{}}
647685
assertStateTransitions(t, stateSub, expectedStates)
648686

@@ -662,6 +700,23 @@ func TestStateMachineConfMapper(t *testing.T) {
662700
env.AssertExpectations(t)
663701
}
664702

703+
// TestStateMachineConfMapper tests the confirmation mapping functionality using
704+
// subtests driven by the testStateMachineConfMapperImpl helper function. It
705+
// covers scenarios both with and without requesting the full block details.
706+
func TestStateMachineConfMapper(t *testing.T) {
707+
t.Parallel()
708+
709+
t.Run("full block false", func(t *testing.T) {
710+
t.Parallel()
711+
testStateMachineConfMapperImpl(t, false)
712+
})
713+
714+
t.Run("full block true", func(t *testing.T) {
715+
t.Parallel()
716+
testStateMachineConfMapperImpl(t, true)
717+
})
718+
}
719+
665720
// TestStateMachineSpendMapper tests that the state machine is able to properly
666721
// map the spend event into a custom event that can be used to trigger a state
667722
// transition.

0 commit comments

Comments
 (0)