Skip to content

Commit 56b7c94

Browse files
committed
WIP: init supplycommit verifier
1 parent a41c113 commit 56b7c94

File tree

3 files changed

+557
-0
lines changed

3 files changed

+557
-0
lines changed

universe/supplyverifier/env.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package supplyverifier
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/lightninglabs/taproot-assets/asset"
8+
"github.com/lightninglabs/taproot-assets/tapgarden"
9+
"github.com/lightninglabs/taproot-assets/universe/supplycommit"
10+
)
11+
12+
// OnChainLookup is an interface that is used to look up on-chain information
13+
// about supply commitments.
14+
type OnChainLookup interface {
15+
// UnspentPrecommits returns the set of unspent pre-commitments for a
16+
// given asset spec.
17+
UnspentPrecommits(ctx context.Context,
18+
assetSpec asset.Specifier) (supplycommit.PreCommits, error)
19+
20+
// SupplyCommit returns the latest supply commitment for a given asset
21+
// spec.
22+
SupplyCommit(ctx context.Context,
23+
assetSpec asset.Specifier) (*supplycommit.RootCommitment, error)
24+
25+
// LastVerifiedCommitment returns the last verified supply commitment
26+
// for a given asset spec.
27+
LastVerifiedCommitment(ctx context.Context,
28+
assetSpec asset.Specifier) (*supplycommit.RootCommitment, error)
29+
}
30+
31+
// Environment is a struct that holds all the dependencies that the supply
32+
// verifier needs to carry out its duties.
33+
type Environment struct {
34+
// AssetSpec is the asset specifier that is used to identify the asset
35+
// that we're maintaining a supply commit for.
36+
AssetSpec asset.Specifier
37+
38+
// Chain is our access to the current main chain.
39+
Chain tapgarden.ChainBridge
40+
41+
// OnChainLookup is used to look up on-chain information.
42+
OnChainLookup OnChainLookup
43+
44+
// ErrChan is the channel that is used to send errors to the caller.
45+
ErrChan chan<- error
46+
47+
// QuitChan is the channel that is used to signal that the state
48+
// machine should quit.
49+
QuitChan <-chan struct{}
50+
}
51+
52+
// Name returns the name of the environment.
53+
func (e *Environment) Name() string {
54+
return fmt.Sprintf("supply_verifier(%s)", e.AssetSpec.String())
55+
}

