Merge pull request #1179 from GustavoStingelin/feat/static-address-fsm-diagrams
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run

fsm: generate and verify static address diagrams
This commit is contained in:
Slyghtning 2026-07-21 14:59:35 +02:00 committed by GitHub
commit 4bb7d5ee29
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 198 additions and 46 deletions

View file

@ -124,6 +124,9 @@ jobs:
- name: check - name: check
run: make docs-check run: make docs-check
- name: check generated FSM diagrams
run: make fsm-check
######################## ########################
# run unit-test sqlite3 race # run unit-test sqlite3 race
######################## ########################

View file

@ -194,4 +194,20 @@ docs-check: docs
fsm: fsm:
@$(call print, "Generating state machine docs") @$(call print, "Generating state machine docs")
./scripts/fsm-generate.sh; ./scripts/fsm-generate.sh;
.PHONY: fsm
FSM_FILES := \
fsm/example_fsm.md \
instantout/fsm.md \
instantout/reservation/fsm.md \
staticaddr/deposit/fsm.md \
staticaddr/loopin/fsm.md
fsm-check: fsm
@$(call print, "Verifying generated state machine docs")
if test -n "$$(git status --porcelain -- $(FSM_FILES))"; then \
echo "Generated FSM diagrams are not up-to-date!"; \
git status --porcelain -- $(FSM_FILES); \
git diff -- $(FSM_FILES); \
exit 1; \
fi
.PHONY: fsm fsm-check

View file

@ -2,11 +2,11 @@
stateDiagram-v2 stateDiagram-v2
[*] --> InitFSM: OnRequestStuff [*] --> InitFSM: OnRequestStuff
InitFSM InitFSM
InitFSM --> StuffSentOut: OnStuffSentOut
InitFSM --> StuffFailed: OnError InitFSM --> StuffFailed: OnError
InitFSM --> StuffSentOut: OnStuffSentOut
StuffFailed StuffFailed
StuffSentOut StuffSentOut
StuffSentOut --> StuffSuccess: OnStuffSuccess
StuffSentOut --> StuffFailed: OnError StuffSentOut --> StuffFailed: OnError
StuffSentOut --> StuffSuccess: OnStuffSuccess
StuffSuccess StuffSuccess
``` ```

View file

@ -12,8 +12,12 @@ import (
"github.com/lightninglabs/loop/fsm" "github.com/lightninglabs/loop/fsm"
"github.com/lightninglabs/loop/instantout" "github.com/lightninglabs/loop/instantout"
"github.com/lightninglabs/loop/instantout/reservation" "github.com/lightninglabs/loop/instantout/reservation"
"github.com/lightninglabs/loop/staticaddr/deposit"
"github.com/lightninglabs/loop/staticaddr/loopin"
) )
var errInvalidFSMSelector = errors.New("missing or unknown fsm selector")
func main() { func main() {
if err := run(); err != nil { if err := run(); err != nil {
fmt.Println(err) fmt.Println(err)
@ -35,35 +39,43 @@ func run() error {
return err return err
} }
switch *stateMachine { states, err := getStates(*stateMachine)
if err != nil {
return err
}
return writeMermaidFile(fp, states)
}
func getStates(stateMachine string) (fsm.States, error) {
switch stateMachine {
case "example": case "example":
exampleFSM := &fsm.ExampleFSM{} exampleFSM := &fsm.ExampleFSM{}
err = writeMermaidFile(fp, exampleFSM.GetStates()) return exampleFSM.GetStates(), nil
if err != nil {
return err
}
case "reservation": case "reservation":
reservationFSM := &reservation.FSM{} reservationFSM := &reservation.FSM{}
err = writeMermaidFile(fp, reservationFSM.GetServerInitiatedReservationStates()) return reservationFSM.GetServerInitiatedReservationStates(), nil
if err != nil {
return err
}
case "instantout": case "instantout":
instantout := &instantout.FSM{} instantOutFSM := &instantout.FSM{}
err = writeMermaidFile(fp, instantout.GetV1ReservationStates()) return instantOutFSM.GetV1ReservationStates(), nil
if err != nil {
return err case "staticaddr-deposit":
} depositFSM := &deposit.FSM{}
return depositFSM.DepositStatesV0(), nil
case "staticaddr-loopin":
loopInFSM := &loopin.FSM{}
return loopInFSM.LoopInStatesV0(), nil
default: default:
fmt.Println("Missing or wrong argument: fsm must be one of:") return nil, fmt.Errorf(
fmt.Println("\treservations") "%w %q; supported selectors: example, instantout, "+
fmt.Println("\texample") "reservation, staticaddr-deposit, staticaddr-loopin",
errInvalidFSMSelector, stateMachine,
)
} }
return nil
} }
func writeMermaidFile(filename string, states fsm.States) error { func writeMermaidFile(filename string, states fsm.States) error {
@ -86,8 +98,11 @@ func writeMermaidFile(filename string, states fsm.States) error {
state = "[*]" state = "[*]"
} }
// write transitions // write transitions
for edge, target := range edges.Transitions { for _, edge := range sortedTransitionKeys(edges.Transitions) {
fmt.Fprintf(&b, "%s --> %s: %s\n", state, target, edge) fmt.Fprintf(
&b, "%s --> %s: %s\n", state,
edges.Transitions[fsm.EventType(edge)], edge,
)
} }
} }
@ -110,3 +125,14 @@ func sortedKeys(m fsm.States) []string {
sort.Strings(keys) sort.Strings(keys)
return keys return keys
} }
func sortedTransitionKeys(m fsm.Transitions) []string {
keys := make([]string, len(m))
i := 0
for k := range m {
keys[i] = string(k)
i++
}
sort.Strings(keys)
return keys
}

