Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9d7d511

Browse files
evan-forbesliamsiadlerjohnHlib Kanunnikovrenaynay
committedSep 23, 2021
Refactor DAH creation to better accommodate celestia-node use case (#539)
* Basic DA functionality (#83) * move Messages field to the end of Block.Data * Add some constants for share computation and the NMT: - also a bunch of todos regarding shares computation * First (compiling) stab on creating shares * Test with Evidence and fix bug discovered by test * remove resolved todos * introduce split method * Introduce LenDelimitedMarshaler interface and some reformatting * Introduce TxLenDelimitedMarshaler * add some test cases * fix some comments * fix some comments & linter * Add reserved namespaces to params * Move ll-specific consts into a separate file (consts.go) * Add MarshalDelimited to HexBytes * Add tail-padding shares * Add ComputeShares method on Data to compute all shares * Fix compute the next square num and not the next power of two * lints * Unexport MakeShares function: - it's likely to change and it doesn't have to be part of the public API * lints 2 * First stab on computing row/column roots * fix rebase glitches: - move DA related constants out of params.go * refactor MakeBlock to take in interm. state roots and messages * refactor state.MakeBlock too * Add todos LenDelimitedMarshaler and extract appendShares logic * Simplify shares computation: remove LenDelimitedMarshaler abstraction * actually use DA header to compute the DataRoot everywhere (will lead to failing tests for sure) * WIP: Update block related core data structures in protobuf too * WIP: fix zero shares edge-case and get rid of Block.Data.hash (use dataAvailabilityHeader.Hash() instead) * Fixed tests, only 3 failing tests to go: TestReapMaxBytesMaxGas, TestTxFilter, TestMempoolFilters * Fix TestTxFilter: - the size of the wrapping Data{} proto message increased a few bytes * Fix Message proto and `DataFromProto` * Fix last 2 remaining tests related to the increased block/block.Data size * Use infectious lib instead of leopard * proto-lint: snake_case * some lints and minor changes * linter * panic if pushing to tree fails, extend Data.ToProto() * revert renaming in comment * add todo about refactoring as soon as the rsmt2d allows the user to choose the merkle tree * clean up some unused test helper functions * linter * still debugging the exact right number of bytes for max data... * Implement spec-compliant share splitting (#246) * Export block data compute shares. * Refactor to use ShareSize constant directly. * Change message splitting to prefix namespace ID. * Implement chunking for contiguous. * Add termination condition. * Rename append contiguous to split contiguous. * Update test for small tx. * Add test for two contiguous. * Make tx and msg adjusted share sizes exported constants. * Panic on hopefully-unreachable condition instead of silently skipping. * Update hardcoded response for block format. Co-authored-by: Ismail Khoffi <[email protected]> * fix overwrite bug (#251) * fix overwrite bug and stop splitting shares of size MsgShareSize * remove ineffectual code * review feedback: better docs Co-authored-by: Ismail Khoffi <[email protected]> * remove uneeded copy and only fix the source of the bug Co-authored-by: Ismail Khoffi <[email protected]> * fix overwrite bug while also being consistent with using NamespacedShares * update to the latest rsmt2d for the nmt wrapper Co-authored-by: Ismail Khoffi <[email protected]> * Spec compliant merge shares (#261) * start spec compliant share merging * refactor and finish unit testing * whoops * linter gods * fix initial changes and use constants * use constant * more polish * docs fix* review feedback: docs and out of range panic protection * review feedback: add panic protection from empty input * use constant instead of recalculating `ShareSize`* don't redeclare existing var* be more explicit with returned nil* use constant instead of recalculating `ShareSize`* review feedback: use consistent capitalization * stop accepting reserved namespaces as normal messages * use a descriptive var name for message length * linter and comparison fix * reorg tests, add test for parse delimiter, DataFromBlock and fix evidence marshal bug * catch error for linter * update test MakeShares to include length delimiters for the SHARE_RESERVED_BYTE * minor iteration change * refactor share splitting to fix bug * fix all bugs with third and final refactor * fix conflict * revert unnecessary changes * review feedback: better docs* reivew feedback: add comment for safeLen * review feedback: remove unnecessay comments * review feedback: split up share merging and splitting into their own files * review feedback: more descriptive var names * fix accidental change * add some constant docs * spelling error Co-authored-by: Hlib Kanunnikov <[email protected]> Co-authored-by: John Adler <[email protected]> Co-authored-by: Ismail Khoffi <[email protected]> * refactor to better accomodate real world use cases (celestia node) Co-authored-by: rene <[email protected]> * thank you linter Co-authored-by: Ismail Khoffi <[email protected]> Co-authored-by: John Adler <[email protected]> Co-authored-by: Hlib Kanunnikov <[email protected]> Co-authored-by: rene <[email protected]>
1 parent c5339b9 commit 9d7d511

File tree

5 files changed

+64
-48
lines changed

5 files changed

+64
-48
lines changed
 

‎pkg/consts/consts.go

+3
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,8 @@ var (
6363
// NewBaseHashFunc change accordingly if another hash.Hash should be used as a base hasher in the NMT:
6464
NewBaseHashFunc = sha256.New
6565

66+
// DefaultCodec is the default codec creator used for data erasure
67+
// TODO(ismail): for better efficiency and a larger number shares
68+
// we should switch to the rsmt2d.LeopardFF16 codec:
6669
DefaultCodec = rsmt2d.NewRSGF8Codec
6770
)

‎pkg/da/data_availability_header.go

+25-32
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import (
1414
)
1515

1616
const (
17-
maxDAHSize = consts.MaxSquareSize * 2
18-
minDAHSize = consts.MinSquareSize * 2
17+
maxExtendedSquareWidth = consts.MaxSquareSize * 2
18+
minExtendedSquareWidth = consts.MinSquareSize * 2
1919
)
2020

2121
// DataAvailabilityHeader (DAHeader) contains the row and column roots of the erasure
@@ -38,10 +38,23 @@ type DataAvailabilityHeader struct {
3838
}
3939

4040
// NewDataAvailabilityHeader generates a DataAvailability header using the provided square size and shares
41-
func NewDataAvailabilityHeader(squareSize uint64, shares [][]byte) (DataAvailabilityHeader, error) {
41+
func NewDataAvailabilityHeader(eds *rsmt2d.ExtendedDataSquare) DataAvailabilityHeader {
42+
// generate the row and col roots using the EDS
43+
dah := DataAvailabilityHeader{
44+
RowsRoots: eds.RowRoots(),
45+
ColumnRoots: eds.ColRoots(),
46+
}
47+
48+
// generate the hash of the data using the new roots
49+
dah.Hash()
50+
51+
return dah
52+
}
53+
54+
func ExtendShares(squareSize uint64, shares [][]byte) (*rsmt2d.ExtendedDataSquare, error) {
4255
// Check that square size is with range
4356
if squareSize < consts.MinSquareSize || squareSize > consts.MaxSquareSize {
44-
return DataAvailabilityHeader{}, fmt.Errorf(
57+
return nil, fmt.Errorf(
4558
"invalid square size: min %d max %d provided %d",
4659
consts.MinSquareSize,
4760
consts.MaxSquareSize,
@@ -50,32 +63,14 @@ func NewDataAvailabilityHeader(squareSize uint64, shares [][]byte) (DataAvailabi
5063
}
5164
// check that valid number of shares have been provided
5265
if squareSize*squareSize != uint64(len(shares)) {
53-
return DataAvailabilityHeader{}, fmt.Errorf(
66+
return nil, fmt.Errorf(
5467
"must provide valid number of shares for square size: got %d wanted %d",
5568
len(shares),
5669
squareSize*squareSize,
5770
)
5871
}
59-
6072
tree := wrapper.NewErasuredNamespacedMerkleTree(squareSize)
61-
62-
// TODO(ismail): for better efficiency and a larger number shares
63-
// we should switch to the rsmt2d.LeopardFF16 codec:
64-
extendedDataSquare, err := rsmt2d.ComputeExtendedDataSquare(shares, rsmt2d.NewRSGF8Codec(), tree.Constructor)
65-
if err != nil {
66-
return DataAvailabilityHeader{}, err
67-
}
68-
69-
// generate the row and col roots using the EDS
70-
dah := DataAvailabilityHeader{
71-
RowsRoots: extendedDataSquare.RowRoots(),
72-
ColumnRoots: extendedDataSquare.ColRoots(),
73-
}
74-
75-
// generate the hash of the data using the new roots
76-
dah.Hash()
77-
78-
return dah, nil
73+
return rsmt2d.ComputeExtendedDataSquare(shares, consts.DefaultCodec(), tree.Constructor)
7974
}
8075

8176
// String returns hex representation of merkle hash of the DAHeader.
@@ -143,16 +138,16 @@ func (dah *DataAvailabilityHeader) ValidateBasic() error {
143138
if dah == nil {
144139
return errors.New("nil data availability header is not valid")
145140
}
146-
if len(dah.ColumnRoots) < minDAHSize || len(dah.RowsRoots) < minDAHSize {
141+
if len(dah.ColumnRoots) < minExtendedSquareWidth || len(dah.RowsRoots) < minExtendedSquareWidth {
147142
return fmt.Errorf(
148143
"minimum valid DataAvailabilityHeader has at least %d row and column roots",
149-
minDAHSize,
144+
minExtendedSquareWidth,
150145
)
151146
}
152-
if len(dah.ColumnRoots) > maxDAHSize || len(dah.RowsRoots) > maxDAHSize {
147+
if len(dah.ColumnRoots) > maxExtendedSquareWidth || len(dah.RowsRoots) > maxExtendedSquareWidth {
153148
return fmt.Errorf(
154149
"maximum valid DataAvailabilityHeader has at most %d row and column roots",
155-
maxDAHSize,
150+
maxExtendedSquareWidth,
156151
)
157152
}
158153
if len(dah.ColumnRoots) != len(dah.RowsRoots) {
@@ -190,13 +185,11 @@ func MinDataAvailabilityHeader() DataAvailabilityHeader {
190185
for i := 0; i < consts.MinSharecount; i++ {
191186
shares[i] = tailPaddingShare
192187
}
193-
dah, err := NewDataAvailabilityHeader(
194-
consts.MinSquareSize,
195-
shares,
196-
)
188+
eds, err := ExtendShares(consts.MinSquareSize, shares)
197189
if err != nil {
198190
panic(err)
199191
}
192+
dah := NewDataAvailabilityHeader(eds)
200193
return dah
201194
}
202195

‎pkg/da/data_availability_header_test.go

+31-11
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,13 @@ func TestNewDataAvailabilityHeader(t *testing.T) {
3737
type test struct {
3838
name string
3939
expectedHash []byte
40-
expectedErr bool
4140
squareSize uint64
4241
shares [][]byte
4342
}
4443

4544
tests := []test{
4645
{
47-
name: "typical",
48-
expectedErr: false,
46+
name: "typical",
4947
expectedHash: []byte{
5048
0xfe, 0x9c, 0x6b, 0xd8, 0xe5, 0x7c, 0xd1, 0x5d, 0x1f, 0xd6, 0x55, 0x7e, 0x87, 0x7d, 0xd9, 0x7d,
5149
0xdb, 0xf2, 0x66, 0xfa, 0x60, 0x24, 0x2d, 0xb3, 0xa0, 0x9c, 0x4f, 0x4e, 0x5b, 0x2a, 0x2c, 0x2a,
@@ -54,15 +52,36 @@ func TestNewDataAvailabilityHeader(t *testing.T) {
5452
shares: generateShares(4, 1),
5553
},
5654
{
57-
name: "max square size",
58-
expectedErr: false,
55+
name: "max square size",
5956
expectedHash: []byte{
6057
0xe2, 0x87, 0x23, 0xd0, 0x2d, 0x54, 0x25, 0x5f, 0x79, 0x43, 0x8e, 0xfb, 0xb7, 0xe8, 0xfa, 0xf5,
6158
0xbf, 0x93, 0x50, 0xb3, 0x64, 0xd0, 0x4f, 0xa7, 0x7b, 0xb1, 0x83, 0x3b, 0x8, 0xba, 0xd3, 0xa4,
6259
},
6360
squareSize: consts.MaxSquareSize,
6461
shares: generateShares(consts.MaxSquareSize*consts.MaxSquareSize, 99),
6562
},
63+
}
64+
65+
for _, tt := range tests {
66+
tt := tt
67+
eds, err := ExtendShares(tt.squareSize, tt.shares)
68+
require.NoError(t, err)
69+
resdah := NewDataAvailabilityHeader(eds)
70+
require.Equal(t, tt.squareSize*2, uint64(len(resdah.ColumnRoots)), tt.name)
71+
require.Equal(t, tt.squareSize*2, uint64(len(resdah.RowsRoots)), tt.name)
72+
require.Equal(t, tt.expectedHash, resdah.hash, tt.name)
73+
}
74+
}
75+
76+
func TestExtendShares(t *testing.T) {
77+
type test struct {
78+
name string
79+
expectedErr bool
80+
squareSize uint64
81+
shares [][]byte
82+
}
83+
84+
tests := []test{
6685
{
6786
name: "too large square size",
6887
expectedErr: true,
@@ -79,15 +98,13 @@ func TestNewDataAvailabilityHeader(t *testing.T) {
7998

8099
for _, tt := range tests {
81100
tt := tt
82-
resdah, err := NewDataAvailabilityHeader(tt.squareSize, tt.shares)
101+
eds, err := ExtendShares(tt.squareSize, tt.shares)
83102
if tt.expectedErr {
84103
require.NotNil(t, err)
85104
continue
86105
}
87106
require.NoError(t, err)
88-
require.Equal(t, tt.squareSize*2, uint64(len(resdah.ColumnRoots)), tt.name)
89-
require.Equal(t, tt.squareSize*2, uint64(len(resdah.RowsRoots)), tt.name)
90-
require.Equal(t, tt.expectedHash, resdah.hash, tt.name)
107+
require.Equal(t, tt.squareSize*2, eds.Width(), tt.name)
91108
}
92109
}
93110

@@ -98,8 +115,9 @@ func TestDataAvailabilityHeaderProtoConversion(t *testing.T) {
98115
}
99116

100117
shares := generateShares(consts.MaxSquareSize*consts.MaxSquareSize, 1)
101-
bigdah, err := NewDataAvailabilityHeader(consts.MaxSquareSize, shares)
118+
eds, err := ExtendShares(consts.MaxSquareSize, shares)
102119
require.NoError(t, err)
120+
bigdah := NewDataAvailabilityHeader(eds)
103121

104122
tests := []test{
105123
{
@@ -133,8 +151,10 @@ func Test_DAHValidateBasic(t *testing.T) {
133151
}
134152

135153
shares := generateShares(consts.MaxSquareSize*consts.MaxSquareSize, 1)
136-
bigdah, err := NewDataAvailabilityHeader(consts.MaxSquareSize, shares)
154+
eds, err := ExtendShares(consts.MaxSquareSize, shares)
137155
require.NoError(t, err)
156+
bigdah := NewDataAvailabilityHeader(eds)
157+
138158
// make a mutant dah that has too many roots
139159
var tooBigDah DataAvailabilityHeader
140160
tooBigDah.ColumnRoots = make([][]byte, consts.MaxSquareSize*consts.MaxSquareSize)

‎pkg/wrapper/nmt_wrapper_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestPushErasuredNamespacedMerkleTree(t *testing.T) {
2727
tree := n.Constructor()
2828

2929
// push test data to the tree
30-
for i, d := range generateErasuredData(t, tc.squareSize, rsmt2d.NewRSGF8Codec()) {
30+
for i, d := range generateErasuredData(t, tc.squareSize, consts.DefaultCodec()) {
3131
// push will panic if there's an error
3232
tree.Push(d, rsmt2d.SquareIndex{Axis: uint(0), Cell: uint(i)})
3333
}
@@ -64,7 +64,7 @@ func TestErasureNamespacedMerkleTreePanics(t *testing.T) {
6464
"push over square size",
6565
assert.PanicTestFunc(
6666
func() {
67-
data := generateErasuredData(t, 16, rsmt2d.NewRSGF8Codec())
67+
data := generateErasuredData(t, 16, consts.DefaultCodec())
6868
n := NewErasuredNamespacedMerkleTree(uint64(15))
6969
tree := n.Constructor()
7070
for i, d := range data {
@@ -76,7 +76,7 @@ func TestErasureNamespacedMerkleTreePanics(t *testing.T) {
7676
"push in incorrect lexigraphic order",
7777
assert.PanicTestFunc(
7878
func() {
79-
data := generateErasuredData(t, 16, rsmt2d.NewRSGF8Codec())
79+
data := generateErasuredData(t, 16, consts.DefaultCodec())
8080
n := NewErasuredNamespacedMerkleTree(uint64(16))
8181
tree := n.Constructor()
8282
for i := len(data) - 1; i > 0; i-- {
@@ -104,7 +104,7 @@ func TestExtendedDataSquare(t *testing.T) {
104104

105105
tree := NewErasuredNamespacedMerkleTree(uint64(squareSize))
106106

107-
_, err := rsmt2d.ComputeExtendedDataSquare(raw, rsmt2d.NewRSGF8Codec(), tree.Constructor)
107+
_, err := rsmt2d.ComputeExtendedDataSquare(raw, consts.DefaultCodec(), tree.Constructor)
108108
assert.NoError(t, err)
109109
}
110110

‎types/shares_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func TestDataFromSquare(t *testing.T) {
252252
shares, _ := data.ComputeShares()
253253
rawShares := shares.RawShares()
254254

255-
eds, err := rsmt2d.ComputeExtendedDataSquare(rawShares, rsmt2d.NewRSGF8Codec(), rsmt2d.NewDefaultTree)
255+
eds, err := rsmt2d.ComputeExtendedDataSquare(rawShares, consts.DefaultCodec(), rsmt2d.NewDefaultTree)
256256
if err != nil {
257257
t.Error(err)
258258
}

0 commit comments

Comments
 (0)
Please sign in to comment.