diff --git a/api/client/client_test.go b/api/client/client_test.go index 9c9a8c8d2..97fc84819 100644 --- a/api/client/client_test.go +++ b/api/client/client_test.go @@ -33,8 +33,6 @@ import ( daMock "github.com/celestiaorg/celestia-node/nodebuilder/da/mocks" "github.com/celestiaorg/celestia-node/nodebuilder/das" dasMock "github.com/celestiaorg/celestia-node/nodebuilder/das/mocks" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" - fraudMock "github.com/celestiaorg/celestia-node/nodebuilder/fraud/mocks" headerapi "github.com/celestiaorg/celestia-node/nodebuilder/header" headerMock "github.com/celestiaorg/celestia-node/nodebuilder/header/mocks" "github.com/celestiaorg/celestia-node/nodebuilder/node" @@ -279,7 +277,6 @@ func TestSubmission_QueuedSubmission(t *testing.T) { type mockAPI struct { State *stateMock.MockModule Share *shareMock.MockModule - Fraud *fraudMock.MockModule Header *headerMock.MockModule Das *dasMock.MockModule P2P *p2pMock.MockModule @@ -296,7 +293,6 @@ func setupMockRPCServer(t *testing.T, ctx context.Context) (*nodebuilder.Node, * mockAPI := &mockAPI{ stateMock.NewMockModule(ctrl), shareMock.NewMockModule(ctrl), - fraudMock.NewMockModule(ctrl), headerMock.NewMockModule(ctrl), dasMock.NewMockModule(ctrl), p2pMock.NewMockModule(ctrl), @@ -310,7 +306,6 @@ func setupMockRPCServer(t *testing.T, ctx context.Context) (*nodebuilder.Node, * // given the behavior of fx.Invoke, this invoke will be called last as it is added at the root // level module. For further information, check the documentation on fx.Invoke. invokeRPC := fx.Invoke(func(srv *rpc.Server) { - srv.RegisterService("fraud", mockAPI.Fraud, &fraud.API{}) srv.RegisterService("das", mockAPI.Das, &das.API{}) srv.RegisterService("header", mockAPI.Header, &headerapi.API{}) srv.RegisterService("state", mockAPI.State, &statemod.API{}) diff --git a/api/client/read_client.go b/api/client/read_client.go index 62ea74348..d2b8f0192 100644 --- a/api/client/read_client.go +++ b/api/client/read_client.go @@ -10,7 +10,6 @@ import ( "github.com/celestiaorg/celestia-node/libs/utils" blobapi "github.com/celestiaorg/celestia-node/nodebuilder/blob" blobstreamapi "github.com/celestiaorg/celestia-node/nodebuilder/blobstream" - fraudapi "github.com/celestiaorg/celestia-node/nodebuilder/fraud" headerapi "github.com/celestiaorg/celestia-node/nodebuilder/header" shareapi "github.com/celestiaorg/celestia-node/nodebuilder/share" ) @@ -31,7 +30,6 @@ type ReadClient struct { Blob blobapi.Module Header headerapi.Module Share shareapi.Module - Fraud fraudapi.Module Blobstream blobstreamapi.Module closer func() error @@ -87,13 +85,6 @@ func NewReadClient(ctx context.Context, cfg ReadConfig) (*ReadClient, error) { return nil, fmt.Errorf("failed to initialize header client: %w", err) } - fraudAPI := fraudapi.API{} - fraudCloser, err := jsonrpc.NewClient( - ctx, cfg.BridgeDAAddr, "fraud", &fraudAPI.Internal, cfg.HTTPHeader) - if err != nil { - return nil, fmt.Errorf("failed to initialize fraud client: %w", err) - } - // Initialize blob read client blobAPI := blobapi.API{} blobCloser, err := jsonrpc.NewClient( @@ -107,7 +98,6 @@ func NewReadClient(ctx context.Context, cfg ReadConfig) (*ReadClient, error) { shareCloser() blobstreamCloser() headerCloser() - fraudCloser() blobCloser() return nil } diff --git a/api/docgen/examples.go b/api/docgen/examples.go index 524ec72ab..c748bfd6d 100644 --- a/api/docgen/examples.go +++ b/api/docgen/examples.go @@ -22,7 +22,6 @@ import ( "golang.org/x/text/cases" "golang.org/x/text/language" - "github.com/celestiaorg/go-fraud" libhead "github.com/celestiaorg/go-header" libshare "github.com/celestiaorg/go-square/v4/share" "github.com/celestiaorg/rsmt2d" @@ -32,7 +31,6 @@ import ( "github.com/celestiaorg/celestia-node/header" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/share" - "github.com/celestiaorg/celestia-node/share/eds/byzantine" "github.com/celestiaorg/celestia-node/state" ) @@ -78,18 +76,6 @@ func init() { add(time.Second) add(node.Bridge) add(auth.Permission("admin")) - add(byzantine.BadEncoding) - - // TODO: this case requires more debugging, simple to leave it as it was. - exampleValues[reflect.TypeOf((*fraud.Proof[*header.ExtendedHeader])(nil)).Elem()] = byzantine.CreateBadEncodingProof( - []byte("bad encoding proof"), - 42, - &byzantine.ErrByzantine{ - Index: 0, - Shares: []*byzantine.ShareWithProof{}, - Axis: rsmt2d.Axis(0), - }, - ) add(errors.New("error")) add(state.Balance{Amount: math.NewInt(42), Denom: "utia"}) diff --git a/api/rpc/client/client.go b/api/rpc/client/client.go index ad5195f4d..c74f672fb 100644 --- a/api/rpc/client/client.go +++ b/api/rpc/client/client.go @@ -12,7 +12,6 @@ import ( "github.com/celestiaorg/celestia-node/nodebuilder/blobstream" "github.com/celestiaorg/celestia-node/nodebuilder/da" "github.com/celestiaorg/celestia-node/nodebuilder/das" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" "github.com/celestiaorg/celestia-node/nodebuilder/header" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/nodebuilder/p2p" @@ -27,7 +26,6 @@ var ( ) type Client struct { - Fraud fraud.API Header header.API State state.API Share share.API @@ -93,7 +91,6 @@ func moduleMap(client *Client) map[string]any { "share": &client.Share.Internal, "state": &client.State.Internal, "header": &client.Header.Internal, - "fraud": &client.Fraud.Internal, "das": &client.DAS.Internal, "p2p": &client.P2P.Internal, "node": &client.Node.Internal, diff --git a/api/rpc_test.go b/api/rpc_test.go index 6953f19ee..927891110 100644 --- a/api/rpc_test.go +++ b/api/rpc_test.go @@ -28,8 +28,6 @@ import ( daMock "github.com/celestiaorg/celestia-node/nodebuilder/da/mocks" "github.com/celestiaorg/celestia-node/nodebuilder/das" dasMock "github.com/celestiaorg/celestia-node/nodebuilder/das/mocks" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" - fraudMock "github.com/celestiaorg/celestia-node/nodebuilder/fraud/mocks" "github.com/celestiaorg/celestia-node/nodebuilder/header" headerMock "github.com/celestiaorg/celestia-node/nodebuilder/header/mocks" "github.com/celestiaorg/celestia-node/nodebuilder/node" @@ -128,7 +126,6 @@ func TestRPCCallsTokenExpired(t *testing.T) { // api contains all modules that are made available as the node's // public API surface type api struct { - Fraud fraud.Module Header header.Module State statemod.Module Share share.Module @@ -344,7 +341,6 @@ func setupNodeWithAuthedRPC(t *testing.T, mockAPI := &mockAPI{ stateMock.NewMockModule(ctrl), shareMock.NewMockModule(ctrl), - fraudMock.NewMockModule(ctrl), headerMock.NewMockModule(ctrl), dasMock.NewMockModule(ctrl), p2pMock.NewMockModule(ctrl), @@ -357,7 +353,6 @@ func setupNodeWithAuthedRPC(t *testing.T, // given the behavior of fx.Invoke, this invoke will be called last as it is added at the root // level module. For further information, check the documentation on fx.Invoke. invokeRPC := fx.Invoke(func(srv *rpc.Server) { - srv.RegisterService("fraud", mockAPI.Fraud, &fraud.API{}) srv.RegisterService("das", mockAPI.Das, &das.API{}) srv.RegisterService("header", mockAPI.Header, &header.API{}) srv.RegisterService("state", mockAPI.State, &statemod.API{}) @@ -384,7 +379,6 @@ func setupNodeWithAuthedRPC(t *testing.T, type mockAPI struct { State *stateMock.MockModule Share *shareMock.MockModule - Fraud *fraudMock.MockModule Header *headerMock.MockModule Das *dasMock.MockModule P2P *p2pMock.MockModule diff --git a/cmd/cel-shed/p2p.go b/cmd/cel-shed/p2p.go index df213145d..c1faed89a 100644 --- a/cmd/cel-shed/p2p.go +++ b/cmd/cel-shed/p2p.go @@ -16,7 +16,6 @@ import ( "go.uber.org/fx" "github.com/celestiaorg/celestia-node/nodebuilder" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/nodebuilder/p2p" ) @@ -118,7 +117,6 @@ var p2pConnectBootstrappersCmd = &cobra.Command{ app := fx.New( fx.NopLogger, modp2p, - fx.Provide(fraud.Unmarshaler), fx.Provide(cmd.Context), fx.Provide(store.Keystore), fx.Provide(store.Datastore), diff --git a/das/daser.go b/das/daser.go index 73afd03bc..f4a99eee8 100644 --- a/das/daser.go +++ b/das/daser.go @@ -9,12 +9,10 @@ import ( "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log/v2" - "github.com/celestiaorg/go-fraud" libhead "github.com/celestiaorg/go-header" "github.com/celestiaorg/celestia-node/header" "github.com/celestiaorg/celestia-node/share" - "github.com/celestiaorg/celestia-node/share/eds/byzantine" "github.com/celestiaorg/celestia-node/share/shwap/p2p/shrex/shrexsub" ) @@ -25,7 +23,6 @@ type DASer struct { params Parameters da share.Availability - bcast fraud.Broadcaster[*header.ExtendedHeader] hsub libhead.Subscriber[*header.ExtendedHeader] // listens for new headers in the network getter libhead.Store[*header.ExtendedHeader] // retrieves past headers @@ -48,14 +45,12 @@ func NewDASer( hsub libhead.Subscriber[*header.ExtendedHeader], getter libhead.Store[*header.ExtendedHeader], dstore datastore.Datastore, - bcast fraud.Broadcaster[*header.ExtendedHeader], shrexBroadcast shrexsub.BroadcastFn, options ...Option, ) (*DASer, error) { d := &DASer{ params: DefaultParameters(), da: da, - bcast: bcast, hsub: hsub, getter: getter, store: newCheckpointStore(dstore), @@ -197,19 +192,7 @@ func (d *DASer) Stop(ctx context.Context) error { } func (d *DASer) sample(ctx context.Context, h *header.ExtendedHeader) error { - err := d.da.SharesAvailable(ctx, h) - if err != nil { - var byzantineErr *byzantine.ErrByzantine - if errors.As(err, &byzantineErr) { - log.Warn("Propagating proof...") - sendErr := d.bcast.Broadcast(ctx, byzantine.CreateBadEncodingProof(h.Hash(), h.Height(), byzantineErr)) - if sendErr != nil { - log.Errorw("fraud proof propagating failed", "err", sendErr) - } - } - return err - } - return nil + return d.da.SharesAvailable(ctx, h) } // SamplingStats returns the current statistics over the DA sampling process. diff --git a/das/daser_test.go b/das/daser_test.go index 9b5c7d9f8..f338b293b 100644 --- a/das/daser_test.go +++ b/das/daser_test.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/celestiaorg/go-fraud/fraudtest" libhead "github.com/celestiaorg/go-header" "github.com/celestiaorg/celestia-node/header" @@ -31,12 +30,12 @@ func TestDASerLifecycle(t *testing.T) { avail := mocks.NewMockAvailability(ctrl) avail.EXPECT().SharesAvailable(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) // 15 headers from the past and 15 future headers - mockGet, sub, mockService := createDASerSubcomponents(t, 15, 15) + mockGet, sub := createDASerSubcomponents(t, 15, 15) ctx, cancel := context.WithTimeout(context.Background(), timeout) t.Cleanup(cancel) - daser, err := NewDASer(avail, sub, mockGet, ds, mockService, newBroadcastMock(1)) + daser, err := NewDASer(avail, sub, mockGet, ds, newBroadcastMock(1)) require.NoError(t, err) err = daser.Start(ctx) @@ -62,12 +61,12 @@ func TestDASer_Restart(t *testing.T) { avail := mocks.NewMockAvailability(ctrl) avail.EXPECT().SharesAvailable(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) // 15 headers from the past and 15 future headers - mockGet, sub, mockService := createDASerSubcomponents(t, 15, 15) + mockGet, sub := createDASerSubcomponents(t, 15, 15) ctx, cancel := context.WithTimeout(context.Background(), timeout) t.Cleanup(cancel) - daser, err := NewDASer(avail, sub, mockGet, ds, mockService, newBroadcastMock(1)) + daser, err := NewDASer(avail, sub, mockGet, ds, newBroadcastMock(1)) require.NoError(t, err) err = daser.Start(ctx) @@ -88,7 +87,7 @@ func TestDASer_Restart(t *testing.T) { restartCtx, restartCancel := context.WithTimeout(context.Background(), timeout) t.Cleanup(restartCancel) - daser, err = NewDASer(avail, sub, mockGet, ds, mockService, newBroadcastMock(1)) + daser, err = NewDASer(avail, sub, mockGet, ds, newBroadcastMock(1)) require.NoError(t, err) err = daser.Start(restartCtx) @@ -105,77 +104,6 @@ func TestDASer_Restart(t *testing.T) { assert.EqualValues(t, 60, checkpoint.SampleFrom-1) } -// TODO(@walldiss): BEFP test will not work until BEFP-shwap integration -// func TestDASer_stopsAfter_BEFP(t *testing.T) { -// ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) -// t.Cleanup(cancel) -// -// ds := ds_sync.MutexWrap(datastore.NewMapDatastore()) -// // create mock network -// net, err := mocknet.FullMeshLinked(1) -// require.NoError(t, err) -// // create pubsub for host -// ps, err := pubsub.NewGossipSub(ctx, net.Hosts()[0], -// pubsub.WithMessageSignaturePolicy(pubsub.StrictNoSign)) -// require.NoError(t, err) -// -// ctrl := gomock.NewController(t) -// avail := mocks.NewMockAvailability(ctrl) -// avail.EXPECT().SharesAvailable(gomock.Any(), gomock.Any()).AnyTimes().Return(nil) -// // 15 headers from the past and 15 future headers -// mockGet, sub, _ := createDASerSubcomponents(t, 15, 15) -// -// // create fraud service and break one header -// getter := func(ctx context.Context, height uint64) (*header.ExtendedHeader, error) { -// return mockGet.GetByHeight(ctx, height) -// } -// headGetter := func(ctx context.Context) (*header.ExtendedHeader, error) { -// return mockGet.Head(ctx) -// } -// unmarshaler := fraud.MultiUnmarshaler[*header.ExtendedHeader]{ -// Unmarshalers: map[fraud.ProofType]func([]byte) (fraud.Proof[*header.ExtendedHeader], error){ -// byzantine.BadEncoding: func(data []byte) (fraud.Proof[*header.ExtendedHeader], error) { -// befp := &byzantine.BadEncodingProof{} -// return befp, befp.UnmarshalBinary(data) -// }, -// }, -// } -// -// fserv := fraudserv.NewProofService[*header.ExtendedHeader](ps, -// net.Hosts()[0], -// getter, -// headGetter, -// unmarshaler, -// ds, -// false, -// "private", -// ) -// require.NoError(t, fserv.Start(ctx)) -// mockGet.headers[1] = headerfraud.CreateFraudExtHeader(t, mockGet.headers[1]) -// newCtx := context.Background() -// -// // create and start DASer -// daser, err := NewDASer(avail, sub, mockGet, ds, fserv, newBroadcastMock(1)) -// require.NoError(t, err) -// -// resultCh := make(chan error) -// go fraud.OnProof[*header.ExtendedHeader](newCtx, fserv, byzantine.BadEncoding, -// func(fraud.Proof[*header.ExtendedHeader]) { -// resultCh <- daser.Stop(newCtx) -// }) -// -// require.NoError(t, daser.Start(newCtx)) -// // wait for fraud proof will be handled -// select { -// case <-ctx.Done(): -// t.Fatal(ctx.Err()) -// case res := <-resultCh: -// require.NoError(t, res) -// } -// // wait for manager to finish catchup -// require.False(t, daser.running.Load()) -//} - func TestDASerSampleTimeout(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) t.Cleanup(cancel) @@ -202,10 +130,9 @@ func TestDASerSampleTimeout(t *testing.T) { ds := ds_sync.MutexWrap(datastore.NewMapDatastore()) sub := new(headertest.Subscriber) - fserv := &fraudtest.DummyService[*header.ExtendedHeader]{} // create and start DASer - daser, err := NewDASer(avail, sub, getter, ds, fserv, newBroadcastMock(1), + daser, err := NewDASer(avail, sub, getter, ds, newBroadcastMock(1), WithSampleTimeout(1)) require.NoError(t, err) @@ -230,11 +157,9 @@ func createDASerSubcomponents( ) ( libhead.Store[*header.ExtendedHeader], libhead.Subscriber[*header.ExtendedHeader], - *fraudtest.DummyService[*header.ExtendedHeader], ) { mockGet, sub := createMockGetterAndSub(t, numGetter, numSub) - fraud := &fraudtest.DummyService[*header.ExtendedHeader]{} - return mockGet, sub, fraud + return mockGet, sub } func createMockGetterAndSub( diff --git a/go.mod b/go.mod index 5f203add2..7e638f5be 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b github.com/benbjohnson/clock v1.3.5 github.com/celestiaorg/celestia-app/v8 v8.0.0-20260319203113-2ec59a0a61e4 - github.com/celestiaorg/go-fraud v0.2.3 github.com/celestiaorg/go-header v0.8.5 github.com/celestiaorg/go-libp2p-messenger v0.2.2 github.com/celestiaorg/go-square/merkle v0.0.0-20240117232118-fd78256df076 diff --git a/go.sum b/go.sum index b13553df5..76ecb5f03 100644 --- a/go.sum +++ b/go.sum @@ -812,8 +812,6 @@ github.com/celestiaorg/cosmos-sdk/x/upgrade v0.2.0 h1:GyDYfK8dLETlUI7F+w+3QYQgAs github.com/celestiaorg/cosmos-sdk/x/upgrade v0.2.0/go.mod h1:T4K9O18zQNKNpt4YvTL3lcUt4aKOEU05ZIFWVdQi3Ak= github.com/celestiaorg/go-datastore v0.0.0-20250801131506-48a63ae531e4 h1:udw77BU45zmvTV7798FhR1wHFmsFpu4GnA5mubtMcR0= github.com/celestiaorg/go-datastore v0.0.0-20250801131506-48a63ae531e4/go.mod h1:W+pI1NsUsz3tcsAACMtfC+IZdnQTnC/7VfPoJBQuts0= -github.com/celestiaorg/go-fraud v0.2.3 h1:vsGmd5HtGL92q/pvjN0cpDsXn7hGJSbVZwOJl+dNX8E= -github.com/celestiaorg/go-fraud v0.2.3/go.mod h1:h2Or0jHka/TDlQ3XsJV6OibIiwm49UiGVEu2jHKzybA= github.com/celestiaorg/go-header v0.8.5 h1:MkzlioiSeybKVNDa0805fS3mS3NG8ub93Gs2xaKwSZ4= github.com/celestiaorg/go-header v0.8.5/go.mod h1:DKl6pcKCJ0ehGUgDmfxBNz6Lv0Ky4E1Oyrcx96eQm/4= github.com/celestiaorg/go-libp2p-messenger v0.2.2 h1:osoUfqjss7vWTIZrrDSy953RjQz+ps/vBFE7bychLEc= @@ -1676,8 +1674,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= -github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= @@ -2045,8 +2043,6 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= -go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= diff --git a/header/headertest/fraud/testing.go b/header/headertest/fraud/testing.go deleted file mode 100644 index c44fb7a70..000000000 --- a/header/headertest/fraud/testing.go +++ /dev/null @@ -1,98 +0,0 @@ -package headerfraud - -import ( - "context" - "testing" - "time" - - "github.com/cometbft/cometbft/libs/bytes" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - "github.com/cometbft/cometbft/types" - "github.com/stretchr/testify/require" - - "github.com/celestiaorg/celestia-app/v8/pkg/da" - "github.com/celestiaorg/nmt" - "github.com/celestiaorg/rsmt2d" - - "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/header/headertest" - "github.com/celestiaorg/celestia-node/share/eds/edstest" - "github.com/celestiaorg/celestia-node/share/ipld" - "github.com/celestiaorg/celestia-node/store" -) - -// FraudMaker allows to produce an invalid header at the specified height in order to produce the -// BEFP. -type FraudMaker struct { - t *testing.T - - vals []types.PrivValidator - valSet *types.ValidatorSet - - // height of the invalid header - height int64 - - prevHash bytes.HexBytes -} - -func NewFraudMaker(t *testing.T, height int64, vals []types.PrivValidator, valSet *types.ValidatorSet) *FraudMaker { - return &FraudMaker{ - t: t, - vals: vals, - valSet: valSet, - height: height, - } -} - -func (f *FraudMaker) MakeExtendedHeader(odsSize int, edsStore *store.Store) header.ConstructFn { - return func( - h *types.Header, - comm *types.Commit, - vals *types.ValidatorSet, - eds *rsmt2d.ExtendedDataSquare, - ) (*header.ExtendedHeader, error) { - if h.Height < f.height { - return header.MakeExtendedHeader(h, comm, vals, eds) - } - - hdr := *h - if h.Height == f.height { - adder := ipld.NewProofsAdder(odsSize, false) - square := edstest.RandByzantineEDS(f.t, odsSize, nmt.NodeVisitor(adder.VisitFn())) - dah, err := da.NewDataAvailabilityHeader(square) - require.NoError(f.t, err) - hdr.DataHash = dah.Hash() - - ctx := ipld.CtxWithProofsAdder(context.Background(), adder) - require.NoError(f.t, edsStore.PutODSQ4(ctx, &dah, uint64(h.Height), square)) - - *eds = *square - } - if h.Height > f.height { - hdr.LastBlockID.Hash = f.prevHash - } - - blockID := comm.BlockID - blockID.Hash = hdr.Hash() - voteSet := types.NewVoteSet(hdr.ChainID, hdr.Height, 0, tmproto.PrecommitType, f.valSet) - commit, err := headertest.MakeCommit(blockID, hdr.Height, 0, voteSet, f.vals, time.Now()) - require.NoError(f.t, err) - - *h = hdr - *comm = *commit - f.prevHash = h.Hash() - return header.MakeExtendedHeader(h, comm, vals, eds) - } -} - -func CreateFraudExtHeader( - t *testing.T, - eh *header.ExtendedHeader, -) *header.ExtendedHeader { - square := edstest.RandByzantineEDS(t, len(eh.DAH.RowRoots)) - dah, err := da.NewDataAvailabilityHeader(square) - require.NoError(t, err) - eh.DAH = &dah - eh.DataHash = dah.Hash() - return eh -} diff --git a/nodebuilder/das/constructors.go b/nodebuilder/das/constructors.go index a280ef945..40ae7b536 100644 --- a/nodebuilder/das/constructors.go +++ b/nodebuilder/das/constructors.go @@ -6,7 +6,6 @@ import ( "github.com/ipfs/go-datastore" - "github.com/celestiaorg/go-fraud" libhead "github.com/celestiaorg/go-header" "github.com/celestiaorg/celestia-node/das" @@ -40,9 +39,8 @@ func newDASer( hsub libhead.Subscriber[*header.ExtendedHeader], store libhead.Store[*header.ExtendedHeader], batching datastore.Batching, - fraudServ fraud.Service[*header.ExtendedHeader], bFn shrexsub.BroadcastFn, options ...das.Option, ) (*das.DASer, error) { - return das.NewDASer(da, hsub, store, batching, fraudServ, bFn, options...) + return das.NewDASer(da, hsub, store, batching, bFn, options...) } diff --git a/nodebuilder/default_services.go b/nodebuilder/default_services.go index 0c12bc1f0..018b7e71d 100644 --- a/nodebuilder/default_services.go +++ b/nodebuilder/default_services.go @@ -5,7 +5,6 @@ import ( "github.com/celestiaorg/celestia-node/nodebuilder/blobstream" "github.com/celestiaorg/celestia-node/nodebuilder/da" "github.com/celestiaorg/celestia-node/nodebuilder/das" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" "github.com/celestiaorg/celestia-node/nodebuilder/header" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/nodebuilder/p2p" @@ -16,7 +15,6 @@ import ( // PackageToAPI maps a package to its API struct. Currently only used for // method discovery for openrpc spec generation var PackageToAPI = map[string]any{ - "fraud": &fraud.API{}, "state": &state.API{}, "share": &share.API{}, "header": &header.API{}, diff --git a/nodebuilder/fraud/constructors.go b/nodebuilder/fraud/constructors.go deleted file mode 100644 index 14593f3fc..000000000 --- a/nodebuilder/fraud/constructors.go +++ /dev/null @@ -1,72 +0,0 @@ -package fraud - -import ( - "context" - - "github.com/ipfs/go-datastore" - pubsub "github.com/libp2p/go-libp2p-pubsub" - "github.com/libp2p/go-libp2p/core/host" - "go.uber.org/fx" - - "github.com/celestiaorg/go-fraud" - "github.com/celestiaorg/go-fraud/fraudserv" - libhead "github.com/celestiaorg/go-header" - "github.com/celestiaorg/go-header/sync" - - "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/nodebuilder/p2p" -) - -func Unmarshaler() fraud.ProofUnmarshaler[*header.ExtendedHeader] { - return defaultProofUnmarshaler -} - -func newFraudServiceWithSync( - lc fx.Lifecycle, - sub *pubsub.PubSub, - host host.Host, - sync *sync.Syncer[*header.ExtendedHeader], - hstore libhead.Store[*header.ExtendedHeader], - registry fraud.ProofUnmarshaler[*header.ExtendedHeader], - ds datastore.Batching, - network p2p.Network, -) (Module, fraud.Service[*header.ExtendedHeader], error) { - syncerEnabled := true - headGetter := func(ctx context.Context) (*header.ExtendedHeader, error) { - return sync.Head(ctx) - } - pservice := fraudserv.NewProofService(sub, host, hstore.GetByHeight, - headGetter, registry, ds, syncerEnabled, network.String()) - lc.Append(fx.Hook{ - OnStart: pservice.Start, - OnStop: pservice.Stop, - }) - return &module{ - Service: pservice, - }, pservice, nil -} - -func newFraudServiceWithoutSync( - lc fx.Lifecycle, - sub *pubsub.PubSub, - host host.Host, - sync *sync.Syncer[*header.ExtendedHeader], - hstore libhead.Store[*header.ExtendedHeader], - registry fraud.ProofUnmarshaler[*header.ExtendedHeader], - ds datastore.Batching, - network p2p.Network, -) (Module, fraud.Service[*header.ExtendedHeader], error) { - syncerEnabled := false - headGetter := func(ctx context.Context) (*header.ExtendedHeader, error) { - return sync.Head(ctx) - } - pservice := fraudserv.NewProofService(sub, host, hstore.GetByHeight, - headGetter, registry, ds, syncerEnabled, network.String()) - lc.Append(fx.Hook{ - OnStart: pservice.Start, - OnStop: pservice.Stop, - }) - return &module{ - Service: pservice, - }, pservice, nil -} diff --git a/nodebuilder/fraud/fraud.go b/nodebuilder/fraud/fraud.go deleted file mode 100644 index 5577f049d..000000000 --- a/nodebuilder/fraud/fraud.go +++ /dev/null @@ -1,120 +0,0 @@ -package fraud - -import ( - "context" - "encoding/json" - "errors" - - "github.com/celestiaorg/go-fraud" - - "github.com/celestiaorg/celestia-node/header" -) - -var _ Module = (*API)(nil) - -// Module encompasses the behavior necessary to subscribe and broadcast fraud proofs within the -// network. Any method signature changed here needs to also be changed in the API struct. -// -//go:generate mockgen -destination=mocks/api.go -package=mocks . Module -type Module interface { - // Subscribe allows to subscribe on a Proof pub sub topic by its type. - Subscribe(context.Context, fraud.ProofType) (<-chan *Proof, error) - // Get fetches fraud proofs from the disk by its type. - Get(context.Context, fraud.ProofType) ([]Proof, error) -} - -// API is a wrapper around Module for the RPC. -type API struct { - Internal struct { - Subscribe func(context.Context, fraud.ProofType) (<-chan *Proof, error) `perm:"read"` - Get func(context.Context, fraud.ProofType) ([]Proof, error) `perm:"read"` - } -} - -func (api *API) Subscribe(ctx context.Context, proofType fraud.ProofType) (<-chan *Proof, error) { - return api.Internal.Subscribe(ctx, proofType) -} - -func (api *API) Get(ctx context.Context, proofType fraud.ProofType) ([]Proof, error) { - return api.Internal.Get(ctx, proofType) -} - -var _ Module = (*module)(nil) - -// module is an implementation of Module that uses fraud.module as a backend. It is used to -// provide fraud proofs as a non-interface type to the API, and wrap fraud.Subscriber with a -// channel of Proofs. -type module struct { - fraud.Service[*header.ExtendedHeader] -} - -func (s *module) Subscribe(ctx context.Context, proofType fraud.ProofType) (<-chan *Proof, error) { - subscription, err := s.Service.Subscribe(proofType) - if err != nil { - return nil, err - } - proofs := make(chan *Proof) - go func() { - defer close(proofs) - defer subscription.Cancel() - for { - proof, err := subscription.Proof(ctx) - if err != nil { - if !errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, context.Canceled) { - log.Errorw("fetching proof from subscription", "err", err) - } - return - } - select { - case <-ctx.Done(): - return - case proofs <- &Proof{Proof: proof}: - } - } - }() - return proofs, nil -} - -func (s *module) Get(ctx context.Context, proofType fraud.ProofType) ([]Proof, error) { - originalProofs, err := s.Service.Get(ctx, proofType) - if err != nil { - return nil, err - } - proofs := make([]Proof, len(originalProofs)) - for i, originalProof := range originalProofs { - proofs[i].Proof = originalProof - } - return proofs, nil -} - -// Proof embeds the fraud.Proof interface type to provide a concrete type for JSON serialization. -type Proof struct { - fraud.Proof[*header.ExtendedHeader] -} - -type fraudProofJSON struct { - ProofType fraud.ProofType `json:"proof_type"` - Data []byte `json:"data"` -} - -func (f *Proof) UnmarshalJSON(data []byte) error { - var fp fraudProofJSON - err := json.Unmarshal(data, &fp) - if err != nil { - return err - } - f.Proof, err = defaultProofUnmarshaler.Unmarshal(fp.ProofType, fp.Data) - return err -} - -func (f *Proof) MarshalJSON() ([]byte, error) { - marshaledProof, err := f.MarshalBinary() - if err != nil { - return nil, err - } - fraudProof := &fraudProofJSON{ - ProofType: f.Type(), - Data: marshaledProof, - } - return json.Marshal(fraudProof) -} diff --git a/nodebuilder/fraud/lifecycle.go b/nodebuilder/fraud/lifecycle.go deleted file mode 100644 index e89eaee3c..000000000 --- a/nodebuilder/fraud/lifecycle.go +++ /dev/null @@ -1,89 +0,0 @@ -package fraud - -import ( - "context" - "errors" - "fmt" - - "github.com/ipfs/go-datastore" - - "github.com/celestiaorg/go-fraud" - libhead "github.com/celestiaorg/go-header" -) - -// service defines minimal interface with service lifecycle methods -type service interface { - Start(context.Context) error - Stop(context.Context) error -} - -// ServiceBreaker wraps any service with fraud proof subscription of a specific type. -// If proof happens the service is Stopped automatically. -// TODO(@Wondertan): Support multiple fraud types. -type ServiceBreaker[S service, H libhead.Header[H]] struct { - Service S - FraudType fraud.ProofType - FraudServ fraud.Service[H] - - ctx context.Context - cancel context.CancelFunc - sub fraud.Subscription[H] -} - -// Start starts the inner service if there are no fraud proofs stored. -// Subscribes for fraud and stops the service whenever necessary. -func (breaker *ServiceBreaker[S, H]) Start(ctx context.Context) error { - if breaker == nil { - return nil - } - - proofs, err := breaker.FraudServ.Get(ctx, breaker.FraudType) - switch { - default: - return fmt.Errorf("getting proof(%s): %w", breaker.FraudType, err) - case err == nil: - return &fraud.ErrFraudExists[H]{Proof: proofs} - case errors.Is(err, datastore.ErrNotFound): - } - - err = breaker.Service.Start(ctx) - if err != nil { - return err - } - - breaker.sub, err = breaker.FraudServ.Subscribe(breaker.FraudType) - if err != nil { - return fmt.Errorf("subscribing for proof(%s): %w", breaker.FraudType, err) - } - - breaker.ctx, breaker.cancel = context.WithCancel(context.Background()) - go breaker.awaitProof() - return nil -} - -// Stop stops the service and cancels subscription. -func (breaker *ServiceBreaker[S, H]) Stop(ctx context.Context) error { - if breaker == nil { - return nil - } - - if breaker.ctx.Err() != nil { - // short circuit if the service was already stopped - return nil - } - - breaker.sub.Cancel() - defer breaker.cancel() - return breaker.Service.Stop(ctx) -} - -func (breaker *ServiceBreaker[S, H]) awaitProof() { - _, err := breaker.sub.Proof(breaker.ctx) - if err != nil { - return - } - - if err := breaker.Stop(breaker.ctx); err != nil && !errors.Is(err, context.Canceled) { - log.Errorw("stopping service", "err", err.Error()) - } -} diff --git a/nodebuilder/fraud/mocks/api.go b/nodebuilder/fraud/mocks/api.go deleted file mode 100644 index fcc7a5823..000000000 --- a/nodebuilder/fraud/mocks/api.go +++ /dev/null @@ -1,67 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/celestiaorg/celestia-node/nodebuilder/fraud (interfaces: Module) - -// Package mocks is a generated GoMock package. -package mocks - -import ( - context "context" - reflect "reflect" - - fraud "github.com/celestiaorg/celestia-node/nodebuilder/fraud" - fraud0 "github.com/celestiaorg/go-fraud" - gomock "github.com/golang/mock/gomock" -) - -// MockModule is a mock of Module interface. -type MockModule struct { - ctrl *gomock.Controller - recorder *MockModuleMockRecorder -} - -// MockModuleMockRecorder is the mock recorder for MockModule. -type MockModuleMockRecorder struct { - mock *MockModule -} - -// NewMockModule creates a new mock instance. -func NewMockModule(ctrl *gomock.Controller) *MockModule { - mock := &MockModule{ctrl: ctrl} - mock.recorder = &MockModuleMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockModule) EXPECT() *MockModuleMockRecorder { - return m.recorder -} - -// Get mocks base method. -func (m *MockModule) Get(arg0 context.Context, arg1 fraud0.ProofType) ([]fraud.Proof, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0, arg1) - ret0, _ := ret[0].([]fraud.Proof) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Get indicates an expected call of Get. -func (mr *MockModuleMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockModule)(nil).Get), arg0, arg1) -} - -// Subscribe mocks base method. -func (m *MockModule) Subscribe(arg0 context.Context, arg1 fraud0.ProofType) (<-chan *fraud.Proof, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Subscribe", arg0, arg1) - ret0, _ := ret[0].(<-chan *fraud.Proof) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Subscribe indicates an expected call of Subscribe. -func (mr *MockModuleMockRecorder) Subscribe(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockModule)(nil).Subscribe), arg0, arg1) -} diff --git a/nodebuilder/fraud/module.go b/nodebuilder/fraud/module.go deleted file mode 100644 index 9c1fbda1f..000000000 --- a/nodebuilder/fraud/module.go +++ /dev/null @@ -1,38 +0,0 @@ -package fraud - -import ( - logging "github.com/ipfs/go-log/v2" - "go.uber.org/fx" - - "github.com/celestiaorg/go-fraud" - - "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/nodebuilder/node" -) - -var log = logging.Logger("module/fraud") - -func ConstructModule(tp node.Type) fx.Option { - baseComponent := fx.Options( - fx.Provide(Unmarshaler), - fx.Provide(func(serv fraud.Service[*header.ExtendedHeader]) fraud.Getter[*header.ExtendedHeader] { - return serv - }), - ) - switch tp { - case node.Light: - return fx.Module( - "fraud", - baseComponent, - fx.Provide(newFraudServiceWithSync), - ) - case node.Bridge: - return fx.Module( - "fraud", - baseComponent, - fx.Provide(newFraudServiceWithoutSync), - ) - default: - panic("invalid node type") - } -} diff --git a/nodebuilder/fraud/unmarshaler.go b/nodebuilder/fraud/unmarshaler.go deleted file mode 100644 index d5e0461f0..000000000 --- a/nodebuilder/fraud/unmarshaler.go +++ /dev/null @@ -1,32 +0,0 @@ -package fraud - -import ( - "github.com/celestiaorg/go-fraud" - - "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/share/eds/byzantine" -) - -var defaultProofUnmarshaler proofRegistry - -type proofRegistry struct{} - -func (pr proofRegistry) List() []fraud.ProofType { - return []fraud.ProofType{ - byzantine.BadEncoding, - } -} - -func (pr proofRegistry) Unmarshal(proofType fraud.ProofType, data []byte) (fraud.Proof[*header.ExtendedHeader], error) { - switch proofType { - case byzantine.BadEncoding: - befp := &byzantine.BadEncodingProof{} - err := befp.UnmarshalBinary(data) - if err != nil { - return nil, err - } - return befp, nil - default: - return nil, &fraud.ErrNoUnmarshaler{ProofType: proofType} - } -} diff --git a/nodebuilder/module.go b/nodebuilder/module.go index cb0ef9c1f..336b59339 100644 --- a/nodebuilder/module.go +++ b/nodebuilder/module.go @@ -12,7 +12,6 @@ import ( "github.com/celestiaorg/celestia-node/nodebuilder/core" "github.com/celestiaorg/celestia-node/nodebuilder/da" "github.com/celestiaorg/celestia-node/nodebuilder/das" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" modhead "github.com/celestiaorg/celestia-node/nodebuilder/header" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/nodebuilder/p2p" @@ -49,7 +48,6 @@ func ConstructModule(tp node.Type, network p2p.Network, cfg *Config, store Store share.ConstructModule(tp, &cfg.Share), state.ConstructModule(tp, &cfg.State, &cfg.Core), das.ConstructModule(&cfg.DASer), - fraud.ConstructModule(tp), blob.ConstructModule(), da.ConstructModule(), node.ConstructModule(tp), diff --git a/nodebuilder/node.go b/nodebuilder/node.go index 48b3c1080..f64201316 100644 --- a/nodebuilder/node.go +++ b/nodebuilder/node.go @@ -24,7 +24,6 @@ import ( "github.com/celestiaorg/celestia-node/nodebuilder/blobstream" "github.com/celestiaorg/celestia-node/nodebuilder/da" "github.com/celestiaorg/celestia-node/nodebuilder/das" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" "github.com/celestiaorg/celestia-node/nodebuilder/header" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/nodebuilder/p2p" @@ -71,7 +70,6 @@ type Node struct { ShareServ share.Module // not optional HeaderServ header.Module // not optional StateServ state.Module // not optional - FraudServ fraud.Module // not optional BlobServ blob.Module // not optional DASer das.Module // not optional AdminServ node.Module // not optional diff --git a/nodebuilder/p2p/pubsub.go b/nodebuilder/p2p/pubsub.go index 214592aaf..e02c19375 100644 --- a/nodebuilder/p2p/pubsub.go +++ b/nodebuilder/p2p/pubsub.go @@ -15,11 +15,7 @@ import ( "go.uber.org/fx" "golang.org/x/crypto/blake2b" - "github.com/celestiaorg/go-fraud" - "github.com/celestiaorg/go-fraud/fraudserv" headp2p "github.com/celestiaorg/go-header/p2p" - - "github.com/celestiaorg/celestia-node/header" ) func init() { @@ -107,19 +103,12 @@ type pubSubParams struct { Host hst.Host Bootstrappers Bootstrappers Network Network - Unmarshaler fraud.ProofUnmarshaler[*header.ExtendedHeader] } func topicScoreParams(params pubSubParams) map[string]*pubsub.TopicScoreParams { - mp := map[string]*pubsub.TopicScoreParams{ + return map[string]*pubsub.TopicScoreParams{ headp2p.PubsubTopicID(params.Network.String()): &headp2p.GossibSubScore, } - - for _, pt := range params.Unmarshaler.List() { - mp[fraudserv.PubsubTopicID(pt.String(), params.Network.String())] = &fraudserv.GossibSubScore - } - - return mp } func peerScoreParams(bootstrappers Bootstrappers, cfg *Config) (*pubsub.PeerScoreParams, error) { diff --git a/nodebuilder/rpc/constructors.go b/nodebuilder/rpc/constructors.go index 184750f4e..dbc8029f2 100644 --- a/nodebuilder/rpc/constructors.go +++ b/nodebuilder/rpc/constructors.go @@ -8,7 +8,6 @@ import ( "github.com/celestiaorg/celestia-node/nodebuilder/blobstream" "github.com/celestiaorg/celestia-node/nodebuilder/da" "github.com/celestiaorg/celestia-node/nodebuilder/das" - "github.com/celestiaorg/celestia-node/nodebuilder/fraud" "github.com/celestiaorg/celestia-node/nodebuilder/header" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/nodebuilder/p2p" @@ -20,7 +19,6 @@ import ( func registerEndpoints( stateMod state.Module, shareMod share.Module, - fraudMod fraud.Module, headerMod header.Module, daserMod das.Module, p2pMod p2p.Module, @@ -30,7 +28,6 @@ func registerEndpoints( blobstreamMod blobstream.Module, serv *rpc.Server, ) { - serv.RegisterService("fraud", fraudMod, &fraud.API{}) serv.RegisterService("das", daserMod, &das.API{}) serv.RegisterService("header", headerMod, &header.API{}) serv.RegisterService("state", stateMod, &state.API{}) diff --git a/nodebuilder/settings.go b/nodebuilder/settings.go index d11e2d80e..f844ae031 100644 --- a/nodebuilder/settings.go +++ b/nodebuilder/settings.go @@ -23,10 +23,7 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/fx" - "github.com/celestiaorg/go-fraud" - "github.com/celestiaorg/celestia-node/blob" - "github.com/celestiaorg/celestia-node/header" "github.com/celestiaorg/celestia-node/libs/utils" modcore "github.com/celestiaorg/celestia-node/nodebuilder/core" "github.com/celestiaorg/celestia-node/nodebuilder/das" @@ -114,7 +111,6 @@ func WithMetrics(metricOpts []otlpmetrichttp.Option, nodeType node.Type) fx.Opti } return nil }), - fx.Invoke(fraud.WithMetrics[*header.ExtendedHeader]), fx.Invoke(node.WithMetrics), fx.Invoke(share.WithDiscoveryMetrics), fx.Invoke(share.WithBlockStoreMetrics), diff --git a/nodebuilder/tests/fraud_test.go b/nodebuilder/tests/fraud_test.go deleted file mode 100644 index 0b79ca8bc..000000000 --- a/nodebuilder/tests/fraud_test.go +++ /dev/null @@ -1,164 +0,0 @@ -//go:build fraud || integration - -package tests - -import ( - "context" - "testing" - "time" - - "github.com/cometbft/cometbft/types" - "github.com/stretchr/testify/require" - "go.uber.org/fx" - - "github.com/celestiaorg/go-fraud" - - "github.com/celestiaorg/celestia-node/header" - headerfraud "github.com/celestiaorg/celestia-node/header/headertest/fraud" - "github.com/celestiaorg/celestia-node/nodebuilder" - "github.com/celestiaorg/celestia-node/nodebuilder/core" - "github.com/celestiaorg/celestia-node/nodebuilder/node" - "github.com/celestiaorg/celestia-node/nodebuilder/tests/swamp" - "github.com/celestiaorg/celestia-node/share/eds/byzantine" - "github.com/celestiaorg/celestia-node/store" -) - -/* -Test-Case: Full Node will propagate a fraud proof to the network, once ByzantineError will be received from sampling. -Pre-Requisites: -- CoreClient is started by swamp. -Steps: -1. Create a Bridge Node(BN) with broken extended header at height 10. -2. Start a BN. -3. Create a Full Node(FN) with a connection to BN as a trusted peer. -4. Start a FN. -5. Subscribe to a fraud proof and wait when it will be received. -6. Check FN is not synced to 15. -Note: 15 is not available because DASer/Syncer will be stopped -before reaching this height due to receiving a fraud proof. -Another note: this test disables share exchange to speed up test results. -7. Spawn a Light Node(LN) in order to sync a BEFP. -8. Ensure that the BEFP was received. -9. Try to start a Full Node(FN) that contains a BEFP in its store. -*/ -func TestFraudProofHandling(t *testing.T) { - t.Skip("unsupported temporary") - - ctx, cancel := context.WithTimeout(context.Background(), swamp.DefaultTestTimeout) - t.Cleanup(cancel) - - const ( - blocks = 15 - blockSize = 4 - blockTime = time.Second - ) - - sw := swamp.NewSwamp(t, swamp.WithBlockTime(blockTime)) - _, fillDn := swamp.FillBlocks(ctx, sw.ClientContext, sw.Accounts[0], blockSize, blocks) - set, val := sw.Validators(t) - fMaker := headerfraud.NewFraudMaker(t, 10, []types.PrivValidator{val}, set) - - storeCfg := store.DefaultParameters() - edsStore, err := store.NewStore(storeCfg, t.TempDir()) - require.NoError(t, err) - t.Cleanup(func() { - _ = edsStore.Stop(ctx) - }) - - // 1. - bridge := sw.NewBridgeNode( - core.WithHeaderConstructFn(fMaker.MakeExtendedHeader(16, edsStore)), - fx.Replace(edsStore), - ) - // 2. - err = bridge.Start(ctx) - require.NoError(t, err) - sw.SetBootstrapper(t, bridge) - // 3. - cfg := sw.DefaultTestConfig(node.Bridge) - cfg.Share.UseShareExchange = false - store := nodebuilder.MockStore(t, cfg) - full := sw.MustNewNodeWithStore(node.Bridge, store) - - // 4. - err = full.Start(ctx) - require.NoError(t, err) - - fullClient := getAdminClient(ctx, full, t) - - // 5. - subCtx, subCancel := context.WithCancel(ctx) - subscr, err := fullClient.Fraud.Subscribe(subCtx, byzantine.BadEncoding) - require.NoError(t, err) - select { - case p := <-subscr: - require.Equal(t, 10, int(p.Height())) - t.Log("Caught the proof....") - subCancel() - case <-ctx.Done(): - subCancel() - t.Fatal("full node did not receive a fraud proof in time") - } - - getCtx, getCancel := context.WithTimeout(ctx, time.Second) - proofs, err := fullClient.Fraud.Get(getCtx, byzantine.BadEncoding) - getCancel() - - require.NoError(t, err) - require.Len(t, proofs, 1) - require.True(t, proofs[0].Type() == byzantine.BadEncoding) - // This is an obscure way to check if the Syncer was stopped. - // If we cannot get a height header within a timeframe it means the syncer was stopped - // FIXME: Eventually, this should be a check on service registry managing and keeping - // lifecycles of each Module. - // 6. - // random height after befp.height - height := uint64(15) - // initial timeout is set to 5 sec, as we are targeting the height=15, - // blockTime=1 sec, expected befp.height=10 - timeOut := blockTime * 5 - // during befp validation the node can still receive headers and it mostly depends on - // the operating system or hardware(e.g. on macOS tests is working 100% time with a single - // height=15, and on the Linux VM sometimes the last height is 17-18). So, lets give a chance for - // our befp validator to check the fraud proof and stop the syncer. - for height < 20 { - syncCtx, syncCancel := context.WithTimeout(context.Background(), timeOut) - _, err = full.HeaderServ.WaitForHeight(syncCtx, height) - syncCancel() - if err != nil { - break - } - timeOut = blockTime - height++ - } - require.ErrorIs(t, err, context.DeadlineExceeded) - - // 7. - light := sw.NewLightNode() - require.NoError(t, light.Start(ctx)) - lightClient := getAdminClient(ctx, light, t) - - // 8. - subCtx, subCancel = context.WithCancel(ctx) - subscr, err = lightClient.Fraud.Subscribe(subCtx, byzantine.BadEncoding) - require.NoError(t, err) - select { - case p := <-subscr: - require.Equal(t, 10, int(p.Height())) - subCancel() - case <-ctx.Done(): - subCancel() - t.Fatal("light node did not receive a fraud proof in time") - } - - // 9. - fN := sw.MustNewNodeWithStore(node.Bridge, store) - err = fN.Start(ctx) - var fpExist *fraud.ErrFraudExists[*header.ExtendedHeader] - require.ErrorAs(t, err, &fpExist) - - sw.StopNode(ctx, bridge) - sw.StopNode(ctx, full) - sw.StopNode(ctx, light) - require.NoError(t, <-fillDn) -} diff --git a/nodebuilder/tests/tastora/go.mod b/nodebuilder/tests/tastora/go.mod index cd47ce03c..cf05f40ff 100644 --- a/nodebuilder/tests/tastora/go.mod +++ b/nodebuilder/tests/tastora/go.mod @@ -43,7 +43,6 @@ require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.24.0 // indirect - github.com/celestiaorg/go-fraud v0.2.3 // indirect github.com/celestiaorg/go-header v0.8.5 // indirect github.com/celestiaorg/go-libp2p-messenger v0.2.2 // indirect github.com/celestiaorg/go-square/merkle v0.0.0-20240117232118-fd78256df076 // indirect diff --git a/nodebuilder/tests/tastora/go.sum b/nodebuilder/tests/tastora/go.sum index 56a1a70c7..b11c91c41 100644 --- a/nodebuilder/tests/tastora/go.sum +++ b/nodebuilder/tests/tastora/go.sum @@ -808,8 +808,6 @@ github.com/celestiaorg/cosmos-sdk/x/upgrade v0.2.0 h1:GyDYfK8dLETlUI7F+w+3QYQgAs github.com/celestiaorg/cosmos-sdk/x/upgrade v0.2.0/go.mod h1:T4K9O18zQNKNpt4YvTL3lcUt4aKOEU05ZIFWVdQi3Ak= github.com/celestiaorg/go-datastore v0.0.0-20250801131506-48a63ae531e4 h1:udw77BU45zmvTV7798FhR1wHFmsFpu4GnA5mubtMcR0= github.com/celestiaorg/go-datastore v0.0.0-20250801131506-48a63ae531e4/go.mod h1:W+pI1NsUsz3tcsAACMtfC+IZdnQTnC/7VfPoJBQuts0= -github.com/celestiaorg/go-fraud v0.2.3 h1:vsGmd5HtGL92q/pvjN0cpDsXn7hGJSbVZwOJl+dNX8E= -github.com/celestiaorg/go-fraud v0.2.3/go.mod h1:h2Or0jHka/TDlQ3XsJV6OibIiwm49UiGVEu2jHKzybA= github.com/celestiaorg/go-header v0.8.5 h1:MkzlioiSeybKVNDa0805fS3mS3NG8ub93Gs2xaKwSZ4= github.com/celestiaorg/go-header v0.8.5/go.mod h1:DKl6pcKCJ0ehGUgDmfxBNz6Lv0Ky4E1Oyrcx96eQm/4= github.com/celestiaorg/go-libp2p-messenger v0.2.2 h1:osoUfqjss7vWTIZrrDSy953RjQz+ps/vBFE7bychLEc= @@ -1682,8 +1680,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= -github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= @@ -2065,8 +2063,6 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= -go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= diff --git a/share/eds/byzantine/bad_encoding.go b/share/eds/byzantine/bad_encoding.go deleted file mode 100644 index d7ddf30e8..000000000 --- a/share/eds/byzantine/bad_encoding.go +++ /dev/null @@ -1,256 +0,0 @@ -package byzantine - -import ( - "bytes" - "errors" - "fmt" - "slices" - - "github.com/celestiaorg/celestia-app/v8/pkg/wrapper" - "github.com/celestiaorg/go-fraud" - "github.com/celestiaorg/rsmt2d" - - "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/share" - pb "github.com/celestiaorg/celestia-node/share/eds/byzantine/pb" -) - -const ( - version = "v0.1" - - BadEncoding fraud.ProofType = "badencoding" + version -) - -type BadEncodingProof struct { - headerHash []byte - BlockHeight uint64 - // ShareWithProof contains all shares from row or col. - // Shares that did not pass verification in rsmt2d will be nil. - // For non-nil shares MerkleProofs are computed. - Shares []*ShareWithProof - // Index represents the row/col index where ErrByzantineRow/ErrByzantineColl occurred. - Index uint32 - // Axis represents the axis that verification failed on. - Axis rsmt2d.Axis -} - -// CreateBadEncodingProof creates a new Bad Encoding Fraud Proof that should be propagated through -// network. The fraud proof will contain shares that did not pass verification and their relevant -// Merkle proofs. -func CreateBadEncodingProof( - hash []byte, - height uint64, - errByzantine *ErrByzantine, -) fraud.Proof[*header.ExtendedHeader] { - return &BadEncodingProof{ - headerHash: hash, - BlockHeight: height, - Shares: errByzantine.Shares, - Index: errByzantine.Index, - Axis: errByzantine.Axis, - } -} - -// Type returns type of fraud proof. -func (p *BadEncodingProof) Type() fraud.ProofType { - return BadEncoding -} - -// HeaderHash returns block hash. -func (p *BadEncodingProof) HeaderHash() []byte { - return p.headerHash -} - -// Height returns block height. -func (p *BadEncodingProof) Height() uint64 { - return p.BlockHeight -} - -// MarshalBinary converts BadEncodingProof to binary. -func (p *BadEncodingProof) MarshalBinary() ([]byte, error) { - shares := make([]*pb.Share, 0, len(p.Shares)) - for _, share := range p.Shares { - shares = append(shares, share.ShareWithProofToProto()) - } - - badEncodingFraudProof := pb.BadEncoding{ - HeaderHash: p.headerHash, - Height: p.BlockHeight, - Shares: shares, - Index: p.Index, - Axis: pb.Axis(p.Axis), - } - return badEncodingFraudProof.Marshal() -} - -// UnmarshalBinary converts binary to BadEncodingProof. -func (p *BadEncodingProof) UnmarshalBinary(data []byte) error { - in := pb.BadEncoding{} - if err := in.Unmarshal(data); err != nil { - return err - } - sh, err := ProtoToShare(in.Shares) - if err != nil { - return err - } - befp := &BadEncodingProof{ - headerHash: in.HeaderHash, - BlockHeight: in.Height, - Shares: sh, - Index: in.Index, - Axis: rsmt2d.Axis(in.Axis), - } - - *p = *befp - - return nil -} - -var ( - errHeightMismatch = errors.New("height reported in proof does not match with the header's height") - errIncorrectIndex = errors.New("row/col index is more then the roots amount") - errIncorrectAmountOfShares = errors.New("incorrect amount of shares") - errIncorrectShare = errors.New("incorrect share received") - errNMTTreeRootsMatch = errors.New("recomputed root matches the DAH root") -) - -var invalidProofPrefix = fmt.Sprintf("invalid %s proof", BadEncoding) - -// Validate ensures that fraud proof is correct. -// Validate checks that provided Merkle Proofs correspond to the shares, -// rebuilds bad row or col from received shares, computes Merkle Root -// and compares it with block's Merkle Root. -func (p *BadEncodingProof) Validate(hdr *header.ExtendedHeader) error { - if hdr.Height() != p.BlockHeight { - log.Debugf("%s: %s. expected block's height: %d, got: %d", - invalidProofPrefix, - errHeightMismatch, - hdr.Height(), - p.BlockHeight, - ) - return errHeightMismatch - } - - if len(hdr.DAH.RowRoots) != len(hdr.DAH.ColumnRoots) { - // NOTE: This should never happen as callers of this method should not feed it with a - // malformed extended header. - panic(fmt.Sprintf( - "invalid extended header: length of row and column roots do not match. (rowRoots=%d) (colRoots=%d)", - len(hdr.DAH.RowRoots), - len(hdr.DAH.ColumnRoots)), - ) - } - - width := len(hdr.DAH.RowRoots) - if int(p.Index) >= width { - log.Debugf("%s:%s (%d >= %d)", - invalidProofPrefix, errIncorrectIndex, int(p.Index), width, - ) - return errIncorrectIndex - } - - if len(p.Shares) != width { - // Since p.Shares should contain all the shares from either a row or a - // column, it should exactly match the number of row roots. In this - // context, the number of row roots is the width of the extended data - // square. - log.Infof("%s: %s (%d >= %d)", - invalidProofPrefix, errIncorrectAmountOfShares, int(p.Index), width, - ) - return errIncorrectAmountOfShares - } - - odsWidth := width / 2 - var amount int - for _, share := range p.Shares { - if share == nil { - continue - } - amount++ - if amount == odsWidth { - break - } - } - - if amount < odsWidth { - log.Debugf("%s: %s. not enough shares provided to reconstruct row/col", - invalidProofPrefix, errIncorrectAmountOfShares) - return errIncorrectAmountOfShares - } - - indexes := make([]int, 0) //nolint:prealoc - // verify that Merkle proofs correspond to particular shares. - shares := make([][]byte, width) - for index, shr := range p.Shares { - if shr == nil { - continue - } - // validate inclusion of the share into one of the DAHeader roots - if ok := shr.Validate(hdr.DAH, p.Axis, int(p.Index), index); !ok { - log.Debugf("%s: %s at index %d", invalidProofPrefix, errIncorrectShare, index) - return errIncorrectShare - } - shares[index] = shr.ToBytes() - indexes = append(indexes, shr.Proof.Start()) - } - - isSorted := slices.IsSorted(indexes) - if !isSorted { - err := errors.New("provided share list is not sorted") - log.Debugf("%v", err) - return err - } - - codec := share.DefaultRSMT2DCodec() - - // We can conclude that the proof is valid in case we proved the inclusion of `Shares` but - // the row/col can't be reconstructed, or the building of NMTree fails. - rebuiltShares, err := codec.Decode(shares) - if err != nil { - log.Debugw("failed to decode shares at height", - "height", hdr.Height(), "err", err, - ) - return nil - } - - rebuiltExtendedShares, err := codec.Encode(rebuiltShares[0:odsWidth]) - if err != nil { - log.Debugw("failed to encode shares at height", - "height", hdr.Height(), "err", err, - ) - return nil - } - copy(rebuiltShares[odsWidth:], rebuiltExtendedShares) - - tree := wrapper.NewErasuredNamespacedMerkleTree(uint64(odsWidth), uint(p.Index)) - for _, share := range rebuiltShares { - err = tree.Push(share) - if err != nil { - log.Debugw("failed to build a tree from the reconstructed shares at height", - "height", hdr.Height(), "err", err, - ) - return nil - } - } - - expectedRoot, err := tree.Root() - if err != nil { - log.Debugw("failed to build a tree root at height", - "height", hdr.Height(), "err", err, - ) - return nil - } - - // root is a merkle root of the row/col where ErrByzantine occurred - root := hdr.DAH.RowRoots[p.Index] - if p.Axis == rsmt2d.Col { - root = hdr.DAH.ColumnRoots[p.Index] - } - - // comparing rebuilt Merkle Root of bad row/col with respective Merkle Root of row/col from block. - if bytes.Equal(expectedRoot, root) { - log.Debugf("invalid %s proof:%s", BadEncoding, errNMTTreeRootsMatch) - return errNMTTreeRootsMatch - } - return nil -} diff --git a/share/eds/byzantine/bad_encoding_test.go b/share/eds/byzantine/bad_encoding_test.go deleted file mode 100644 index bbf05a288..000000000 --- a/share/eds/byzantine/bad_encoding_test.go +++ /dev/null @@ -1,376 +0,0 @@ -package byzantine - -import ( - "context" - "hash" - "testing" - "time" - - core "github.com/cometbft/cometbft/types" - "github.com/ipfs/boxo/blockservice" - blocks "github.com/ipfs/go-block-format" - "github.com/ipfs/go-cid" - mhcore "github.com/multiformats/go-multihash/core" - "github.com/stretchr/testify/require" - - "github.com/celestiaorg/celestia-app/v8/test/util/malicious" - libshare "github.com/celestiaorg/go-square/v4/share" - "github.com/celestiaorg/nmt" - "github.com/celestiaorg/rsmt2d" - - "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/share" - "github.com/celestiaorg/celestia-node/share/eds/edstest" - "github.com/celestiaorg/celestia-node/share/ipld" -) - -func TestBEFP_Validate(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer t.Cleanup(cancel) - bServ := ipld.NewMemBlockservice() - - byzSquare := edstest.RandByzantineEDS(t, 16) - roots, err := share.NewAxisRoots(byzSquare) - require.NoError(t, err) - err = ipld.ImportEDS(ctx, byzSquare, bServ) - require.NoError(t, err) - - var errRsmt2d *rsmt2d.ErrByzantineData - err = byzSquare.Repair(roots.RowRoots, roots.ColumnRoots) - require.ErrorAs(t, err, &errRsmt2d) - - byzantine := NewErrByzantine(ctx, bServ.Blockstore(), roots, errRsmt2d) - var errByz *ErrByzantine - require.ErrorAs(t, byzantine, &errByz) - - proof := CreateBadEncodingProof([]byte("hash"), 0, errByz) - befp, ok := proof.(*BadEncodingProof) - require.True(t, ok) - test := []struct { - name string - prepareFn func() error - expectedResult func(error) - }{ - { - name: "valid BEFP", - prepareFn: func() error { - return proof.Validate(&header.ExtendedHeader{DAH: roots}) - }, - expectedResult: func(err error) { - require.NoError(t, err) - }, - }, - { - name: "invalid BEFP for valid header", - prepareFn: func() error { - validSquare := edstest.RandEDS(t, 2) - validRoots, err := share.NewAxisRoots(validSquare) - require.NoError(t, err) - err = ipld.ImportEDS(ctx, validSquare, bServ) - require.NoError(t, err) - validShares := validSquare.Flattened() - errInvalidByz := NewErrByzantine(ctx, bServ.Blockstore(), validRoots, - &rsmt2d.ErrByzantineData{ - Axis: rsmt2d.Row, - Index: 0, - Shares: validShares[0:4], - }, - ) - var errInvalid *ErrByzantine - require.ErrorAs(t, errInvalidByz, &errInvalid) - invalidBefp := CreateBadEncodingProof([]byte("hash"), 0, errInvalid) - return invalidBefp.Validate(&header.ExtendedHeader{DAH: validRoots}) - }, - expectedResult: func(err error) { - require.ErrorIs(t, err, errNMTTreeRootsMatch) - }, - }, - { - name: "invalid BEFP with unordered shares list", - prepareFn: func() error { - validSquare := edstest.RandEDS(t, 2) - validRoots, err := share.NewAxisRoots(validSquare) - require.NoError(t, err) - err = ipld.ImportEDS(ctx, validSquare, bServ) - require.NoError(t, err) - validShares := validSquare.Flattened() - errInvalidByz := NewErrByzantine(ctx, bServ.Blockstore(), validRoots, - &rsmt2d.ErrByzantineData{ - Axis: rsmt2d.Row, - Index: 0, - Shares: validShares[0:4], - }, - ) - var errInvalid *ErrByzantine - require.ErrorAs(t, errInvalidByz, &errInvalid) - errInvalid.Shares[0], errInvalid.Shares[1] = errInvalid.Shares[1], errInvalid.Shares[0] - invalidBefp := CreateBadEncodingProof([]byte("hash"), 0, errInvalid) - return invalidBefp.Validate(&header.ExtendedHeader{DAH: validRoots}) - }, - expectedResult: func(err error) { - require.Error(t, err) - }, - }, - { - name: "incorrect share with Proof", - prepareFn: func() error { - // break the first shareWithProof to test negative case - sh, err := libshare.RandShares(2) - require.NoError(t, err) - nmtProof := nmt.NewInclusionProof(0, 1, nil, false) - befp.Shares[0] = &ShareWithProof{sh[0], &nmtProof, rsmt2d.Row} - return proof.Validate(&header.ExtendedHeader{DAH: roots}) - }, - expectedResult: func(err error) { - require.ErrorIs(t, err, errIncorrectShare) - }, - }, - { - name: "invalid amount of shares", - prepareFn: func() error { - befp.Shares = befp.Shares[0 : len(befp.Shares)/2] - return proof.Validate(&header.ExtendedHeader{DAH: roots}) - }, - expectedResult: func(err error) { - require.ErrorIs(t, err, errIncorrectAmountOfShares) - }, - }, - { - name: "not enough shares to recompute the root", - prepareFn: func() error { - befp.Shares[0] = nil - return proof.Validate(&header.ExtendedHeader{DAH: roots}) - }, - expectedResult: func(err error) { - require.ErrorIs(t, err, errIncorrectAmountOfShares) - }, - }, - { - name: "index out of bounds", - prepareFn: func() error { - befp.Index = 100 - return proof.Validate(&header.ExtendedHeader{DAH: roots}) - }, - expectedResult: func(err error) { - require.ErrorIs(t, err, errIncorrectIndex) - }, - }, - { - name: "heights mismatch", - prepareFn: func() error { - return proof.Validate(&header.ExtendedHeader{ - RawHeader: core.Header{ - Height: 42, - }, - DAH: roots, - }) - }, - expectedResult: func(err error) { - require.ErrorIs(t, err, errHeightMismatch) - }, - }, - } - - for _, tt := range test { - t.Run(tt.name, func(t *testing.T) { - err = tt.prepareFn() - tt.expectedResult(err) - }) - } -} - -// TestIncorrectBadEncodingFraudProof asserts that BEFP is not generated for the correct data -func TestIncorrectBadEncodingFraudProof(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - bServ := ipld.NewMemBlockservice() - - squareSize := 8 - shares, err := libshare.RandShares(squareSize * squareSize) - require.NoError(t, err) - eds, err := ipld.AddShares(ctx, shares, bServ) - require.NoError(t, err) - - roots, err := share.NewAxisRoots(eds) - require.NoError(t, err) - - // get an arbitrary row - rowIdx := squareSize / 2 - shareProofs := make([]*ShareWithProof, 0, eds.Width()) - for i := range shareProofs { - proof, err := GetShareWithProof(ctx, bServ, roots, shares[i], rsmt2d.Row, rowIdx, i) - require.NoError(t, err) - shareProofs = append(shareProofs, proof) - } - - // create a fake error for data that was encoded correctly - fakeError := ErrByzantine{ - Index: uint32(rowIdx), - Shares: shareProofs, - Axis: rsmt2d.Row, - } - - h := &header.ExtendedHeader{ - RawHeader: core.Header{ - Height: 420, - }, - DAH: roots, - Commit: &core.Commit{ - BlockID: core.BlockID{ - Hash: []byte("made up hash"), - }, - }, - } - - proof := CreateBadEncodingProof(h.Hash(), h.Height(), &fakeError) - err = proof.Validate(h) - require.Error(t, err) -} - -func TestBEFP_ValidateOutOfOrderShares(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - t.Cleanup(cancel) - - size := 4 - eds := edstest.RandEDS(t, size) - - shares := eds.Flattened() - shares[0], shares[4] = shares[4], shares[0] // corrupting eds - - bServ := newNamespacedBlockService() - batchAddr := ipld.NewNmtNodeAdder(ctx, bServ, ipld.MaxSizeBatchOption(size*2)) - - eds, err := rsmt2d.ImportExtendedDataSquare(shares, - share.DefaultRSMT2DCodec(), - malicious.NewConstructor(uint64(size), nmt.NodeVisitor(batchAddr.Visit)), - ) - require.NoError(t, err, "failure to recompute the extended data square") - - roots, err := share.NewAxisRoots(eds) - require.NoError(t, err) - - var errRsmt2d *rsmt2d.ErrByzantineData - err = eds.Repair(roots.RowRoots, roots.ColumnRoots) - require.ErrorAs(t, err, &errRsmt2d) - - err = batchAddr.Commit() - require.NoError(t, err) - - byzantine := NewErrByzantine(ctx, bServ.Blockstore(), roots, errRsmt2d) - var errByz *ErrByzantine - require.ErrorAs(t, byzantine, &errByz) - - befp := CreateBadEncodingProof([]byte("hash"), 0, errByz) - err = befp.Validate(&header.ExtendedHeader{DAH: roots}) - require.NoError(t, err) -} - -// namespacedBlockService wraps `BlockService` and extends the verification part -// to avoid returning blocks that has out of order namespaces. -type namespacedBlockService struct { - blockservice.BlockService - // the data structure that is used on the networking level, in order - // to verify the order of the namespaces - prefix *cid.Prefix -} - -func newNamespacedBlockService() *namespacedBlockService { - sha256NamespaceFlagged := uint64(0x7701) - // register the nmt hasher to validate the order of namespaces - mhcore.Register(sha256NamespaceFlagged, func() hash.Hash { - nh := nmt.NewNmtHasher(share.NewSHA256Hasher(), libshare.NamespaceSize, true) - nh.Reset() - return nh - }) - - bs := &namespacedBlockService{} - bs.BlockService = ipld.NewMemBlockservice() - - bs.prefix = &cid.Prefix{ - Version: 1, - Codec: sha256NamespaceFlagged, - MhType: sha256NamespaceFlagged, - // equals to NmtHasher.Size() - MhLength: share.NewSHA256Hasher().Size() + 2*libshare.NamespaceSize, - } - return bs -} - -func (n *namespacedBlockService) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { - block, err := n.BlockService.GetBlock(ctx, c) - if err != nil { - return nil, err - } - - _, err = n.prefix.Sum(block.RawData()) - if err != nil { - return nil, err - } - return block, nil -} - -func (n *namespacedBlockService) GetBlocks(ctx context.Context, cids []cid.Cid) <-chan blocks.Block { - blockCh := n.BlockService.GetBlocks(ctx, cids) - resultCh := make(chan blocks.Block) - - go func() { - for { - select { - case <-ctx.Done(): - close(resultCh) - return - case block, ok := <-blockCh: - if !ok { - close(resultCh) - return - } - if _, err := n.prefix.Sum(block.RawData()); err != nil { - continue - } - resultCh <- block - } - } - }() - return resultCh -} - -// TestBEFP_ForgedByReorderedShares checks whether a valid row can be made to look -// byzantine by reordering otherwise valid shares with valid inclusion proofs. -func TestBEFP_ForgedByReorderedShares(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - t.Cleanup(cancel) - bServ := ipld.NewMemBlockservice() - size := 4 - shares, err := libshare.RandShares(size * size) - require.NoError(t, err) - eds, err := ipld.AddShares(ctx, shares, bServ) - require.NoError(t, err) - roots, err := share.NewAxisRoots(eds) - require.NoError(t, err) - rowIdx := 0 - width := int(eds.Width()) - row := eds.Row(uint(rowIdx)) - shareProofs := make([]*ShareWithProof, width) - for i := 0; i < width; i++ { - sh, err := libshare.NewShare(row[i]) - require.NoError(t, err) - proof, err := GetShareWithProof(ctx, bServ, roots, sh, rsmt2d.Row, rowIdx, i) - require.NoError(t, err) - shareProofs[i] = proof - } - // Reorder two shares while keeping their proofs intact. - shareProofs[0], shareProofs[1] = shareProofs[1], shareProofs[0] - fakeErr := ErrByzantine{ - Index: uint32(rowIdx), - Shares: shareProofs, - Axis: rsmt2d.Row, - } - h := &header.ExtendedHeader{ - RawHeader: core.Header{Height: 1}, - DAH: roots, - } - proof := CreateBadEncodingProof([]byte("hash"), h.Height(), &fakeErr) - err = proof.Validate(h) - require.Error(t, err) -} diff --git a/share/eds/byzantine/pb/share.pb.go b/share/eds/byzantine/pb/share.pb.go deleted file mode 100644 index af79d48b1..000000000 --- a/share/eds/byzantine/pb/share.pb.go +++ /dev/null @@ -1,789 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: share/eds/byzantine/pb/share.proto - -package share_eds_byzantine_pb - -import ( - fmt "fmt" - pb "github.com/celestiaorg/nmt/pb" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type Axis int32 - -const ( - Axis_ROW Axis = 0 - Axis_COL Axis = 1 -) - -var Axis_name = map[int32]string{ - 0: "ROW", - 1: "COL", -} - -var Axis_value = map[string]int32{ - "ROW": 0, - "COL": 1, -} - -func (x Axis) String() string { - return proto.EnumName(Axis_name, int32(x)) -} - -func (Axis) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d28ce8f160a920d1, []int{0} -} - -type Share struct { - Data []byte `protobuf:"bytes,1,opt,name=Data,proto3" json:"Data,omitempty"` - Proof *pb.Proof `protobuf:"bytes,2,opt,name=Proof,proto3" json:"Proof,omitempty"` - ProofAxis Axis `protobuf:"varint,3,opt,name=ProofAxis,proto3,enum=share.eds.byzantine.pb.Axis" json:"ProofAxis,omitempty"` -} - -func (m *Share) Reset() { *m = Share{} } -func (m *Share) String() string { return proto.CompactTextString(m) } -func (*Share) ProtoMessage() {} -func (*Share) Descriptor() ([]byte, []int) { - return fileDescriptor_d28ce8f160a920d1, []int{0} -} -func (m *Share) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Share) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Share.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Share) XXX_Merge(src proto.Message) { - xxx_messageInfo_Share.Merge(m, src) -} -func (m *Share) XXX_Size() int { - return m.Size() -} -func (m *Share) XXX_DiscardUnknown() { - xxx_messageInfo_Share.DiscardUnknown(m) -} - -var xxx_messageInfo_Share proto.InternalMessageInfo - -func (m *Share) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -func (m *Share) GetProof() *pb.Proof { - if m != nil { - return m.Proof - } - return nil -} - -func (m *Share) GetProofAxis() Axis { - if m != nil { - return m.ProofAxis - } - return Axis_ROW -} - -type BadEncoding struct { - HeaderHash []byte `protobuf:"bytes,1,opt,name=HeaderHash,proto3" json:"HeaderHash,omitempty"` - Height uint64 `protobuf:"varint,2,opt,name=Height,proto3" json:"Height,omitempty"` - Shares []*Share `protobuf:"bytes,3,rep,name=Shares,proto3" json:"Shares,omitempty"` - Index uint32 `protobuf:"varint,4,opt,name=Index,proto3" json:"Index,omitempty"` - Axis Axis `protobuf:"varint,5,opt,name=Axis,proto3,enum=share.eds.byzantine.pb.Axis" json:"Axis,omitempty"` -} - -func (m *BadEncoding) Reset() { *m = BadEncoding{} } -func (m *BadEncoding) String() string { return proto.CompactTextString(m) } -func (*BadEncoding) ProtoMessage() {} -func (*BadEncoding) Descriptor() ([]byte, []int) { - return fileDescriptor_d28ce8f160a920d1, []int{1} -} -func (m *BadEncoding) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BadEncoding) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BadEncoding.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *BadEncoding) XXX_Merge(src proto.Message) { - xxx_messageInfo_BadEncoding.Merge(m, src) -} -func (m *BadEncoding) XXX_Size() int { - return m.Size() -} -func (m *BadEncoding) XXX_DiscardUnknown() { - xxx_messageInfo_BadEncoding.DiscardUnknown(m) -} - -var xxx_messageInfo_BadEncoding proto.InternalMessageInfo - -func (m *BadEncoding) GetHeaderHash() []byte { - if m != nil { - return m.HeaderHash - } - return nil -} - -func (m *BadEncoding) GetHeight() uint64 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *BadEncoding) GetShares() []*Share { - if m != nil { - return m.Shares - } - return nil -} - -func (m *BadEncoding) GetIndex() uint32 { - if m != nil { - return m.Index - } - return 0 -} - -func (m *BadEncoding) GetAxis() Axis { - if m != nil { - return m.Axis - } - return Axis_ROW -} - -func init() { - proto.RegisterEnum("share.eds.byzantine.pb.Axis", Axis_name, Axis_value) - proto.RegisterType((*Share)(nil), "share.eds.byzantine.pb.Share") - proto.RegisterType((*BadEncoding)(nil), "share.eds.byzantine.pb.BadEncoding") -} - -func init() { - proto.RegisterFile("share/eds/byzantine/pb/share.proto", fileDescriptor_d28ce8f160a920d1) -} - -var fileDescriptor_d28ce8f160a920d1 = []byte{ - // 310 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x31, 0x4b, 0xc4, 0x30, - 0x1c, 0xc5, 0x1b, 0xaf, 0x3d, 0xf1, 0x7f, 0x7a, 0x1e, 0x41, 0x8e, 0x20, 0x1a, 0xca, 0x81, 0x50, - 0x1c, 0x52, 0x39, 0x71, 0x71, 0xf3, 0x54, 0x38, 0x41, 0x38, 0x89, 0x83, 0x73, 0x62, 0xe2, 0xb5, - 0x4b, 0x5b, 0x9a, 0x0e, 0xd5, 0xc1, 0xcf, 0xe0, 0x87, 0x72, 0x70, 0xbc, 0xd1, 0x51, 0xda, 0x2f, - 0x22, 0x4d, 0x8b, 0x3a, 0x28, 0xb8, 0xbd, 0xf7, 0xf2, 0x0b, 0x79, 0x8f, 0xc0, 0xc4, 0x44, 0x22, - 0xd7, 0xa1, 0x56, 0x26, 0x94, 0x8f, 0x4f, 0x22, 0x29, 0xe2, 0x44, 0x87, 0x99, 0x0c, 0x6d, 0xcc, - 0xb2, 0x3c, 0x2d, 0x52, 0x3c, 0x6e, 0x8d, 0x56, 0x86, 0x7d, 0x31, 0x2c, 0x93, 0xbb, 0xc3, 0x4c, - 0x86, 0x59, 0x9e, 0xa6, 0x0f, 0x2d, 0x37, 0x79, 0x06, 0xef, 0xb6, 0x21, 0x31, 0x06, 0xf7, 0x42, - 0x14, 0x82, 0x20, 0x1f, 0x05, 0x9b, 0xdc, 0x6a, 0x7c, 0x00, 0xde, 0x4d, 0xc3, 0x92, 0x35, 0x1f, - 0x05, 0x83, 0xe9, 0x36, 0xeb, 0x6e, 0x4a, 0x66, 0x63, 0xde, 0x9e, 0xe2, 0x53, 0xd8, 0xb0, 0xe2, - 0xac, 0x8c, 0x0d, 0xe9, 0xf9, 0x28, 0x18, 0x4e, 0xf7, 0xd8, 0xef, 0xef, 0x33, 0x51, 0xc6, 0x86, - 0x7f, 0xe3, 0x93, 0x57, 0x04, 0x83, 0x99, 0x50, 0x97, 0xc9, 0x7d, 0xaa, 0xe2, 0x64, 0x89, 0x29, - 0xc0, 0x5c, 0x0b, 0xa5, 0xf3, 0xb9, 0x30, 0x51, 0x57, 0xe6, 0x47, 0x82, 0xc7, 0xd0, 0x9f, 0xeb, - 0x78, 0x19, 0x15, 0xb6, 0x93, 0xcb, 0x3b, 0x87, 0x4f, 0xa0, 0x6f, 0x77, 0x34, 0x05, 0x7a, 0xc1, - 0x60, 0xba, 0xff, 0x57, 0x01, 0x4b, 0xf1, 0x0e, 0xc6, 0x3b, 0xe0, 0x5d, 0x25, 0x4a, 0x97, 0xc4, - 0xf5, 0x51, 0xb0, 0xc5, 0x5b, 0x83, 0x8f, 0xc0, 0xb5, 0x5b, 0xbc, 0x7f, 0x6c, 0xb1, 0xe4, 0x21, - 0x01, 0xb7, 0x71, 0x78, 0x1d, 0x7a, 0x7c, 0x71, 0x37, 0x72, 0x1a, 0x71, 0xbe, 0xb8, 0x1e, 0xa1, - 0x19, 0x79, 0xab, 0x28, 0x5a, 0x55, 0x14, 0x7d, 0x54, 0x14, 0xbd, 0xd4, 0xd4, 0x59, 0xd5, 0xd4, - 0x79, 0xaf, 0xa9, 0x23, 0xfb, 0xf6, 0x07, 0x8e, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x5d, - 0x8d, 0x6c, 0xcf, 0x01, 0x00, 0x00, -} - -func (m *Share) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Share) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Share) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.ProofAxis != 0 { - i = encodeVarintShare(dAtA, i, uint64(m.ProofAxis)) - i-- - dAtA[i] = 0x18 - } - if m.Proof != nil { - { - size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintShare(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if len(m.Data) > 0 { - i -= len(m.Data) - copy(dAtA[i:], m.Data) - i = encodeVarintShare(dAtA, i, uint64(len(m.Data))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *BadEncoding) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *BadEncoding) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BadEncoding) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Axis != 0 { - i = encodeVarintShare(dAtA, i, uint64(m.Axis)) - i-- - dAtA[i] = 0x28 - } - if m.Index != 0 { - i = encodeVarintShare(dAtA, i, uint64(m.Index)) - i-- - dAtA[i] = 0x20 - } - if len(m.Shares) > 0 { - for iNdEx := len(m.Shares) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Shares[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintShare(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if m.Height != 0 { - i = encodeVarintShare(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x10 - } - if len(m.HeaderHash) > 0 { - i -= len(m.HeaderHash) - copy(dAtA[i:], m.HeaderHash) - i = encodeVarintShare(dAtA, i, uint64(len(m.HeaderHash))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintShare(dAtA []byte, offset int, v uint64) int { - offset -= sovShare(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Share) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Data) - if l > 0 { - n += 1 + l + sovShare(uint64(l)) - } - if m.Proof != nil { - l = m.Proof.Size() - n += 1 + l + sovShare(uint64(l)) - } - if m.ProofAxis != 0 { - n += 1 + sovShare(uint64(m.ProofAxis)) - } - return n -} - -func (m *BadEncoding) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.HeaderHash) - if l > 0 { - n += 1 + l + sovShare(uint64(l)) - } - if m.Height != 0 { - n += 1 + sovShare(uint64(m.Height)) - } - if len(m.Shares) > 0 { - for _, e := range m.Shares { - l = e.Size() - n += 1 + l + sovShare(uint64(l)) - } - } - if m.Index != 0 { - n += 1 + sovShare(uint64(m.Index)) - } - if m.Axis != 0 { - n += 1 + sovShare(uint64(m.Axis)) - } - return n -} - -func sovShare(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozShare(x uint64) (n int) { - return sovShare(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Share) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Share: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Share: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthShare - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthShare - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) - if m.Data == nil { - m.Data = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthShare - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthShare - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Proof == nil { - m.Proof = &pb.Proof{} - } - if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofAxis", wireType) - } - m.ProofAxis = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ProofAxis |= Axis(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipShare(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthShare - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BadEncoding) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: BadEncoding: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BadEncoding: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HeaderHash", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthShare - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthShare - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.HeaderHash = append(m.HeaderHash[:0], dAtA[iNdEx:postIndex]...) - if m.HeaderHash == nil { - m.HeaderHash = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Shares", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthShare - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthShare - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Shares = append(m.Shares, &Share{}) - if err := m.Shares[len(m.Shares)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) - } - m.Index = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Index |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Axis", wireType) - } - m.Axis = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowShare - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Axis |= Axis(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipShare(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthShare - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipShare(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShare - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShare - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShare - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthShare - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupShare - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthShare - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthShare = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowShare = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupShare = fmt.Errorf("proto: unexpected end of group") -) diff --git a/share/eds/byzantine/pb/share.proto b/share/eds/byzantine/pb/share.proto deleted file mode 100644 index 52abefe7a..000000000 --- a/share/eds/byzantine/pb/share.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; - -package share.eds.byzantine.pb; -import "pb/proof.proto"; - -message Share { - bytes Data = 1; - proof.pb.Proof Proof = 2; - axis ProofAxis = 3; -} - -enum axis { - ROW = 0; - COL = 1; -} - -message BadEncoding { - bytes HeaderHash = 1; - uint64 Height = 2; - repeated Share Shares = 3; - uint32 Index = 4; - axis Axis = 5; -} diff --git a/share/eds/byzantine/share_proof.go b/share/eds/byzantine/share_proof.go index 65b2d3854..95db686ad 100644 --- a/share/eds/byzantine/share_proof.go +++ b/share/eds/byzantine/share_proof.go @@ -9,11 +9,9 @@ import ( libshare "github.com/celestiaorg/go-square/v4/share" "github.com/celestiaorg/nmt" - nmt_pb "github.com/celestiaorg/nmt/pb" "github.com/celestiaorg/rsmt2d" "github.com/celestiaorg/celestia-node/share" - pb "github.com/celestiaorg/celestia-node/share/eds/byzantine/pb" "github.com/celestiaorg/celestia-node/share/ipld" ) @@ -53,23 +51,6 @@ func (s *ShareWithProof) Validate(roots *share.AxisRoots, axisType rsmt2d.Axis, ) } -func (s *ShareWithProof) ShareWithProofToProto() *pb.Share { - if s == nil { - return &pb.Share{} - } - return &pb.Share{ - Data: s.ToBytes(), - Proof: &nmt_pb.Proof{ - Start: int64(s.Proof.Start()), - End: int64(s.Proof.End()), - Nodes: s.Proof.Nodes(), - LeafHash: s.Proof.LeafHash(), - IsMaxNamespaceIgnored: s.Proof.IsMaxNamespaceIDIgnored(), - }, - ProofAxis: pb.Axis(s.Axis), - } -} - // GetShareWithProof attempts to get a share with proof for the given share. It first tries to get // a row proof and if that fails or proof is invalid, it tries to get a column proof. func GetShareWithProof( @@ -114,35 +95,6 @@ func GetShareWithProof( return nil, errors.New("failed to collect proof") } -func ProtoToShare(protoShares []*pb.Share) ([]*ShareWithProof, error) { - shares := make([]*ShareWithProof, len(protoShares)) - for i, protoSh := range protoShares { - if protoSh.Proof == nil { - continue - } - proof := ProtoToProof(protoSh.Proof) - sh, err := libshare.NewShare(protoSh.Data) - if err != nil { - return nil, err - } - shares[i] = &ShareWithProof{ - Share: sh, - Proof: &proof, - Axis: rsmt2d.Axis(protoSh.ProofAxis), - } - } - return shares, nil -} - -func ProtoToProof(protoProof *nmt_pb.Proof) nmt.Proof { - return nmt.NewInclusionProof( - int(protoProof.Start), - int(protoProof.End), - protoProof.Nodes, - protoProof.IsMaxNamespaceIgnored, - ) -} - func rootHashForCoordinates(r *share.AxisRoots, axisType rsmt2d.Axis, x, y int) []byte { if axisType == rsmt2d.Row { return r.RowRoots[y] diff --git a/share/eds/retriever_test.go b/share/eds/retriever_test.go index 525251b79..b59a5d36b 100644 --- a/share/eds/retriever_test.go +++ b/share/eds/retriever_test.go @@ -96,7 +96,7 @@ func TestRetriever_MultipleRandQuadrants(t *testing.T) { assert.NoError(t, err) } -func TestFraudProofValidation(t *testing.T) { +func TestByzantineError(t *testing.T) { bServ := ipld.NewMemBlockservice() odsSize := []int{2, 4, 16, 32, 64, 128} @@ -106,13 +106,9 @@ func TestFraudProofValidation(t *testing.T) { t.Cleanup(cancel) var errByz *byzantine.ErrByzantine - faultHeader, err := generateByzantineError(ctx, t, size, bServ) + _, err := generateByzantineError(ctx, t, size, bServ) require.NotNil(t, err) require.True(t, errors.As(err, &errByz), err.Error()) - - p := byzantine.CreateBadEncodingProof([]byte("hash"), faultHeader.Height(), errByz) - err = p.Validate(faultHeader) - require.NoError(t, err) }) } } @@ -132,44 +128,6 @@ func generateByzantineError( return h, err } -/* -BenchmarkBEFPValidation/ods_size:2 31273 38819 ns/op 68052 B/op 366 allocs/op -BenchmarkBEFPValidation/ods_size:4 14664 80439 ns/op 135892 B/op 894 allocs/op -BenchmarkBEFPValidation/ods_size:16 2850 386178 ns/op 587890 B/op 4945 allocs/op -BenchmarkBEFPValidation/ods_size:32 1399 874490 ns/op 1233399 B/op 11284 allocs/op -BenchmarkBEFPValidation/ods_size:64 619 2047540 ns/op 2578008 B/op 25364 allocs/op -BenchmarkBEFPValidation/ods_size:128 259 4934375 ns/op 5418406 B/op 56345 allocs/op -*/ -func BenchmarkBEFPValidation(b *testing.B) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) - defer b.Cleanup(cancel) - bServ := ipld.NewMemBlockservice() - r := NewRetriever(bServ) - t := &testing.T{} - odsSize := []int{2, 4, 16, 32, 64, 128} - for _, size := range odsSize { - b.Run(fmt.Sprintf("ods size:%d", size), func(b *testing.B) { - b.ResetTimer() - b.StopTimer() - eds := edstest.RandByzantineEDS(t, size) - err := ipld.ImportEDS(ctx, eds, bServ) - require.NoError(t, err) - h := headertest.ExtendedHeaderFromEDS(t, 1, eds) - _, err = r.Retrieve(ctx, h.DAH) - var errByz *byzantine.ErrByzantine - require.ErrorAs(t, err, &errByz) - b.StartTimer() - - for b.Loop() { - b.ReportAllocs() - p := byzantine.CreateBadEncodingProof([]byte("hash"), h.Height(), errByz) - err = p.Validate(h) - require.NoError(b, err) - } - }) - } -} - /* BenchmarkNewErrByzantineData/ods_size:2 29605 38846 ns/op 49518 B/op 579 allocs/op BenchmarkNewErrByzantineData/ods_size:4 11380 105302 ns/op 134967 B/op 1571 allocs/op