View file

@ -2,35 +2,41 @@
stateDiagram-v2 stateDiagram-v2
[*] --> Init: OnStart [*] --> Init: OnStart
BuildHtlc BuildHtlc
BuildHtlc --> InstantOutFailed: OnError
BuildHtlc --> PushPreimage: OnHtlcSigReceived BuildHtlc --> PushPreimage: OnHtlcSigReceived
BuildHtlc --> InstantFailedOutFailed: OnError BuildHtlc --> InstantOutFailed: OnRecover
BuildHtlc --> InstantFailedOutFailed: OnRecover
FailedHtlcSweep FailedHtlcSweep
FailedHtlcSweep --> PublishHtlcSweep: OnRecover
FinishedHtlcPreimageSweep
FinishedSweeplessSweep FinishedSweeplessSweep
Init Init
Init --> InstantOutFailed: OnError
Init --> SendPaymentAndPollAccepted: OnInit Init --> SendPaymentAndPollAccepted: OnInit
Init --> InstantFailedOutFailed: OnError Init --> InstantOutFailed: OnRecover
Init --> InstantFailedOutFailed: OnRecover InstantOutFailed
InstantFailedOutFailed
PublishHtlc PublishHtlc
PublishHtlc --> FailedHtlcSweep: OnError PublishHtlc --> FailedHtlcSweep: OnError
PublishHtlc --> PublishHtlcSweep: OnHtlcPublished
PublishHtlc --> PublishHtlc: OnRecover PublishHtlc --> PublishHtlc: OnRecover
PublishHtlc --> WaitForHtlcSweepConfirmed: OnHtlcBroadcasted PublishHtlcSweep
PublishHtlcSweep --> FailedHtlcSweep: OnError
PublishHtlcSweep --> WaitForHtlcSweepConfirmed: OnHtlcSweepPublished
PublishHtlcSweep --> PublishHtlcSweep: OnRecover
PushPreimage PushPreimage
PushPreimage --> InstantOutFailed: OnError
PushPreimage --> PublishHtlc: OnErrorPublishHtlc
PushPreimage --> PushPreimage: OnRecover PushPreimage --> PushPreimage: OnRecover
PushPreimage --> WaitForSweeplessSweepConfirmed: OnSweeplessSweepPublished PushPreimage --> WaitForSweeplessSweepConfirmed: OnSweeplessSweepPublished
PushPreimage --> InstantFailedOutFailed: OnError
PushPreimage --> PublishHtlc: OnErrorPublishHtlc
SendPaymentAndPollAccepted SendPaymentAndPollAccepted
SendPaymentAndPollAccepted --> InstantOutFailed: OnError
SendPaymentAndPollAccepted --> BuildHtlc: OnPaymentAccepted SendPaymentAndPollAccepted --> BuildHtlc: OnPaymentAccepted
SendPaymentAndPollAccepted --> InstantFailedOutFailed: OnError SendPaymentAndPollAccepted --> InstantOutFailed: OnRecover
SendPaymentAndPollAccepted --> InstantFailedOutFailed: OnRecover
WaitForHtlcSweepConfirmed WaitForHtlcSweepConfirmed
WaitForHtlcSweepConfirmed --> FailedHtlcSweep: OnError
WaitForHtlcSweepConfirmed --> FinishedHtlcPreimageSweep: OnHtlcSwept WaitForHtlcSweepConfirmed --> FinishedHtlcPreimageSweep: OnHtlcSwept
WaitForHtlcSweepConfirmed --> WaitForHtlcSweepConfirmed: OnRecover WaitForHtlcSweepConfirmed --> WaitForHtlcSweepConfirmed: OnRecover
WaitForHtlcSweepConfirmed --> FailedHtlcSweep: OnError
WaitForSweeplessSweepConfirmed WaitForSweeplessSweepConfirmed
WaitForSweeplessSweepConfirmed --> FinishedSweeplessSweep: OnSweeplessSweepConfirmed
WaitForSweeplessSweepConfirmed --> WaitForSweeplessSweepConfirmed: OnRecover
WaitForSweeplessSweepConfirmed --> PublishHtlc: OnError WaitForSweeplessSweepConfirmed --> PublishHtlc: OnError
WaitForSweeplessSweepConfirmed --> WaitForSweeplessSweepConfirmed: OnRecover
WaitForSweeplessSweepConfirmed --> FinishedSweeplessSweep: OnSweeplessSweepConfirmed
``` ```

