@@ -2,6 +2,7 @@ package supplycommit
2
2
3
3
import (
4
4
"bytes"
5
+ "context"
5
6
"fmt"
6
7
"io"
7
8
20
21
// ErrInvalidStateTransition is returned when we receive an unexpected
21
22
// event for a given state.
22
23
ErrInvalidStateTransition = fmt .Errorf ("invalid state transition" )
24
+
25
+ // ErrEventTimeout is returned when waiting for a synchronous event
26
+ // times out due to context cancellation.
27
+ ErrEventTimeout = fmt .Errorf ("event processing timeout" )
28
+
29
+ // ErrNilDoneChannel is returned when attempting to wait for a
30
+ // synchronous event that doesn't have a done channel.
31
+ ErrNilDoneChannel = fmt .Errorf ("done channel is nil" )
23
32
)
24
33
25
34
// Event is a special interface used to create the equivalent of a sum-type, but
@@ -96,15 +105,68 @@ type SupplyUpdateEvent interface {
96
105
Encode (io.Writer ) error
97
106
}
98
107
108
+ // SyncSupplyUpdateEvent is an interface that extends SupplyUpdateEvent with
109
+ // the ability to signal completion when the event has been processed.
110
+ type SyncSupplyUpdateEvent interface {
111
+ SupplyUpdateEvent
112
+
113
+ // SignalDone signals completion on the done channel if it exists.
114
+ // It sends the error (or nil for success) and does not block.
115
+ SignalDone (error )
116
+
117
+ // WaitForDone waits for the event to be processed by waiting on its
118
+ // done channel. This is a helper method that can be used by callers who
119
+ // want synchronous confirmation that their event has been persisted.
120
+ WaitForDone (context.Context ) error
121
+ }
122
+
123
+ // waitForDone is an internal helper function that waits for an event to be
124
+ // processed by waiting on its done channel.
125
+ func waitForDone (ctx context.Context , done chan error ) error {
126
+ if done == nil {
127
+ return ErrNilDoneChannel
128
+ }
129
+
130
+ select {
131
+ case err := <- done :
132
+ return err
133
+ case <- ctx .Done ():
134
+ return fmt .Errorf ("%w: %w" , ErrEventTimeout , ctx .Err ())
135
+ }
136
+ }
137
+
99
138
// NewIgnoreEvent signals that a caller wishes to update the ignore portion of
100
139
// the supply tree with a new outpoint + script key combo.
101
140
type NewIgnoreEvent struct {
102
141
universe.SignedIgnoreTuple
142
+
143
+ // Done is an optional channel that will receive an error (or nil for
144
+ // success) when the event has been processed and written to disk. If
145
+ // nil, the event is processed asynchronously.
146
+ Done chan error
103
147
}
104
148
105
149
// eventSealed is a special method that is used to seal the interface.
106
150
func (n * NewIgnoreEvent ) eventSealed () {}
107
151
152
+ // SignalDone signals completion on the done channel if it exists. It sends the
153
+ // error (or nil for success) and does not block.
154
+ func (n * NewIgnoreEvent ) SignalDone (err error ) {
155
+ if n .Done != nil {
156
+ select {
157
+ case n .Done <- err :
158
+ default :
159
+ }
160
+ }
161
+ }
162
+
163
+ // WaitForDone waits for the event to be processed by waiting on its done
164
+ // channel. This is a helper method that can be used by callers who want
165
+ // synchronous confirmation that their event has been persisted.
166
+ func (n * NewIgnoreEvent ) WaitForDone (ctx context.Context ) error {
167
+ return waitForDone (ctx , n .Done )
168
+ }
169
+
108
170
// BlockHeight returns the block height of the update.
109
171
func (n * NewIgnoreEvent ) BlockHeight () uint32 {
110
172
return n .SignedIgnoreTuple .IgnoreTuple .Val .BlockHeight
@@ -141,15 +203,42 @@ func (n *NewIgnoreEvent) Encode(w io.Writer) error {
141
203
// SupplyUpdateEvent interface.
142
204
var _ SupplyUpdateEvent = (* NewIgnoreEvent )(nil )
143
205
206
+ // A compile time assertion to ensure that NewIgnoreEvent implements the
207
+ // SyncSupplyUpdateEvent interface.
208
+ var _ SyncSupplyUpdateEvent = (* NewIgnoreEvent )(nil )
209
+
144
210
// NewBurnEvent signals that a caller wishes to update the burn portion of
145
211
// the supply tree with a new burnt asset.
146
212
type NewBurnEvent struct {
147
213
universe.BurnLeaf
214
+
215
+ // Done is an optional channel that will receive an error (or nil for
216
+ // success) when the event has been processed and written to disk.
217
+ // If nil, the event is processed asynchronously.
218
+ Done chan error
148
219
}
149
220
150
221
// eventSealed is a special method that is used to seal the interface.
151
222
func (n * NewBurnEvent ) eventSealed () {}
152
223
224
+ // SignalDone signals completion on the done channel if it exists. It sends
225
+ // the error (or nil for success) and does not block.
226
+ func (n * NewBurnEvent ) SignalDone (err error ) {
227
+ if n .Done != nil {
228
+ select {
229
+ case n .Done <- err :
230
+ default :
231
+ }
232
+ }
233
+ }
234
+
235
+ // WaitForDone waits for the event to be processed by waiting on its done
236
+ // channel. This is a helper method that can be used by callers who want
237
+ // synchronous confirmation that their event has been persisted.
238
+ func (n * NewBurnEvent ) WaitForDone (ctx context.Context ) error {
239
+ return waitForDone (ctx , n .Done )
240
+ }
241
+
153
242
// BlockHeight returns the block height of the update.
154
243
func (n * NewBurnEvent ) BlockHeight () uint32 {
155
244
return n .BurnLeaf .BurnProof .BlockHeight
@@ -187,6 +276,10 @@ func (n *NewBurnEvent) Encode(w io.Writer) error {
187
276
// SupplyUpdateEvent interface.
188
277
var _ SupplyUpdateEvent = (* NewBurnEvent )(nil )
189
278
279
+ // A compile time assertion to ensure that NewBurnEvent implements the
280
+ // SyncSupplyUpdateEvent interface.
281
+ var _ SyncSupplyUpdateEvent = (* NewBurnEvent )(nil )
282
+
190
283
// NewMintEvent signals that a caller wishes to update the mint portion of the
191
284
// supply tree with a new minted asset.
192
285
type NewMintEvent struct {
@@ -198,6 +291,11 @@ type NewMintEvent struct {
198
291
199
292
// MintHeight is the height of the block that contains the mint.
200
293
MintHeight uint32
294
+
295
+ // Done is an optional channel that will receive an error (or nil for
296
+ // success) when the event has been processed and written to disk.
297
+ // If nil, the event is processed asynchronously.
298
+ Done chan error
201
299
}
202
300
203
301
// BlockHeight returns the block height of the update.
@@ -208,6 +306,24 @@ func (n *NewMintEvent) BlockHeight() uint32 {
208
306
// eventSealed is a special method that is used to seal the interface.
209
307
func (n * NewMintEvent ) eventSealed () {}
210
308
309
+ // SignalDone signals completion on the done channel if it exists. It sends
310
+ // the error (or nil for success) and does not block.
311
+ func (n * NewMintEvent ) SignalDone (err error ) {
312
+ if n .Done != nil {
313
+ select {
314
+ case n .Done <- err :
315
+ default :
316
+ }
317
+ }
318
+ }
319
+
320
+ // WaitForDone waits for the event to be processed by waiting on its done
321
+ // channel. This is a helper method that can be used by callers who want
322
+ // synchronous confirmation that their event has been persisted.
323
+ func (n * NewMintEvent ) WaitForDone (ctx context.Context ) error {
324
+ return waitForDone (ctx , n .Done )
325
+ }
326
+
211
327
// ScriptKey returns the script key that is used to identify the target
212
328
// asset.
213
329
func (n * NewMintEvent ) ScriptKey () asset.SerializedKey {
@@ -279,6 +395,10 @@ func (n *NewMintEvent) Decode(r io.Reader) error {
279
395
// SupplyUpdateEvent interface.
280
396
var _ SupplyUpdateEvent = (* NewMintEvent )(nil )
281
397
398
+ // A compile time assertion to ensure that NewMintEvent implements the
399
+ // SyncSupplyUpdateEvent interface.
400
+ var _ SyncSupplyUpdateEvent = (* NewMintEvent )(nil )
401
+
282
402
// DefaultState is the idle state of the state machine. We start in this state
283
403
// when there are no pending changes that need to committed.
284
404
//
0 commit comments