diff --git a/beacon-chain/rpc/eth/beacon/BUILD.bazel b/beacon-chain/rpc/eth/beacon/BUILD.bazel index 656024f82..681cf77e2 100644 --- a/beacon-chain/rpc/eth/beacon/BUILD.bazel +++ b/beacon-chain/rpc/eth/beacon/BUILD.bazel @@ -6,10 +6,12 @@ go_library( "blinded_blocks.go", "blocks.go", "config.go", + "handlers.go", "log.go", "pool.go", "server.go", "state.go", + "structs.go", "sync_committee.go", "validator.go", ], @@ -49,7 +51,9 @@ go_library( "//crypto/bls:go_default_library", "//encoding/bytesutil:go_default_library", "//encoding/ssz/detect:go_default_library", + "//network:go_default_library", "//network/forks:go_default_library", + "//proto/engine/v1:go_default_library", "//proto/eth/v1:go_default_library", "//proto/eth/v2:go_default_library", "//proto/migration:go_default_library", @@ -57,8 +61,10 @@ go_library( "//runtime/version:go_default_library", "//time/slots:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", + "@com_github_go_playground_validator_v10//:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", + "@com_github_wealdtech_go_bytesutil//:go_default_library", "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_opencensus_go//trace:go_default_library", "@org_golang_google_grpc//codes:go_default_library", @@ -75,6 +81,7 @@ go_test( "blinded_blocks_test.go", "blocks_test.go", "config_test.go", + "handlers_test.go", "init_test.go", "pool_test.go", "server_test.go", @@ -129,6 +136,7 @@ go_test( "@com_github_golang_mock//gomock:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", + "@com_github_stretchr_testify//mock:go_default_library", "@com_github_wealdtech_go_bytesutil//:go_default_library", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", diff --git a/beacon-chain/rpc/eth/beacon/blinded_blocks.go b/beacon-chain/rpc/eth/beacon/blinded_blocks.go index 81e4af40a..d19d0175c 100644 --- a/beacon-chain/rpc/eth/beacon/blinded_blocks.go +++ b/beacon-chain/rpc/eth/beacon/blinded_blocks.go @@ -146,7 +146,7 @@ func (bs *Server) SubmitBlindedBlock(ctx context.Context, req *ethpbv2.SignedBli ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlindedBlock") defer span.End() - if err := rpchelpers.ValidateSync(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -189,7 +189,7 @@ func (bs *Server) SubmitBlindedBlockSSZ(ctx context.Context, req *ethpbv2.SSZCon ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlindedBlockSSZ") defer span.End() - if err := rpchelpers.ValidateSync(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } diff --git a/beacon-chain/rpc/eth/beacon/blocks.go b/beacon-chain/rpc/eth/beacon/blocks.go index 7a599c20c..1513d5bf1 100644 --- a/beacon-chain/rpc/eth/beacon/blocks.go +++ b/beacon-chain/rpc/eth/beacon/blocks.go @@ -43,7 +43,7 @@ var ( // determines the best block root and state root to use for a Checkpoint Sync starting from that point. // DEPRECATED: GetWeakSubjectivity endpoint will no longer be supported func (bs *Server) GetWeakSubjectivity(ctx context.Context, _ *empty.Empty) (*ethpbv1.WeakSubjectivityResponse, error) { - if err := rpchelpers.ValidateSync(ctx, bs.SyncChecker, bs.HeadFetcher, bs.GenesisTimeFetcher, bs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, bs.SyncChecker, bs.HeadFetcher, bs.GenesisTimeFetcher, bs.OptimisticModeFetcher); err != nil { // This is already a grpc error, so we can't wrap it any further return nil, err } @@ -206,7 +206,7 @@ func (bs *Server) SubmitBlock(ctx context.Context, req *ethpbv2.SignedBeaconBloc ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlock") defer span.End() - if err := rpchelpers.ValidateSync(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -246,7 +246,7 @@ func (bs *Server) SubmitBlockSSZ(ctx context.Context, req *ethpbv2.SSZContainer) ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlockSSZ") defer span.End() - if err := rpchelpers.ValidateSync(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } diff --git a/beacon-chain/rpc/eth/beacon/handlers.go b/beacon-chain/rpc/eth/beacon/handlers.go new file mode 100644 index 000000000..02d88a1be --- /dev/null +++ b/beacon-chain/rpc/eth/beacon/handlers.go @@ -0,0 +1,375 @@ +package beacon + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/go-playground/validator/v10" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers" + "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v4/network" + eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" +) + +const ( + broadcastValidationQueryParam = "broadcast_validation" + broadcastValidationConsensus = "consensus" + broadcastValidationConsensusAndEquivocation = "consensus_and_equivocation" +) + +// PublishBlindedBlockV2 instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct and publish a +// `SignedBeaconBlock` by swapping out the `transactions_root` for the corresponding full list of `transactions`. +// The beacon node should broadcast a newly constructed `SignedBeaconBlock` to the beacon network, +// to be included in the beacon chain. The beacon node is not required to validate the signed +// `BeaconBlock`, and a successful response (20X) only indicates that the broadcast has been +// successful. The beacon node is expected to integrate the new block into its state, and +// therefore validate the block internally, however blocks which fail the validation are still +// broadcast but a different status code is returned (202). Pre-Bellatrix, this endpoint will accept +// a `SignedBeaconBlock`. The broadcast behaviour may be adjusted via the `broadcast_validation` +// query parameter. +func (bs *Server) PublishBlindedBlockV2(w http.ResponseWriter, r *http.Request) { + if ok := bs.checkSync(r.Context(), w); !ok { + return + } + + validate := validator.New() + body, err := io.ReadAll(r.Body) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not read request body", + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + + var capellaBlock *SignedBlindedBeaconBlockCapella + if err = unmarshalStrict(body, &capellaBlock); err == nil { + if err = validate.Struct(capellaBlock); err == nil { + consensusBlock, err := capellaBlock.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + + var bellatrixBlock *SignedBlindedBeaconBlockBellatrix + if err = unmarshalStrict(body, &bellatrixBlock); err == nil { + if err = validate.Struct(bellatrixBlock); err == nil { + consensusBlock, err := bellatrixBlock.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + var altairBlock *SignedBeaconBlockAltair + if err = unmarshalStrict(body, &altairBlock); err == nil { + if err = validate.Struct(altairBlock); err == nil { + consensusBlock, err := altairBlock.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + var phase0Block *SignedBeaconBlock + if err = unmarshalStrict(body, &phase0Block); err == nil { + if err = validate.Struct(phase0Block); err == nil { + consensusBlock, err := phase0Block.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + + errJson := &network.DefaultErrorJson{ + Message: "Body does not represent a valid block type", + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) +} + +// PublishBlockV2 instructs the beacon node to broadcast a newly signed beacon block to the beacon network, +// to be included in the beacon chain. A success response (20x) indicates that the block +// passed gossip validation and was successfully broadcast onto the network. +// The beacon node is also expected to integrate the block into the state, but may broadcast it +// before doing so, so as to aid timely delivery of the block. Should the block fail full +// validation, a separate success response code (202) is used to indicate that the block was +// successfully broadcast but failed integration. The broadcast behaviour may be adjusted via the +// `broadcast_validation` query parameter. +func (bs *Server) PublishBlockV2(w http.ResponseWriter, r *http.Request) { + if ok := bs.checkSync(r.Context(), w); !ok { + return + } + + validate := validator.New() + body, err := io.ReadAll(r.Body) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not read request body", + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + + var capellaBlock *SignedBeaconBlockCapella + if err = unmarshalStrict(body, &capellaBlock); err == nil { + if err = validate.Struct(capellaBlock); err == nil { + consensusBlock, err := capellaBlock.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + var bellatrixBlock *SignedBeaconBlockBellatrix + if err = unmarshalStrict(body, &bellatrixBlock); err == nil { + if err = validate.Struct(bellatrixBlock); err == nil { + consensusBlock, err := bellatrixBlock.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + var altairBlock *SignedBeaconBlockAltair + if err = unmarshalStrict(body, &altairBlock); err == nil { + if err = validate.Struct(altairBlock); err == nil { + consensusBlock, err := altairBlock.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + var phase0Block *SignedBeaconBlock + if err = unmarshalStrict(body, &phase0Block); err == nil { + if err = validate.Struct(phase0Block); err == nil { + consensusBlock, err := phase0Block.ToGeneric() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not decode request body into consensus block: " + err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + if err = bs.validateBroadcast(r, consensusBlock); err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + bs.proposeBlock(r.Context(), w, consensusBlock) + return + } + } + + errJson := &network.DefaultErrorJson{ + Message: "Body does not represent a valid block type", + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) +} + +func (bs *Server) proposeBlock(ctx context.Context, w http.ResponseWriter, blk *eth.GenericSignedBeaconBlock) { + _, err := bs.V1Alpha1ValidatorServer.ProposeBeaconBlock(ctx, blk) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: err.Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } +} + +func unmarshalStrict(data []byte, v interface{}) error { + dec := json.NewDecoder(bytes.NewReader(data)) + dec.DisallowUnknownFields() + return dec.Decode(v) +} + +func (bs *Server) validateBroadcast(r *http.Request, blk *eth.GenericSignedBeaconBlock) error { + switch r.URL.Query().Get(broadcastValidationQueryParam) { + case broadcastValidationConsensus: + b, err := blocks.NewSignedBeaconBlock(blk.Block) + if err != nil { + return errors.Wrapf(err, "could not create signed beacon block") + } + if err = bs.validateConsensus(r.Context(), b); err != nil { + return errors.Wrap(err, "consensus validation failed") + } + case broadcastValidationConsensusAndEquivocation: + b, err := blocks.NewSignedBeaconBlock(blk.Block) + if err != nil { + return errors.Wrapf(err, "could not create signed beacon block") + } + if err = bs.validateConsensus(r.Context(), b); err != nil { + return errors.Wrap(err, "consensus validation failed") + } + if err = bs.validateEquivocation(b.Block()); err != nil { + return errors.Wrap(err, "equivocation validation failed") + } + default: + return nil + } + return nil +} + +func (bs *Server) validateConsensus(ctx context.Context, blk interfaces.ReadOnlySignedBeaconBlock) error { + parentRoot := blk.Block().ParentRoot() + parentState, err := bs.Stater.State(ctx, parentRoot[:]) + if err != nil { + return errors.Wrap(err, "could not get parent state") + } + _, err = transition.ExecuteStateTransition(ctx, parentState, blk) + if err != nil { + return errors.Wrap(err, "could not execute state transition") + } + return nil +} + +func (bs *Server) validateEquivocation(blk interfaces.ReadOnlyBeaconBlock) error { + if bs.ForkchoiceFetcher.HighestReceivedBlockSlot() == blk.Slot() { + return fmt.Errorf("block for slot %d already exists in fork choice", blk.Slot()) + } + return nil +} + +func (bs *Server) checkSync(ctx context.Context, w http.ResponseWriter) bool { + isSyncing, syncDetails, err := helpers.ValidateSyncHTTP(ctx, bs.SyncChecker, bs.HeadFetcher, bs.TimeFetcher, bs.OptimisticModeFetcher) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: "Could not check if node is syncing: " + err.Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return false + } + if isSyncing { + msg := "Beacon node is currently syncing and not serving request on that endpoint" + details, err := json.Marshal(syncDetails) + if err == nil { + msg += " Details: " + string(details) + } + errJson := &network.DefaultErrorJson{ + Message: msg, + Code: http.StatusServiceUnavailable, + } + network.WriteError(w, errJson) + return false + } + return true +} diff --git a/beacon-chain/rpc/eth/beacon/handlers_test.go b/beacon-chain/rpc/eth/beacon/handlers_test.go new file mode 100644 index 000000000..6f7b00efb --- /dev/null +++ b/beacon-chain/rpc/eth/beacon/handlers_test.go @@ -0,0 +1,1275 @@ +package beacon + +import ( + "bytes" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/golang/mock/gomock" + testing2 "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" + mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" + eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v4/testing/assert" + mock2 "github.com/prysmaticlabs/prysm/v4/testing/mock" + "github.com/stretchr/testify/mock" +) + +func TestPublishBlockV2(t *testing.T) { + ctrl := gomock.NewController(t) + + t.Run("Phase 0", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_Phase0) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(phase0Block))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("Altair", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_Altair) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(altairBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("Bellatrix", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_Bellatrix) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(bellatrixBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("Capella", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_Capella) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(capellaBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("invalid block", func(t *testing.T) { + server := &Server{ + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(blindedBellatrixBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlockV2(writer, request) + assert.Equal(t, http.StatusBadRequest, writer.Code) + assert.Equal(t, true, strings.Contains(writer.Body.String(), "Body does not represent a valid block type")) + }) + t.Run("syncing", func(t *testing.T) { + chainService := &testing2.ChainService{} + server := &Server{ + SyncChecker: &mockSync.Sync{IsSyncing: true}, + HeadFetcher: chainService, + TimeFetcher: chainService, + OptimisticModeFetcher: chainService, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte("foo"))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlockV2(writer, request) + assert.Equal(t, http.StatusServiceUnavailable, writer.Code) + assert.Equal(t, true, strings.Contains(writer.Body.String(), "Beacon node is currently syncing and not serving request on that endpoint")) + }) +} + +func TestPublishBlindedBlockV2(t *testing.T) { + ctrl := gomock.NewController(t) + + t.Run("Phase 0", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_Phase0) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(phase0Block))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlindedBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("Altair", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_Altair) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(altairBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlindedBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("Bellatrix", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_BlindedBellatrix) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(blindedBellatrixBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlindedBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("Capella", func(t *testing.T) { + v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl) + v1alpha1Server.EXPECT().ProposeBeaconBlock(gomock.Any(), mock.MatchedBy(func(req *eth.GenericSignedBeaconBlock) bool { + _, ok := req.Block.(*eth.GenericSignedBeaconBlock_BlindedCapella) + return ok + })) + server := &Server{ + V1Alpha1ValidatorServer: v1alpha1Server, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(blindedCapellaBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlindedBlockV2(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + }) + t.Run("invalid block", func(t *testing.T) { + server := &Server{ + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte(bellatrixBlock))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlindedBlockV2(writer, request) + assert.Equal(t, http.StatusBadRequest, writer.Code) + assert.Equal(t, true, strings.Contains(writer.Body.String(), "Body does not represent a valid block type")) + }) + t.Run("syncing", func(t *testing.T) { + chainService := &testing2.ChainService{} + server := &Server{ + SyncChecker: &mockSync.Sync{IsSyncing: true}, + HeadFetcher: chainService, + TimeFetcher: chainService, + OptimisticModeFetcher: chainService, + } + + request := httptest.NewRequest("GET", "http://foo.example", bytes.NewReader([]byte("foo"))) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + server.PublishBlindedBlockV2(writer, request) + assert.Equal(t, http.StatusServiceUnavailable, writer.Code) + assert.Equal(t, true, strings.Contains(writer.Body.String(), "Beacon node is currently syncing and not serving request on that endpoint")) + }) +} + +const ( + phase0Block = `{ + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body": { + "randao_reveal": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "eth1_data": { + "deposit_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "deposit_count": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "graffiti": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "proposer_slashings": [ + { + "signed_header_1": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "signed_header_2": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "attester_slashings": [ + { + "attestation_1": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + }, + "attestation_2": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + } + ], + "attestations": [ + { + "aggregation_bits": "0x01", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + ], + "deposits": [ + { + "proof": [ + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + ], + "data": { + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "withdrawal_credentials": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "amount": "1", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "voluntary_exits": [ + { + "message": { + "epoch": "1", + "validator_index": "1" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ] + } + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +}` + altairBlock = `{ + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body": { + "randao_reveal": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "eth1_data": { + "deposit_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "deposit_count": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "graffiti": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "proposer_slashings": [ + { + "signed_header_1": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "signed_header_2": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "attester_slashings": [ + { + "attestation_1": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + }, + "attestation_2": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + } + ], + "attestations": [ + { + "aggregation_bits": "0x01", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + ], + "deposits": [ + { + "proof": [ + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + ], + "data": { + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "withdrawal_credentials": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "amount": "1", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "voluntary_exits": [ + { + "message": { + "epoch": "1", + "validator_index": "1" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ], + "sync_aggregate": { + "sync_committee_bits": "0x01", + "sync_committee_signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +}` + bellatrixBlock = `{ + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body": { + "randao_reveal": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "eth1_data": { + "deposit_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "deposit_count": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "graffiti": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "proposer_slashings": [ + { + "signed_header_1": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "signed_header_2": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "attester_slashings": [ + { + "attestation_1": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + }, + "attestation_2": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + } + ], + "attestations": [ + { + "aggregation_bits": "0x01", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + ], + "deposits": [ + { + "proof": [ + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + ], + "data": { + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "withdrawal_credentials": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "amount": "1", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "voluntary_exits": [ + { + "message": { + "epoch": "1", + "validator_index": "1" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ], + "sync_aggregate": { + "sync_committee_bits": "0x01", + "sync_committee_signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "execution_payload": { + "parent_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "fee_recipient": "0xabcf8e0d4e9587369b2301d0790347320302cc09", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "receipts_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "block_number": "1", + "gas_limit": "1", + "gas_used": "1", + "timestamp": "1", + "extra_data": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "base_fee_per_gas": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions": [ + "0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86" + ] + } + } + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +}` + blindedBellatrixBlock = `{ + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body": { + "randao_reveal": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "eth1_data": { + "deposit_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "deposit_count": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "graffiti": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "proposer_slashings": [ + { + "signed_header_1": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "signed_header_2": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "attester_slashings": [ + { + "attestation_1": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + }, + "attestation_2": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + } + ], + "attestations": [ + { + "aggregation_bits": "0x01", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + ], + "deposits": [ + { + "proof": [ + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + ], + "data": { + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "withdrawal_credentials": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "amount": "1", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "voluntary_exits": [ + { + "message": { + "epoch": "1", + "validator_index": "1" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ], + "sync_aggregate": { + "sync_committee_bits": "0x01", + "sync_committee_signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "execution_payload_header": { + "parent_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "fee_recipient": "0xabcf8e0d4e9587369b2301d0790347320302cc09", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "receipts_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "block_number": "1", + "gas_limit": "1", + "gas_used": "1", + "timestamp": "1", + "extra_data": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "base_fee_per_gas": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +}` + capellaBlock = `{ + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body": { + "randao_reveal": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "eth1_data": { + "deposit_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "deposit_count": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "graffiti": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "proposer_slashings": [ + { + "signed_header_1": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "signed_header_2": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "attester_slashings": [ + { + "attestation_1": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + }, + "attestation_2": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + } + ], + "attestations": [ + { + "aggregation_bits": "0x01", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + ], + "deposits": [ + { + "proof": [ + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + ], + "data": { + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "withdrawal_credentials": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "amount": "1", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "voluntary_exits": [ + { + "message": { + "epoch": "1", + "validator_index": "1" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ], + "sync_aggregate": { + "sync_committee_bits": "0x01", + "sync_committee_signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "execution_payload": { + "parent_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "fee_recipient": "0xabcf8e0d4e9587369b2301d0790347320302cc09", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "receipts_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "block_number": "1", + "gas_limit": "1", + "gas_used": "1", + "timestamp": "1", + "extra_data": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "base_fee_per_gas": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions": [ + "0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86" + ], + "withdrawals": [ + { + "index": "1", + "validator_index": "1", + "address": "0xabcf8e0d4e9587369b2301d0790347320302cc09", + "amount": "1" + } + ] + }, + "bls_to_execution_changes": [ + { + "message": { + "validator_index": "1", + "from_bls_pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "to_execution_address": "0xabcf8e0d4e9587369b2301d0790347320302cc09" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ] + } + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +}` + blindedCapellaBlock = `{ + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body": { + "randao_reveal": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "eth1_data": { + "deposit_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "deposit_count": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "graffiti": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "proposer_slashings": [ + { + "signed_header_1": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "signed_header_2": { + "message": { + "slot": "1", + "proposer_index": "1", + "parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "attester_slashings": [ + { + "attestation_1": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + }, + "attestation_2": { + "attesting_indices": [ + "1" + ], + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + } + ], + "attestations": [ + { + "aggregation_bits": "0x01", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + "data": { + "slot": "1", + "index": "1", + "beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "source": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "target": { + "epoch": "1", + "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + } + } + } + ], + "deposits": [ + { + "proof": [ + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + ], + "data": { + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "withdrawal_credentials": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "amount": "1", + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + } + ], + "voluntary_exits": [ + { + "message": { + "epoch": "1", + "validator_index": "1" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ], + "sync_aggregate": { + "sync_committee_bits": "0x01", + "sync_committee_signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + }, + "execution_payload_header": { + "parent_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "fee_recipient": "0xabcf8e0d4e9587369b2301d0790347320302cc09", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "receipts_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "block_number": "1", + "gas_limit": "1", + "gas_used": "1", + "timestamp": "1", + "extra_data": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "base_fee_per_gas": "1", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "withdrawals_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "bls_to_execution_changes": [ + { + "message": { + "validator_index": "1", + "from_bls_pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + "to_execution_address": "0xabcf8e0d4e9587369b2301d0790347320302cc09" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } + ] + } + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" +}` +) diff --git a/beacon-chain/rpc/eth/beacon/server.go b/beacon-chain/rpc/eth/beacon/server.go index 366c137a9..7c6796cdd 100644 --- a/beacon-chain/rpc/eth/beacon/server.go +++ b/beacon-chain/rpc/eth/beacon/server.go @@ -45,4 +45,5 @@ type Server struct { ExecutionPayloadReconstructor execution.ExecutionPayloadReconstructor FinalizationFetcher blockchain.FinalizationFetcher BLSChangesPool blstoexec.PoolManager + ForkchoiceFetcher blockchain.ForkchoiceFetcher } diff --git a/beacon-chain/rpc/eth/beacon/structs.go b/beacon-chain/rpc/eth/beacon/structs.go new file mode 100644 index 000000000..0d6f4cd7e --- /dev/null +++ b/beacon-chain/rpc/eth/beacon/structs.go @@ -0,0 +1,1650 @@ +package beacon + +import ( + "math/big" + "strconv" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" + bytesutil2 "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" + enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1" + eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" + "github.com/wealdtech/go-bytesutil" +) + +type SignedBeaconBlock struct { + Message BeaconBlock `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BeaconBlock struct { + Slot string `json:"slot" validate:"required"` + ProposerIndex string `json:"proposer_index" validate:"required"` + ParentRoot string `json:"parent_root" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + Body BeaconBlockBody `json:"body" validate:"required"` +} + +type BeaconBlockBody struct { + RandaoReveal string `json:"randao_reveal" validate:"required"` + Eth1Data Eth1Data `json:"eth1_data" validate:"required"` + Graffiti string `json:"graffiti" validate:"required"` + ProposerSlashings []ProposerSlashing `json:"proposer_slashings" validate:"required"` + AttesterSlashings []AttesterSlashing `json:"attester_slashings" validate:"required"` + Attestations []Attestation `json:"attestations" validate:"required"` + Deposits []Deposit `json:"deposits" validate:"required"` + VoluntaryExits []SignedVoluntaryExit `json:"voluntary_exits" validate:"required"` +} + +type SignedBeaconBlockAltair struct { + Message BeaconBlockAltair `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BeaconBlockAltair struct { + Slot string `json:"slot" validate:"required"` + ProposerIndex string `json:"proposer_index" validate:"required"` + ParentRoot string `json:"parent_root" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + Body BeaconBlockBodyAltair `json:"body" validate:"required"` +} + +type BeaconBlockBodyAltair struct { + RandaoReveal string `json:"randao_reveal" validate:"required"` + Eth1Data Eth1Data `json:"eth1_data" validate:"required"` + Graffiti string `json:"graffiti" validate:"required"` + ProposerSlashings []ProposerSlashing `json:"proposer_slashings" validate:"required"` + AttesterSlashings []AttesterSlashing `json:"attester_slashings" validate:"required"` + Attestations []Attestation `json:"attestations" validate:"required"` + Deposits []Deposit `json:"deposits" validate:"required"` + VoluntaryExits []SignedVoluntaryExit `json:"voluntary_exits" validate:"required"` + SyncAggregate SyncAggregate `json:"sync_aggregate" validate:"required"` +} + +type SignedBeaconBlockBellatrix struct { + Message BeaconBlockBellatrix `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BeaconBlockBellatrix struct { + Slot string `json:"slot" validate:"required"` + ProposerIndex string `json:"proposer_index" validate:"required"` + ParentRoot string `json:"parent_root" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + Body BeaconBlockBodyBellatrix `json:"body" validate:"required"` +} + +type BeaconBlockBodyBellatrix struct { + RandaoReveal string `json:"randao_reveal" validate:"required"` + Eth1Data Eth1Data `json:"eth1_data" validate:"required"` + Graffiti string `json:"graffiti" validate:"required"` + ProposerSlashings []ProposerSlashing `json:"proposer_slashings" validate:"required"` + AttesterSlashings []AttesterSlashing `json:"attester_slashings" validate:"required"` + Attestations []Attestation `json:"attestations" validate:"required"` + Deposits []Deposit `json:"deposits" validate:"required"` + VoluntaryExits []SignedVoluntaryExit `json:"voluntary_exits" validate:"required"` + SyncAggregate SyncAggregate `json:"sync_aggregate" validate:"required"` + ExecutionPayload ExecutionPayload `json:"execution_payload" validate:"required"` +} + +type SignedBlindedBeaconBlockBellatrix struct { + Message BlindedBeaconBlockBellatrix `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BlindedBeaconBlockBellatrix struct { + Slot string `json:"slot" validate:"required"` + ProposerIndex string `json:"proposer_index" validate:"required"` + ParentRoot string `json:"parent_root" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + Body BlindedBeaconBlockBodyBellatrix `json:"body" validate:"required"` +} + +type BlindedBeaconBlockBodyBellatrix struct { + RandaoReveal string `json:"randao_reveal" validate:"required"` + Eth1Data Eth1Data `json:"eth1_data" validate:"required"` + Graffiti string `json:"graffiti" validate:"required"` + ProposerSlashings []ProposerSlashing `json:"proposer_slashings" validate:"required"` + AttesterSlashings []AttesterSlashing `json:"attester_slashings" validate:"required"` + Attestations []Attestation `json:"attestations" validate:"required"` + Deposits []Deposit `json:"deposits" validate:"required"` + VoluntaryExits []SignedVoluntaryExit `json:"voluntary_exits" validate:"required"` + SyncAggregate SyncAggregate `json:"sync_aggregate" validate:"required"` + ExecutionPayloadHeader ExecutionPayloadHeader `json:"execution_payload_header" validate:"required"` +} + +type SignedBeaconBlockCapella struct { + Message BeaconBlockCapella `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BeaconBlockCapella struct { + Slot string `json:"slot" validate:"required"` + ProposerIndex string `json:"proposer_index" validate:"required"` + ParentRoot string `json:"parent_root" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + Body BeaconBlockBodyCapella `json:"body" validate:"required"` +} + +type BeaconBlockBodyCapella struct { + RandaoReveal string `json:"randao_reveal" validate:"required"` + Eth1Data Eth1Data `json:"eth1_data" validate:"required"` + Graffiti string `json:"graffiti" validate:"required"` + ProposerSlashings []ProposerSlashing `json:"proposer_slashings" validate:"required"` + AttesterSlashings []AttesterSlashing `json:"attester_slashings" validate:"required"` + Attestations []Attestation `json:"attestations" validate:"required"` + Deposits []Deposit `json:"deposits" validate:"required"` + VoluntaryExits []SignedVoluntaryExit `json:"voluntary_exits" validate:"required"` + SyncAggregate SyncAggregate `json:"sync_aggregate" validate:"required"` + ExecutionPayload ExecutionPayloadCapella `json:"execution_payload" validate:"required"` + BlsToExecutionChanges []SignedBlsToExecutionChange `json:"bls_to_execution_changes" validate:"required"` +} + +type SignedBlindedBeaconBlockCapella struct { + Message BlindedBeaconBlockCapella `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BlindedBeaconBlockCapella struct { + Slot string `json:"slot" validate:"required"` + ProposerIndex string `json:"proposer_index" validate:"required"` + ParentRoot string `json:"parent_root" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + Body BlindedBeaconBlockBodyCapella `json:"body" validate:"required"` +} + +type BlindedBeaconBlockBodyCapella struct { + RandaoReveal string `json:"randao_reveal" validate:"required"` + Eth1Data Eth1Data `json:"eth1_data" validate:"required"` + Graffiti string `json:"graffiti" validate:"required"` + ProposerSlashings []ProposerSlashing `json:"proposer_slashings" validate:"required"` + AttesterSlashings []AttesterSlashing `json:"attester_slashings" validate:"required"` + Attestations []Attestation `json:"attestations" validate:"required"` + Deposits []Deposit `json:"deposits" validate:"required"` + VoluntaryExits []SignedVoluntaryExit `json:"voluntary_exits" validate:"required"` + SyncAggregate SyncAggregate `json:"sync_aggregate" validate:"required"` + ExecutionPayloadHeader ExecutionPayloadHeaderCapella `json:"execution_payload_header" validate:"required"` + BlsToExecutionChanges []SignedBlsToExecutionChange `json:"bls_to_execution_changes" validate:"required"` +} + +type Eth1Data struct { + DepositRoot string `json:"deposit_root" validate:"required"` + DepositCount string `json:"deposit_count" validate:"required"` + BlockHash string `json:"block_hash" validate:"required"` +} + +type ProposerSlashing struct { + SignedHeader1 SignedBeaconBlockHeader `json:"signed_header_1" validate:"required"` + SignedHeader2 SignedBeaconBlockHeader `json:"signed_header_2" validate:"required"` +} + +type AttesterSlashing struct { + Attestation1 IndexedAttestation `json:"attestation_1" validate:"required"` + Attestation2 IndexedAttestation `json:"attestation_2" validate:"required"` +} + +type Attestation struct { + AggregationBits string `json:"aggregation_bits" validate:"required"` + Data AttestationData `json:"data" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type Deposit struct { + Proof []string `json:"proof" validate:"required"` + Data DepositData `json:"data" validate:"required"` +} + +type DepositData struct { + Pubkey string `json:"pubkey" validate:"required"` + WithdrawalCredentials string `json:"withdrawal_credentials" validate:"required"` + Amount string `json:"amount" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type SignedVoluntaryExit struct { + Message VoluntaryExit `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type VoluntaryExit struct { + Epoch string `json:"epoch" validate:"required"` + ValidatorIndex string `json:"validator_index" validate:"required"` +} + +type SignedBeaconBlockHeader struct { + Message BeaconBlockHeader `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BeaconBlockHeader struct { + Slot string `json:"slot" validate:"required"` + ProposerIndex string `json:"proposer_index" validate:"required"` + ParentRoot string `json:"parent_root" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + BodyRoot string `json:"body_root" validate:"required"` +} + +type IndexedAttestation struct { + AttestingIndices []string `json:"attesting_indices" validate:"required"` + Data AttestationData `json:"data" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type AttestationData struct { + Slot string `json:"slot" validate:"required"` + Index string `json:"index" validate:"required"` + BeaconBlockRoot string `json:"beacon_block_root" validate:"required"` + Source Checkpoint `json:"source" validate:"required"` + Target Checkpoint `json:"target" validate:"required"` +} + +type Checkpoint struct { + Epoch string `json:"epoch" validate:"required"` + Root string `json:"root" validate:"required"` +} + +type SyncAggregate struct { + SyncCommitteeBits string `json:"sync_committee_bits" validate:"required"` + SyncCommitteeSignature string `json:"sync_committee_signature" validate:"required"` +} + +type ExecutionPayload struct { + ParentHash string `json:"parent_hash" validate:"required"` + FeeRecipient string `json:"fee_recipient" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + ReceiptsRoot string `json:"receipts_root" validate:"required"` + LogsBloom string `json:"logs_bloom" validate:"required"` + PrevRandao string `json:"prev_randao" validate:"required"` + BlockNumber string `json:"block_number" validate:"required"` + GasLimit string `json:"gas_limit" validate:"required"` + GasUsed string `json:"gas_used" validate:"required"` + Timestamp string `json:"timestamp" validate:"required"` + ExtraData string `json:"extra_data" validate:"required"` + BaseFeePerGas string `json:"base_fee_per_gas" validate:"required"` + BlockHash string `json:"block_hash" validate:"required"` + Transactions []string `json:"transactions" validate:"required"` +} + +type ExecutionPayloadHeader struct { + ParentHash string `json:"parent_hash" validate:"required"` + FeeRecipient string `json:"fee_recipient" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + ReceiptsRoot string `json:"receipts_root" validate:"required"` + LogsBloom string `json:"logs_bloom" validate:"required"` + PrevRandao string `json:"prev_randao" validate:"required"` + BlockNumber string `json:"block_number" validate:"required"` + GasLimit string `json:"gas_limit" validate:"required"` + GasUsed string `json:"gas_used" validate:"required"` + Timestamp string `json:"timestamp" validate:"required"` + ExtraData string `json:"extra_data" validate:"required"` + BaseFeePerGas string `json:"base_fee_per_gas" validate:"required"` + BlockHash string `json:"block_hash" validate:"required"` + TransactionsRoot string `json:"transactions_root" validate:"required"` +} + +type ExecutionPayloadCapella struct { + ParentHash string `json:"parent_hash" validate:"required"` + FeeRecipient string `json:"fee_recipient" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + ReceiptsRoot string `json:"receipts_root" validate:"required"` + LogsBloom string `json:"logs_bloom" validate:"required"` + PrevRandao string `json:"prev_randao" validate:"required"` + BlockNumber string `json:"block_number" validate:"required"` + GasLimit string `json:"gas_limit" validate:"required"` + GasUsed string `json:"gas_used" validate:"required"` + Timestamp string `json:"timestamp" validate:"required"` + ExtraData string `json:"extra_data" validate:"required"` + BaseFeePerGas string `json:"base_fee_per_gas" validate:"required"` + BlockHash string `json:"block_hash" validate:"required"` + Transactions []string `json:"transactions" validate:"required"` + Withdrawals []Withdrawal `json:"withdrawals" validate:"required"` +} + +type ExecutionPayloadHeaderCapella struct { + ParentHash string `json:"parent_hash" validate:"required"` + FeeRecipient string `json:"fee_recipient" validate:"required"` + StateRoot string `json:"state_root" validate:"required"` + ReceiptsRoot string `json:"receipts_root" validate:"required"` + LogsBloom string `json:"logs_bloom" validate:"required"` + PrevRandao string `json:"prev_randao" validate:"required"` + BlockNumber string `json:"block_number" validate:"required"` + GasLimit string `json:"gas_limit" validate:"required"` + GasUsed string `json:"gas_used" validate:"required"` + Timestamp string `json:"timestamp" validate:"required"` + ExtraData string `json:"extra_data" validate:"required"` + BaseFeePerGas string `json:"base_fee_per_gas" validate:"required"` + BlockHash string `json:"block_hash" validate:"required"` + TransactionsRoot string `json:"transactions_root" validate:"required"` + WithdrawalsRoot string `json:"withdrawals_root" validate:"required"` +} + +type Withdrawal struct { + WithdrawalIndex string `json:"index" validate:"required"` + ValidatorIndex string `json:"validator_index" validate:"required"` + ExecutionAddress string `json:"address" validate:"required"` + Amount string `json:"amount" validate:"required"` +} + +type SignedBlsToExecutionChange struct { + Message BlsToExecutionChange `json:"message" validate:"required"` + Signature string `json:"signature" validate:"required"` +} + +type BlsToExecutionChange struct { + ValidatorIndex string `json:"validator_index" validate:"required"` + FromBlsPubkey string `json:"from_bls_pubkey" validate:"required"` + ToExecutionAddress string `json:"to_execution_address" validate:"required"` +} + +func (b *SignedBeaconBlock) ToGeneric() (*eth.GenericSignedBeaconBlock, error) { + sig, err := hexutil.Decode(b.Signature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Signature") + } + slot, err := strconv.ParseUint(b.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Slot") + } + proposerIndex, err := strconv.ParseUint(b.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ProposerIndex") + } + parentRoot, err := hexutil.Decode(b.Message.ParentRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ParentRoot") + } + stateRoot, err := hexutil.Decode(b.Message.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.StateRoot") + } + randaoReveal, err := hexutil.Decode(b.Message.Body.RandaoReveal) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.RandaoReveal") + } + depositRoot, err := hexutil.Decode(b.Message.Body.Eth1Data.DepositRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositRoot") + } + depositCount, err := strconv.ParseUint(b.Message.Body.Eth1Data.DepositCount, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositCount") + } + blockHash, err := hexutil.Decode(b.Message.Body.Eth1Data.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.BlockHash") + } + graffiti, err := hexutil.Decode(b.Message.Body.Graffiti) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Graffiti") + } + proposerSlashings, err := convertProposerSlashings(b.Message.Body.ProposerSlashings) + if err != nil { + return nil, err + } + attesterSlashings, err := convertAttesterSlashings(b.Message.Body.AttesterSlashings) + if err != nil { + return nil, err + } + atts, err := convertAtts(b.Message.Body.Attestations) + if err != nil { + return nil, err + } + deposits, err := convertDeposits(b.Message.Body.Deposits) + if err != nil { + return nil, err + } + exits, err := convertExits(b.Message.Body.VoluntaryExits) + if err != nil { + return nil, err + } + + block := ð.SignedBeaconBlock{ + Block: ð.BeaconBlock{ + Slot: primitives.Slot(slot), + ProposerIndex: primitives.ValidatorIndex(proposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + Body: ð.BeaconBlockBody{ + RandaoReveal: randaoReveal, + Eth1Data: ð.Eth1Data{ + DepositRoot: depositRoot, + DepositCount: depositCount, + BlockHash: blockHash, + }, + Graffiti: graffiti, + ProposerSlashings: proposerSlashings, + AttesterSlashings: attesterSlashings, + Attestations: atts, + Deposits: deposits, + VoluntaryExits: exits, + }, + }, + Signature: sig, + } + return ð.GenericSignedBeaconBlock{Block: ð.GenericSignedBeaconBlock_Phase0{Phase0: block}}, nil +} + +func (b *SignedBeaconBlockAltair) ToGeneric() (*eth.GenericSignedBeaconBlock, error) { + sig, err := hexutil.Decode(b.Signature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Signature") + } + slot, err := strconv.ParseUint(b.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Slot") + } + proposerIndex, err := strconv.ParseUint(b.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ProposerIndex") + } + parentRoot, err := hexutil.Decode(b.Message.ParentRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ParentRoot") + } + stateRoot, err := hexutil.Decode(b.Message.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.StateRoot") + } + randaoReveal, err := hexutil.Decode(b.Message.Body.RandaoReveal) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.RandaoReveal") + } + depositRoot, err := hexutil.Decode(b.Message.Body.Eth1Data.DepositRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositRoot") + } + depositCount, err := strconv.ParseUint(b.Message.Body.Eth1Data.DepositCount, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositCount") + } + blockHash, err := hexutil.Decode(b.Message.Body.Eth1Data.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.BlockHash") + } + graffiti, err := hexutil.Decode(b.Message.Body.Graffiti) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Graffiti") + } + proposerSlashings, err := convertProposerSlashings(b.Message.Body.ProposerSlashings) + if err != nil { + return nil, err + } + attesterSlashings, err := convertAttesterSlashings(b.Message.Body.AttesterSlashings) + if err != nil { + return nil, err + } + atts, err := convertAtts(b.Message.Body.Attestations) + if err != nil { + return nil, err + } + deposits, err := convertDeposits(b.Message.Body.Deposits) + if err != nil { + return nil, err + } + exits, err := convertExits(b.Message.Body.VoluntaryExits) + if err != nil { + return nil, err + } + syncCommitteeBits, err := bytesutil.FromHexString(b.Message.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeBits") + } + syncCommitteeSig, err := hexutil.Decode(b.Message.Body.SyncAggregate.SyncCommitteeSignature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeSignature") + } + + block := ð.SignedBeaconBlockAltair{ + Block: ð.BeaconBlockAltair{ + Slot: primitives.Slot(slot), + ProposerIndex: primitives.ValidatorIndex(proposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + Body: ð.BeaconBlockBodyAltair{ + RandaoReveal: randaoReveal, + Eth1Data: ð.Eth1Data{ + DepositRoot: depositRoot, + DepositCount: depositCount, + BlockHash: blockHash, + }, + Graffiti: graffiti, + ProposerSlashings: proposerSlashings, + AttesterSlashings: attesterSlashings, + Attestations: atts, + Deposits: deposits, + VoluntaryExits: exits, + SyncAggregate: ð.SyncAggregate{ + SyncCommitteeBits: syncCommitteeBits, + SyncCommitteeSignature: syncCommitteeSig, + }, + }, + }, + Signature: sig, + } + return ð.GenericSignedBeaconBlock{Block: ð.GenericSignedBeaconBlock_Altair{Altair: block}}, nil +} + +func (b *SignedBeaconBlockBellatrix) ToGeneric() (*eth.GenericSignedBeaconBlock, error) { + sig, err := hexutil.Decode(b.Signature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Signature") + } + slot, err := strconv.ParseUint(b.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Slot") + } + proposerIndex, err := strconv.ParseUint(b.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ProposerIndex") + } + parentRoot, err := hexutil.Decode(b.Message.ParentRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ParentRoot") + } + stateRoot, err := hexutil.Decode(b.Message.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.StateRoot") + } + randaoReveal, err := hexutil.Decode(b.Message.Body.RandaoReveal) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.RandaoReveal") + } + depositRoot, err := hexutil.Decode(b.Message.Body.Eth1Data.DepositRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositRoot") + } + depositCount, err := strconv.ParseUint(b.Message.Body.Eth1Data.DepositCount, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositCount") + } + blockHash, err := hexutil.Decode(b.Message.Body.Eth1Data.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.BlockHash") + } + graffiti, err := hexutil.Decode(b.Message.Body.Graffiti) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Graffiti") + } + proposerSlashings, err := convertProposerSlashings(b.Message.Body.ProposerSlashings) + if err != nil { + return nil, err + } + attesterSlashings, err := convertAttesterSlashings(b.Message.Body.AttesterSlashings) + if err != nil { + return nil, err + } + atts, err := convertAtts(b.Message.Body.Attestations) + if err != nil { + return nil, err + } + deposits, err := convertDeposits(b.Message.Body.Deposits) + if err != nil { + return nil, err + } + exits, err := convertExits(b.Message.Body.VoluntaryExits) + if err != nil { + return nil, err + } + syncCommitteeBits, err := bytesutil.FromHexString(b.Message.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeBits") + } + syncCommitteeSig, err := hexutil.Decode(b.Message.Body.SyncAggregate.SyncCommitteeSignature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeSignature") + } + payloadParentHash, err := hexutil.Decode(b.Message.Body.ExecutionPayload.ParentHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.ParentHash") + } + payloadFeeRecipient, err := hexutil.Decode(b.Message.Body.ExecutionPayload.FeeRecipient) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.FeeRecipient") + } + payloadStateRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayload.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.StateRoot") + } + payloadReceiptsRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayload.ReceiptsRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.ReceiptsRoot") + } + payloadLogsBloom, err := hexutil.Decode(b.Message.Body.ExecutionPayload.LogsBloom) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.LogsBloom") + } + payloadPrevRandao, err := hexutil.Decode(b.Message.Body.ExecutionPayload.PrevRandao) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.PrevRandao") + } + payloadBlockNumber, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.BlockNumber, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.BlockNumber") + } + payloadGasLimit, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.GasLimit, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.GasLimit") + } + payloadGasUsed, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.GasUsed, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.GasUsed") + } + payloadTimestamp, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.Timestamp, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.Timestamp") + } + payloadExtraData, err := hexutil.Decode(b.Message.Body.ExecutionPayload.ExtraData) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.ExtraData") + } + payloadBaseFeePerGas, err := uint256ToHex(b.Message.Body.ExecutionPayload.BaseFeePerGas) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.BaseFeePerGas") + } + payloadBlockHash, err := hexutil.Decode(b.Message.Body.ExecutionPayload.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.BlockHash") + } + payloadTxs := make([][]byte, len(b.Message.Body.ExecutionPayload.Transactions)) + for i, tx := range b.Message.Body.ExecutionPayload.Transactions { + payloadTxs[i], err = hexutil.Decode(tx) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ExecutionPayload.Transactions[%d]", i) + } + } + + block := ð.SignedBeaconBlockBellatrix{ + Block: ð.BeaconBlockBellatrix{ + Slot: primitives.Slot(slot), + ProposerIndex: primitives.ValidatorIndex(proposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + Body: ð.BeaconBlockBodyBellatrix{ + RandaoReveal: randaoReveal, + Eth1Data: ð.Eth1Data{ + DepositRoot: depositRoot, + DepositCount: depositCount, + BlockHash: blockHash, + }, + Graffiti: graffiti, + ProposerSlashings: proposerSlashings, + AttesterSlashings: attesterSlashings, + Attestations: atts, + Deposits: deposits, + VoluntaryExits: exits, + SyncAggregate: ð.SyncAggregate{ + SyncCommitteeBits: syncCommitteeBits, + SyncCommitteeSignature: syncCommitteeSig, + }, + ExecutionPayload: &enginev1.ExecutionPayload{ + ParentHash: payloadParentHash, + FeeRecipient: payloadFeeRecipient, + StateRoot: payloadStateRoot, + ReceiptsRoot: payloadReceiptsRoot, + LogsBloom: payloadLogsBloom, + PrevRandao: payloadPrevRandao, + BlockNumber: payloadBlockNumber, + GasLimit: payloadGasLimit, + GasUsed: payloadGasUsed, + Timestamp: payloadTimestamp, + ExtraData: payloadExtraData, + BaseFeePerGas: payloadBaseFeePerGas, + BlockHash: payloadBlockHash, + Transactions: payloadTxs, + }, + }, + }, + Signature: sig, + } + return ð.GenericSignedBeaconBlock{Block: ð.GenericSignedBeaconBlock_Bellatrix{Bellatrix: block}}, nil +} + +func (b *SignedBlindedBeaconBlockBellatrix) ToGeneric() (*eth.GenericSignedBeaconBlock, error) { + sig, err := hexutil.Decode(b.Signature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Signature") + } + slot, err := strconv.ParseUint(b.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Slot") + } + proposerIndex, err := strconv.ParseUint(b.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ProposerIndex") + } + parentRoot, err := hexutil.Decode(b.Message.ParentRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ParentRoot") + } + stateRoot, err := hexutil.Decode(b.Message.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.StateRoot") + } + randaoReveal, err := hexutil.Decode(b.Message.Body.RandaoReveal) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.RandaoReveal") + } + depositRoot, err := hexutil.Decode(b.Message.Body.Eth1Data.DepositRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositRoot") + } + depositCount, err := strconv.ParseUint(b.Message.Body.Eth1Data.DepositCount, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositCount") + } + blockHash, err := hexutil.Decode(b.Message.Body.Eth1Data.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.BlockHash") + } + graffiti, err := hexutil.Decode(b.Message.Body.Graffiti) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Graffiti") + } + proposerSlashings, err := convertProposerSlashings(b.Message.Body.ProposerSlashings) + if err != nil { + return nil, err + } + attesterSlashings, err := convertAttesterSlashings(b.Message.Body.AttesterSlashings) + if err != nil { + return nil, err + } + atts, err := convertAtts(b.Message.Body.Attestations) + if err != nil { + return nil, err + } + deposits, err := convertDeposits(b.Message.Body.Deposits) + if err != nil { + return nil, err + } + exits, err := convertExits(b.Message.Body.VoluntaryExits) + if err != nil { + return nil, err + } + syncCommitteeBits, err := bytesutil.FromHexString(b.Message.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeBits") + } + syncCommitteeSig, err := hexutil.Decode(b.Message.Body.SyncAggregate.SyncCommitteeSignature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeSignature") + } + payloadParentHash, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.ParentHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.ParentHash") + } + payloadFeeRecipient, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.FeeRecipient) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.FeeRecipient") + } + payloadStateRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.StateRoot") + } + payloadReceiptsRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.ReceiptsRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.ReceiptsRoot") + } + payloadLogsBloom, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.LogsBloom) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.LogsBloom") + } + payloadPrevRandao, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.PrevRandao) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.PrevRandao") + } + payloadBlockNumber, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.BlockNumber, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.BlockNumber") + } + payloadGasLimit, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.GasLimit, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.GasLimit") + } + payloadGasUsed, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.GasUsed, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.GasUsed") + } + payloadTimestamp, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.Timestamp, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.Timestamp") + } + payloadExtraData, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.ExtraData) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.ExtraData") + } + payloadBaseFeePerGas, err := uint256ToHex(b.Message.Body.ExecutionPayloadHeader.BaseFeePerGas) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.BaseFeePerGas") + } + payloadBlockHash, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.BlockHash") + } + payloadTxsRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.TransactionsRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.TransactionsRoot") + } + + block := ð.SignedBlindedBeaconBlockBellatrix{ + Block: ð.BlindedBeaconBlockBellatrix{ + Slot: primitives.Slot(slot), + ProposerIndex: primitives.ValidatorIndex(proposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + Body: ð.BlindedBeaconBlockBodyBellatrix{ + RandaoReveal: randaoReveal, + Eth1Data: ð.Eth1Data{ + DepositRoot: depositRoot, + DepositCount: depositCount, + BlockHash: blockHash, + }, + Graffiti: graffiti, + ProposerSlashings: proposerSlashings, + AttesterSlashings: attesterSlashings, + Attestations: atts, + Deposits: deposits, + VoluntaryExits: exits, + SyncAggregate: ð.SyncAggregate{ + SyncCommitteeBits: syncCommitteeBits, + SyncCommitteeSignature: syncCommitteeSig, + }, + ExecutionPayloadHeader: &enginev1.ExecutionPayloadHeader{ + ParentHash: payloadParentHash, + FeeRecipient: payloadFeeRecipient, + StateRoot: payloadStateRoot, + ReceiptsRoot: payloadReceiptsRoot, + LogsBloom: payloadLogsBloom, + PrevRandao: payloadPrevRandao, + BlockNumber: payloadBlockNumber, + GasLimit: payloadGasLimit, + GasUsed: payloadGasUsed, + Timestamp: payloadTimestamp, + ExtraData: payloadExtraData, + BaseFeePerGas: payloadBaseFeePerGas, + BlockHash: payloadBlockHash, + TransactionsRoot: payloadTxsRoot, + }, + }, + }, + Signature: sig, + } + return ð.GenericSignedBeaconBlock{Block: ð.GenericSignedBeaconBlock_BlindedBellatrix{BlindedBellatrix: block}}, nil +} + +func (b *SignedBeaconBlockCapella) ToGeneric() (*eth.GenericSignedBeaconBlock, error) { + sig, err := hexutil.Decode(b.Signature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Signature") + } + slot, err := strconv.ParseUint(b.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Slot") + } + proposerIndex, err := strconv.ParseUint(b.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ProposerIndex") + } + parentRoot, err := hexutil.Decode(b.Message.ParentRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ParentRoot") + } + stateRoot, err := hexutil.Decode(b.Message.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.StateRoot") + } + randaoReveal, err := hexutil.Decode(b.Message.Body.RandaoReveal) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.RandaoReveal") + } + depositRoot, err := hexutil.Decode(b.Message.Body.Eth1Data.DepositRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositRoot") + } + depositCount, err := strconv.ParseUint(b.Message.Body.Eth1Data.DepositCount, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositCount") + } + blockHash, err := hexutil.Decode(b.Message.Body.Eth1Data.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.BlockHash") + } + graffiti, err := hexutil.Decode(b.Message.Body.Graffiti) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Graffiti") + } + proposerSlashings, err := convertProposerSlashings(b.Message.Body.ProposerSlashings) + if err != nil { + return nil, err + } + attesterSlashings, err := convertAttesterSlashings(b.Message.Body.AttesterSlashings) + if err != nil { + return nil, err + } + atts, err := convertAtts(b.Message.Body.Attestations) + if err != nil { + return nil, err + } + deposits, err := convertDeposits(b.Message.Body.Deposits) + if err != nil { + return nil, err + } + exits, err := convertExits(b.Message.Body.VoluntaryExits) + if err != nil { + return nil, err + } + syncCommitteeBits, err := bytesutil.FromHexString(b.Message.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeBits") + } + syncCommitteeSig, err := hexutil.Decode(b.Message.Body.SyncAggregate.SyncCommitteeSignature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeSignature") + } + payloadParentHash, err := hexutil.Decode(b.Message.Body.ExecutionPayload.ParentHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.ParentHash") + } + payloadFeeRecipient, err := hexutil.Decode(b.Message.Body.ExecutionPayload.FeeRecipient) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.FeeRecipient") + } + payloadStateRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayload.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.StateRoot") + } + payloadReceiptsRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayload.ReceiptsRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.ReceiptsRoot") + } + payloadLogsBloom, err := hexutil.Decode(b.Message.Body.ExecutionPayload.LogsBloom) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.LogsBloom") + } + payloadPrevRandao, err := hexutil.Decode(b.Message.Body.ExecutionPayload.PrevRandao) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.PrevRandao") + } + payloadBlockNumber, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.BlockNumber, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.BlockNumber") + } + payloadGasLimit, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.GasLimit, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.GasLimit") + } + payloadGasUsed, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.GasUsed, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.GasUsed") + } + payloadTimestamp, err := strconv.ParseUint(b.Message.Body.ExecutionPayload.Timestamp, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.Timestamp") + } + payloadExtraData, err := hexutil.Decode(b.Message.Body.ExecutionPayload.ExtraData) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.ExtraData") + } + payloadBaseFeePerGas, err := uint256ToHex(b.Message.Body.ExecutionPayload.BaseFeePerGas) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.BaseFeePerGas") + } + payloadBlockHash, err := hexutil.Decode(b.Message.Body.ExecutionPayload.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayload.BlockHash") + } + txs := make([][]byte, len(b.Message.Body.ExecutionPayload.Transactions)) + for i, tx := range b.Message.Body.ExecutionPayload.Transactions { + txs[i], err = hexutil.Decode(tx) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ExecutionPayload.Transactions[%d]", i) + } + } + withdrawals := make([]*enginev1.Withdrawal, len(b.Message.Body.ExecutionPayload.Withdrawals)) + for i, w := range b.Message.Body.ExecutionPayload.Withdrawals { + withdrawalIndex, err := strconv.ParseUint(w.WithdrawalIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ExecutionPayload.Withdrawals[%d].WithdrawalIndex", i) + } + validatorIndex, err := strconv.ParseUint(w.ValidatorIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ExecutionPayload.Withdrawals[%d].ValidatorIndex", i) + } + address, err := hexutil.Decode(w.ExecutionAddress) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ExecutionPayload.Withdrawals[%d].ExecutionAddress", i) + } + amount, err := strconv.ParseUint(w.Amount, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ExecutionPayload.Withdrawals[%d].Amount", i) + } + withdrawals[i] = &enginev1.Withdrawal{ + Index: withdrawalIndex, + ValidatorIndex: primitives.ValidatorIndex(validatorIndex), + Address: address, + Amount: amount, + } + } + blsChanges, err := convertBlsChanges(b.Message.Body.BlsToExecutionChanges) + if err != nil { + return nil, err + } + + block := ð.SignedBeaconBlockCapella{ + Block: ð.BeaconBlockCapella{ + Slot: primitives.Slot(slot), + ProposerIndex: primitives.ValidatorIndex(proposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + Body: ð.BeaconBlockBodyCapella{ + RandaoReveal: randaoReveal, + Eth1Data: ð.Eth1Data{ + DepositRoot: depositRoot, + DepositCount: depositCount, + BlockHash: blockHash, + }, + Graffiti: graffiti, + ProposerSlashings: proposerSlashings, + AttesterSlashings: attesterSlashings, + Attestations: atts, + Deposits: deposits, + VoluntaryExits: exits, + SyncAggregate: ð.SyncAggregate{ + SyncCommitteeBits: syncCommitteeBits, + SyncCommitteeSignature: syncCommitteeSig, + }, + ExecutionPayload: &enginev1.ExecutionPayloadCapella{ + ParentHash: payloadParentHash, + FeeRecipient: payloadFeeRecipient, + StateRoot: payloadStateRoot, + ReceiptsRoot: payloadReceiptsRoot, + LogsBloom: payloadLogsBloom, + PrevRandao: payloadPrevRandao, + BlockNumber: payloadBlockNumber, + GasLimit: payloadGasLimit, + GasUsed: payloadGasUsed, + Timestamp: payloadTimestamp, + ExtraData: payloadExtraData, + BaseFeePerGas: payloadBaseFeePerGas, + BlockHash: payloadBlockHash, + Transactions: txs, + Withdrawals: withdrawals, + }, + BlsToExecutionChanges: blsChanges, + }, + }, + Signature: sig, + } + return ð.GenericSignedBeaconBlock{Block: ð.GenericSignedBeaconBlock_Capella{Capella: block}}, nil +} + +func (b *SignedBlindedBeaconBlockCapella) ToGeneric() (*eth.GenericSignedBeaconBlock, error) { + sig, err := hexutil.Decode(b.Signature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Signature") + } + slot, err := strconv.ParseUint(b.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Slot") + } + proposerIndex, err := strconv.ParseUint(b.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ProposerIndex") + } + parentRoot, err := hexutil.Decode(b.Message.ParentRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.ParentRoot") + } + stateRoot, err := hexutil.Decode(b.Message.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.StateRoot") + } + randaoReveal, err := hexutil.Decode(b.Message.Body.RandaoReveal) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.RandaoReveal") + } + depositRoot, err := hexutil.Decode(b.Message.Body.Eth1Data.DepositRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositRoot") + } + depositCount, err := strconv.ParseUint(b.Message.Body.Eth1Data.DepositCount, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.DepositCount") + } + blockHash, err := hexutil.Decode(b.Message.Body.Eth1Data.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Eth1Data.BlockHash") + } + graffiti, err := hexutil.Decode(b.Message.Body.Graffiti) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.Graffiti") + } + proposerSlashings, err := convertProposerSlashings(b.Message.Body.ProposerSlashings) + if err != nil { + return nil, err + } + attesterSlashings, err := convertAttesterSlashings(b.Message.Body.AttesterSlashings) + if err != nil { + return nil, err + } + atts, err := convertAtts(b.Message.Body.Attestations) + if err != nil { + return nil, err + } + deposits, err := convertDeposits(b.Message.Body.Deposits) + if err != nil { + return nil, err + } + exits, err := convertExits(b.Message.Body.VoluntaryExits) + if err != nil { + return nil, err + } + syncCommitteeBits, err := bytesutil.FromHexString(b.Message.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeBits") + } + syncCommitteeSig, err := hexutil.Decode(b.Message.Body.SyncAggregate.SyncCommitteeSignature) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.SyncAggregate.SyncCommitteeSignature") + } + payloadParentHash, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.ParentHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.ParentHash") + } + payloadFeeRecipient, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.FeeRecipient) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.FeeRecipient") + } + payloadStateRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.StateRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.StateRoot") + } + payloadReceiptsRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.ReceiptsRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.ReceiptsRoot") + } + payloadLogsBloom, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.LogsBloom) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.LogsBloom") + } + payloadPrevRandao, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.PrevRandao) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.PrevRandao") + } + payloadBlockNumber, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.BlockNumber, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.BlockNumber") + } + payloadGasLimit, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.GasLimit, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.GasLimit") + } + payloadGasUsed, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.GasUsed, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.GasUsed") + } + payloadTimestamp, err := strconv.ParseUint(b.Message.Body.ExecutionPayloadHeader.Timestamp, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.Timestamp") + } + payloadExtraData, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.ExtraData) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.ExtraData") + } + payloadBaseFeePerGas, err := uint256ToHex(b.Message.Body.ExecutionPayloadHeader.BaseFeePerGas) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.BaseFeePerGas") + } + payloadBlockHash, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.BlockHash) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.BlockHash") + } + payloadTxsRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.TransactionsRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.TransactionsRoot") + } + payloadWithdrawalsRoot, err := hexutil.Decode(b.Message.Body.ExecutionPayloadHeader.WithdrawalsRoot) + if err != nil { + return nil, errors.Wrap(err, "could not decode b.Message.Body.ExecutionPayloadHeader.WithdrawalsRoot") + } + blsChanges, err := convertBlsChanges(b.Message.Body.BlsToExecutionChanges) + if err != nil { + return nil, err + } + + block := ð.SignedBlindedBeaconBlockCapella{ + Block: ð.BlindedBeaconBlockCapella{ + Slot: primitives.Slot(slot), + ProposerIndex: primitives.ValidatorIndex(proposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + Body: ð.BlindedBeaconBlockBodyCapella{ + RandaoReveal: randaoReveal, + Eth1Data: ð.Eth1Data{ + DepositRoot: depositRoot, + DepositCount: depositCount, + BlockHash: blockHash, + }, + Graffiti: graffiti, + ProposerSlashings: proposerSlashings, + AttesterSlashings: attesterSlashings, + Attestations: atts, + Deposits: deposits, + VoluntaryExits: exits, + SyncAggregate: ð.SyncAggregate{ + SyncCommitteeBits: syncCommitteeBits, + SyncCommitteeSignature: syncCommitteeSig, + }, + ExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderCapella{ + ParentHash: payloadParentHash, + FeeRecipient: payloadFeeRecipient, + StateRoot: payloadStateRoot, + ReceiptsRoot: payloadReceiptsRoot, + LogsBloom: payloadLogsBloom, + PrevRandao: payloadPrevRandao, + BlockNumber: payloadBlockNumber, + GasLimit: payloadGasLimit, + GasUsed: payloadGasUsed, + Timestamp: payloadTimestamp, + ExtraData: payloadExtraData, + BaseFeePerGas: payloadBaseFeePerGas, + BlockHash: payloadBlockHash, + TransactionsRoot: payloadTxsRoot, + WithdrawalsRoot: payloadWithdrawalsRoot, + }, + BlsToExecutionChanges: blsChanges, + }, + }, + Signature: sig, + } + return ð.GenericSignedBeaconBlock{Block: ð.GenericSignedBeaconBlock_BlindedCapella{BlindedCapella: block}}, nil +} + +func convertProposerSlashings(src []ProposerSlashing) ([]*eth.ProposerSlashing, error) { + if src == nil { + return nil, errors.New("nil b.Message.Body.ProposerSlashings") + } + + proposerSlashings := make([]*eth.ProposerSlashing, len(src)) + for i, s := range src { + h1Sig, err := hexutil.Decode(s.SignedHeader1.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader1.Signature", i) + } + h1Slot, err := strconv.ParseUint(s.SignedHeader1.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader1.Message.Slot", i) + } + h1ProposerIndex, err := strconv.ParseUint(s.SignedHeader1.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader1.Message.ProposerIndex", i) + } + h1ParentRoot, err := hexutil.Decode(s.SignedHeader1.Message.ParentRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader1.Message.ParentRoot", i) + } + h1StateRoot, err := hexutil.Decode(s.SignedHeader1.Message.StateRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader1.Message.StateRoot", i) + } + h1BodyRoot, err := hexutil.Decode(s.SignedHeader1.Message.BodyRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader1.Message.BodyRoot", i) + } + h2Sig, err := hexutil.Decode(s.SignedHeader2.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader2.Signature", i) + } + h2Slot, err := strconv.ParseUint(s.SignedHeader2.Message.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader2.Message.Slot", i) + } + h2ProposerIndex, err := strconv.ParseUint(s.SignedHeader2.Message.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader2.Message.ProposerIndex", i) + } + h2ParentRoot, err := hexutil.Decode(s.SignedHeader2.Message.ParentRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader2.Message.ParentRoot", i) + } + h2StateRoot, err := hexutil.Decode(s.SignedHeader2.Message.StateRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader2.Message.StateRoot", i) + } + h2BodyRoot, err := hexutil.Decode(s.SignedHeader2.Message.BodyRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.ProposerSlashings[%d].SignedHeader2.Message.BodyRoot", i) + } + proposerSlashings[i] = ð.ProposerSlashing{ + Header_1: ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: primitives.Slot(h1Slot), + ProposerIndex: primitives.ValidatorIndex(h1ProposerIndex), + ParentRoot: h1ParentRoot, + StateRoot: h1StateRoot, + BodyRoot: h1BodyRoot, + }, + Signature: h1Sig, + }, + Header_2: ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: primitives.Slot(h2Slot), + ProposerIndex: primitives.ValidatorIndex(h2ProposerIndex), + ParentRoot: h2ParentRoot, + StateRoot: h2StateRoot, + BodyRoot: h2BodyRoot, + }, + Signature: h2Sig, + }, + } + } + return proposerSlashings, nil +} + +func convertAttesterSlashings(src []AttesterSlashing) ([]*eth.AttesterSlashing, error) { + if src == nil { + return nil, errors.New("nil b.Message.Body.AttesterSlashings") + } + + attesterSlashings := make([]*eth.AttesterSlashing, len(src)) + for i, s := range src { + a1Sig, err := hexutil.Decode(s.Attestation1.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Signature", i) + } + a1AttestingIndices := make([]uint64, len(s.Attestation1.AttestingIndices)) + for j, ix := range s.Attestation1.AttestingIndices { + attestingIndex, err := strconv.ParseUint(ix, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.AttestingIndices[%d]", i, j) + } + a1AttestingIndices[j] = attestingIndex + } + a1Slot, err := strconv.ParseUint(s.Attestation1.Data.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Data.Slot", i) + } + a1CommitteeIndex, err := strconv.ParseUint(s.Attestation1.Data.Index, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Data.Index", i) + } + a1BeaconBlockRoot, err := hexutil.Decode(s.Attestation1.Data.BeaconBlockRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Data.BeaconBlockRoot", i) + } + a1SourceEpoch, err := strconv.ParseUint(s.Attestation1.Data.Source.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Data.Source.Epoch", i) + } + a1SourceRoot, err := hexutil.Decode(s.Attestation1.Data.Source.Root) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Data.Source.Root", i) + } + a1TargetEpoch, err := strconv.ParseUint(s.Attestation1.Data.Target.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Data.Target.Epoch", i) + } + a1TargetRoot, err := hexutil.Decode(s.Attestation1.Data.Target.Root) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation1.Data.Target.Root", i) + } + a2Sig, err := hexutil.Decode(s.Attestation2.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Signature", i) + } + a2AttestingIndices := make([]uint64, len(s.Attestation2.AttestingIndices)) + for j, ix := range s.Attestation2.AttestingIndices { + attestingIndex, err := strconv.ParseUint(ix, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.AttestingIndices[%d]", i, j) + } + a2AttestingIndices[j] = attestingIndex + } + a2Slot, err := strconv.ParseUint(s.Attestation2.Data.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Data.Slot", i) + } + a2CommitteeIndex, err := strconv.ParseUint(s.Attestation2.Data.Index, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Data.Index", i) + } + a2BeaconBlockRoot, err := hexutil.Decode(s.Attestation2.Data.BeaconBlockRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Data.BeaconBlockRoot", i) + } + a2SourceEpoch, err := strconv.ParseUint(s.Attestation2.Data.Source.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Data.Source.Epoch", i) + } + a2SourceRoot, err := hexutil.Decode(s.Attestation2.Data.Source.Root) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Data.Source.Root", i) + } + a2TargetEpoch, err := strconv.ParseUint(s.Attestation2.Data.Target.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Data.Target.Epoch", i) + } + a2TargetRoot, err := hexutil.Decode(s.Attestation2.Data.Target.Root) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.AttesterSlashings[%d].Attestation2.Data.Target.Root", i) + } + attesterSlashings[i] = ð.AttesterSlashing{ + Attestation_1: ð.IndexedAttestation{ + AttestingIndices: a1AttestingIndices, + Data: ð.AttestationData{ + Slot: primitives.Slot(a1Slot), + CommitteeIndex: primitives.CommitteeIndex(a1CommitteeIndex), + BeaconBlockRoot: a1BeaconBlockRoot, + Source: ð.Checkpoint{ + Epoch: primitives.Epoch(a1SourceEpoch), + Root: a1SourceRoot, + }, + Target: ð.Checkpoint{ + Epoch: primitives.Epoch(a1TargetEpoch), + Root: a1TargetRoot, + }, + }, + Signature: a1Sig, + }, + Attestation_2: ð.IndexedAttestation{ + AttestingIndices: a2AttestingIndices, + Data: ð.AttestationData{ + Slot: primitives.Slot(a2Slot), + CommitteeIndex: primitives.CommitteeIndex(a2CommitteeIndex), + BeaconBlockRoot: a2BeaconBlockRoot, + Source: ð.Checkpoint{ + Epoch: primitives.Epoch(a2SourceEpoch), + Root: a2SourceRoot, + }, + Target: ð.Checkpoint{ + Epoch: primitives.Epoch(a2TargetEpoch), + Root: a2TargetRoot, + }, + }, + Signature: a2Sig, + }, + } + } + return attesterSlashings, nil +} + +func convertAtts(src []Attestation) ([]*eth.Attestation, error) { + if src == nil { + return nil, errors.New("nil b.Message.Body.Attestations") + } + + atts := make([]*eth.Attestation, len(src)) + for i, a := range src { + sig, err := hexutil.Decode(a.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Signature", i) + } + slot, err := strconv.ParseUint(a.Data.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Data.Slot", i) + } + committeeIndex, err := strconv.ParseUint(a.Data.Index, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Data.Index", i) + } + beaconBlockRoot, err := hexutil.Decode(a.Data.BeaconBlockRoot) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Data.BeaconBlockRoot", i) + } + sourceEpoch, err := strconv.ParseUint(a.Data.Source.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Data.Source.Epoch", i) + } + sourceRoot, err := hexutil.Decode(a.Data.Source.Root) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Data.Source.Root", i) + } + targetEpoch, err := strconv.ParseUint(a.Data.Target.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Data.Target.Epoch", i) + } + targetRoot, err := hexutil.Decode(a.Data.Target.Root) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Attestations[%d].Data.Target.Root", i) + } + atts[i] = ð.Attestation{ + AggregationBits: []byte(a.AggregationBits), + Data: ð.AttestationData{ + Slot: primitives.Slot(slot), + CommitteeIndex: primitives.CommitteeIndex(committeeIndex), + BeaconBlockRoot: beaconBlockRoot, + Source: ð.Checkpoint{ + Epoch: primitives.Epoch(sourceEpoch), + Root: sourceRoot, + }, + Target: ð.Checkpoint{ + Epoch: primitives.Epoch(targetEpoch), + Root: targetRoot, + }, + }, + Signature: sig, + } + } + return atts, nil +} + +func convertDeposits(src []Deposit) ([]*eth.Deposit, error) { + if src == nil { + return nil, errors.New("nil b.Message.Body.Deposits") + } + + deposits := make([]*eth.Deposit, len(src)) + for i, d := range src { + proof := make([][]byte, len(d.Proof)) + for j, p := range d.Proof { + var err error + proof[j], err = hexutil.Decode(p) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Deposits[%d].Proof[%d]", i, j) + } + } + pubkey, err := hexutil.Decode(d.Data.Pubkey) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Deposits[%d].Pubkey", i) + } + withdrawalCreds, err := hexutil.Decode(d.Data.WithdrawalCredentials) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Deposits[%d].WithdrawalCredentials", i) + } + amount, err := strconv.ParseUint(d.Data.Amount, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Deposits[%d].Amount", i) + } + sig, err := hexutil.Decode(d.Data.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.Deposits[%d].Signature", i) + } + deposits[i] = ð.Deposit{ + Proof: proof, + Data: ð.Deposit_Data{ + PublicKey: pubkey, + WithdrawalCredentials: withdrawalCreds, + Amount: amount, + Signature: sig, + }, + } + } + return deposits, nil +} + +func convertExits(src []SignedVoluntaryExit) ([]*eth.SignedVoluntaryExit, error) { + if src == nil { + return nil, errors.New("nil b.Message.Body.VoluntaryExits") + } + + exits := make([]*eth.SignedVoluntaryExit, len(src)) + for i, e := range src { + sig, err := hexutil.Decode(e.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.VoluntaryExits[%d].Signature", i) + } + epoch, err := strconv.ParseUint(e.Message.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.VoluntaryExits[%d].Epoch", i) + } + validatorIndex, err := strconv.ParseUint(e.Message.ValidatorIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.VoluntaryExits[%d].ValidatorIndex", i) + } + exits[i] = ð.SignedVoluntaryExit{ + Exit: ð.VoluntaryExit{ + Epoch: primitives.Epoch(epoch), + ValidatorIndex: primitives.ValidatorIndex(validatorIndex), + }, + Signature: sig, + } + } + return exits, nil +} + +func convertBlsChanges(src []SignedBlsToExecutionChange) ([]*eth.SignedBLSToExecutionChange, error) { + if src == nil { + return nil, errors.New("nil b.Message.Body.BlsToExecutionChanges") + } + + changes := make([]*eth.SignedBLSToExecutionChange, len(src)) + for i, ch := range src { + sig, err := hexutil.Decode(ch.Signature) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.BlsToExecutionChanges[%d].Signature", i) + } + index, err := strconv.ParseUint(ch.Message.ValidatorIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.BlsToExecutionChanges[%d].Message.ValidatorIndex", i) + } + pubkey, err := hexutil.Decode(ch.Message.FromBlsPubkey) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.BlsToExecutionChanges[%d].Message.FromBlsPubkey", i) + } + address, err := hexutil.Decode(ch.Message.ToExecutionAddress) + if err != nil { + return nil, errors.Wrapf(err, "could not decode b.Message.Body.BlsToExecutionChanges[%d].Message.ToExecutionAddress", i) + } + changes[i] = ð.SignedBLSToExecutionChange{ + Message: ð.BLSToExecutionChange{ + ValidatorIndex: primitives.ValidatorIndex(index), + FromBlsPubkey: pubkey, + ToExecutionAddress: address, + }, + Signature: sig, + } + } + return changes, nil +} + +func uint256ToHex(num string) ([]byte, error) { + uint256, ok := new(big.Int).SetString(num, 10) + if !ok { + return nil, errors.New("could not parse Uint256") + } + bigEndian := uint256.Bytes() + if len(bigEndian) > 32 { + return nil, errors.New("number too big for Uint256") + } + return bytesutil2.ReverseByteOrder(bytesutil2.PadTo(bigEndian, 32)), nil +} diff --git a/beacon-chain/rpc/eth/helpers/sync.go b/beacon-chain/rpc/eth/helpers/sync.go index cc2aad1f3..ca975d927 100644 --- a/beacon-chain/rpc/eth/helpers/sync.go +++ b/beacon-chain/rpc/eth/helpers/sync.go @@ -20,9 +20,9 @@ import ( "google.golang.org/grpc/status" ) -// ValidateSync checks whether the node is currently syncing and returns an error if it is. +// ValidateSyncGRPC checks whether the node is currently syncing and returns an error if it is. // It also appends syncing info to gRPC headers. -func ValidateSync( +func ValidateSyncGRPC( ctx context.Context, syncChecker sync.Checker, headFetcher blockchain.HeadFetcher, @@ -38,8 +38,8 @@ func ValidateSync( return status.Errorf(codes.Internal, "Could not check optimistic status: %v", err) } - syncDetailsContainer := &syncDetailsContainer{ - SyncDetails: &SyncDetailsJson{ + syncDetailsContainer := &SyncDetailsContainer{ + Data: &SyncDetailsJson{ HeadSlot: strconv.FormatUint(uint64(headSlot), 10), SyncDistance: strconv.FormatUint(uint64(timeFetcher.CurrentSlot()-headSlot), 10), IsSyncing: true, @@ -58,6 +58,35 @@ func ValidateSync( return status.Error(codes.Unavailable, "Syncing to latest head, not ready to respond") } +// ValidateSyncHTTP checks whether the node is currently syncing and returns sync information. +// It returns information whether the node is currently syncing along with sync details. +func ValidateSyncHTTP( + ctx context.Context, + syncChecker sync.Checker, + headFetcher blockchain.HeadFetcher, + timeFetcher blockchain.TimeFetcher, + optimisticModeFetcher blockchain.OptimisticModeFetcher, +) (bool, *SyncDetailsContainer, error) { + if !syncChecker.Syncing() { + return false, nil, nil + } + + headSlot := headFetcher.HeadSlot() + isOptimistic, err := optimisticModeFetcher.IsOptimistic(ctx) + if err != nil { + return true, nil, errors.Wrap(err, "could not check optimistic status") + } + syncDetails := &SyncDetailsContainer{ + Data: &SyncDetailsJson{ + HeadSlot: strconv.FormatUint(uint64(headSlot), 10), + SyncDistance: strconv.FormatUint(uint64(timeFetcher.CurrentSlot()-headSlot), 10), + IsSyncing: true, + IsOptimistic: isOptimistic, + }, + } + return true, syncDetails, nil +} + // IsOptimistic checks whether the beacon state's block is optimistic. func IsOptimistic( ctx context.Context, @@ -197,7 +226,7 @@ type SyncDetailsJson struct { ElOffline bool `json:"el_offline"` } -// SyncDetailsContainer is a wrapper for SyncDetails. -type syncDetailsContainer struct { - SyncDetails *SyncDetailsJson `json:"sync_details"` +// SyncDetailsContainer is a wrapper for Data. +type SyncDetailsContainer struct { + Data *SyncDetailsJson `json:"data"` } diff --git a/beacon-chain/rpc/eth/helpers/sync_test.go b/beacon-chain/rpc/eth/helpers/sync_test.go index 527880b5f..5590ccd13 100644 --- a/beacon-chain/rpc/eth/helpers/sync_test.go +++ b/beacon-chain/rpc/eth/helpers/sync_test.go @@ -42,7 +42,7 @@ func TestValidateSync(t *testing.T) { Slot: &headSlot, State: st, } - err = ValidateSync(ctx, syncChecker, chainService, chainService, chainService) + err = ValidateSyncGRPC(ctx, syncChecker, chainService, chainService, chainService) require.NotNil(t, err) sts, ok := grpc.ServerTransportStreamFromContext(ctx).(*runtime.ServerTransportStream) require.Equal(t, true, ok, "type assertion failed") @@ -51,7 +51,7 @@ func TestValidateSync(t *testing.T) { require.Equal(t, true, ok, "could not retrieve custom error metadata value") assert.DeepEqual( t, - []string{`{"sync_details":{"head_slot":"50","sync_distance":"50","is_syncing":true,"is_optimistic":false,"el_offline":false}}`}, + []string{`{"data":{"head_slot":"50","sync_distance":"50","is_syncing":true,"is_optimistic":false,"el_offline":false}}`}, v, ) }) @@ -67,7 +67,7 @@ func TestValidateSync(t *testing.T) { Slot: &headSlot, State: st, } - err = ValidateSync(ctx, syncChecker, nil, nil, chainService) + err = ValidateSyncGRPC(ctx, syncChecker, nil, nil, chainService) require.NoError(t, err) }) } diff --git a/beacon-chain/rpc/eth/validator/validator.go b/beacon-chain/rpc/eth/validator/validator.go index 4fa65b2f2..e742b6917 100644 --- a/beacon-chain/rpc/eth/validator/validator.go +++ b/beacon-chain/rpc/eth/validator/validator.go @@ -44,7 +44,7 @@ func (vs *Server) GetAttesterDuties(ctx context.Context, req *ethpbv1.AttesterDu ctx, span := trace.StartSpan(ctx, "validator.GetAttesterDuties") defer span.End() - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -133,7 +133,7 @@ func (vs *Server) GetProposerDuties(ctx context.Context, req *ethpbv1.ProposerDu ctx, span := trace.StartSpan(ctx, "validator.GetProposerDuties") defer span.End() - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -224,7 +224,7 @@ func (vs *Server) GetSyncCommitteeDuties(ctx context.Context, req *ethpbv2.SyncC ctx, span := trace.StartSpan(ctx, "validator.GetSyncCommitteeDuties") defer span.End() - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -307,7 +307,7 @@ func (vs *Server) ProduceBlockV2(ctx context.Context, req *ethpbv1.ProduceBlockR ctx, span := trace.StartSpan(ctx, "validator.ProduceBlockV2") defer span.End() - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -406,7 +406,7 @@ func (vs *Server) ProduceBlockV2SSZ(ctx context.Context, req *ethpbv1.ProduceBlo ctx, span := trace.StartSpan(ctx, "validator.ProduceBlockV2SSZ") defer span.End() - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -515,7 +515,7 @@ func (vs *Server) ProduceBlindedBlock(ctx context.Context, req *ethpbv1.ProduceB if !vs.BlockBuilder.Configured() { return nil, status.Error(codes.Internal, "Block builder not configured") } - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -614,7 +614,7 @@ func (vs *Server) ProduceBlindedBlockSSZ(ctx context.Context, req *ethpbv1.Produ if !vs.BlockBuilder.Configured() { return nil, status.Error(codes.Internal, "Block builder not configured") } - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -891,7 +891,7 @@ func (vs *Server) SubmitBeaconCommitteeSubscription(ctx context.Context, req *et ctx, span := trace.StartSpan(ctx, "validator.SubmitBeaconCommitteeSubscription") defer span.End() - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } @@ -972,7 +972,7 @@ func (vs *Server) SubmitSyncCommitteeSubscription(ctx context.Context, req *ethp ctx, span := trace.StartSpan(ctx, "validator.SubmitSyncCommitteeSubscription") defer span.End() - if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { + if err := rpchelpers.ValidateSyncGRPC(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher, vs.OptimisticModeFetcher); err != nil { // We simply return the error because it's already a gRPC error. return nil, err } diff --git a/beacon-chain/rpc/service.go b/beacon-chain/rpc/service.go index b8500cbf2..ebedfc4af 100644 --- a/beacon-chain/rpc/service.go +++ b/beacon-chain/rpc/service.go @@ -340,7 +340,10 @@ func (s *Service) Start() { ExecutionPayloadReconstructor: s.cfg.ExecutionPayloadReconstructor, BLSChangesPool: s.cfg.BLSChangesPool, FinalizationFetcher: s.cfg.FinalizationFetcher, + ForkchoiceFetcher: s.cfg.ForkchoiceFetcher, } + s.cfg.Router.HandleFunc("/eth/v2/beacon/blocks", beaconChainServerV1.PublishBlockV2) + s.cfg.Router.HandleFunc("/eth/v2/beacon/blinded_blocks", beaconChainServerV1.PublishBlindedBlockV2) ethpbv1alpha1.RegisterNodeServer(s.grpcServer, nodeServer) ethpbservice.RegisterBeaconNodeServer(s.grpcServer, nodeServerV1) ethpbv1alpha1.RegisterHealthServer(s.grpcServer, nodeServer) diff --git a/deps.bzl b/deps.bzl index 053e41434..dbbb1b59f 100644 --- a/deps.bzl +++ b/deps.bzl @@ -1304,26 +1304,26 @@ def prysm_deps(): go_repository( name = "com_github_go_playground_assert_v2", importpath = "github.com/go-playground/assert/v2", - sum = "h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=", - version = "v2.0.1", + sum = "h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=", + version = "v2.2.0", ) go_repository( name = "com_github_go_playground_locales", importpath = "github.com/go-playground/locales", - sum = "h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=", - version = "v0.14.0", + sum = "h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=", + version = "v0.14.1", ) go_repository( name = "com_github_go_playground_universal_translator", importpath = "github.com/go-playground/universal-translator", - sum = "h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=", - version = "v0.18.0", + sum = "h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=", + version = "v0.18.1", ) go_repository( name = "com_github_go_playground_validator_v10", importpath = "github.com/go-playground/validator/v10", - sum = "h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=", - version = "v10.11.1", + sum = "h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ=", + version = "v10.13.0", ) go_repository( @@ -2415,8 +2415,8 @@ def prysm_deps(): go_repository( name = "com_github_leodido_go_urn", importpath = "github.com/leodido/go-urn", - sum = "h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=", - version = "v1.2.1", + sum = "h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=", + version = "v1.2.3", ) go_repository( @@ -3806,8 +3806,8 @@ def prysm_deps(): go_repository( name = "com_github_stretchr_testify", importpath = "github.com/stretchr/testify", - sum = "h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=", - version = "v1.8.1", + sum = "h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=", + version = "v1.8.2", ) go_repository( name = "com_github_subosito_gotenv", @@ -4680,8 +4680,8 @@ def prysm_deps(): go_repository( name = "org_golang_x_crypto", importpath = "golang.org/x/crypto", - sum = "h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=", - version = "v0.5.0", + sum = "h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=", + version = "v0.7.0", ) go_repository( name = "org_golang_x_exp", diff --git a/go.mod b/go.mod index 583105ce8..9b3ab6fc6 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,7 @@ require ( github.com/schollz/progressbar/v3 v3.3.4 github.com/sirupsen/logrus v1.9.0 github.com/status-im/keycard-go v0.2.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e github.com/trailofbits/go-mutexasserts v0.0.0-20230328101604-8cdbc5f3d279 @@ -80,7 +80,7 @@ require ( go.etcd.io/bbolt v1.3.5 go.opencensus.io v0.24.0 go.uber.org/automaxprocs v1.3.0 - golang.org/x/crypto v0.5.0 + golang.org/x/crypto v0.7.0 golang.org/x/exp v0.0.0-20230206171751-46f607a40771 golang.org/x/mod v0.10.0 golang.org/x/sync v0.1.0 @@ -126,8 +126,8 @@ require ( github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect @@ -157,7 +157,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.1 // indirect github.com/koron/go-ssdp v0.0.3 // indirect github.com/kr/text v0.2.0 // indirect - github.com/leodido/go-urn v1.2.1 // indirect + github.com/leodido/go-urn v1.2.3 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect @@ -246,7 +246,7 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-playground/validator/v10 v10.11.1 + github.com/go-playground/validator/v10 v10.13.0 github.com/peterh/liner v1.2.0 // indirect github.com/prysmaticlabs/gohashtree v0.0.3-alpha golang.org/x/sys v0.7.0 // indirect diff --git a/go.sum b/go.sum index dbcbd31b8..9f74d0bc1 100644 --- a/go.sum +++ b/go.sum @@ -390,17 +390,17 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9 github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= +github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -744,8 +744,8 @@ github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awS github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA= +github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= @@ -1101,7 +1101,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -1204,8 +1203,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= @@ -1371,10 +1371,9 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1481,7 +1480,6 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1599,7 +1597,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=