View file

@ -2,20 +2,28 @@
stateDiagram-v2 stateDiagram-v2
[*] --> Init: OnServerRequest [*] --> Init: OnServerRequest
Confirmed Confirmed
Confirmed --> SpendBroadcasted: OnSpendBroadcasted Confirmed --> Confirmed: OnError
Confirmed --> TimedOut: OnTimedOut Confirmed --> Locked: OnLocked
Confirmed --> Confirmed: OnRecover Confirmed --> Confirmed: OnRecover
Confirmed --> Spent: OnSpent
Confirmed --> TimedOut: OnTimedOut
Failed Failed
Init Init
Init --> WaitForConfirmation: OnBroadcast Init --> WaitForConfirmation: OnBroadcast
Init --> Failed: OnRecover
Init --> Failed: OnError Init --> Failed: OnError
SpendBroadcasted Init --> Failed: OnRecover
SpendBroadcasted --> SpendConfirmed: OnSpendConfirmed Locked
SpendConfirmed Locked --> Locked: OnError
Locked --> Locked: OnRecover
Locked --> Spent: OnSpent
Locked --> TimedOut: OnTimedOut
Locked --> Confirmed: OnUnlocked
Spent
Spent --> Spent: OnSpent
TimedOut TimedOut
TimedOut --> TimedOut: OnTimedOut
WaitForConfirmation WaitForConfirmation
WaitForConfirmation --> WaitForConfirmation: OnRecover
WaitForConfirmation --> Confirmed: OnConfirmed WaitForConfirmation --> Confirmed: OnConfirmed
WaitForConfirmation --> WaitForConfirmation: OnRecover
WaitForConfirmation --> TimedOut: OnTimedOut WaitForConfirmation --> TimedOut: OnTimedOut
``` ```

View file

@ -1,4 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail
go run ./fsm/stateparser/stateparser.go --out ./fsm/example_fsm.md --fsm example go run ./fsm/stateparser/stateparser.go --out ./fsm/example_fsm.md --fsm example
go run ./fsm/stateparser/stateparser.go --out ./reservation/reservation_fsm.md --fsm reservation go run ./fsm/stateparser/stateparser.go --out ./instantout/reservation/fsm.md --fsm reservation
go run ./fsm/stateparser/stateparser.go --out ./instantout/fsm.md --fsm instantout go run ./fsm/stateparser/stateparser.go --out ./instantout/fsm.md --fsm instantout
go run ./fsm/stateparser/stateparser.go --out ./staticaddr/deposit/fsm.md --fsm staticaddr-deposit
go run ./fsm/stateparser/stateparser.go --out ./staticaddr/loopin/fsm.md --fsm staticaddr-loopin

52
staticaddr/deposit/fsm.md Normal file
View file

