9
9
"io"
10
10
"time"
11
11
12
+ "github.com/pkg/errors"
13
+
12
14
sdk "github.com/cosmos/cosmos-sdk/types"
13
15
executortypes "github.com/initia-labs/opinit-bots-go/executor/types"
14
16
nodetypes "github.com/initia-labs/opinit-bots-go/node/types"
@@ -27,92 +29,115 @@ func (bs *BatchSubmitter) rawBlockHandler(args nodetypes.RawBlockArgs) error {
27
29
pbb := new (cmtproto.Block )
28
30
err := proto .Unmarshal (args .BlockBytes , pbb )
29
31
if err != nil {
30
- return err
32
+ return errors . Wrap ( err , "failed to unmarshal block" )
31
33
}
32
34
33
35
err = bs .prepareBatch (args .BlockHeight , pbb .Header .Time )
34
36
if err != nil {
35
- return err
37
+ return errors . Wrap ( err , "failed to prepare batch" )
36
38
}
39
+
37
40
err = bs .handleBatch (args .BlockBytes )
38
41
if err != nil {
39
- return err
42
+ return errors . Wrap ( err , "failed to handle batch" )
40
43
}
41
44
42
45
err = bs .checkBatch (args .BlockHeight , pbb .Header .Time )
43
46
if err != nil {
44
- return err
47
+ return errors . Wrap ( err , "failed to check batch" )
45
48
}
46
49
50
+ // store the processed state into db with batch operation
47
51
batchKVs := make ([]types.RawKV , 0 )
48
52
batchKVs = append (batchKVs , bs .node .SyncInfoToRawKV (args .BlockHeight ))
49
- batchMsgkvs , err := bs .da .ProcessedMsgsToRawKV (bs .processedMsgs , false )
53
+ batchMsgKVs , err := bs .da .ProcessedMsgsToRawKV (bs .processedMsgs , false )
50
54
if err != nil {
51
- return err
55
+ return errors . Wrap ( err , "failed to convert processed messages to raw key value" )
52
56
}
53
- batchKVs = append (batchKVs , batchMsgkvs ... )
54
- if len (batchMsgkvs ) > 0 {
57
+ batchKVs = append (batchKVs , batchMsgKVs ... )
58
+ if len (batchMsgKVs ) > 0 {
55
59
batchKVs = append (batchKVs , bs .SubmissionInfoToRawKV (pbb .Header .Time .UnixNano ()))
56
60
}
57
61
err = bs .db .RawBatchSet (batchKVs ... )
58
62
if err != nil {
59
- return err
63
+ return errors . Wrap ( err , "failed to set raw batch" )
60
64
}
65
+
66
+ // broadcast processed messages
61
67
for _ , processedMsg := range bs .processedMsgs {
62
68
bs .da .BroadcastMsgs (processedMsg )
63
69
}
70
+
71
+ // clear processed messages
64
72
bs .processedMsgs = bs .processedMsgs [:0 ]
73
+
65
74
return nil
66
75
}
67
76
68
77
func (bs * BatchSubmitter ) prepareBatch (blockHeight uint64 , blockTime time.Time ) error {
78
+
79
+ // check whether the requested block height is reached to the l2 block number of the next batch info.
69
80
if nextBatchInfo := bs .NextBatchInfo (); nextBatchInfo != nil && nextBatchInfo .Output .L2BlockNumber < blockHeight {
81
+
82
+ // if the next batch info is reached, finalize the current batch and update the batch info.
70
83
if bs .batchWriter != nil {
71
84
err := bs .batchWriter .Close ()
72
85
if err != nil {
73
- return err
86
+ return errors . Wrap ( err , "failed to close batch writer" )
74
87
}
75
88
}
76
89
err := bs .batchFile .Truncate (0 )
77
90
if err != nil {
78
- return err
91
+ return errors . Wrap ( err , "failed to truncate batch file" )
79
92
}
80
93
_ , err = bs .batchFile .Seek (0 , 0 )
81
94
if err != nil {
82
- return err
95
+ return errors . Wrap ( err , "failed to seek batch file" )
83
96
}
97
+
98
+ // save sync info
84
99
err = bs .node .SaveSyncInfo (nextBatchInfo .Output .L2BlockNumber )
85
100
if err != nil {
86
- return err
101
+ return errors . Wrap ( err , "failed to save sync info" )
87
102
}
103
+
88
104
// set last processed block height to l2 block number
89
105
bs .node .SetSyncInfo (nextBatchInfo .Output .L2BlockNumber )
90
- bs .PopBatchInfo ()
106
+ bs .DequeueBatchInfo ()
91
107
92
108
// error will restart block process from nextBatchInfo.Output.L2BlockNumber + 1
93
109
return fmt .Errorf ("batch info updated: reset from %d" , nextBatchInfo .Output .L2BlockNumber )
94
110
}
95
111
96
112
if bs .batchHeader != nil {
113
+ // if the batch header end is not set, it means the batch is not finalized yet.
97
114
if bs .batchHeader .End == 0 {
98
115
return nil
99
116
}
117
+
100
118
err := bs .finalizeBatch (blockHeight )
101
119
if err != nil {
102
- return err
120
+ return errors . Wrap ( err , "failed to finalize batch" )
103
121
}
122
+
123
+ // update last submission time
104
124
bs .lastSubmissionTime = blockTime
105
125
}
106
- bs .batchHeader = & executortypes.BatchHeader {}
126
+
127
+ // reset batch header
107
128
var err error
129
+ bs .batchHeader = & executortypes.BatchHeader {}
130
+
108
131
// linux command gzip use level 6 as default
109
132
bs .batchWriter , err = gzip .NewWriterLevel (bs .batchFile , 6 )
110
133
if err != nil {
111
134
return err
112
135
}
136
+
113
137
return nil
114
138
}
115
139
140
+ // write block bytes to batch file
116
141
func (bs * BatchSubmitter ) handleBatch (blockBytes []byte ) error {
117
142
encodedBlockBytes := base64 .StdEncoding .EncodeToString (blockBytes )
118
143
_ , err := bs .batchWriter .Write (append ([]byte (encodedBlockBytes ), ',' ))
@@ -122,23 +147,27 @@ func (bs *BatchSubmitter) handleBatch(blockBytes []byte) error {
122
147
return nil
123
148
}
124
149
150
+ // finalize batch and create batch messages
125
151
func (bs * BatchSubmitter ) finalizeBatch (blockHeight uint64 ) error {
152
+
153
+ // write last block's commit to batch file
126
154
rawCommit , err := bs .node .QueryRawCommit (int64 (blockHeight ))
127
155
if err != nil {
128
- return err
156
+ return errors . Wrap ( err , "failed to query raw commit" )
129
157
}
130
158
encodedRawCommit := base64 .StdEncoding .EncodeToString (rawCommit )
131
159
_ , err = bs .batchWriter .Write ([]byte (encodedRawCommit ))
132
160
if err != nil {
133
- return err
161
+ return errors . Wrap ( err , "failed to write raw commit" )
134
162
}
135
163
err = bs .batchWriter .Close ()
136
164
if err != nil {
137
- return err
165
+ return errors . Wrap ( err , "failed to close batch writer" )
138
166
}
139
167
140
168
batchBuffer := make ([]byte , bs .batchCfg .MaxChunkSize )
141
169
checksums := make ([][]byte , 0 )
170
+
142
171
// room for batch header
143
172
bs .processedMsgs = append (bs .processedMsgs , nodetypes.ProcessedMsgs {
144
173
Timestamp : time .Now ().UnixNano (),
@@ -152,7 +181,9 @@ func (bs *BatchSubmitter) finalizeBatch(blockHeight uint64) error {
152
181
} else if readLength == 0 {
153
182
break
154
183
}
155
- batchBuffer = batchBuffer [:readLength ]
184
+
185
+ // trim the buffer to the actual read length
186
+ batchBuffer := batchBuffer [:readLength ]
156
187
msg , err := bs .createBatchMsg (batchBuffer )
157
188
if err != nil {
158
189
return err
@@ -168,6 +199,8 @@ func (bs *BatchSubmitter) finalizeBatch(blockHeight uint64) error {
168
199
break
169
200
}
170
201
}
202
+
203
+ // update batch header
171
204
bs .batchHeader .Chunks = checksums
172
205
headerBytes , err := json .Marshal (bs .batchHeader )
173
206
if err != nil {
@@ -178,6 +211,8 @@ func (bs *BatchSubmitter) finalizeBatch(blockHeight uint64) error {
178
211
return err
179
212
}
180
213
bs .processedMsgs [0 ].Msgs = []sdk.Msg {msg }
214
+
215
+ // reset batch file
181
216
err = bs .batchFile .Truncate (0 )
182
217
if err != nil {
183
218
return err
@@ -186,23 +221,32 @@ func (bs *BatchSubmitter) finalizeBatch(blockHeight uint64) error {
186
221
if err != nil {
187
222
return err
188
223
}
224
+
189
225
return nil
190
226
}
191
227
192
228
func (bs * BatchSubmitter ) checkBatch (blockHeight uint64 , blockTime time.Time ) error {
193
229
info , err := bs .batchFile .Stat ()
194
230
if err != nil {
195
- return err
231
+ return errors . Wrap ( err , "failed to get batch file stat" )
196
232
}
197
233
234
+ // if the block time is after the last submission time + submission interval * 2/3
235
+ // or the block time is after the last submission time + max submission time
236
+ // or the batch file size is greater than (max chunks - 1) * max chunk size
237
+ // then finalize the batch
198
238
if blockTime .After (bs .lastSubmissionTime .Add (bs .bridgeInfo .BridgeConfig .SubmissionInterval * 2 / 3 )) ||
199
239
blockTime .After (bs .lastSubmissionTime .Add (time .Duration (bs .batchCfg .MaxSubmissionTime )* time .Second )) ||
200
240
info .Size () > (bs .batchCfg .MaxChunks - 1 )* bs .batchCfg .MaxChunkSize {
241
+
242
+ // finalize the batch
201
243
bs .batchHeader .End = blockHeight
202
244
}
245
+
203
246
return nil
204
247
}
205
248
249
+ // TODO: support celestia
206
250
func (bs * BatchSubmitter ) createBatchMsg (batchBytes []byte ) (sdk.Msg , error ) {
207
251
submitter , err := bs .da .GetAddressStr ()
208
252
if err != nil {
@@ -216,6 +260,7 @@ func (bs *BatchSubmitter) createBatchMsg(batchBytes []byte) (sdk.Msg, error) {
216
260
), nil
217
261
}
218
262
263
+ // UpdateBatchInfo appends the batch info with the given chain, submitter, output index, and l2 block number
219
264
func (bs * BatchSubmitter ) UpdateBatchInfo (chain string , submitter string , outputIndex uint64 , l2BlockNumber uint64 ) {
220
265
bs .batchInfoMu .Lock ()
221
266
defer bs .batchInfoMu .Unlock ()
@@ -231,13 +276,15 @@ func (bs *BatchSubmitter) UpdateBatchInfo(chain string, submitter string, output
231
276
})
232
277
}
233
278
279
+ // BatchInfo returns the current batch info
234
280
func (bs * BatchSubmitter ) BatchInfo () * ophosttypes.BatchInfoWithOutput {
235
281
bs .batchInfoMu .Lock ()
236
282
defer bs .batchInfoMu .Unlock ()
237
283
238
284
return & bs .batchInfos [0 ]
239
285
}
240
286
287
+ // NextBatchInfo returns the next batch info in the queue
241
288
func (bs * BatchSubmitter ) NextBatchInfo () * ophosttypes.BatchInfoWithOutput {
242
289
bs .batchInfoMu .Lock ()
243
290
defer bs .batchInfoMu .Unlock ()
@@ -247,7 +294,8 @@ func (bs *BatchSubmitter) NextBatchInfo() *ophosttypes.BatchInfoWithOutput {
247
294
return & bs .batchInfos [1 ]
248
295
}
249
296
250
- func (bs * BatchSubmitter ) PopBatchInfo () {
297
+ // DequeueBatchInfo removes the first batch info from the queue
298
+ func (bs * BatchSubmitter ) DequeueBatchInfo () {
251
299
bs .batchInfoMu .Lock ()
252
300
defer bs .batchInfoMu .Unlock ()
253
301
0 commit comments