universe/supplyverifier/states.go

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
package supplyverifier
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/btcsuite/btcd/chaincfg/chainhash"
7+
"github.com/lightninglabs/taproot-assets/universe/supplycommit"
8+
"github.com/lightningnetwork/lnd/chainntnfs"
9+
"github.com/lightningnetwork/lnd/protofsm"
10+
)
11+
12+
var (
13+
// ErrInvalidStateTransition is returned when we receive an unexpected
14+
// event for a given state.
15+
ErrInvalidStateTransition = fmt.Errorf("invalid state transition")
16+
)
17+
18+
// Event is a special interface used to create the equivalent of a sum-type, but
19+
// using a "sealed" interface.
20+
type Event interface {
21+
eventSealed()
22+
}
23+
24+
// Events is a special type constraint that enumerates all the possible protocol
25+
// events.
26+
type Events interface {
27+
}
28+
29+
// StateTransition is the StateTransition type specific to the supply verifier
30+
// state machine.
31+
type StateTransition = protofsm.StateTransition[Event, *Environment]
32+
33+
// State is our sum-type ish interface that represents the current universe
34+
// commitment verification state.
35+
type State interface {
36+
stateSealed()
37+
IsTerminal() bool
38+
ProcessEvent(Event, *Environment) (*StateTransition, error)
39+
String() string
40+
}
41+
42+
// StateMachine is a state machine that handles verifying the on-chain supply
43+
// commitment for a given asset.
44+
type StateMachine = protofsm.StateMachine[Event, *Environment]
45+
46+
// Config is a configuration struct that is used to initialize a new supply
47+
// verifier state machine.
48+
type Config = protofsm.StateMachineCfg[Event, *Environment]
49+
50+
// InitEvent is the first event that is sent to the state machine.
51+
type InitEvent struct{}
52+
53+
// eventSealed is a special method that is used to seal the interface.
54+
func (i *InitEvent) eventSealed() {}
55+
56+
// WatchLatestOutputsEvent is an event that prompts the state machine to watch
57+
// for the spend of the latest unspent outputs.
58+
type WatchLatestOutputsEvent struct{}
59+
60+
// eventSealed is a special method that is used to seal the interface.
61+
func (w *WatchLatestOutputsEvent) eventSealed() {}
62+
63+
// WatchOutputsEvent is an event that carries the set of outputs to watch.
64+
type WatchOutputsEvent struct {
65+
PreCommits supplycommit.PreCommits
66+
SupplyCommit *supplycommit.RootCommitment
67+
}
68+
69+
// eventSealed is a special method that is used to seal the interface.
70+
func (e *WatchOutputsEvent) eventSealed() {}
71+
72+
// SpendEvent is sent in response to an intent to be notified of a spend of an
73+
// outpoint.
74+
type SpendEvent struct {
75+
// SpendDetail is the details of the spend that was observed on-chain.
76+
SpendDetail *chainntnfs.SpendDetail
77+
78+
// PreCommitments is the set of all pre-commitments that were being
79+
// watched for a spend.
80+
PreCommitments []supplycommit.PreCommitment
81+
82+
// SpentPreCommitment is the pre-commitment that was spent. This will
83+
// be non-nil only if the spent output was a pre-commitment.
84+
SpentPreCommitment *supplycommit.PreCommitment
85+
86+
// SpentSupplyCommitment is the supply commitment that was spent. This
87+
// will be non-nil only if the spent output was a supply commitment.
88+
SpentSupplyCommitment *supplycommit.RootCommitment
89+
}
90+
91+
// eventSealed is a special method that is used to seal the interface.
92+
func (s *SpendEvent) eventSealed() {}
93+
94+
// ProofsSyncedEvent is sent once the proofs for a supply commitment have been
95+
// synced.
96+
type ProofsSyncedEvent struct {
97+
nextCommitment *supplycommit.RootCommitment
98+
spendEvent *SpendEvent
99+
}
100+
101+
// eventSealed is a special method that is used to seal the interface.
102+
func (p *ProofsSyncedEvent) eventSealed() {}
103+
104+
// DefaultState is the initial state of the FSM. In this state we'll perform
105+
// initial sanity checks.
106+
type DefaultState struct {
107+
}
108+
109+
// stateSealed is a special method that is used to seal the interface.
110+
func (d *DefaultState) stateSealed() {}
111+
112+
// IsTerminal returns true if the target state is a terminal state.
113+
func (d *DefaultState) IsTerminal() bool {
114+
return false
115+
}
116+
117+
// String returns the name of the state.
118+
func (d *DefaultState) String() string {
119+
return "DefaultState"
120+
}
121+
122+
// WatchOutputsSpendState is a state where we wait for a spend of one of the
123+
// outputs we're watching. The outputs may have already been spent, in which
124+
// case we'll transition forward immediately.
125+
type WatchOutputsSpendState struct{}
126+
127+
// stateSealed is a special method that is used to seal the interface.
128+
func (w *WatchOutputsSpendState) stateSealed() {}
129+
130+
// IsTerminal returns true if the target state is a terminal state.
131+
func (w *WatchOutputsSpendState) IsTerminal() bool {
132+
return false
133+
}
134+
135+
// String returns the name of the state.
136+
func (w *WatchOutputsSpendState) String() string {
137+
return "WatchOutputsSpendState"
138+
}
139+
140+
// SyncSupplyProofsState is the state where we sync proofs related to a
141+
// supply commitment transaction.
142+
type SyncSupplyProofsState struct {
143+
lastCommitment *supplycommit.RootCommitment
144+
145+
// lastSpendTxID is the transaction ID of the last spend event we
146+
// processed. This is used to prevent processing the same spend event
147+
// multiple times when watching multiple inputs that are spent in the
148+
// same transaction.
149+
lastSpendTxID *chainhash.Hash
150+
}
151+
152+
// stateSealed is a special method that is used to seal the interface.
153+
func (s *SyncSupplyProofsState) stateSealed() {}
154+
155+
// IsTerminal returns true if the target state is a terminal state.
156+
func (s *SyncSupplyProofsState) IsTerminal() bool {
157+
return false
158+
}
159+
160+
// String returns the name of the state.
161+
func (s *SyncSupplyProofsState) String() string {
162+
return "SyncSupplyProofsState"
163+
}
164+
165+
// VerifySupplyCommitState is the state where we verify a supply commitment
166+
// given a spend event and synced proofs.
167+
type VerifySupplyCommitState struct {
168+
lastCommitment *supplycommit.RootCommitment
169+
170+
// lastSpendTxID is the transaction ID of the last spend event we
171+
// processed. This is used to prevent processing the same spend event
172+
// multiple times when watching multiple inputs that are spent in the
173+
// same transaction.
174+
lastSpendTxID *chainhash.Hash
175+
}
176+
177+
// stateSealed is a special method that is used to seal the interface.
178+
func (v *VerifySupplyCommitState) stateSealed() {}
179+
180+
// IsTerminal returns true if the target state is a terminal state.
181+
func (v *VerifySupplyCommitState) IsTerminal() bool {
182+
return false
183+
}
184+
185+
// String returns the name of the state.
186+
func (v *VerifySupplyCommitState) String() string {
187+
return "VerifySupplyCommitState"
188+
}
189+
190+
// IdleState is the state we reach when a valid unspent commitment output is
191+
// observed. We wait for a spend to re-enter the sync state.
192+
type IdleState struct {
193+
lastCommitment *supplycommit.RootCommitment
194+
}
195+
196+
// stateSealed is a special method that is used to seal the interface.
197+
func (i *IdleState) stateSealed() {}
198+
199+
// IsTerminal returns true if the target state is a terminal state.
200+
func (i *IdleState) IsTerminal() bool {
201+
return false
202+
}
203+
204+
// String returns the name of the state.
205+
func (i *IdleState) String() string {
206+
return "IdleState"
207+
}
208+
209+
// FsmState is a type alias for the state of the supply verifier state machine.
210+
type FsmState = protofsm.State[Event, *Environment]
211+
212+
// FsmEvent is a type alias for the event type of the supply verifier state
213+
// machine.
214+
type FsmEvent = protofsm.EmittedEvent[Event]
215+
216+
// StateSub is a type alias for the state subscriber of the supply verifier
217+
// state machine.
218+
type StateSub = protofsm.StateSubscriber[Event, *Environment]

0 commit comments

Comments
 (0)