Skip to content

Commit 77bcc9d

Browse files
authored
test(swamp/share): cover share module with swamp tests (#4036)
1 parent 396b45a commit 77bcc9d

File tree

5 files changed

+291
-26
lines changed

5 files changed

+291
-26
lines changed

.github/workflows/integration-tests.yml

+15
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,18 @@ jobs:
143143

144144
- name: run sync tests
145145
run: make test-integration SHORT=true TAGS=pruning
146+
147+
share_tests:
148+
name: Integration Tests Share
149+
runs-on: ubuntu-latest
150+
151+
steps:
152+
- uses: actions/checkout@v4
153+
154+
- name: set up go
155+
uses: actions/setup-go@v5
156+
with:
157+
go-version: ${{ inputs.go-version }}
158+
159+
- name: run share tests
160+
run: make test-integration SHORT=true TAGS=share

blob/helper.go

+16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package blob
33
import (
44
"sort"
55

6+
"github.com/celestiaorg/go-square/merkle"
7+
"github.com/celestiaorg/go-square/v2/inclusion"
68
libshare "github.com/celestiaorg/go-square/v2/share"
79
)
810

@@ -32,6 +34,20 @@ func ToLibBlobs(blobs ...*Blob) []*libshare.Blob {
3234
return libBlobs
3335
}
3436

37+
// ToNodeBlobs converts libshare blob type to the node's specific blob type.
38+
func ToNodeBlobs(blobs ...*libshare.Blob) ([]*Blob, error) {
39+
nodeBlobs := make([]*Blob, len(blobs))
40+
hashFromByteSlices := merkle.HashFromByteSlices
41+
for i, blob := range blobs {
42+
com, err := inclusion.CreateCommitment(blob, hashFromByteSlices, subtreeRootThreshold)
43+
if err != nil {
44+
return nil, err
45+
}
46+
nodeBlobs[i] = &Blob{Blob: blob, Commitment: com, index: -1}
47+
}
48+
return nodeBlobs, nil
49+
}
50+
3551
func calculateIndex(rowLength, blobIndex int) (row, col int) {
3652
row = blobIndex / rowLength
3753
col = blobIndex - (row * rowLength)

nodebuilder/tests/blob_test.go

+16-26
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,9 @@ func TestBlobModule(t *testing.T) {
3030
require.NoError(t, err)
3131
libBlobs1, err := libshare.GenerateV0Blobs([]int{4}, false)
3232
require.NoError(t, err)
33-
blobs := make([]*blob.Blob, 0, len(libBlobs0)+len(libBlobs1))
3433

35-
for _, libBlob := range append(libBlobs0, libBlobs1...) {
36-
blob, err := convert(libBlob)
37-
require.NoError(t, err)
38-
blobs = append(blobs, blob)
39-
}
34+
blobs, err := blob.ToNodeBlobs(append(libBlobs0, libBlobs1...)...)
35+
require.NoError(t, err)
4036

4137
bridge := sw.NewBridgeNode()
4238
require.NoError(t, bridge.Start(ctx))
@@ -68,9 +64,9 @@ func TestBlobModule(t *testing.T) {
6864
)
6965
require.NoError(t, err)
7066

71-
v1, err := convert(v1Blob)
67+
v1, err := blob.ToNodeBlobs(v1Blob)
7268
require.NoError(t, err)
73-
blobs = append(blobs, v1)
69+
blobs = append(blobs, v1[0])
7470

7571
height, err := fullClient.Blob.Submit(ctx, blobs, state.NewTxConfig())
7672
require.NoError(t, err)
@@ -109,12 +105,12 @@ func TestBlobModule(t *testing.T) {
109105
{
110106
name: "Get BlobV1",
111107
doFn: func(t *testing.T) {
112-
blobV1, err := fullClient.Blob.Get(ctx, height, v1.Namespace(), v1.Commitment)
108+
blobV1, err := fullClient.Blob.Get(ctx, height, v1[0].Namespace(), v1[0].Commitment)
113109
require.NoError(t, err)
114110
assert.Equal(t, libshare.ShareVersionOne, blobV1.ShareVersion())
115-
assert.Equal(t, v1.Commitment, blobV1.Commitment)
111+
assert.Equal(t, v1[0].Commitment, blobV1.Commitment)
116112
assert.NotNil(t, blobV1.Signer())
117-
assert.Equal(t, blobV1.Signer(), v1.Signer())
113+
assert.Equal(t, blobV1.Signer(), v1[0].Signer())
118114

119115
},
120116
},
@@ -140,15 +136,15 @@ func TestBlobModule(t *testing.T) {
140136
doFn: func(t *testing.T) {
141137
libBlob, err := libshare.GenerateV0Blobs([]int{4}, false)
142138
require.NoError(t, err)
143-
newBlob, err := convert(libBlob[0])
139+
newBlob, err := blob.ToNodeBlobs(libBlob[0])
144140
require.NoError(t, err)
145141

146-
b, err := fullClient.Blob.Get(ctx, height, newBlob.Namespace(), newBlob.Commitment)
142+
b, err := fullClient.Blob.Get(ctx, height, newBlob[0].Namespace(), newBlob[0].Commitment)
147143
assert.Nil(t, b)
148144
require.Error(t, err)
149145
require.ErrorContains(t, err, blob.ErrBlobNotFound.Error())
150146

151-
blobs, err := fullClient.Blob.GetAll(ctx, height, []libshare.Namespace{newBlob.Namespace()})
147+
blobs, err := fullClient.Blob.GetAll(ctx, height, []libshare.Namespace{newBlob[0].Namespace()})
152148
require.NoError(t, err)
153149
assert.Empty(t, blobs)
154150
},
@@ -158,23 +154,23 @@ func TestBlobModule(t *testing.T) {
158154
doFn: func(t *testing.T) {
159155
libBlob, err := libshare.GenerateV0Blobs([]int{8, 4}, true)
160156
require.NoError(t, err)
161-
b, err := convert(libBlob[0])
157+
b, err := blob.ToNodeBlobs(libBlob[0])
162158
require.NoError(t, err)
163159

164-
height, err := fullClient.Blob.Submit(ctx, []*blob.Blob{b, b}, state.NewTxConfig())
160+
height, err := fullClient.Blob.Submit(ctx, []*blob.Blob{b[0], b[0]}, state.NewTxConfig())
165161
require.NoError(t, err)
166162

167163
_, err = fullClient.Header.WaitForHeight(ctx, height)
168164
require.NoError(t, err)
169165

170-
b0, err := fullClient.Blob.Get(ctx, height, b.Namespace(), b.Commitment)
166+
b0, err := fullClient.Blob.Get(ctx, height, b[0].Namespace(), b[0].Commitment)
171167
require.NoError(t, err)
172-
require.Equal(t, b.Commitment, b0.Commitment)
168+
require.Equal(t, b[0].Commitment, b0.Commitment)
173169

174-
proof, err := fullClient.Blob.GetProof(ctx, height, b.Namespace(), b.Commitment)
170+
proof, err := fullClient.Blob.GetProof(ctx, height, b[0].Namespace(), b[0].Commitment)
175171
require.NoError(t, err)
176172

177-
included, err := fullClient.Blob.Included(ctx, height, b.Namespace(), proof, b.Commitment)
173+
included, err := fullClient.Blob.Included(ctx, height, b[0].Namespace(), proof, b[0].Commitment)
178174
require.NoError(t, err)
179175
require.True(t, included)
180176
},
@@ -212,9 +208,3 @@ func TestBlobModule(t *testing.T) {
212208
})
213209
}
214210
}
215-
216-
// convert converts a libshare.Blob to a blob.Blob.
217-
// convert may be deduplicated with convertBlobs from the blob package.
218-
func convert(libBlob *libshare.Blob) (nodeBlob *blob.Blob, err error) {
219-
return blob.NewBlob(libBlob.ShareVersion(), libBlob.Namespace(), libBlob.Data(), libBlob.Signer())
220-
}

nodebuilder/tests/share_test.go

+221
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
//go:build share || integration
2+
3+
package tests
4+
5+
import (
6+
"context"
7+
"testing"
8+
"time"
9+
10+
"github.com/libp2p/go-libp2p/core/host"
11+
"github.com/libp2p/go-libp2p/core/peer"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
15+
libshare "github.com/celestiaorg/go-square/v2/share"
16+
17+
"github.com/celestiaorg/celestia-node/api/rpc/client"
18+
"github.com/celestiaorg/celestia-node/blob"
19+
"github.com/celestiaorg/celestia-node/nodebuilder/node"
20+
"github.com/celestiaorg/celestia-node/nodebuilder/tests/swamp"
21+
"github.com/celestiaorg/celestia-node/share/shwap"
22+
"github.com/celestiaorg/celestia-node/state"
23+
)
24+
25+
func TestShareModule(t *testing.T) {
26+
ctx, cancel := context.WithTimeout(context.Background(), 25*time.Second)
27+
t.Cleanup(cancel)
28+
sw := swamp.NewSwamp(t, swamp.WithBlockTime(time.Second*1))
29+
blobSize := 128
30+
libBlob, err := libshare.GenerateV0Blobs([]int{blobSize}, true)
31+
require.NoError(t, err)
32+
33+
nodeBlob, err := blob.ToNodeBlobs(libBlob[0])
34+
require.NoError(t, err)
35+
36+
bridge := sw.NewBridgeNode()
37+
require.NoError(t, bridge.Start(ctx))
38+
addrs, err := peer.AddrInfoToP2pAddrs(host.InfoFromHost(bridge.Host))
39+
require.NoError(t, err)
40+
41+
fullCfg := sw.DefaultTestConfig(node.Full)
42+
fullCfg.Header.TrustedPeers = append(fullCfg.Header.TrustedPeers, addrs[0].String())
43+
fullNode := sw.NewNodeWithConfig(node.Full, fullCfg)
44+
require.NoError(t, fullNode.Start(ctx))
45+
46+
addrsFull, err := peer.AddrInfoToP2pAddrs(host.InfoFromHost(fullNode.Host))
47+
require.NoError(t, err)
48+
49+
lightCfg := sw.DefaultTestConfig(node.Light)
50+
lightCfg.Header.TrustedPeers = append(lightCfg.Header.TrustedPeers, addrsFull[0].String())
51+
lightNode := sw.NewNodeWithConfig(node.Light, lightCfg)
52+
require.NoError(t, lightNode.Start(ctx))
53+
54+
bridgeClient := getAdminClient(ctx, bridge, t)
55+
fullClient := getAdminClient(ctx, fullNode, t)
56+
lightClient := getAdminClient(ctx, lightNode, t)
57+
58+
height, err := fullClient.Blob.Submit(ctx, nodeBlob, state.NewTxConfig())
59+
require.NoError(t, err)
60+
61+
_, err = fullClient.Header.WaitForHeight(ctx, height)
62+
require.NoError(t, err)
63+
_, err = lightClient.Header.WaitForHeight(ctx, height)
64+
require.NoError(t, err)
65+
66+
sampledBlob, err := fullClient.Blob.Get(ctx, height, nodeBlob[0].Namespace(), nodeBlob[0].Commitment)
67+
require.NoError(t, err)
68+
69+
hdr, err := fullClient.Header.GetByHeight(ctx, height)
70+
require.NoError(t, err)
71+
72+
coords, err := shwap.SampleCoordsFrom1DIndex(sampledBlob.Index(), len(hdr.DAH.RowRoots))
73+
require.NoError(t, err)
74+
75+
blobAsShares, err := blob.BlobsToShares(sampledBlob)
76+
require.NoError(t, err)
77+
// different clients allow to test different getters that are used to get the data.
78+
clients := []*client.Client{lightClient, fullClient, bridgeClient}
79+
80+
testCases := []struct {
81+
name string
82+
doFn func(t *testing.T)
83+
}{
84+
{
85+
name: "SharesAvailable",
86+
doFn: func(t *testing.T) {
87+
for _, client := range clients {
88+
err := client.Share.SharesAvailable(ctx, height)
89+
require.NoError(t, err)
90+
}
91+
},
92+
},
93+
{
94+
name: "GetShareQ1",
95+
doFn: func(t *testing.T) {
96+
for _, client := range clients {
97+
// compare the share from quadrant1 by its coordinate.
98+
// Additionally check that received share the same as the first share of the blob.
99+
sh, err := client.Share.GetShare(ctx, height, coords.Row, coords.Col)
100+
require.NoError(t, err)
101+
assert.Equal(t, blobAsShares[0], sh)
102+
}
103+
},
104+
},
105+
{
106+
name: "GetShareQ4",
107+
doFn: func(t *testing.T) {
108+
for _, client := range clients {
109+
_, err := client.Share.GetShare(ctx, height, len(hdr.DAH.RowRoots)-1, len(hdr.DAH.ColumnRoots)-1)
110+
require.NoError(t, err)
111+
}
112+
},
113+
},
114+
{
115+
name: "GetSamplesQ1",
116+
doFn: func(t *testing.T) {
117+
dah := hdr.DAH
118+
requestCoords := []shwap.SampleCoords{coords}
119+
for _, client := range clients {
120+
// request from the first quadrant using the blob coordinates.
121+
samples, err := client.Share.GetSamples(ctx, hdr, requestCoords)
122+
require.NoError(t, err)
123+
err = samples[0].Verify(dah, coords.Row, coords.Col)
124+
require.NoError(t, err)
125+
require.Equal(t, blobAsShares[0], samples[0].Share)
126+
}
127+
},
128+
},
129+
{
130+
name: "GetSamplesQ4",
131+
doFn: func(t *testing.T) {
132+
dah := hdr.DAH
133+
coords := shwap.SampleCoords{Row: len(dah.RowRoots) - 1, Col: len(dah.RowRoots) - 1}
134+
requestCoords := []shwap.SampleCoords{coords}
135+
for _, client := range clients {
136+
// getting the last sample from the eds(from quadrant 4).
137+
samples, err := client.Share.GetSamples(ctx, hdr, requestCoords)
138+
require.NoError(t, err)
139+
err = samples[0].Verify(dah, coords.Row, coords.Col)
140+
require.NoError(t, err)
141+
}
142+
},
143+
},
144+
{
145+
name: "GetEDS",
146+
doFn: func(t *testing.T) {
147+
for _, client := range clients {
148+
eds, err := client.Share.GetEDS(ctx, height)
149+
require.NoError(t, err)
150+
rawShares := eds.Row(uint(coords.Row))
151+
sh, err := libshare.FromBytes([][]byte{rawShares[coords.Col]})
152+
require.NoError(t, err)
153+
assert.Equal(t, blobAsShares[0], sh[0])
154+
}
155+
},
156+
},
157+
{
158+
name: "GetRowQ1",
159+
doFn: func(t *testing.T) {
160+
dah := hdr.DAH
161+
for _, client := range clients {
162+
// request row from the first half of the EDS(using the blob's coordinates).
163+
row, err := client.Share.GetRow(ctx, height, coords.Row)
164+
require.NoError(t, err)
165+
// verify row against the DAH.
166+
err = row.Verify(dah, coords.Row)
167+
require.NoError(t, err)
168+
shrs, err := row.Shares()
169+
require.NoError(t, err)
170+
// additionally compare shares
171+
assert.Equal(t, blobAsShares[0], shrs[coords.Col])
172+
}
173+
},
174+
},
175+
{
176+
name: "GetRowQ4",
177+
doFn: func(t *testing.T) {
178+
dah := hdr.DAH
179+
coords := shwap.SampleCoords{Row: len(dah.RowRoots) - 1, Col: len(dah.RowRoots) - 1}
180+
for _, client := range clients {
181+
// request the last row
182+
row, err := client.Share.GetRow(ctx, height, coords.Row)
183+
require.NoError(t, err)
184+
// verify against DAH
185+
err = row.Verify(dah, coords.Row)
186+
require.NoError(t, err)
187+
}
188+
},
189+
},
190+
{
191+
name: "GetNamespaceData",
192+
doFn: func(t *testing.T) {
193+
dah := hdr.DAH
194+
for _, client := range clients {
195+
// request data from the blob's namespace
196+
nsData, err := client.Share.GetNamespaceData(ctx, height, blobAsShares[0].Namespace())
197+
require.NoError(t, err)
198+
199+
// verify against the DAH
200+
err = nsData.Verify(dah, blobAsShares[0].Namespace())
201+
require.NoError(t, err)
202+
203+
b, err := libshare.ParseBlobs(nsData.Flatten())
204+
require.NoError(t, err)
205+
206+
blb, err := blob.ToNodeBlobs(b[0])
207+
require.NoError(t, err)
208+
// compare commitments
209+
require.Equal(t, nodeBlob[0].Commitment, blb[0].Commitment)
210+
211+
}
212+
},
213+
},
214+
}
215+
216+
for _, tt := range testCases {
217+
t.Run(tt.name, func(t *testing.T) {
218+
tt.doFn(t)
219+
})
220+
}
221+
}

0 commit comments

Comments
 (0)