Skip to content

Commit c3fac0e

Browse files
authored
Merge pull request #8337 from lightningnetwork/protofsm
[1/4] - protofsm: add new package for driving generic protocol FSMs
2 parents e1df8e9 + 2e3c0b2 commit c3fac0e

File tree

5 files changed

+1292
-0
lines changed

5 files changed

+1292
-0
lines changed

protofsm/daemon_events.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package protofsm
2+
3+
import (
4+
"github.com/btcsuite/btcd/btcec/v2"
5+
"github.com/btcsuite/btcd/chaincfg/chainhash"
6+
"github.com/btcsuite/btcd/wire"
7+
"github.com/lightningnetwork/lnd/chainntnfs"
8+
"github.com/lightningnetwork/lnd/fn"
9+
"github.com/lightningnetwork/lnd/lnwire"
10+
)
11+
12+
// DaemonEvent is a special event that can be emitted by a state transition
13+
// function. A state machine can use this to perform side effects, such as
14+
// sending a message to a peer, or broadcasting a transaction.
15+
type DaemonEvent interface {
16+
daemonSealed()
17+
}
18+
19+
// DaemonEventSet is a set of daemon events that can be emitted by a state
20+
// transition.
21+
type DaemonEventSet []DaemonEvent
22+
23+
// DaemonEvents is a special type constraint that enumerates all the possible
24+
// types of daemon events.
25+
type DaemonEvents interface {
26+
SendMsgEvent[any] | BroadcastTxn | RegisterSpend[any] |
27+
RegisterConf[any]
28+
}
29+
30+
// SendPredicate is a function that returns true if the target message should
31+
// sent.
32+
type SendPredicate = func() bool
33+
34+
// SendMsgEvent is a special event that can be emitted by a state transition
35+
// that instructs the daemon to send the contained message to the target peer.
36+
type SendMsgEvent[Event any] struct {
37+
// TargetPeer is the peer to send the message to.
38+
TargetPeer btcec.PublicKey
39+
40+
// Msgs is the set of messages to send to the target peer.
41+
Msgs []lnwire.Message
42+
43+
// SendWhen implements a system for a conditional send once a special
44+
// send predicate has been met.
45+
//
46+
// TODO(roasbeef): contrast with usage of OnCommitFlush, etc
47+
SendWhen fn.Option[SendPredicate]
48+
49+
// PostSendEvent is an optional event that is to be emitted after the
50+
// message has been sent. If a SendWhen is specified, then this will
51+
// only be executed after that returns true to unblock the send.
52+
PostSendEvent fn.Option[Event]
53+
}
54+
55+
// daemonSealed indicates that this struct is a DaemonEvent instance.
56+
func (s *SendMsgEvent[E]) daemonSealed() {}
57+
58+
// BroadcastTxn indicates the target transaction should be broadcast to the
59+
// network.
60+
type BroadcastTxn struct {
61+
// Tx is the transaction to broadcast.
62+
Tx *wire.MsgTx
63+
64+
// Label is an optional label to attach to the transaction.
65+
Label string
66+
}
67+
68+
// daemonSealed indicates that this struct is a DaemonEvent instance.
69+
func (b *BroadcastTxn) daemonSealed() {}
70+
71+
// SpendMapper is a function that's used to map a spend notification to a
72+
// custom state machine event.
73+
type SpendMapper[Event any] func(*chainntnfs.SpendDetail) Event
74+
75+
// RegisterSpend is used to request that a certain event is sent into the state
76+
// machine once the specified outpoint has been spent.
77+
type RegisterSpend[Event any] struct {
78+
// OutPoint is the outpoint on chain to watch.
79+
OutPoint wire.OutPoint
80+
81+
// PkScript is the script that we expect to be spent along with the
82+
// outpoint.
83+
PkScript []byte
84+
85+
// HeightHint is a value used to give the chain scanner a hint on how
86+
// far back it needs to start its search.
87+
HeightHint uint32
88+
89+
// PostSpendEvent is a special spend mapper, that if present, will be
90+
// used to map the protofsm spend event to a custom event.
91+
PostSpendEvent fn.Option[SpendMapper[Event]]
92+
}
93+
94+
// daemonSealed indicates that this struct is a DaemonEvent instance.
95+
func (r *RegisterSpend[E]) daemonSealed() {}
96+
97+
// RegisterConf is used to request that a certain event is sent into the state
98+
// machien once the specified outpoint has been spent.
99+
type RegisterConf[Event any] struct {
100+
// Txid is the txid of the txn we want to watch the chain for.
101+
Txid chainhash.Hash
102+
103+
// PkScript is the script that we expect to be created along with the
104+
// outpoint.
105+
PkScript []byte
106+
107+
// HeightHint is a value used to give the chain scanner a hint on how
108+
// far back it needs to start its search.
109+
HeightHint uint32
110+
111+
// NumConfs is the number of confirmations that the spending
112+
// transaction needs to dispatch an event.
113+
NumConfs fn.Option[uint32]
114+
115+
// PostConfEvent is an event that's sent back to the requester once the
116+
// transaction specified above has confirmed in the chain with
117+
// sufficient depth.
118+
PostConfEvent fn.Option[Event]
119+
}
120+
121+
// daemonSealed indicates that this struct is a DaemonEvent instance.
122+
func (r *RegisterConf[E]) daemonSealed() {}

protofsm/log.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package protofsm
2+
3+
import (
4+
"github.com/btcsuite/btclog"
5+
"github.com/lightningnetwork/lnd/build"
6+
)
7+
8+
// log is a logger that is initialized with no output filters. This
9+
// means the package will not perform any logging by default until the caller
10+
// requests it.
11+
var log btclog.Logger
12+
13+
// The default amount of logging is none.
14+
func init() {
15+
UseLogger(build.NewSubLogger("PFSM", nil))
16+
}
17+
18+
// DisableLog disables all library log output. Logging output is disabled
19+
// by default until UseLogger is called.
20+
func DisableLog() {
21+
UseLogger(btclog.Disabled)
22+
}
23+
24+
// UseLogger uses a specified Logger to output package logging info.
25+
// This should be used in preference to SetLogWriter if the caller is also
26+
// using btclog.
27+
func UseLogger(logger btclog.Logger) {
28+
log = logger
29+
}

protofsm/msg_mapper.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package protofsm
2+
3+
import (
4+
"github.com/lightningnetwork/lnd/fn"
5+
"github.com/lightningnetwork/lnd/lnwire"
6+
)
7+
8+
// MsgMapper is used to map incoming wire messages into a FSM event. This is
9+
// useful to decouple the translation of an outside or wire message into an
10+
// event type that can be understood by the FSM.
11+
type MsgMapper[Event any] interface {
12+
// MapMsg maps a wire message into a FSM event. If the message is not
13+
// mappable, then an None is returned.
14+
MapMsg(msg lnwire.Message) fn.Option[Event]
15+
}

0 commit comments

Comments
 (0)