@@ -4,7 +4,11 @@ import (
4
4
"bytes"
5
5
"encoding/binary"
6
6
7
+ "github.com/gogo/protobuf/proto"
8
+ tmbytes "github.com/lazyledger/lazyledger-core/libs/bytes"
9
+ tmproto "github.com/lazyledger/lazyledger-core/proto/tendermint/types"
7
10
"github.com/lazyledger/nmt/namespace"
11
+ "github.com/lazyledger/rsmt2d"
8
12
)
9
13
10
14
// Share contains the raw share data without the corresponding namespace.
@@ -42,8 +46,9 @@ func (tx Tx) MarshalDelimited() ([]byte, error) {
42
46
lenBuf := make ([]byte , binary .MaxVarintLen64 )
43
47
length := uint64 (len (tx ))
44
48
n := binary .PutUvarint (lenBuf , length )
49
+ out := append (lenBuf [:n ], tx ... )
45
50
46
- return append ( lenBuf [: n ], tx ... ) , nil
51
+ return out , nil
47
52
}
48
53
49
54
// MarshalDelimited marshals the raw data (excluding the namespace) of this
@@ -83,12 +88,10 @@ func splitContiguous(nid namespace.ID, rawDatas [][]byte) []NamespacedShare {
83
88
innerIndex := 0
84
89
for outerIndex < len (rawDatas ) {
85
90
var rawData []byte
86
- startIndex := 0
87
- rawData , outerIndex , innerIndex , startIndex = getNextChunk (rawDatas , outerIndex , innerIndex , TxShareSize )
88
- rawShare := append (append (append (
89
- make ([]byte , 0 , len (nid )+ 1 + len (rawData )),
91
+ rawData , outerIndex , innerIndex , _ = getNextChunk (rawDatas , outerIndex , innerIndex , MsgShareSize )
92
+ rawShare := append (append (
93
+ make ([]byte , 0 , MsgShareSize ),
90
94
nid ... ),
91
- byte (startIndex )),
92
95
rawData ... )
93
96
paddedShare := zeroPadIfNecessary (rawShare , ShareSize )
94
97
share := NamespacedShare {paddedShare , nid }
@@ -97,8 +100,6 @@ func splitContiguous(nid namespace.ID, rawDatas [][]byte) []NamespacedShare {
97
100
return shares
98
101
}
99
102
100
- // TODO(ismail): implement corresponding merge method for clients requesting
101
- // shares for a particular namespace
102
103
func split (rawData []byte , nid namespace.ID ) []NamespacedShare {
103
104
shares := make ([]NamespacedShare , 0 )
104
105
firstRawShare := append (append (
@@ -184,3 +185,328 @@ func zeroPadIfNecessary(share []byte, width int) []byte {
184
185
}
185
186
return share
186
187
}
188
+
189
+ // DataFromSquare extracts block data from an extended data square.
190
+ func DataFromSquare (eds * rsmt2d.ExtendedDataSquare ) (Data , error ) {
191
+ originalWidth := eds .Width () / 2
192
+
193
+ // sort block data by namespace
194
+ // define a slice for the raw share data of each type
195
+ var (
196
+ // transactions
197
+ txsShares [][]byte
198
+ // intermediate state roots
199
+ isrShares [][]byte
200
+ // evidence
201
+ evdShares [][]byte
202
+ // messages
203
+ msgShares [][]byte
204
+ )
205
+
206
+ // iterate over each row index
207
+ for x := uint (0 ); x < originalWidth ; x ++ {
208
+ // iterate over each col index
209
+ for y := uint (0 ); y < originalWidth ; y ++ {
210
+ // sort the data of that share types via namespace
211
+ share := eds .Cell (x , y )
212
+ nid := share [:NamespaceSize ]
213
+ switch {
214
+ case bytes .Compare (TxNamespaceID , nid ) == 0 :
215
+ txsShares = append (txsShares , share )
216
+
217
+ case bytes .Compare (IntermediateStateRootsNamespaceID , nid ) == 0 :
218
+ isrShares = append (isrShares , share )
219
+
220
+ case bytes .Compare (EvidenceNamespaceID , nid ) == 0 :
221
+ evdShares = append (evdShares , share )
222
+
223
+ case bytes .Compare (TailPaddingNamespaceID , nid ) == 0 :
224
+ continue
225
+
226
+ // every other namespaceID should be a message
227
+ default :
228
+ msgShares = append (msgShares , share )
229
+ }
230
+ }
231
+ }
232
+
233
+ // pass the raw share data to their respective parsers
234
+ txs := parseTxs (txsShares )
235
+
236
+ isrs := parseIsrs (isrShares )
237
+
238
+ evd , err := parseEvd (evdShares )
239
+ if err != nil {
240
+ return Data {}, err
241
+ }
242
+
243
+ msgs , err := parseMsgs (msgShares )
244
+ if err != nil {
245
+ return Data {}, err
246
+ }
247
+
248
+ return Data {
249
+ Txs : txs ,
250
+ IntermediateStateRoots : isrs ,
251
+ Evidence : evd ,
252
+ Messages : msgs ,
253
+ }, nil
254
+ }
255
+
256
+ func parseTxs (shares [][]byte ) Txs {
257
+ // parse the sharse
258
+ rawTxs := parseShares (shares )
259
+
260
+ // convert to the Tx type
261
+ txs := make (Txs , len (rawTxs ))
262
+ for i := 0 ; i < len (txs ); i ++ {
263
+ txs [i ] = Tx (rawTxs [i ])
264
+ }
265
+
266
+ return txs
267
+ }
268
+
269
+ func parseIsrs (shares [][]byte ) IntermediateStateRoots {
270
+ rawISRs := parseShares (shares )
271
+
272
+ ISRs := make ([]tmbytes.HexBytes , len (rawISRs ))
273
+ for i := 0 ; i < len (ISRs ); i ++ {
274
+ ISRs [i ] = rawISRs [i ]
275
+ }
276
+
277
+ return IntermediateStateRoots {RawRootsList : ISRs }
278
+ }
279
+
280
+ // parseMsgs collects all messages from the shares provided
281
+ func parseEvd (shares [][]byte ) (EvidenceData , error ) {
282
+ rawEvd := parseShares (shares )
283
+
284
+ evdList := make (EvidenceList , len (rawEvd ))
285
+
286
+ // parse into protobuf bytes
287
+ for i := 0 ; i < len (rawEvd ); i ++ {
288
+ // unmarshal the evidence
289
+ var protoEvd * tmproto.Evidence
290
+ err := proto .Unmarshal (rawEvd [i ], protoEvd )
291
+ if err != nil {
292
+ return EvidenceData {}, err
293
+ }
294
+
295
+ evd , err := EvidenceFromProto (protoEvd )
296
+ if err != nil {
297
+ return EvidenceData {}, err
298
+ }
299
+
300
+ evdList [i ] = evd
301
+ }
302
+
303
+ return EvidenceData {Evidence : evdList }, nil
304
+ }
305
+
306
+ // parseMsgs collects all messages from the shares provided
307
+ func parseMsgs (shares [][]byte ) (Messages , error ) {
308
+ msgList , err := parseMsgShares (shares )
309
+ if err != nil {
310
+ return MessagesEmpty , err
311
+ }
312
+
313
+ return Messages {
314
+ MessagesList : msgList ,
315
+ }, nil
316
+ }
317
+
318
+ // parseShares iterates through raw shares and separates the contiguous chunks
319
+ // of data. we use this for transactions, evidence, and intermediate state roots
320
+ func parseShares (shares [][]byte ) [][]byte {
321
+ currentShare := shares [0 ][NamespaceSize + ShareReservedBytes :]
322
+ txLen := uint8 (shares [0 ][NamespaceSize ])
323
+ var parsed [][]byte
324
+ for cursor := 0 ; cursor < len (shares ); {
325
+ var p []byte
326
+
327
+ currentShare , cursor , txLen , p = next (shares , currentShare , cursor , txLen )
328
+ if p != nil {
329
+ parsed = append (parsed , p )
330
+ }
331
+ }
332
+
333
+ return parsed
334
+ }
335
+
336
+ // next returns the next chunk of a contiguous share. Used for parsing
337
+ // transaction, evidence, and intermediate state root block data.
338
+ func next (shares [][]byte , current []byte , cursor int , l uint8 ) ([]byte , int , uint8 , []byte ) {
339
+ switch {
340
+ // the rest of the shares should be tail padding
341
+ case l == 0 :
342
+
343
+ cursor ++
344
+ if len (shares ) != cursor {
345
+ panic ("contiguous share of length zero" )
346
+ }
347
+ return nil , cursor , 0 , nil
348
+
349
+ // the tx is contained in the current share
350
+ case int (l ) < len (current ):
351
+
352
+ tx := append (make ([]byte , 0 , l ), current [:l ]... )
353
+
354
+ // set the next txLen and update the next share
355
+ txLen := current [l ]
356
+
357
+ // make sure that nothing panics if txLen is at the end of the share
358
+ if len (current ) < int (l )+ ShareReservedBytes + 1 {
359
+ cursor ++
360
+ return shares [cursor ][NamespaceSize :], cursor , txLen , tx
361
+ }
362
+
363
+ current := current [l + ShareReservedBytes :]
364
+ // try printing current everytime instead
365
+
366
+ return current , cursor , txLen , tx
367
+
368
+ // the tx requires some portion of the following share
369
+ case int (l ) > len (current ):
370
+
371
+ cursor ++
372
+
373
+ // merge the current and the next share
374
+
375
+ current := append (current , shares [cursor ][NamespaceSize :]... )
376
+
377
+ // try again using the next share
378
+ return next (shares , current , cursor , l )
379
+
380
+ // the tx is exactly the same size of the current share
381
+ case int (l ) == len (current ):
382
+
383
+ tx := make ([]byte , l )
384
+ copy (tx , current )
385
+
386
+ cursor ++
387
+
388
+ // if this is the end of shares only return the tx
389
+ if cursor == len (shares ) {
390
+ return []byte {}, cursor , 0 , tx
391
+ }
392
+
393
+ // set the next txLen and next share
394
+ next := shares [cursor ][NamespaceSize + ShareReservedBytes :]
395
+ nextTxLen := shares [cursor ][NamespaceSize ]
396
+
397
+ return next , cursor , nextTxLen , tx
398
+ }
399
+
400
+ // this code is unreachable but the compiler doesn't know that
401
+ return nil , 0 , 0 , nil
402
+ }
403
+
404
+ // parseMessages iterates through raw shares and separates the contiguous chunks
405
+ // of data. we use this for transactions, evidence, and intermediate state roots
406
+ func parseMsgShares (shares [][]byte ) ([]Message , error ) {
407
+ // set the first nid and current share
408
+ nid := shares [0 ][:NamespaceSize ]
409
+ currentShare := shares [0 ][NamespaceSize :]
410
+
411
+ // find and remove the msg len delimiter
412
+ currentShare , msgLen , err := tailorMsg (currentShare )
413
+ if err != nil {
414
+ return nil , err
415
+ }
416
+
417
+ var msgs []Message
418
+ for cursor := 0 ; cursor < len (shares ); {
419
+ var msg Message
420
+ currentShare , cursor , msgLen , msg , err = nextMsg (
421
+ shares ,
422
+ currentShare ,
423
+ nid ,
424
+ cursor ,
425
+ msgLen ,
426
+ )
427
+ if err != nil {
428
+ return nil , err
429
+ }
430
+ if msg .Data != nil {
431
+ msgs = append (msgs , msg )
432
+ }
433
+ }
434
+
435
+ return msgs , nil
436
+ }
437
+
438
+ // next returns the next chunk of a contiguous share. Used for parsing
439
+ // transaction, evidence, and intermediate state root block data.
440
+ func nextMsg (shares [][]byte , current , nid []byte , cursor int , l uint64 ) ([]byte , int , uint64 , Message , error ) {
441
+ switch {
442
+ // the rest of the share should be tail padding
443
+ case l == 0 :
444
+ cursor ++
445
+ if len (shares ) != cursor {
446
+ panic ("message of length zero" )
447
+ }
448
+ return nil , cursor , 0 , MessageEmpty , nil
449
+
450
+ // the msg is contained in the current share
451
+ case int (l ) < len (current ):
452
+ msg := Message {NamespaceID : nid , Data : current [:l ]}
453
+
454
+ // set the next msgLen and update the next share
455
+ next , msgLen , err := tailorMsg (current [l :])
456
+ if err != nil {
457
+ return nil , 0 , 0 , MessageEmpty , err
458
+ }
459
+
460
+ return next , cursor , msgLen , msg , nil
461
+
462
+ // the msg requires some portion of the following share
463
+ case int (l ) > len (current ):
464
+ cursor ++
465
+
466
+ // merge the current and the next share
467
+ current := append (current , shares [cursor ][NamespaceSize :]... )
468
+
469
+ // try again using the next share
470
+ return nextMsg (shares , current , nid , cursor , l )
471
+
472
+ // the msg is exactly the same size of the current share
473
+ case l == uint64 (len (current )):
474
+ msg := Message {NamespaceID : nid , Data : current }
475
+
476
+ cursor ++
477
+
478
+ // if this is the end of shares only return the msg
479
+ if cursor == len (shares ) {
480
+ return []byte {}, cursor , 0 , msg , nil
481
+ }
482
+
483
+ // set the next msgLen and next share
484
+ next , nextMsgLen , err := tailorMsg (shares [cursor ][NamespaceSize :])
485
+ if err != nil {
486
+ return nil , 0 , 0 , MessageEmpty , err
487
+ }
488
+
489
+ return next , cursor , nextMsgLen , msg , nil
490
+ }
491
+
492
+ // this code is unreachable but the compiler doesn't know that
493
+ return nil , 0 , 0 , MessageEmpty , nil
494
+ }
495
+
496
+ // tailorMsg finds and returns the length delimiter of the message provided
497
+ // while also removing the delimiter bytes from the input
498
+ func tailorMsg (input []byte ) ([]byte , uint64 , error ) {
499
+ // read the length of the message
500
+ r := bytes .NewBuffer (input [:binary .MaxVarintLen64 ])
501
+ msgLen , err := binary .ReadUvarint (r )
502
+ if err != nil {
503
+ return nil , 0 , err
504
+ }
505
+
506
+ // calculate the number of bytes used by the delimiter
507
+ lenBuf := make ([]byte , binary .MaxVarintLen64 )
508
+ n := binary .PutUvarint (lenBuf , msgLen )
509
+
510
+ // return the input without the length delimiter
511
+ return input [n + 1 :], msgLen , nil
512
+ }
0 commit comments