@@ -125,46 +125,60 @@ type stateQuery[Event any, Env Environment] struct {
125125//
126126// TODO(roasbeef): terminal check, daemon event execution, init?
127127type 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
485498func (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 )
0 commit comments