@@ -119,46 +119,60 @@ type stateQuery[Event any, Env Environment] struct {
119119//
120120// TODO(roasbeef): terminal check, daemon event execution, init?
121121type StateMachine [Event any , Env Environment ] struct {
122- currentState State [Event , Env ]
123- env Env
124-
125- daemon DaemonAdapters
122+ cfg StateMachineCfg [Event , Env ]
126123
124+ // events is the channel that will be used to send new events to the
125+ // FSM.
127126 events chan Event
128127
129- quit chan struct {}
130- wg sync.WaitGroup
131-
132128 // newStateEvents is an EventDistributor that will be used to notify
133129 // any relevant callers of new state transitions that occur.
134130 newStateEvents * fn.EventDistributor [State [Event , Env ]]
135131
132+ // stateQuery is a channel that will be used by outside callers to
133+ // query the internal state machine state.
136134 stateQuery chan stateQuery [Event , Env ]
137135
138- initEvent fn.Option [DaemonEvent ]
139-
140136 startOnce sync.Once
141137 stopOnce sync.Once
142138
143139 // TODO(roasbeef): also use that context guard here?
140+ quit chan struct {}
141+ wg sync.WaitGroup
142+ }
143+
144+ // StateMachineCfg is a configuration struct that's used to create a new state
145+ // machine.
146+ type StateMachineCfg [Event any , Env Environment ] struct {
147+ // Daemon is a set of adapters that will be used to bridge the FSM to
148+ // the daemon.
149+ Daemon DaemonAdapters
150+
151+ // InitialState is the initial state of the state machine.
152+ InitialState State [Event , Env ]
153+
154+ // Env is the environment that the state machine will use to execute.
155+ Env Env
156+
157+ // InitEvent is an optional event that will be sent to the state
158+ // machine as if it was emitted at the onset of the state machine. This
159+ // can be used to set up tracking state such as a txid confirmation
160+ // event.
161+ InitEvent fn.Option [DaemonEvent ]
144162}
145163
146164// NewStateMachine creates a new state machine given a set of daemon adapters,
147165// an initial state, an environment, and an event to process as if emitted at
148166// the onset of the state machine. Such an event can be used to set up tracking
149167// state such as a txid confirmation event.
150- func NewStateMachine [Event any , Env Environment ](adapters DaemonAdapters ,
151- initialState State [Event , Env ], env Env ,
152- initEvent fn.Option [DaemonEvent ]) StateMachine [Event , Env ] {
168+ func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ],
169+ ) StateMachine [Event , Env ] {
153170
154171 return StateMachine [Event , Env ]{
155- daemon : adapters ,
172+ cfg : cfg ,
156173 events : make (chan Event , 1 ),
157- currentState : initialState ,
158174 stateQuery : make (chan stateQuery [Event , Env ]),
159175 quit : make (chan struct {}),
160- env : env ,
161- initEvent : initEvent ,
162176 newStateEvents : fn .NewEventDistributor [State [Event , Env ]](),
163177 }
164178}
@@ -237,7 +251,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
237251 // any preconditions as well as post-send events.
238252 case * SendMsgEvent [Event ]:
239253 sendAndCleanUp := func () error {
240- err := s .daemon .SendMessages (
254+ err := s .cfg . Daemon .SendMessages (
241255 daemonEvent .TargetPeer , daemonEvent .Msgs ,
242256 )
243257 if err != nil {
@@ -301,7 +315,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
301315 // If this is a broadcast transaction event, then we'll broadcast with
302316 // the label attached.
303317 case * BroadcastTxn :
304- err := s .daemon .BroadcastTransaction (
318+ err := s .cfg . Daemon .BroadcastTransaction (
305319 daemonEvent .Tx , daemonEvent .Label ,
306320 )
307321 if err != nil {
@@ -315,7 +329,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
315329 // The state machine has requested a new event to be sent once a
316330 // transaction spending a specified outpoint has confirmed.
317331 case * RegisterSpend [Event ]:
318- spendEvent , err := s .daemon .RegisterSpendNtfn (
332+ spendEvent , err := s .cfg . Daemon .RegisterSpendNtfn (
319333 & daemonEvent .OutPoint , daemonEvent .PkScript ,
320334 daemonEvent .HeightHint ,
321335 )
@@ -351,7 +365,7 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
351365 // specified txid+pkScript pair has confirmed.
352366 case * RegisterConf [Event ]:
353367 numConfs := daemonEvent .NumConfs .UnwrapOr (1 )
354- confEvent , err := s .daemon .RegisterConfirmationsNtfn (
368+ confEvent , err := s .cfg . Daemon .RegisterConfirmationsNtfn (
355369 & daemonEvent .Txid , daemonEvent .PkScript ,
356370 numConfs , daemonEvent .HeightHint ,
357371 )
@@ -391,9 +405,8 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
391405// applyEvents applies a new event to the state machine. This will continue
392406// until no further events are emitted by the state machine. Along the way,
393407// we'll also ensure to execute any daemon events that are emitted.
394- func (s * StateMachine [Event , Env ]) applyEvents (newEvent Event ) (State [Event , Env ], error ) {
395- // TODO(roasbeef): make starting state as part of env?
396- currentState := s .currentState
408+ func (s * StateMachine [Event , Env ]) applyEvents (currentState State [Event , Env ],
409+ newEvent Event ) (State [Event , Env ], error ) {
397410
398411 eventQueue := fn .NewQueue (newEvent )
399412
@@ -406,7 +419,7 @@ func (s *StateMachine[Event, Env]) applyEvents(newEvent Event) (State[Event, Env
406419 // Apply the state transition function of the current
407420 // state given this new event and our existing env.
408421 transition , err := currentState .ProcessEvent (
409- event , s .env ,
422+ event , s .cfg . Env ,
410423 )
411424 if err != nil {
412425 return err
@@ -469,12 +482,11 @@ func (s *StateMachine[Event, Env]) applyEvents(newEvent Event) (State[Event, Env
469482func (s * StateMachine [Event , Env ]) driveMachine () {
470483 defer s .wg .Done ()
471484
472- // TODO(roasbeef): move into env? read only to start with
473- currentState := s .currentState
485+ currentState := s .cfg .InitialState
474486
475487 // Before we start, if we have an init daemon event specified, then
476488 // we'll handle that now.
477- err := fn .MapOptionZ (s .initEvent , func (event DaemonEvent ) error {
489+ err := fn .MapOptionZ (s .cfg . InitEvent , func (event DaemonEvent ) error {
478490 return s .executeDaemonEvent (event )
479491 })
480492 if err != nil {
@@ -492,7 +504,7 @@ func (s *StateMachine[Event, Env]) driveMachine() {
492504 // machine forward until we either run out of internal events,
493505 // or we reach a terminal state.
494506 case newEvent := <- s .events :
495- newState , err := s .applyEvents (newEvent )
507+ newState , err := s .applyEvents (currentState , newEvent )
496508 if err != nil {
497509 // TODO(roasbeef): hard error?
498510 log .Errorf ("unable to apply event: %v" , err )
0 commit comments