From 74ba7a6c39f6b85bb3420a2b7283dfbbd950abe0 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Thu, 10 Oct 2024 05:09:58 -0700 Subject: [PATCH] test(nodebuilder): fuzzer for fullClient.DataAvailability submission This change presents a fuzzer for testing out fullClient data availability submission, in which the inputs to .Submit are mutated then the responses tested out to check for logical conformation. I ran this fuzzer for about 8 hours on my machine, but ideally we should get this repository up on oss-fuzz for continuous fuzzing. --- nodebuilder/tests/fuzz_test.go | 201 ++++++++++++++++++ .../tests/testdata/bytes-submit/0.bytes | Bin 0 -> 3822 bytes .../tests/testdata/bytes-submit/1.bytes | Bin 0 -> 1910 bytes .../tests/testdata/bytes-submit/2.bytes | Bin 0 -> 1910 bytes 4 files changed, 201 insertions(+) create mode 100644 nodebuilder/tests/fuzz_test.go create mode 100755 nodebuilder/tests/testdata/bytes-submit/0.bytes create mode 100755 nodebuilder/tests/testdata/bytes-submit/1.bytes create mode 100755 nodebuilder/tests/testdata/bytes-submit/2.bytes diff --git a/nodebuilder/tests/fuzz_test.go b/nodebuilder/tests/fuzz_test.go new file mode 100644 index 0000000000..14dc9aef51 --- /dev/null +++ b/nodebuilder/tests/fuzz_test.go @@ -0,0 +1,201 @@ +//go:build da || integration + +package tests + +import ( + "bytes" + "context" + "encoding/json" + "os" + "path/filepath" + "testing" + "time" + + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/stretchr/testify/require" + + "github.com/celestiaorg/celestia-node/nodebuilder/da" + "github.com/celestiaorg/celestia-node/nodebuilder/node" + "github.com/celestiaorg/celestia-node/nodebuilder/tests/swamp" + "github.com/celestiaorg/celestia-node/share" +) + +var namespace, _ = share.NewBlobNamespaceV0([]byte("namespace")) + +type daModuleCorpus struct { + Blobs [][]byte `json:"blobs"` +} + +func FuzzDaModule(f *testing.F) { + // 1. Retrieve the fuzz corpra. + corpraPath := filepath.Join("testdata", "bytes-submit", "*.bytes") + globbed, err := filepath.Glob(corpraPath) + if err != nil { + f.Fatal(err) + } + + blobs := [][]byte{} + for _, path := range globbed { + data, err := os.ReadFile(path) + if err != nil { + f.Fatal(err) + } + blobs = append(blobs, data) + } + + jsonBlob, err := json.Marshal(&daModuleCorpus{Blobs: blobs}) + if err != nil { + f.Fatal(err) + } + f.Add(jsonBlob) + + dmc := new(daModuleCorpus) + if err := json.Unmarshal(jsonBlob, dmc); err != nil { + return + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + t := new(testing.T) + sw := swamp.NewSwamp(t, swamp.WithBlockTime(10*time.Second)) + + bridge := sw.NewBridgeNode() + if err := bridge.Start(ctx); err != nil { + return + } + + addrs, err := peer.AddrInfoToP2pAddrs(host.InfoFromHost(bridge.Host)) + if err != nil { + return + } + + fullCfg := sw.DefaultTestConfig(node.Full) + fullCfg.Header.TrustedPeers = append(fullCfg.Header.TrustedPeers, addrs[0].String()) + fullNode := sw.NewNodeWithConfig(node.Full, fullCfg) + require.NoError(f, fullNode.Start(ctx)) + + addrsFull, err := peer.AddrInfoToP2pAddrs(host.InfoFromHost(fullNode.Host)) + if err != nil { + return + } + + lightCfg := sw.DefaultTestConfig(node.Light) + lightCfg.Header.TrustedPeers = append(lightCfg.Header.TrustedPeers, addrsFull[0].String()) + lightNode := sw.NewNodeWithConfig(node.Light, lightCfg) + if err := lightNode.Start(ctx); err != nil { + return + } + + fullClient := getAdminClient(ctx, fullNode, t) + lightClient := getAdminClient(ctx, lightNode, t) + + // 2. Now run the fuzzers. + f.Fuzz(func(t *testing.T, jsonBlob []byte) { + daBlobs := dmc.Blobs + ids, err := fullClient.DA.Submit(ctx, daBlobs, -1, namespace) + if err != nil { + return + } + + tests := []struct { + name string + doFn func(t *testing.T) + }{ + { + name: "MaxBlobSize", + doFn: func(t *testing.T) { + _, _ = fullClient.DA.MaxBlobSize(ctx) + }, + }, + { + name: "GetProofs + Validate", + doFn: func(t *testing.T) { + h, _ := da.SplitID(ids[0]) + lightClient.Header.WaitForHeight(ctx, h) + proofs, err := lightClient.DA.GetProofs(ctx, ids, namespace) + if err != nil { + return + } + if len(proofs) == 0 { + return + } + _, _ = fullClient.DA.Validate(ctx, ids, proofs, namespace) + }, + }, + { + name: "GetIDs", + doFn: func(t *testing.T) { + height, _ := da.SplitID(ids[0]) + _, err := fullClient.DA.GetIDs(ctx, height, namespace) + if err != nil { + return + } + _, _ = lightClient.Header.GetByHeight(ctx, height) + }, + }, + { + name: "Get", + doFn: func(t *testing.T) { + h, _ := da.SplitID(ids[0]) + lightClient.Header.WaitForHeight(ctx, h) + fetched, err := lightClient.DA.Get(ctx, ids, namespace) + if err != nil { + return + } + if g, w := len(fetched), len(ids); g != w { + t.Fatalf("len(fetched)=%d != len(ids)=%d", g, w) + } + for i := range fetched { + if !bytes.Equal(fetched[i], daBlobs[i]) { + t.Errorf("!bytes.Equal(fetched[%d], daBlbos[%d]\n\tFetched: % x\n\tDaBlobs: % x\n", i, i, fetched[i], daBlobs[i]) + } + } + }, + }, + { + name: "Commit", + doFn: func(t *testing.T) { + fetched, err := fullClient.DA.Commit(ctx, daBlobs, namespace) + require.NoError(t, err) + require.Len(t, fetched, len(ids)) + for i := range fetched { + _, commitment := da.SplitID(ids[i]) + require.EqualValues(t, fetched[i], commitment) + } + }, + }, + { + name: "SubmitWithOptions - valid", + doFn: func(t *testing.T) { + ids, err := fullClient.DA.SubmitWithOptions(ctx, daBlobs, -1, namespace, []byte(`{"key_name": "validator"}`)) + require.NoError(t, err) + require.NotEmpty(t, ids) + }, + }, + { + name: "SubmitWithOptions - invalid JSON", + doFn: func(t *testing.T) { + ids, err := fullClient.DA.SubmitWithOptions(ctx, daBlobs, -1, namespace, []byte("not JSON")) + require.Error(t, err) + require.Nil(t, ids) + }, + }, + { + name: "SubmitWithOptions - invalid key name", + doFn: func(t *testing.T) { + ids, err := fullClient.DA.SubmitWithOptions(ctx, daBlobs, -1, namespace, []byte(`{"key_name": "invalid"}`)) + require.Error(t, err) + require.Nil(t, ids) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.doFn(t) + }) + } + }) +} diff --git a/nodebuilder/tests/testdata/bytes-submit/0.bytes b/nodebuilder/tests/testdata/bytes-submit/0.bytes new file mode 100755 index 0000000000000000000000000000000000000000..0e1eec7e4092ba022b14577d52ccdf93d92b692d GIT binary patch literal 3822 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 literal 0 HcmV?d00001