@ -0,0 +1,52 @@
```mermaid
stateDiagram-v2
[*] --> Deposited: OnStart
ChannelPublished
ChannelPublished --> ChannelPublished: OnExpiry
Deposited
Deposited --> Deposited: OnError
Deposited --> PublishExpirySweep: OnExpiry
Deposited --> LoopingIn: OnLoopInInitiated
Deposited --> OpeningChannel: OnOpeningChannel
Deposited --> Deposited: OnRecover
Deposited --> SweepHtlcTimeout: OnSweepingHtlcTimeout
Deposited --> Withdrawing: OnWithdrawInitiated
Expired
Expired --> Expired: OnExpiry
HtlcTimeoutSwept
HtlcTimeoutSwept --> HtlcTimeoutSwept: OnExpiry
LoopedIn
LoopedIn --> LoopedIn: OnExpiry
LoopingIn
LoopingIn --> Deposited: OnError
LoopingIn --> PublishExpirySweep: OnExpiry
LoopingIn --> LoopingIn: OnLoopInInitiated
LoopingIn --> LoopedIn: OnLoopedIn
LoopingIn --> LoopingIn: OnRecover
LoopingIn --> SweepHtlcTimeout: OnSweepingHtlcTimeout
OpeningChannel
OpeningChannel --> ChannelPublished: OnChannelPublished
OpeningChannel --> Deposited: OnError
OpeningChannel --> OpeningChannel: OnExpiry
OpeningChannel --> OpeningChannel: OnRecover
PublishExpirySweep
PublishExpirySweep --> Deposited: OnError
PublishExpirySweep --> WaitForExpirySweep: OnExpiryPublished
PublishExpirySweep --> PublishExpirySweep: OnRecover
SweepHtlcTimeout
SweepHtlcTimeout --> HtlcTimeoutSwept: OnHtlcTimeoutSwept
SweepHtlcTimeout --> SweepHtlcTimeout: OnRecover
WaitForExpirySweep
WaitForExpirySweep --> Deposited: OnError
WaitForExpirySweep --> Expired: OnExpirySwept
WaitForExpirySweep --> PublishExpirySweep: OnRecover
Withdrawing
Withdrawing --> Deposited: OnError
Withdrawing --> Withdrawing: OnExpiry
Withdrawing --> Withdrawing: OnRecover
Withdrawing --> Withdrawing: OnWithdrawInitiated
Withdrawing --> Withdrawn: OnWithdrawn
Withdrawn
Withdrawn --> Withdrawn: OnExpiry
Withdrawn --> Withdrawn: OnWithdrawn
```

37
staticaddr/loopin/fsm.md Normal file
View file

@ -0,0 +1,37 @@
```mermaid
stateDiagram-v2
[*] --> InitHtlcTx: OnInitHtlc
Failed
HtlcTimeoutSwept
InitHtlcTx
InitHtlcTx --> UnlockDeposits: OnError
InitHtlcTx --> SignHtlcTx: OnHtlcInitiated
InitHtlcTx --> UnlockDeposits: OnRecover
MonitorHtlcTimeoutSweep
MonitorHtlcTimeoutSweep --> Failed: OnError
MonitorHtlcTimeoutSweep --> HtlcTimeoutSwept: OnHtlcTimeoutSwept
MonitorHtlcTimeoutSweep --> MonitorHtlcTimeoutSweep: OnRecover
MonitorInvoiceAndHtlcTx
MonitorInvoiceAndHtlcTx --> UnlockDeposits: OnError
MonitorInvoiceAndHtlcTx --> PaymentReceived: OnPaymentReceived
MonitorInvoiceAndHtlcTx --> MonitorInvoiceAndHtlcTx: OnRecover
MonitorInvoiceAndHtlcTx --> Failed: OnSwapTimedOut
MonitorInvoiceAndHtlcTx --> SweepHtlcTimeout: OnSweepHtlcTimeout
PaymentReceived
PaymentReceived --> SucceededTransitioningFailed: OnError
PaymentReceived --> Succeeded: OnRecover
PaymentReceived --> Succeeded: OnSucceeded
SignHtlcTx
SignHtlcTx --> UnlockDeposits: OnError
SignHtlcTx --> MonitorInvoiceAndHtlcTx: OnHtlcTxSigned
SignHtlcTx --> UnlockDeposits: OnRecover
Succeeded
SucceededTransitioningFailed
SweepHtlcTimeout
SweepHtlcTimeout --> Failed: OnError
SweepHtlcTimeout --> MonitorHtlcTimeoutSweep: OnHtlcTimeoutSweepPublished
SweepHtlcTimeout --> SweepHtlcTimeout: OnRecover
UnlockDeposits
UnlockDeposits --> Failed: OnError
UnlockDeposits --> UnlockDeposits: OnRecover
```