Skip to content

Commit 2716388

Browse files
committed
protofsm: convert state machine args into config
1 parent 2ee238f commit 2716388

File tree

2 files changed

+70
-42
lines changed

2 files changed

+70
-42
lines changed

protofsm/state_machine.go

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -125,46 +125,60 @@ type stateQuery[Event any, Env Environment] struct {
125125
//
126126
// TODO(roasbeef): terminal check, daemon event execution, init?
127127
type StateMachine[Event any, Env Environment] struct {
128-
currentState State[Event, Env]
129-
env Env
130-
131-
daemon DaemonAdapters
128+
cfg StateMachineCfg[Event, Env]
132129

130+
// events is the channel that will be used to send new events to the
131+
// FSM.
133132
events chan Event
134133

135-
quit chan struct{}
136-
wg sync.WaitGroup
137-
138134
// newStateEvents is an EventDistributor that will be used to notify
139135
// any relevant callers of new state transitions that occur.
140136
newStateEvents *fn.EventDistributor[State[Event, Env]]
141137

138+
// stateQuery is a channel that will be used by outside callers to
139+
// query the internal state machine state.
142140
stateQuery chan stateQuery[Event, Env]
143141

144-
initEvent fn.Option[DaemonEvent]
145-
146142
startOnce sync.Once
147143
stopOnce sync.Once
148144

149145
// TODO(roasbeef): also use that context guard here?
146+
quit chan struct{}
147+
wg sync.WaitGroup
148+
}
149+
150+
// StateMachineCfg is a configuration struct that's used to create a new state
151+
// machine.
152+
type StateMachineCfg[Event any, Env Environment] struct {
153+
// Daemon is a set of adapters that will be used to bridge the FSM to
154+
// the daemon.
155+
Daemon DaemonAdapters
156+
157+
// InitialState is the initial state of the state machine.
158+
InitialState State[Event, Env]
159+
160+
// Env is the environment that the state machine will use to execute.
161+
Env Env
162+
163+
// InitEvent is an optional event that will be sent to the state
164+
// machine as if it was emitted at the onset of the state machine. This
165+
// can be used to set up tracking state such as a txid confirmation
166+
// event.
167+
InitEvent fn.Option[DaemonEvent]
150168
}
151169

152170
// NewStateMachine creates a new state machine given a set of daemon adapters,
153171
// an initial state, an environment, and an event to process as if emitted at
154172
// the onset of the state machine. Such an event can be used to set up tracking
155173
// state such as a txid confirmation event.
156-
func NewStateMachine[Event any, Env Environment](adapters DaemonAdapters,
157-
initialState State[Event, Env], env Env,
158-
initEvent fn.Option[DaemonEvent]) StateMachine[Event, Env] {
174+
func NewStateMachine[Event any, Env Environment](cfg StateMachineCfg[Event, Env],
175+
) StateMachine[Event, Env] {
159176

160177
return StateMachine[Event, Env]{
161-
daemon: adapters,
178+
cfg: cfg,
162179
events: make(chan Event, 1),
163-
currentState: initialState,
164180
stateQuery: make(chan stateQuery[Event, Env]),
165181
quit: make(chan struct{}),
166-
env: env,
167-
initEvent: initEvent,
168182
newStateEvents: fn.NewEventDistributor[State[Event, Env]](),
169183
}
170184
}
@@ -243,7 +257,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
243257
// any preconditions as well as post-send events.
244258
case *SendMsgEvent[Event]:
245259
sendAndCleanUp := func() error {
246-
err := s.daemon.SendMessages(
260+
err := s.cfg.Daemon.SendMessages(
247261
daemonEvent.TargetPeer, daemonEvent.Msgs,
248262
)
249263
if err != nil {
@@ -307,7 +321,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
307321
// If this is a disable channel event, then we'll disable the channel.
308322
// This is usually done for things like co-op closes.
309323
case *DisableChannelEvent:
310-
err := s.daemon.DisableChannel(daemonEvent.ChanPoint)
324+
err := s.cfg.Daemon.DisableChannel(daemonEvent.ChanPoint)
311325
if err != nil {
312326
return fmt.Errorf("unable to disable channel: %w", err)
313327
}
@@ -317,7 +331,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
317331
// If this is a broadcast transaction event, then we'll broadcast with
318332
// the label attached.
319333
case *BroadcastTxn:
320-
err := s.daemon.BroadcastTransaction(
334+
err := s.cfg.Daemon.BroadcastTransaction(
321335
daemonEvent.Tx, daemonEvent.Label,
322336
)
323337
if err != nil {
@@ -331,7 +345,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
331345
// The state machine has requested a new event to be sent once a
332346
// transaction spending a specified outpoint has confirmed.
333347
case *RegisterSpend[Event]:
334-
spendEvent, err := s.daemon.RegisterSpendNtfn(
348+
spendEvent, err := s.cfg.Daemon.RegisterSpendNtfn(
335349
&daemonEvent.OutPoint, daemonEvent.PkScript,
336350
daemonEvent.HeightHint,
337351
)
@@ -367,7 +381,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
367381
// specified txid+pkScript pair has confirmed.
368382
case *RegisterConf[Event]:
369383
numConfs := daemonEvent.NumConfs.UnwrapOr(1)
370-
confEvent, err := s.daemon.RegisterConfirmationsNtfn(
384+
confEvent, err := s.cfg.Daemon.RegisterConfirmationsNtfn(
371385
&daemonEvent.Txid, daemonEvent.PkScript,
372386
numConfs, daemonEvent.HeightHint,
373387
)
@@ -407,9 +421,8 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
407421
// applyEvents applies a new event to the state machine. This will continue
408422
// until no further events are emitted by the state machine. Along the way,
409423
// we'll also ensure to execute any daemon events that are emitted.
410-
func (s *StateMachine[Event, Env]) applyEvents(newEvent Event) (State[Event, Env], error) {
411-
// TODO(roasbeef): make starting state as part of env?
412-
currentState := s.currentState
424+
func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
425+
newEvent Event) (State[Event, Env], error) {
413426

414427
eventQueue := fn.NewQueue(newEvent)
415428

@@ -422,7 +435,7 @@ func (s *StateMachine[Event, Env]) applyEvents(newEvent Event) (State[Event, Env
422435
// Apply the state transition function of the current
423436
// state given this new event and our existing env.
424437
transition, err := currentState.ProcessEvent(
425-
event, s.env,
438+
event, s.cfg.Env,
426439
)
427440
if err != nil {
428441
return err
@@ -485,12 +498,11 @@ func (s *StateMachine[Event, Env]) applyEvents(newEvent Event) (State[Event, Env
485498
func (s *StateMachine[Event, Env]) driveMachine() {
486499
defer s.wg.Done()
487500

488-
// TODO(roasbeef): move into env? read only to start with
489-
currentState := s.currentState
501+
currentState := s.cfg.InitialState
490502

491503
// Before we start, if we have an init daemon event specified, then
492504
// we'll handle that now.
493-
err := fn.MapOptionZ(s.initEvent, func(event DaemonEvent) error {
505+
err := fn.MapOptionZ(s.cfg.InitEvent, func(event DaemonEvent) error {
494506
return s.executeDaemonEvent(event)
495507
})
496508
if err != nil {
@@ -508,7 +520,7 @@ func (s *StateMachine[Event, Env]) driveMachine() {
508520
// machine forward until we either run out of internal events,
509521
// or we reach a terminal state.
510522
case newEvent := <-s.events:
511-
newState, err := s.applyEvents(newEvent)
523+
newState, err := s.applyEvents(currentState, newEvent)
512524
if err != nil {
513525
// TODO(roasbeef): hard error?
514526
log.Errorf("unable to apply event: %v", err)
@@ -521,7 +533,7 @@ func (s *StateMachine[Event, Env]) driveMachine() {
521533
// state machine and call any relevant clean up call
522534
// backs that might have been registered.
523535
if currentState.IsTerminal() {
524-
err := s.env.CleanUp()
536+
err := s.cfg.Env.CleanUp()
525537
if err != nil {
526538
log.Errorf("unable to clean up "+
527539
"env: %v", err)

protofsm/state_machine_test.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,13 @@ func TestStateMachineTerminateCleanup(t *testing.T) {
230230

231231
adapters := newDaemonAdapters()
232232

233-
stateMachine := NewStateMachine[dummyEvents, *dummyEnv](
234-
adapters, startingState, env, fn.None[DaemonEvent](),
235-
)
233+
cfg := StateMachineCfg[dummyEvents, *dummyEnv]{
234+
Daemon: adapters,
235+
InitialState: startingState,
236+
Env: env,
237+
InitEvent: fn.None[DaemonEvent](),
238+
}
239+
stateMachine := NewStateMachine(cfg)
236240
stateMachine.Start()
237241
defer stateMachine.Stop()
238242

@@ -268,9 +272,13 @@ func TestStateMachineOnInitDaemonEvent(t *testing.T) {
268272
PostSendEvent: fn.Some(dummyEvents(&goToFin{})),
269273
}
270274

271-
stateMachine := NewStateMachine[dummyEvents, *dummyEnv](
272-
adapters, startingState, env, fn.Some[DaemonEvent](initEvent),
273-
)
275+
cfg := StateMachineCfg[dummyEvents, *dummyEnv]{
276+
Daemon: adapters,
277+
InitialState: startingState,
278+
Env: env,
279+
InitEvent: fn.Some[DaemonEvent](initEvent),
280+
}
281+
stateMachine := NewStateMachine(cfg)
274282

275283
// Before we start up the state machine, we'll assert that the send
276284
// message adapter is called on start up.
@@ -311,9 +319,13 @@ func TestStateMachineInternalEvents(t *testing.T) {
311319

312320
adapters := newDaemonAdapters()
313321

314-
stateMachine := NewStateMachine[dummyEvents, *dummyEnv](
315-
adapters, startingState, env, fn.None[DaemonEvent](),
316-
)
322+
cfg := StateMachineCfg[dummyEvents, *dummyEnv]{
323+
Daemon: adapters,
324+
InitialState: startingState,
325+
Env: env,
326+
InitEvent: fn.None[DaemonEvent](),
327+
}
328+
stateMachine := NewStateMachine(cfg)
317329
stateMachine.Start()
318330
defer stateMachine.Stop()
319331

@@ -362,9 +374,13 @@ func TestStateMachineDaemonEvents(t *testing.T) {
362374

363375
adapters := newDaemonAdapters()
364376

365-
stateMachine := NewStateMachine[dummyEvents, *dummyEnv](
366-
adapters, startingState, env, fn.None[DaemonEvent](),
367-
)
377+
cfg := StateMachineCfg[dummyEvents, *dummyEnv]{
378+
Daemon: adapters,
379+
InitialState: startingState,
380+
Env: env,
381+
InitEvent: fn.None[DaemonEvent](),
382+
}
383+
stateMachine := NewStateMachine(cfg)
368384
stateMachine.Start()
369385
defer stateMachine.Stop()
370386

0 commit comments

Comments
 (0)