@@ -122,46 +122,60 @@ type stateQuery[Event any, Env Environment] struct {
122122//
123123// TODO(roasbeef): terminal check, daemon event execution, init?
124124type StateMachine [Event any , Env Environment ] struct {
125- currentState State [Event , Env ]
126- env Env
127-
128- daemon DaemonAdapters
125+ cfg StateMachineCfg [Event , Env ]
129126
127+ // events is the channel that will be used to send new events to the
128+ // FSM.
130129 events chan Event
131130
132- quit chan struct {}
133- wg sync.WaitGroup
134-
135131 // newStateEvents is an EventDistributor that will be used to notify
136132 // any relevant callers of new state transitions that occur.
137133 newStateEvents * fn.EventDistributor [State [Event , Env ]]
138134
135+ // stateQuery is a channel that will be used by outside callers to
136+ // query the internal state machine state.
139137 stateQuery chan stateQuery [Event , Env ]
140138
141- initEvent fn.Option [DaemonEvent ]
142-
143139 startOnce sync.Once
144140 stopOnce sync.Once
145141
146142 // TODO(roasbeef): also use that context guard here?
143+ quit chan struct {}
144+ wg sync.WaitGroup
145+ }
146+
147+ // StateMachineCfg is a configuration struct that's used to create a new state
148+ // machine.
149+ type StateMachineCfg [Event any , Env Environment ] struct {
150+ // Daemon is a set of adapters that will be used to bridge the FSM to
151+ // the daemon.
152+ Daemon DaemonAdapters
153+
154+ // InitialState is the initial state of the state machine.
155+ InitialState State [Event , Env ]
156+
157+ // Env is the environment that the state machine will use to execute.
158+ Env Env
159+
160+ // InitEvent is an optional event that will be sent to the state
161+ // machine as if it was emitted at the onset of the state machine. This
162+ // can be used to set up tracking state such as a txid confirmation
163+ // event.
164+ InitEvent fn.Option [DaemonEvent ]
147165}
148166
149167// NewStateMachine creates a new state machine given a set of daemon adapters,
150168// an initial state, an environment, and an event to process as if emitted at
151169// the onset of the state machine. Such an event can be used to set up tracking
152170// state such as a txid confirmation event.
153- func NewStateMachine [Event any , Env Environment ](adapters DaemonAdapters ,
154- initialState State [Event , Env ], env Env ,
155- initEvent fn.Option [DaemonEvent ]) StateMachine [Event , Env ] {
171+ func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ],
172+ ) StateMachine [Event , Env ] {
156173
157174 return StateMachine [Event , Env ]{
158- daemon : adapters ,
175+ cfg : cfg ,
159176 events : make (chan Event , 1 ),
160- currentState : initialState ,
161177 stateQuery : make (chan stateQuery [Event , Env ]),
162178 quit : make (chan struct {}),
163- env : env ,
164- initEvent : initEvent ,
165179 newStateEvents : fn .NewEventDistributor [State [Event , Env ]](),
166180 }
167181}
@@ -240,7 +254,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
240254 // any preconditions as well as post-send events.
241255 case * SendMsgEvent [Event ]:
242256 sendAndCleanUp := func () error {
243- err := s .daemon .SendMessages (
257+ err := s .cfg . Daemon .SendMessages (
244258 daemonEvent .TargetPeer , daemonEvent .Msgs ,
245259 )
246260 if err != nil {
@@ -304,7 +318,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
304318 // If this is a broadcast transaction event, then we'll broadcast with
305319 // the label attached.
306320 case * BroadcastTxn :
307- err := s .daemon .BroadcastTransaction (
321+ err := s .cfg . Daemon .BroadcastTransaction (
308322 daemonEvent .Tx , daemonEvent .Label ,
309323 )
310324 if err != nil {
@@ -318,7 +332,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
318332 // The state machine has requested a new event to be sent once a
319333 // transaction spending a specified outpoint has confirmed.
320334 case * RegisterSpend [Event ]:
321- spendEvent , err := s .daemon .RegisterSpendNtfn (
335+ spendEvent , err := s .cfg . Daemon .RegisterSpendNtfn (
322336 & daemonEvent .OutPoint , daemonEvent .PkScript ,
323337 daemonEvent .HeightHint ,
324338 )
@@ -354,7 +368,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
354368 // specified txid+pkScript pair has confirmed.
355369 case * RegisterConf [Event ]:
356370 numConfs := daemonEvent .NumConfs .UnwrapOr (1 )
357- confEvent , err := s .daemon .RegisterConfirmationsNtfn (
371+ confEvent , err := s .cfg . Daemon .RegisterConfirmationsNtfn (
358372 & daemonEvent .Txid , daemonEvent .PkScript ,
359373 numConfs , daemonEvent .HeightHint ,
360374 )
@@ -394,9 +408,8 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
394408// applyEvents applies a new event to the state machine. This will continue
395409// until no further events are emitted by the state machine. Along the way,
396410// we'll also ensure to execute any daemon events that are emitted.
397- func (s * StateMachine [Event , Env ]) applyEvents (newEvent Event ) (State [Event , Env ], error ) {
398- // TODO(roasbeef): make starting state as part of env?
399- currentState := s .currentState
411+ func (s * StateMachine [Event , Env ]) applyEvents (currentState State [Event , Env ],
412+ newEvent Event ) (State [Event , Env ], error ) {
400413
401414 eventQueue := fn .NewQueue (newEvent )
402415
@@ -409,7 +422,7 @@ func (s *StateMachine[Event, Env]) applyEvents(newEvent Event) (State[Event, Env
409422 // Apply the state transition function of the current
410423 // state given this new event and our existing env.
411424 transition , err := currentState .ProcessEvent (
412- event , s .env ,
425+ event , s .cfg . Env ,
413426 )
414427 if err != nil {
415428 return err
@@ -472,12 +485,11 @@ func (s *StateMachine[Event, Env]) applyEvents(newEvent Event) (State[Event, Env
472485func (s * StateMachine [Event , Env ]) driveMachine () {
473486 defer s .wg .Done ()
474487
475- // TODO(roasbeef): move into env? read only to start with
476- currentState := s .currentState
488+ currentState := s .cfg .InitialState
477489
478490 // Before we start, if we have an init daemon event specified, then
479491 // we'll handle that now.
480- err := fn .MapOptionZ (s .initEvent , func (event DaemonEvent ) error {
492+ err := fn .MapOptionZ (s .cfg . InitEvent , func (event DaemonEvent ) error {
481493 return s .executeDaemonEvent (event )
482494 })
483495 if err != nil {
@@ -495,7 +507,7 @@ func (s *StateMachine[Event, Env]) driveMachine() {
495507 // machine forward until we either run out of internal events,
496508 // or we reach a terminal state.
497509 case newEvent := <- s .events :
498- newState , err := s .applyEvents (newEvent )
510+ newState , err := s .applyEvents (currentState , newEvent )
499511 if err != nil {
500512 // TODO(roasbeef): hard error?
501513 log .Errorf ("unable to apply event: %v" , err )
@@ -508,7 +520,7 @@ func (s *StateMachine[Event, Env]) driveMachine() {
508520 // state machine and call any relevant clean up call
509521 // backs that might have been registered.
510522 if currentState .IsTerminal () {
511- err := s .env .CleanUp ()
523+ err := s .cfg . Env .CleanUp ()
512524 if err != nil {
513525 log .Errorf ("unable to clean up " +
514526 "env: %v" , err )
0 commit comments