From a296a0c7833372105d77781b6163ad5ae1ab3d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kapka?= Date: Thu, 26 Jan 2023 14:07:44 +0100 Subject: [PATCH] Update builder code to Capella (#11904) --- api/client/builder/BUILD.bazel | 7 + api/client/builder/bid.go | 190 +++++++ api/client/builder/client.go | 121 ++++- api/client/builder/client_test.go | 406 +++++++++++---- .../testdata/blinded-block-capella.json | 1 + .../testdata/execution-payload-capella.json | 1 + api/client/builder/testing/BUILD.bazel | 3 +- api/client/builder/testing/mock.go | 7 +- api/client/builder/types.go | 305 +++++++++++ api/client/builder/types_test.go | 472 +++++++++++++++++- beacon-chain/builder/BUILD.bazel | 2 +- beacon-chain/builder/service.go | 10 +- beacon-chain/builder/testing/BUILD.bazel | 4 + beacon-chain/builder/testing/mock.go | 20 +- .../rpc/prysm/v1alpha1/validator/BUILD.bazel | 1 + .../v1alpha1/validator/proposer_bellatrix.go | 97 ++-- .../validator/proposer_bellatrix_test.go | 11 +- proto/prysm/v1alpha1/BUILD.bazel | 3 +- proto/prysm/v1alpha1/beacon_block.pb.go | 257 ++++++++-- proto/prysm/v1alpha1/beacon_block.proto | 31 +- proto/prysm/v1alpha1/generated.ssz.go | 135 ++++- 21 files changed, 1882 insertions(+), 202 deletions(-) create mode 100644 api/client/builder/bid.go create mode 100644 api/client/builder/testdata/blinded-block-capella.json create mode 100644 api/client/builder/testdata/execution-payload-capella.json diff --git a/api/client/builder/BUILD.bazel b/api/client/builder/BUILD.bazel index 5c8dfe73daef..e060d95e7ab2 100644 --- a/api/client/builder/BUILD.bazel +++ b/api/client/builder/BUILD.bazel @@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "bid.go", "client.go", "errors.go", "types.go", @@ -10,6 +11,8 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/api/client/builder", visibility = ["//visibility:public"], deps = [ + "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", "//monitoring/tracing:go_default_library", @@ -17,8 +20,10 @@ go_library( "//network/authorization:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "//runtime/version:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_pkg_errors//:go_default_library", + "@com_github_prysmaticlabs_fastssz//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@io_opencensus_go//trace:go_default_library", ], @@ -34,10 +39,12 @@ go_test( embed = [":go_default_library"], deps = [ "//config/params:go_default_library", + "//consensus-types/blocks:go_default_library", "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "//testing/assert:go_default_library", "//testing/require:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_golang_protobuf//proto:go_default_library", diff --git a/api/client/builder/bid.go b/api/client/builder/bid.go new file mode 100644 index 000000000000..5340ed873275 --- /dev/null +++ b/api/client/builder/bid.go @@ -0,0 +1,190 @@ +package builder + +import ( + ssz "github.com/prysmaticlabs/fastssz" + "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" + ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v3/runtime/version" +) + +// SignedBid is an interface describing the method set of a signed builder bid. +type SignedBid interface { + Message() (Bid, error) + Signature() []byte + Version() int + IsNil() bool +} + +// Bid is an interface describing the method set of a builder bid. +type Bid interface { + Header() (interfaces.ExecutionData, error) + Value() []byte + Pubkey() []byte + Version() int + IsNil() bool + HashTreeRoot() ([32]byte, error) + HashTreeRootWith(hh *ssz.Hasher) error +} + +type signedBuilderBid struct { + p *ethpb.SignedBuilderBid +} + +// WrappedSignedBuilderBid is a constructor which wraps a protobuf signed bit into an interface. +func WrappedSignedBuilderBid(p *ethpb.SignedBuilderBid) (SignedBid, error) { + w := signedBuilderBid{p: p} + if w.IsNil() { + return nil, blocks.ErrNilObjectWrapped + } + return w, nil +} + +// Message -- +func (b signedBuilderBid) Message() (Bid, error) { + return WrappedBuilderBid(b.p.Message) +} + +// Signature -- +func (b signedBuilderBid) Signature() []byte { + return b.p.Signature +} + +// Version -- +func (b signedBuilderBid) Version() int { + return version.Bellatrix +} + +// IsNil -- +func (b signedBuilderBid) IsNil() bool { + return b.p == nil +} + +type signedBuilderBidCapella struct { + p *ethpb.SignedBuilderBidCapella +} + +// WrappedSignedBuilderBidCapella is a constructor which wraps a protobuf signed bit into an interface. +func WrappedSignedBuilderBidCapella(p *ethpb.SignedBuilderBidCapella) (SignedBid, error) { + w := signedBuilderBidCapella{p: p} + if w.IsNil() { + return nil, blocks.ErrNilObjectWrapped + } + return w, nil +} + +// Message -- +func (b signedBuilderBidCapella) Message() (Bid, error) { + return WrappedBuilderBidCapella(b.p.Message) +} + +// Signature -- +func (b signedBuilderBidCapella) Signature() []byte { + return b.p.Signature +} + +// Version -- +func (b signedBuilderBidCapella) Version() int { + return version.Capella +} + +// IsNil -- +func (b signedBuilderBidCapella) IsNil() bool { + return b.p == nil +} + +type builderBid struct { + p *ethpb.BuilderBid +} + +// WrappedBuilderBid is a constructor which wraps a protobuf bid into an interface. +func WrappedBuilderBid(p *ethpb.BuilderBid) (Bid, error) { + w := builderBid{p: p} + if w.IsNil() { + return nil, blocks.ErrNilObjectWrapped + } + return w, nil +} + +// Header -- +func (b builderBid) Header() (interfaces.ExecutionData, error) { + return blocks.WrappedExecutionPayloadHeader(b.p.Header) +} + +// Version -- +func (b builderBid) Version() int { + return version.Bellatrix +} + +// Value -- +func (b builderBid) Value() []byte { + return b.p.Value +} + +// Pubkey -- +func (b builderBid) Pubkey() []byte { + return b.p.Pubkey +} + +// IsNil -- +func (b builderBid) IsNil() bool { + return b.p == nil +} + +// HashTreeRoot -- +func (b builderBid) HashTreeRoot() ([32]byte, error) { + return b.p.HashTreeRoot() +} + +// HashTreeRootWith -- +func (b builderBid) HashTreeRootWith(hh *ssz.Hasher) error { + return b.p.HashTreeRootWith(hh) +} + +type builderBidCapella struct { + p *ethpb.BuilderBidCapella +} + +// WrappedBuilderBidCapella is a constructor which wraps a protobuf bid into an interface. +func WrappedBuilderBidCapella(p *ethpb.BuilderBidCapella) (Bid, error) { + w := builderBidCapella{p: p} + if w.IsNil() { + return nil, blocks.ErrNilObjectWrapped + } + return w, nil +} + +// Header -- +func (b builderBidCapella) Header() (interfaces.ExecutionData, error) { + return blocks.WrappedExecutionPayloadHeaderCapella(b.p.Header) +} + +// Version -- +func (b builderBidCapella) Version() int { + return version.Capella +} + +// Value -- +func (b builderBidCapella) Value() []byte { + return b.p.Value +} + +// Pubkey -- +func (b builderBidCapella) Pubkey() []byte { + return b.p.Pubkey +} + +// IsNil -- +func (b builderBidCapella) IsNil() bool { + return b.p == nil +} + +// HashTreeRoot -- +func (b builderBidCapella) HashTreeRoot() ([32]byte, error) { + return b.p.HashTreeRoot() +} + +// HashTreeRootWith -- +func (b builderBidCapella) HashTreeRootWith(hh *ssz.Hasher) error { + return b.p.HashTreeRootWith(hh) +} diff --git a/api/client/builder/client.go b/api/client/builder/client.go index e443164d5525..88ad654fed89 100644 --- a/api/client/builder/client.go +++ b/api/client/builder/client.go @@ -9,16 +9,20 @@ import ( "net" "net/http" "net/url" + "strings" "text/template" "time" "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/monitoring/tracing" "github.com/prysmaticlabs/prysm/v3/network" "github.com/prysmaticlabs/prysm/v3/network/authorization" v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v3/runtime/version" log "github.com/sirupsen/logrus" "go.opencensus.io/trace" ) @@ -32,6 +36,7 @@ const ( var errMalformedHostname = errors.New("hostname must include port, separated by one colon, like example.com:3500") var errMalformedRequest = errors.New("required request data are missing") +var errNotBlinded = errors.New("submitted block is not blinded") var submitBlindedBlockTimeout = 3 * time.Second // ClientOpt is a functional option for the Client type (http.Client wrapper) @@ -82,9 +87,9 @@ var _ observer = &requestLogger{} // BuilderClient provides a collection of helper methods for calling Builder API endpoints. type BuilderClient interface { NodeURL() string - GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubkey [48]byte) (*ethpb.SignedBuilderBid, error) + GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubkey [48]byte) (SignedBid, error) RegisterValidator(ctx context.Context, svr []*ethpb.SignedValidatorRegistrationV1) error - SubmitBlindedBlock(ctx context.Context, sb *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) + SubmitBlindedBlock(ctx context.Context, sb interfaces.SignedBeaconBlock) (interfaces.ExecutionData, error) Status(ctx context.Context) error } @@ -202,8 +207,8 @@ func execHeaderPath(slot types.Slot, parentHash [32]byte, pubkey [48]byte) (stri return b.String(), nil } -// GetHeader is used by a proposing validator to request an ExecutionPayloadHeader from the Builder node. -func (c *Client) GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubkey [48]byte) (*ethpb.SignedBuilderBid, error) { +// GetHeader is used by a proposing validator to request an execution payload header from the Builder node. +func (c *Client) GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubkey [48]byte) (SignedBid, error) { path, err := execHeaderPath(slot, parentHash, pubkey) if err != nil { return nil, err @@ -212,11 +217,35 @@ func (c *Client) GetHeader(ctx context.Context, slot types.Slot, parentHash [32] if err != nil { return nil, err } - hr := &ExecHeaderResponse{} - if err := json.Unmarshal(hb, hr); err != nil { + v := &VersionResponse{} + if err := json.Unmarshal(hb, v); err != nil { return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey) } - return hr.ToProto() + switch strings.ToLower(v.Version) { + case strings.ToLower(version.String(version.Capella)): + hr := &ExecHeaderResponseCapella{} + if err := json.Unmarshal(hb, hr); err != nil { + return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey) + } + p, err := hr.ToProto() + if err != nil { + return nil, errors.Wrapf(err, "could not extract proto message from header") + } + return WrappedSignedBuilderBidCapella(p) + case strings.ToLower(version.String(version.Bellatrix)): + hr := &ExecHeaderResponse{} + if err := json.Unmarshal(hb, hr); err != nil { + return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey) + } + p, err := hr.ToProto() + if err != nil { + return nil, errors.Wrap(err, "could not extract proto message from header") + } + return WrappedSignedBuilderBid(p) + default: + return nil, fmt.Errorf("unsupported header version %s", strings.ToLower(v.Version)) + } + } // RegisterValidator encodes the SignedValidatorRegistrationV1 message to json (including hex-encoding the byte @@ -247,12 +276,78 @@ func (c *Client) RegisterValidator(ctx context.Context, svr []*ethpb.SignedValid } // SubmitBlindedBlock calls the builder API endpoint that binds the validator to the builder and submits the block. -// The response is the full ExecutionPayload used to create the blinded block. -func (c *Client) SubmitBlindedBlock(ctx context.Context, sb *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) { - v := &SignedBlindedBeaconBlockBellatrix{SignedBlindedBeaconBlockBellatrix: sb} +// The response is the full execution payload used to create the blinded block. +func (c *Client) SubmitBlindedBlock(ctx context.Context, sb interfaces.SignedBeaconBlock) (interfaces.ExecutionData, error) { + if !sb.IsBlinded() { + return nil, errNotBlinded + } + switch sb.Version() { + case version.Bellatrix: + psb, err := sb.PbBlindedBellatrixBlock() + if err != nil { + return nil, errors.Wrapf(err, "could not get protobuf block") + } + b := &SignedBlindedBeaconBlockBellatrix{SignedBlindedBeaconBlockBellatrix: psb} + body, err := json.Marshal(b) + if err != nil { + return nil, errors.Wrap(err, "error encoding the SignedBlindedBeaconBlockBellatrix value body in SubmitBlindedBlock") + } + + ctx, cancel := context.WithTimeout(ctx, submitBlindedBlockTimeout) + defer cancel() + rb, err := c.do(ctx, http.MethodPost, postBlindedBeaconBlockPath, bytes.NewBuffer(body)) + + if err != nil { + return nil, errors.Wrap(err, "error posting the SignedBlindedBeaconBlockBellatrix to the builder api") + } + ep := &ExecPayloadResponse{} + if err := json.Unmarshal(rb, ep); err != nil { + return nil, errors.Wrap(err, "error unmarshaling the builder SubmitBlindedBlock response") + } + p, err := ep.ToProto() + if err != nil { + return nil, errors.Wrapf(err, "could not extract proto message from payload") + } + return blocks.WrappedExecutionPayload(p) + case version.Capella: + psb, err := sb.PbBlindedCapellaBlock() + if err != nil { + return nil, errors.Wrapf(err, "could not get protobuf block") + } + b := &SignedBlindedBeaconBlockCapella{SignedBlindedBeaconBlockCapella: psb} + body, err := json.Marshal(b) + if err != nil { + return nil, errors.Wrap(err, "error encoding the SignedBlindedBeaconBlockCapella value body in SubmitBlindedBlockCapella") + } + + ctx, cancel := context.WithTimeout(ctx, submitBlindedBlockTimeout) + defer cancel() + rb, err := c.do(ctx, http.MethodPost, postBlindedBeaconBlockPath, bytes.NewBuffer(body)) + + if err != nil { + return nil, errors.Wrap(err, "error posting the SignedBlindedBeaconBlockCapella to the builder api") + } + ep := &ExecPayloadResponseCapella{} + if err := json.Unmarshal(rb, ep); err != nil { + return nil, errors.Wrap(err, "error unmarshaling the builder SubmitBlindedBlockCapella response") + } + p, err := ep.ToProto() + if err != nil { + return nil, errors.Wrapf(err, "could not extract proto message from payload") + } + return blocks.WrappedExecutionPayloadCapella(p) + default: + return nil, fmt.Errorf("unsupported block version %s", version.String(sb.Version())) + } +} + +// SubmitBlindedBlockCapella calls the builder API endpoint that binds the validator to the builder and submits the block. +// The response is the full ExecutionPayloadCapella used to create the blinded block. +func (c *Client) SubmitBlindedBlockCapella(ctx context.Context, sb *ethpb.SignedBlindedBeaconBlockCapella) (*v1.ExecutionPayloadCapella, error) { + v := &SignedBlindedBeaconBlockCapella{SignedBlindedBeaconBlockCapella: sb} body, err := json.Marshal(v) if err != nil { - return nil, errors.Wrap(err, "error encoding the SignedBlindedBeaconBlockBellatrix value body in SubmitBlindedBlock") + return nil, errors.Wrap(err, "error encoding the SignedBlindedBeaconBlockCapella value body in SubmitBlindedBlockCapella") } ctx, cancel := context.WithTimeout(ctx, submitBlindedBlockTimeout) @@ -262,9 +357,9 @@ func (c *Client) SubmitBlindedBlock(ctx context.Context, sb *ethpb.SignedBlinded if err != nil { return nil, errors.Wrap(err, "error posting the SignedBlindedBeaconBlockBellatrix to the builder api") } - ep := &ExecPayloadResponse{} + ep := &ExecPayloadResponseCapella{} if err := json.Unmarshal(rb, ep); err != nil { - return nil, errors.Wrap(err, "error unmarshaling the builder SubmitBlindedBlock response") + return nil, errors.Wrap(err, "error unmarshaling the builder SubmitBlindedBlockCapella response") } return ep.ToProto() } diff --git a/api/client/builder/client_test.go b/api/client/builder/client_test.go index ce5121f31d28..2329d04f03d5 100644 --- a/api/client/builder/client_test.go +++ b/api/client/builder/client_test.go @@ -13,10 +13,12 @@ import ( "github.com/prysmaticlabs/go-bitfield" "github.com/prysmaticlabs/prysm/v3/config/params" + "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v3/testing/assert" "github.com/prysmaticlabs/prysm/v3/testing/require" ) @@ -119,99 +121,192 @@ func TestClient_RegisterValidator(t *testing.T) { func TestClient_GetHeader(t *testing.T) { ctx := context.Background() expectedPath := "/eth/v1/builder/header/23/0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2/0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a" - hc := &http.Client{ - Transport: roundtrip(func(r *http.Request) (*http.Response, error) { - require.Equal(t, expectedPath, r.URL.Path) - message := ErrorMessage{ - Code: 500, - Message: "Internal server error", - } - resp, err := json.Marshal(message) - require.NoError(t, err) - return &http.Response{ - StatusCode: http.StatusInternalServerError, - Body: io.NopCloser(bytes.NewBuffer(resp)), - Request: r.Clone(ctx), - }, nil - }), - } - c := &Client{ - hc: hc, - baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, - } var slot types.Slot = 23 parentHash := ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") pubkey := ezDecode(t, "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a") - _, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) - require.ErrorIs(t, err, ErrNotOK) - hc = &http.Client{ - Transport: roundtrip(func(r *http.Request) (*http.Response, error) { - require.Equal(t, expectedPath, r.URL.Path) - return &http.Response{ - StatusCode: http.StatusNoContent, - Body: io.NopCloser(bytes.NewBuffer([]byte("No header is available."))), - Request: r.Clone(ctx), - }, nil - }), - } - c = &Client{ - hc: hc, - baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, - } - _, err = c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) - require.ErrorIs(t, err, ErrNoContent) + t.Run("server error", func(t *testing.T) { + hc := &http.Client{ + Transport: roundtrip(func(r *http.Request) (*http.Response, error) { + require.Equal(t, expectedPath, r.URL.Path) + message := ErrorMessage{ + Code: 500, + Message: "Internal server error", + } + resp, err := json.Marshal(message) + require.NoError(t, err) + return &http.Response{ + StatusCode: http.StatusInternalServerError, + Body: io.NopCloser(bytes.NewBuffer(resp)), + Request: r.Clone(ctx), + }, nil + }), + } + c := &Client{ + hc: hc, + baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, + } - hc = &http.Client{ - Transport: roundtrip(func(r *http.Request) (*http.Response, error) { - require.Equal(t, expectedPath, r.URL.Path) - return &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewBufferString(testExampleHeaderResponse)), - Request: r.Clone(ctx), - }, nil - }), - } - c = &Client{ - hc: hc, - baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, - } - h, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) - require.NoError(t, err) - expectedSig := ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505") - require.Equal(t, true, bytes.Equal(expectedSig, h.Signature)) - expectedTxRoot := ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") - require.Equal(t, true, bytes.Equal(expectedTxRoot, h.Message.Header.TransactionsRoot)) - require.Equal(t, uint64(1), h.Message.Header.GasUsed) - value, err := stringToUint256("652312848583266388373324160190187140051835877600158453279131187530910662656") - require.NoError(t, err) - require.Equal(t, fmt.Sprintf("%#x", value.SSZBytes()), fmt.Sprintf("%#x", h.Message.Value)) + _, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) + require.ErrorIs(t, err, ErrNotOK) + }) + t.Run("header not available", func(t *testing.T) { + hc := &http.Client{ + Transport: roundtrip(func(r *http.Request) (*http.Response, error) { + require.Equal(t, expectedPath, r.URL.Path) + return &http.Response{ + StatusCode: http.StatusNoContent, + Body: io.NopCloser(bytes.NewBuffer([]byte("No header is available."))), + Request: r.Clone(ctx), + }, nil + }), + } + c := &Client{ + hc: hc, + baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, + } + _, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) + require.ErrorIs(t, err, ErrNoContent) + }) + t.Run("bellatrix", func(t *testing.T) { + hc := &http.Client{ + Transport: roundtrip(func(r *http.Request) (*http.Response, error) { + require.Equal(t, expectedPath, r.URL.Path) + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewBufferString(testExampleHeaderResponse)), + Request: r.Clone(ctx), + }, nil + }), + } + c := &Client{ + hc: hc, + baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, + } + h, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) + require.NoError(t, err) + expectedSig := ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505") + require.Equal(t, true, bytes.Equal(expectedSig, h.Signature())) + expectedTxRoot := ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + bid, err := h.Message() + require.NoError(t, err) + bidHeader, err := bid.Header() + require.NoError(t, err) + withdrawalsRoot, err := bidHeader.TransactionsRoot() + require.NoError(t, err) + require.Equal(t, true, bytes.Equal(expectedTxRoot, withdrawalsRoot)) + require.Equal(t, uint64(1), bidHeader.GasUsed()) + value, err := stringToUint256("652312848583266388373324160190187140051835877600158453279131187530910662656") + require.NoError(t, err) + require.Equal(t, fmt.Sprintf("%#x", value.SSZBytes()), fmt.Sprintf("%#x", bid.Value())) + }) + t.Run("capella", func(t *testing.T) { + hc := &http.Client{ + Transport: roundtrip(func(r *http.Request) (*http.Response, error) { + require.Equal(t, expectedPath, r.URL.Path) + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewBufferString(testExampleHeaderResponseCapella)), + Request: r.Clone(ctx), + }, nil + }), + } + c := &Client{ + hc: hc, + baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, + } + h, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) + require.NoError(t, err) + expectedWithdrawalsRoot := ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + bid, err := h.Message() + require.NoError(t, err) + bidHeader, err := bid.Header() + require.NoError(t, err) + withdrawalsRoot, err := bidHeader.WithdrawalsRoot() + require.NoError(t, err) + require.Equal(t, true, bytes.Equal(expectedWithdrawalsRoot, withdrawalsRoot)) + }) + t.Run("unsupported version", func(t *testing.T) { + hc := &http.Client{ + Transport: roundtrip(func(r *http.Request) (*http.Response, error) { + require.Equal(t, expectedPath, r.URL.Path) + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewBufferString(testExampleHeaderResponseUnknownVersion)), + Request: r.Clone(ctx), + }, nil + }), + } + c := &Client{ + hc: hc, + baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, + } + _, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey)) + require.ErrorContains(t, "unsupported header version", err) + }) } func TestSubmitBlindedBlock(t *testing.T) { ctx := context.Background() - hc := &http.Client{ - Transport: roundtrip(func(r *http.Request) (*http.Response, error) { - require.Equal(t, postBlindedBeaconBlockPath, r.URL.Path) - return &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewBufferString(testExampleExecutionPayload)), - Request: r.Clone(ctx), - }, nil - }), - } - c := &Client{ - hc: hc, - baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, - } - sbbb := testSignedBlindedBeaconBlockBellatrix(t) - ep, err := c.SubmitBlindedBlock(ctx, sbbb) - require.NoError(t, err) - require.Equal(t, true, bytes.Equal(ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), ep.ParentHash)) - bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656") - require.NoError(t, err) - require.Equal(t, fmt.Sprintf("%#x", bfpg.SSZBytes()), fmt.Sprintf("%#x", ep.BaseFeePerGas)) - require.Equal(t, uint64(1), ep.GasLimit) + + t.Run("bellatrix", func(t *testing.T) { + hc := &http.Client{ + Transport: roundtrip(func(r *http.Request) (*http.Response, error) { + require.Equal(t, postBlindedBeaconBlockPath, r.URL.Path) + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewBufferString(testExampleExecutionPayload)), + Request: r.Clone(ctx), + }, nil + }), + } + c := &Client{ + hc: hc, + baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, + } + sbbb, err := blocks.NewSignedBeaconBlock(testSignedBlindedBeaconBlockBellatrix(t)) + require.NoError(t, err) + ep, err := c.SubmitBlindedBlock(ctx, sbbb) + require.NoError(t, err) + require.Equal(t, true, bytes.Equal(ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), ep.ParentHash())) + bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656") + require.NoError(t, err) + require.Equal(t, fmt.Sprintf("%#x", bfpg.SSZBytes()), fmt.Sprintf("%#x", ep.BaseFeePerGas())) + require.Equal(t, uint64(1), ep.GasLimit()) + }) + t.Run("capella", func(t *testing.T) { + hc := &http.Client{ + Transport: roundtrip(func(r *http.Request) (*http.Response, error) { + require.Equal(t, postBlindedBeaconBlockPath, r.URL.Path) + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewBufferString(testExampleExecutionPayloadCapella)), + Request: r.Clone(ctx), + }, nil + }), + } + c := &Client{ + hc: hc, + baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"}, + } + sbb, err := blocks.NewSignedBeaconBlock(testSignedBlindedBeaconBlockCapella(t)) + require.NoError(t, err) + ep, err := c.SubmitBlindedBlock(ctx, sbb) + require.NoError(t, err) + withdrawals, err := ep.Withdrawals() + require.NoError(t, err) + require.Equal(t, 1, len(withdrawals)) + assert.Equal(t, uint64(1), withdrawals[0].Index) + assert.Equal(t, types.ValidatorIndex(1), withdrawals[0].ValidatorIndex) + assert.DeepEqual(t, ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943"), withdrawals[0].Address) + assert.Equal(t, uint64(1), withdrawals[0].Amount) + }) + t.Run("not blinded", func(t *testing.T) { + sbb, err := blocks.NewSignedBeaconBlock(ð.SignedBeaconBlockBellatrix{Block: ð.BeaconBlockBellatrix{Body: ð.BeaconBlockBodyBellatrix{}}}) + require.NoError(t, err) + _, err = (&Client{}).SubmitBlindedBlock(ctx, sbb) + require.ErrorIs(t, err, errNotBlinded) + }) } func testSignedBlindedBeaconBlockBellatrix(t *testing.T) *eth.SignedBlindedBeaconBlockBellatrix { @@ -356,6 +451,149 @@ func testSignedBlindedBeaconBlockBellatrix(t *testing.T) *eth.SignedBlindedBeaco } } +func testSignedBlindedBeaconBlockCapella(t *testing.T) *eth.SignedBlindedBeaconBlockCapella { + return ð.SignedBlindedBeaconBlockCapella{ + Block: ð.BlindedBeaconBlockCapella{ + Slot: 1, + ProposerIndex: 1, + ParentRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + StateRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + Body: ð.BlindedBeaconBlockBodyCapella{ + RandaoReveal: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + Eth1Data: ð.Eth1Data{ + DepositRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + DepositCount: 1, + BlockHash: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + Graffiti: ezDecode(t, "0xdeadbeefc0ffee"), + ProposerSlashings: []*eth.ProposerSlashing{ + { + Header_1: ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: 1, + ProposerIndex: 1, + ParentRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + StateRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + BodyRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + }, + Header_2: ð.SignedBeaconBlockHeader{ + Header: ð.BeaconBlockHeader{ + Slot: 1, + ProposerIndex: 1, + ParentRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + StateRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + BodyRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + }, + }, + }, + AttesterSlashings: []*eth.AttesterSlashing{ + { + Attestation_1: ð.IndexedAttestation{ + AttestingIndices: []uint64{1}, + Data: ð.AttestationData{ + Slot: 1, + CommitteeIndex: 1, + BeaconBlockRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + Source: ð.Checkpoint{ + Epoch: 1, + Root: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + Target: ð.Checkpoint{ + Epoch: 1, + Root: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + }, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + }, + Attestation_2: ð.IndexedAttestation{ + AttestingIndices: []uint64{1}, + Data: ð.AttestationData{ + Slot: 1, + CommitteeIndex: 1, + BeaconBlockRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + Source: ð.Checkpoint{ + Epoch: 1, + Root: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + Target: ð.Checkpoint{ + Epoch: 1, + Root: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + }, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + }, + }, + }, + Attestations: []*eth.Attestation{ + { + AggregationBits: bitfield.Bitlist{0x01}, + Data: ð.AttestationData{ + Slot: 1, + CommitteeIndex: 1, + BeaconBlockRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + Source: ð.Checkpoint{ + Epoch: 1, + Root: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + Target: ð.Checkpoint{ + Epoch: 1, + Root: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + }, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + }, + }, + Deposits: []*eth.Deposit{ + { + Proof: [][]byte{ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2")}, + Data: ð.Deposit_Data{ + PublicKey: ezDecode(t, "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"), + WithdrawalCredentials: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + Amount: 1, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + }, + }, + }, + VoluntaryExits: []*eth.SignedVoluntaryExit{ + { + Exit: ð.VoluntaryExit{ + Epoch: 1, + ValidatorIndex: 1, + }, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + }, + }, + SyncAggregate: ð.SyncAggregate{ + SyncCommitteeSignature: make([]byte, 48), + SyncCommitteeBits: bitfield.Bitvector512{0x01}, + }, + ExecutionPayloadHeader: &v1.ExecutionPayloadHeaderCapella{ + ParentHash: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + FeeRecipient: ezDecode(t, "0xabcf8e0d4e9587369b2301d0790347320302cc09"), + StateRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + ReceiptsRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + LogsBloom: ezDecode(t, "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + PrevRandao: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + BlockNumber: 1, + GasLimit: 1, + GasUsed: 1, + Timestamp: 1, + ExtraData: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + BaseFeePerGas: []byte(strconv.FormatUint(1, 10)), + BlockHash: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + TransactionsRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + WithdrawalsRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + }, + }, + }, + Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + } +} + func TestRequestLogger(t *testing.T) { wo := WithObserver(&requestLogger{}) c, err := NewClient("localhost:3500", wo) diff --git a/api/client/builder/testdata/blinded-block-capella.json b/api/client/builder/testdata/blinded-block-capella.json new file mode 100644 index 000000000000..ff89dc3e8ab3 --- /dev/null +++ b/api/client/builder/testdata/blinded-block-capella.json @@ -0,0 +1 @@ +{"slot":"1","proposer_index":"1","parent_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","state_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","body":{"randao_reveal":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505","eth1_data":{"deposit_root":"0x0000000000000000000000000000000000000000000000000000000000000000","deposit_count":"23","block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000"},"graffiti":"0xdeadbeefc0ffee","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"],"data":{"slot":"1","index":"1","beacon_block_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","source":{"epoch":"1","root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"},"target":{"epoch":"1","root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}},"signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"},"attestation_2":{"attesting_indices":["1"],"data":{"slot":"1","index":"1","beacon_block_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","source":{"epoch":"1","root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"},"target":{"epoch":"1","root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}},"signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"}}],"attestations":[{"aggregation_bits":"0x01","data":{"slot":"1","index":"1","beacon_block_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","source":{"epoch":"1","root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"},"target":{"epoch":"1","root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}},"signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"}],"deposits":[{"proof":["0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"],"data":{"pubkey":"0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a","withdrawal_credentials":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","amount":"1","signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"}}],"voluntary_exits":[{"message":{"epoch":"1","validator_index":"1"},"signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"}],"bls_to_execution_changes":[],"sync_aggregate":{"sync_committee_bits":"0x01","sync_committee_signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"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":"452312848583266388373324160190187140051835877600158453279131187530910662656","block_hash":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","transactions_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","withdrawals_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}}} diff --git a/api/client/builder/testdata/execution-payload-capella.json b/api/client/builder/testdata/execution-payload-capella.json new file mode 100644 index 000000000000..f7c9e83b837a --- /dev/null +++ b/api/client/builder/testdata/execution-payload-capella.json @@ -0,0 +1 @@ +{"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":"14074904626401341155369551180448584754667373453244490859944217516317499064576","block_hash":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","transactions_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","withdrawals_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"} diff --git a/api/client/builder/testing/BUILD.bazel b/api/client/builder/testing/BUILD.bazel index c62defced101..9a3f015b528f 100644 --- a/api/client/builder/testing/BUILD.bazel +++ b/api/client/builder/testing/BUILD.bazel @@ -6,9 +6,10 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/api/client/builder/testing", visibility = ["//visibility:public"], deps = [ + "//api/client/builder:go_default_library", + "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", - "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", ], ) diff --git a/api/client/builder/testing/mock.go b/api/client/builder/testing/mock.go index 19bc0c36e4a4..ea96f9bf86c4 100644 --- a/api/client/builder/testing/mock.go +++ b/api/client/builder/testing/mock.go @@ -3,9 +3,10 @@ package testing import ( "context" + "github.com/prysmaticlabs/prysm/v3/api/client/builder" + "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" - v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" ) @@ -25,7 +26,7 @@ func (MockClient) NodeURL() string { } // GetHeader -- -func (MockClient) GetHeader(_ context.Context, _ types.Slot, _ [32]byte, _ [48]byte) (*ethpb.SignedBuilderBid, error) { +func (MockClient) GetHeader(_ context.Context, _ types.Slot, _ [32]byte, _ [48]byte) (builder.SignedBid, error) { return nil, nil } @@ -39,7 +40,7 @@ func (m MockClient) RegisterValidator(_ context.Context, svr []*ethpb.SignedVali } // SubmitBlindedBlock -- -func (MockClient) SubmitBlindedBlock(_ context.Context, _ *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) { +func (MockClient) SubmitBlindedBlock(_ context.Context, _ interfaces.SignedBeaconBlock) (interfaces.ExecutionData, error) { return nil, nil } diff --git a/api/client/builder/types.go b/api/client/builder/types.go index bb6c94f61cc8..a4f27673298d 100644 --- a/api/client/builder/types.go +++ b/api/client/builder/types.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" + types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" @@ -181,6 +182,10 @@ func (s Uint64String) MarshalText() ([]byte, error) { return []byte(fmt.Sprintf("%d", s)), nil } +type VersionResponse struct { + Version string `json:"version"` +} + type ExecHeaderResponse struct { Version string `json:"version"` Data struct { @@ -341,6 +346,186 @@ func (p *ExecutionPayload) ToProto() (*v1.ExecutionPayload, error) { }, nil } +type ExecHeaderResponseCapella struct { + Data struct { + Signature hexutil.Bytes `json:"signature"` + Message *BuilderBidCapella `json:"message"` + } `json:"data"` +} + +func (ehr *ExecHeaderResponseCapella) ToProto() (*eth.SignedBuilderBidCapella, error) { + bb, err := ehr.Data.Message.ToProto() + if err != nil { + return nil, err + } + return ð.SignedBuilderBidCapella{ + Message: bb, + Signature: ehr.Data.Signature, + }, nil +} + +func (bb *BuilderBidCapella) ToProto() (*eth.BuilderBidCapella, error) { + header, err := bb.Header.ToProto() + if err != nil { + return nil, err + } + return ð.BuilderBidCapella{ + Header: header, + Value: bb.Value.SSZBytes(), + Pubkey: bb.Pubkey, + }, nil +} + +func (h *ExecutionPayloadHeaderCapella) ToProto() (*v1.ExecutionPayloadHeaderCapella, error) { + return &v1.ExecutionPayloadHeaderCapella{ + ParentHash: h.ParentHash, + FeeRecipient: h.FeeRecipient, + StateRoot: h.StateRoot, + ReceiptsRoot: h.ReceiptsRoot, + LogsBloom: h.LogsBloom, + PrevRandao: h.PrevRandao, + BlockNumber: uint64(h.BlockNumber), + GasLimit: uint64(h.GasLimit), + GasUsed: uint64(h.GasUsed), + Timestamp: uint64(h.Timestamp), + ExtraData: h.ExtraData, + BaseFeePerGas: h.BaseFeePerGas.SSZBytes(), + BlockHash: h.BlockHash, + TransactionsRoot: h.TransactionsRoot, + WithdrawalsRoot: h.WithdrawalsRoot, + }, nil +} + +type BuilderBidCapella struct { + Header *ExecutionPayloadHeaderCapella `json:"header"` + Value Uint256 `json:"value"` + Pubkey hexutil.Bytes `json:"pubkey"` +} + +type ExecutionPayloadHeaderCapella struct { + ParentHash hexutil.Bytes `json:"parent_hash"` + FeeRecipient hexutil.Bytes `json:"fee_recipient"` + StateRoot hexutil.Bytes `json:"state_root"` + ReceiptsRoot hexutil.Bytes `json:"receipts_root"` + LogsBloom hexutil.Bytes `json:"logs_bloom"` + PrevRandao hexutil.Bytes `json:"prev_randao"` + BlockNumber Uint64String `json:"block_number"` + GasLimit Uint64String `json:"gas_limit"` + GasUsed Uint64String `json:"gas_used"` + Timestamp Uint64String `json:"timestamp"` + ExtraData hexutil.Bytes `json:"extra_data"` + BaseFeePerGas Uint256 `json:"base_fee_per_gas"` + BlockHash hexutil.Bytes `json:"block_hash"` + TransactionsRoot hexutil.Bytes `json:"transactions_root"` + WithdrawalsRoot hexutil.Bytes `json:"withdrawals_root"` + *v1.ExecutionPayloadHeaderCapella +} + +func (h *ExecutionPayloadHeaderCapella) MarshalJSON() ([]byte, error) { + type MarshalCaller ExecutionPayloadHeaderCapella + baseFeePerGas, err := sszBytesToUint256(h.ExecutionPayloadHeaderCapella.BaseFeePerGas) + if err != nil { + return []byte{}, errors.Wrapf(err, "invalid BaseFeePerGas") + } + return json.Marshal(&MarshalCaller{ + ParentHash: h.ExecutionPayloadHeaderCapella.ParentHash, + FeeRecipient: h.ExecutionPayloadHeaderCapella.FeeRecipient, + StateRoot: h.ExecutionPayloadHeaderCapella.StateRoot, + ReceiptsRoot: h.ExecutionPayloadHeaderCapella.ReceiptsRoot, + LogsBloom: h.ExecutionPayloadHeaderCapella.LogsBloom, + PrevRandao: h.ExecutionPayloadHeaderCapella.PrevRandao, + BlockNumber: Uint64String(h.ExecutionPayloadHeaderCapella.BlockNumber), + GasLimit: Uint64String(h.ExecutionPayloadHeaderCapella.GasLimit), + GasUsed: Uint64String(h.ExecutionPayloadHeaderCapella.GasUsed), + Timestamp: Uint64String(h.ExecutionPayloadHeaderCapella.Timestamp), + ExtraData: h.ExecutionPayloadHeaderCapella.ExtraData, + BaseFeePerGas: baseFeePerGas, + BlockHash: h.ExecutionPayloadHeaderCapella.BlockHash, + TransactionsRoot: h.ExecutionPayloadHeaderCapella.TransactionsRoot, + WithdrawalsRoot: h.ExecutionPayloadHeaderCapella.WithdrawalsRoot, + }) +} + +func (h *ExecutionPayloadHeaderCapella) UnmarshalJSON(b []byte) error { + type UnmarshalCaller ExecutionPayloadHeaderCapella + uc := &UnmarshalCaller{} + if err := json.Unmarshal(b, uc); err != nil { + return err + } + ep := ExecutionPayloadHeaderCapella(*uc) + *h = ep + var err error + h.ExecutionPayloadHeaderCapella, err = h.ToProto() + return err +} + +type ExecPayloadResponseCapella struct { + Version string `json:"version"` + Data ExecutionPayloadCapella `json:"data"` +} + +type ExecutionPayloadCapella struct { + ParentHash hexutil.Bytes `json:"parent_hash"` + FeeRecipient hexutil.Bytes `json:"fee_recipient"` + StateRoot hexutil.Bytes `json:"state_root"` + ReceiptsRoot hexutil.Bytes `json:"receipts_root"` + LogsBloom hexutil.Bytes `json:"logs_bloom"` + PrevRandao hexutil.Bytes `json:"prev_randao"` + BlockNumber Uint64String `json:"block_number"` + GasLimit Uint64String `json:"gas_limit"` + GasUsed Uint64String `json:"gas_used"` + Timestamp Uint64String `json:"timestamp"` + ExtraData hexutil.Bytes `json:"extra_data"` + BaseFeePerGas Uint256 `json:"base_fee_per_gas"` + BlockHash hexutil.Bytes `json:"block_hash"` + Transactions []hexutil.Bytes `json:"transactions"` + Withdrawals []Withdrawal `json:"withdrawals"` +} + +func (r *ExecPayloadResponseCapella) ToProto() (*v1.ExecutionPayloadCapella, error) { + return r.Data.ToProto() +} + +func (p *ExecutionPayloadCapella) ToProto() (*v1.ExecutionPayloadCapella, error) { + txs := make([][]byte, len(p.Transactions)) + for i := range p.Transactions { + txs[i] = p.Transactions[i] + } + withdrawals := make([]*v1.Withdrawal, len(p.Withdrawals)) + for i, w := range p.Withdrawals { + withdrawals[i] = &v1.Withdrawal{ + Index: w.Index.Uint64(), + ValidatorIndex: types.ValidatorIndex(w.ValidatorIndex.Uint64()), + Address: w.Address, + Amount: w.Amount.Uint64(), + } + } + return &v1.ExecutionPayloadCapella{ + ParentHash: p.ParentHash, + FeeRecipient: p.FeeRecipient, + StateRoot: p.StateRoot, + ReceiptsRoot: p.ReceiptsRoot, + LogsBloom: p.LogsBloom, + PrevRandao: p.PrevRandao, + BlockNumber: uint64(p.BlockNumber), + GasLimit: uint64(p.GasLimit), + GasUsed: uint64(p.GasUsed), + Timestamp: uint64(p.Timestamp), + ExtraData: p.ExtraData, + BaseFeePerGas: p.BaseFeePerGas.SSZBytes(), + BlockHash: p.BlockHash, + Transactions: txs, + Withdrawals: withdrawals, + }, nil +} + +type Withdrawal struct { + Index Uint256 `json:"index"` + ValidatorIndex Uint256 `json:"validator_index"` + Address hexutil.Bytes `json:"address"` + Amount Uint256 `json:"amount"` +} + type SignedBlindedBeaconBlockBellatrix struct { *eth.SignedBlindedBeaconBlockBellatrix } @@ -651,6 +836,126 @@ func (b *BlindedBeaconBlockBodyBellatrix) MarshalJSON() ([]byte, error) { }) } +type SignedBLSToExecutionChange struct { + *eth.SignedBLSToExecutionChange +} + +func (ch *SignedBLSToExecutionChange) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Message *BLSToExecutionChange `json:"message"` + Signature hexutil.Bytes `json:"signature"` + }{ + Signature: ch.Signature, + Message: &BLSToExecutionChange{ch.Message}, + }) +} + +type BLSToExecutionChange struct { + *eth.BLSToExecutionChange +} + +func (ch *BLSToExecutionChange) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + ValidatorIndex string `json:"validator_index"` + FromBlsPubkey hexutil.Bytes `json:"from_bls_pubkey"` + ToExecutionAddress hexutil.Bytes `json:"to_execution_address"` + }{ + ValidatorIndex: fmt.Sprintf("%d", ch.ValidatorIndex), + FromBlsPubkey: ch.FromBlsPubkey, + ToExecutionAddress: ch.ToExecutionAddress, + }) +} + +type SignedBlindedBeaconBlockCapella struct { + *eth.SignedBlindedBeaconBlockCapella +} + +type BlindedBeaconBlockCapella struct { + *eth.BlindedBeaconBlockCapella +} + +type BlindedBeaconBlockBodyCapella struct { + *eth.BlindedBeaconBlockBodyCapella +} + +func (b *SignedBlindedBeaconBlockCapella) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Message *BlindedBeaconBlockCapella `json:"message"` + Signature hexutil.Bytes `json:"signature"` + }{ + Message: &BlindedBeaconBlockCapella{b.Block}, + Signature: b.Signature, + }) +} + +func (b *BlindedBeaconBlockCapella) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Slot string `json:"slot"` + ProposerIndex string `json:"proposer_index"` + ParentRoot hexutil.Bytes `json:"parent_root"` + StateRoot hexutil.Bytes `json:"state_root"` + Body *BlindedBeaconBlockBodyCapella `json:"body"` + }{ + Slot: fmt.Sprintf("%d", b.Slot), + ProposerIndex: fmt.Sprintf("%d", b.ProposerIndex), + ParentRoot: b.ParentRoot, + StateRoot: b.StateRoot, + Body: &BlindedBeaconBlockBodyCapella{b.Body}, + }) +} + +func (b *BlindedBeaconBlockBodyCapella) MarshalJSON() ([]byte, error) { + sve := make([]*SignedVoluntaryExit, len(b.VoluntaryExits)) + for i := range b.VoluntaryExits { + sve[i] = &SignedVoluntaryExit{SignedVoluntaryExit: b.VoluntaryExits[i]} + } + deps := make([]*Deposit, len(b.Deposits)) + for i := range b.Deposits { + deps[i] = &Deposit{Deposit: b.Deposits[i]} + } + atts := make([]*Attestation, len(b.Attestations)) + for i := range b.Attestations { + atts[i] = &Attestation{Attestation: b.Attestations[i]} + } + atsl := make([]*AttesterSlashing, len(b.AttesterSlashings)) + for i := range b.AttesterSlashings { + atsl[i] = &AttesterSlashing{AttesterSlashing: b.AttesterSlashings[i]} + } + pros := make([]*ProposerSlashing, len(b.ProposerSlashings)) + for i := range b.ProposerSlashings { + pros[i] = &ProposerSlashing{ProposerSlashing: b.ProposerSlashings[i]} + } + chs := make([]*SignedBLSToExecutionChange, len(b.BlsToExecutionChanges)) + for i := range b.BlsToExecutionChanges { + chs[i] = &SignedBLSToExecutionChange{SignedBLSToExecutionChange: b.BlsToExecutionChanges[i]} + } + return json.Marshal(struct { + RandaoReveal hexutil.Bytes `json:"randao_reveal"` + Eth1Data *Eth1Data `json:"eth1_data"` + Graffiti hexutil.Bytes `json:"graffiti"` + ProposerSlashings []*ProposerSlashing `json:"proposer_slashings"` + AttesterSlashings []*AttesterSlashing `json:"attester_slashings"` + Attestations []*Attestation `json:"attestations"` + Deposits []*Deposit `json:"deposits"` + VoluntaryExits []*SignedVoluntaryExit `json:"voluntary_exits"` + BLSToExecutionChanges []*SignedBLSToExecutionChange `json:"bls_to_execution_changes"` + SyncAggregate *SyncAggregate `json:"sync_aggregate"` + ExecutionPayloadHeader *ExecutionPayloadHeaderCapella `json:"execution_payload_header"` + }{ + RandaoReveal: b.RandaoReveal, + Eth1Data: &Eth1Data{b.Eth1Data}, + Graffiti: b.Graffiti, + ProposerSlashings: pros, + AttesterSlashings: atsl, + Attestations: atts, + Deposits: deps, + VoluntaryExits: sve, + BLSToExecutionChanges: chs, + SyncAggregate: &SyncAggregate{b.SyncAggregate}, + ExecutionPayloadHeader: &ExecutionPayloadHeaderCapella{ExecutionPayloadHeaderCapella: b.ExecutionPayloadHeader}, + }) +} + type ErrorMessage struct { Code int `json:"code"` Message string `json:"message"` diff --git a/api/client/builder/types_test.go b/api/client/builder/types_test.go index 6f6b080bfe7b..3d62ce87da1d 100644 --- a/api/client/builder/types_test.go +++ b/api/client/builder/types_test.go @@ -16,6 +16,7 @@ import ( "github.com/prysmaticlabs/go-bitfield" v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v3/testing/assert" "github.com/prysmaticlabs/prysm/v3/testing/require" ) @@ -87,6 +88,62 @@ var testExampleHeaderResponse = `{ } }` +var testExampleHeaderResponseCapella = `{ + "version": "capella", + "data": { + "message": { + "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": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "withdrawals_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "value": "652312848583266388373324160190187140051835877600158453279131187530910662656", + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } +}` + +var testExampleHeaderResponseUnknownVersion = `{ + "version": "bad", + "data": { + "message": { + "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": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "withdrawals_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2" + }, + "value": "652312848583266388373324160190187140051835877600158453279131187530910662656", + "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a" + }, + "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" + } +}` + func TestExecutionHeaderResponseUnmarshal(t *testing.T) { hr := &ExecHeaderResponse{} require.NoError(t, json.Unmarshal([]byte(testExampleHeaderResponse), hr)) @@ -186,6 +243,110 @@ func TestExecutionHeaderResponseUnmarshal(t *testing.T) { } } +func TestExecutionHeaderResponseCapellaUnmarshal(t *testing.T) { + hr := &ExecHeaderResponseCapella{} + require.NoError(t, json.Unmarshal([]byte(testExampleHeaderResponseCapella), hr)) + cases := []struct { + expected string + actual string + name string + }{ + { + expected: "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + actual: hexutil.Encode(hr.Data.Signature), + name: "Signature", + }, + { + expected: "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a", + actual: hexutil.Encode(hr.Data.Message.Pubkey), + name: "ExecHeaderResponse.Pubkey", + }, + { + expected: "652312848583266388373324160190187140051835877600158453279131187530910662656", + actual: hr.Data.Message.Value.String(), + name: "ExecHeaderResponse.Value", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.ParentHash), + name: "ExecHeaderResponse.ExecutionPayloadHeader.ParentHash", + }, + { + expected: "0xabcf8e0d4e9587369b2301d0790347320302cc09", + actual: hexutil.Encode(hr.Data.Message.Header.FeeRecipient), + name: "ExecHeaderResponse.ExecutionPayloadHeader.FeeRecipient", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.StateRoot), + name: "ExecHeaderResponse.ExecutionPayloadHeader.StateRoot", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.ReceiptsRoot), + name: "ExecHeaderResponse.ExecutionPayloadHeader.ReceiptsRoot", + }, + { + expected: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + actual: hexutil.Encode(hr.Data.Message.Header.LogsBloom), + name: "ExecHeaderResponse.ExecutionPayloadHeader.LogsBloom", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.PrevRandao), + name: "ExecHeaderResponse.ExecutionPayloadHeader.PrevRandao", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", hr.Data.Message.Header.BlockNumber), + name: "ExecHeaderResponse.ExecutionPayloadHeader.BlockNumber", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", hr.Data.Message.Header.GasLimit), + name: "ExecHeaderResponse.ExecutionPayloadHeader.GasLimit", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", hr.Data.Message.Header.GasUsed), + name: "ExecHeaderResponse.ExecutionPayloadHeader.GasUsed", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", hr.Data.Message.Header.Timestamp), + name: "ExecHeaderResponse.ExecutionPayloadHeader.Timestamp", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.ExtraData), + name: "ExecHeaderResponse.ExecutionPayloadHeader.ExtraData", + }, + { + expected: "452312848583266388373324160190187140051835877600158453279131187530910662656", + actual: fmt.Sprintf("%d", hr.Data.Message.Header.BaseFeePerGas), + name: "ExecHeaderResponse.ExecutionPayloadHeader.BaseFeePerGas", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.BlockHash), + name: "ExecHeaderResponse.ExecutionPayloadHeader.BlockHash", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.TransactionsRoot), + name: "ExecHeaderResponse.ExecutionPayloadHeader.TransactionsRoot", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(hr.Data.Message.Header.WithdrawalsRoot), + name: "ExecHeaderResponse.ExecutionPayloadHeader.WithdrawalsRoot", + }, + } + for _, c := range cases { + require.Equal(t, c.expected, c.actual, fmt.Sprintf("unexpected value for field %s", c.name)) + } +} + func TestExecutionHeaderResponseToProto(t *testing.T) { bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656") require.NoError(t, err) @@ -244,6 +405,67 @@ func TestExecutionHeaderResponseToProto(t *testing.T) { require.DeepEqual(t, expected, p) } +func TestExecutionHeaderResponseCapellaToProto(t *testing.T) { + bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656") + require.NoError(t, err) + v, err := stringToUint256("652312848583266388373324160190187140051835877600158453279131187530910662656") + require.NoError(t, err) + hr := &ExecHeaderResponseCapella{} + require.NoError(t, json.Unmarshal([]byte(testExampleHeaderResponseCapella), hr)) + p, err := hr.ToProto() + require.NoError(t, err) + signature, err := hexutil.Decode("0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505") + require.NoError(t, err) + pubkey, err := hexutil.Decode("0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a") + require.NoError(t, err) + parentHash, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + feeRecipient, err := hexutil.Decode("0xabcf8e0d4e9587369b2301d0790347320302cc09") + require.NoError(t, err) + stateRoot, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + receiptsRoot, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + logsBloom, err := hexutil.Decode("0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + prevRandao, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + extraData, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + blockHash, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + txRoot, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + withdrawalsRoot, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + + expected := ð.SignedBuilderBidCapella{ + Message: ð.BuilderBidCapella{ + Header: &v1.ExecutionPayloadHeaderCapella{ + ParentHash: parentHash, + FeeRecipient: feeRecipient, + StateRoot: stateRoot, + ReceiptsRoot: receiptsRoot, + LogsBloom: logsBloom, + PrevRandao: prevRandao, + BlockNumber: 1, + GasLimit: 1, + GasUsed: 1, + Timestamp: 1, + ExtraData: extraData, + BaseFeePerGas: bfpg.SSZBytes(), + BlockHash: blockHash, + TransactionsRoot: txRoot, + WithdrawalsRoot: withdrawalsRoot, + }, + Value: v.SSZBytes(), + Pubkey: pubkey, + }, + Signature: signature, + } + require.DeepEqual(t, expected, p) +} + var testExampleExecutionPayload = `{ "version": "bellatrix", "data": { @@ -266,6 +488,36 @@ var testExampleExecutionPayload = `{ } }` +var testExampleExecutionPayloadCapella = `{ + "version": "capella", + "data": { + "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": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions": [ + "0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86" + ], + "withdrawals": [ + { + "index": "1", + "validator_index": "1", + "address": "0xcf8e0d4e9587369b2301d0790347320302cc0943", + "amount": "1" + } + ] + } +}` + func TestExecutionPayloadResponseUnmarshal(t *testing.T) { epr := &ExecPayloadResponse{} require.NoError(t, json.Unmarshal([]byte(testExampleExecutionPayload), epr)) @@ -348,6 +600,95 @@ func TestExecutionPayloadResponseUnmarshal(t *testing.T) { require.Equal(t, txHash, hexutil.Encode(epr.Data.Transactions[0])) } +func TestExecutionPayloadResponseCapellaUnmarshal(t *testing.T) { + epr := &ExecPayloadResponseCapella{} + require.NoError(t, json.Unmarshal([]byte(testExampleExecutionPayloadCapella), epr)) + cases := []struct { + expected string + actual string + name string + }{ + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(epr.Data.ParentHash), + name: "ExecPayloadResponse.ExecutionPayload.ParentHash", + }, + { + expected: "0xabcf8e0d4e9587369b2301d0790347320302cc09", + actual: hexutil.Encode(epr.Data.FeeRecipient), + name: "ExecPayloadResponse.ExecutionPayload.FeeRecipient", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(epr.Data.StateRoot), + name: "ExecPayloadResponse.ExecutionPayload.StateRoot", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(epr.Data.ReceiptsRoot), + name: "ExecPayloadResponse.ExecutionPayload.ReceiptsRoot", + }, + { + expected: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + actual: hexutil.Encode(epr.Data.LogsBloom), + name: "ExecPayloadResponse.ExecutionPayload.LogsBloom", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(epr.Data.PrevRandao), + name: "ExecPayloadResponse.ExecutionPayload.PrevRandao", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", epr.Data.BlockNumber), + name: "ExecPayloadResponse.ExecutionPayload.BlockNumber", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", epr.Data.GasLimit), + name: "ExecPayloadResponse.ExecutionPayload.GasLimit", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", epr.Data.GasUsed), + name: "ExecPayloadResponse.ExecutionPayload.GasUsed", + }, + { + expected: "1", + actual: fmt.Sprintf("%d", epr.Data.Timestamp), + name: "ExecPayloadResponse.ExecutionPayload.Timestamp", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(epr.Data.ExtraData), + name: "ExecPayloadResponse.ExecutionPayload.ExtraData", + }, + { + expected: "452312848583266388373324160190187140051835877600158453279131187530910662656", + actual: fmt.Sprintf("%d", epr.Data.BaseFeePerGas), + name: "ExecPayloadResponse.ExecutionPayload.BaseFeePerGas", + }, + { + expected: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + actual: hexutil.Encode(epr.Data.BlockHash), + name: "ExecPayloadResponse.ExecutionPayload.BlockHash", + }, + } + for _, c := range cases { + require.Equal(t, c.expected, c.actual, fmt.Sprintf("unexpected value for field %s", c.name)) + } + require.Equal(t, 1, len(epr.Data.Transactions)) + txHash := "0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86" + require.Equal(t, txHash, hexutil.Encode(epr.Data.Transactions[0])) + + require.Equal(t, 1, len(epr.Data.Withdrawals)) + w := epr.Data.Withdrawals[0] + assert.Equal(t, uint64(1), w.Index.Uint64()) + assert.Equal(t, uint64(1), w.ValidatorIndex.Uint64()) + assert.DeepEqual(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943", w.Address.String()) + assert.Equal(t, uint64(1), w.Amount.Uint64()) +} + func TestExecutionPayloadResponseToProto(t *testing.T) { hr := &ExecPayloadResponse{} require.NoError(t, json.Unmarshal([]byte(testExampleExecutionPayload), hr)) @@ -396,6 +737,65 @@ func TestExecutionPayloadResponseToProto(t *testing.T) { require.DeepEqual(t, expected, p) } +func TestExecutionPayloadResponseCapellaToProto(t *testing.T) { + hr := &ExecPayloadResponseCapella{} + require.NoError(t, json.Unmarshal([]byte(testExampleExecutionPayloadCapella), hr)) + p, err := hr.ToProto() + require.NoError(t, err) + + parentHash, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + feeRecipient, err := hexutil.Decode("0xabcf8e0d4e9587369b2301d0790347320302cc09") + require.NoError(t, err) + stateRoot, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + receiptsRoot, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + logsBloom, err := hexutil.Decode("0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + prevRandao, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + extraData, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + blockHash, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") + require.NoError(t, err) + + tx, err := hexutil.Decode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86") + require.NoError(t, err) + txList := [][]byte{tx} + address, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943") + require.NoError(t, err) + + bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656") + require.NoError(t, err) + expected := &v1.ExecutionPayloadCapella{ + ParentHash: parentHash, + FeeRecipient: feeRecipient, + StateRoot: stateRoot, + ReceiptsRoot: receiptsRoot, + LogsBloom: logsBloom, + PrevRandao: prevRandao, + BlockNumber: 1, + GasLimit: 1, + GasUsed: 1, + Timestamp: 1, + ExtraData: extraData, + BaseFeePerGas: bfpg.SSZBytes(), + BlockHash: blockHash, + Transactions: txList, + Withdrawals: []*v1.Withdrawal{ + { + Index: 1, + ValidatorIndex: 1, + Address: address, + Amount: 1, + }, + }, + } + require.DeepEqual(t, expected, p) + +} + func pbEth1Data() *eth.Eth1Data { return ð.Eth1Data{ DepositRoot: make([]byte, 32), @@ -604,6 +1004,28 @@ func pbExecutionPayloadHeader(t *testing.T) *v1.ExecutionPayloadHeader { } } +func pbExecutionPayloadHeaderCapella(t *testing.T) *v1.ExecutionPayloadHeaderCapella { + bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656") + require.NoError(t, err) + return &v1.ExecutionPayloadHeaderCapella{ + ParentHash: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + FeeRecipient: ezDecode(t, "0xabcf8e0d4e9587369b2301d0790347320302cc09"), + StateRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + ReceiptsRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + LogsBloom: ezDecode(t, "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + PrevRandao: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + BlockNumber: 1, + GasLimit: 1, + GasUsed: 1, + Timestamp: 1, + ExtraData: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + BaseFeePerGas: bfpg.SSZBytes(), + BlockHash: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + TransactionsRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + WithdrawalsRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + } +} + func TestExecutionPayloadHeader_MarshalJSON(t *testing.T) { h := &ExecutionPayloadHeader{ ExecutionPayloadHeader: pbExecutionPayloadHeader(t), @@ -614,6 +1036,16 @@ func TestExecutionPayloadHeader_MarshalJSON(t *testing.T) { require.Equal(t, expected, string(b)) } +func TestExecutionPayloadHeaderCapella_MarshalJSON(t *testing.T) { + h := &ExecutionPayloadHeaderCapella{ + ExecutionPayloadHeaderCapella: pbExecutionPayloadHeaderCapella(t), + } + b, err := json.Marshal(h) + require.NoError(t, err) + expected := `{"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":"452312848583266388373324160190187140051835877600158453279131187530910662656","block_hash":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","transactions_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2","withdrawals_root":"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}` + require.Equal(t, expected, string(b)) +} + var testBuilderBid = `{ "version":"bellatrix", "data":{ @@ -783,6 +1215,35 @@ func TestMarshalBlindedBeaconBlockBodyBellatrix(t *testing.T) { require.Equal(t, string(expected[0:len(expected)-1]), string(m)) } +func TestMarshalBlindedBeaconBlockBodyCapella(t *testing.T) { + expected, err := os.ReadFile("testdata/blinded-block-capella.json") + require.NoError(t, err) + b := &BlindedBeaconBlockCapella{BlindedBeaconBlockCapella: ð.BlindedBeaconBlockCapella{ + Slot: 1, + ProposerIndex: 1, + ParentRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + StateRoot: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + Body: ð.BlindedBeaconBlockBodyCapella{ + RandaoReveal: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"), + Eth1Data: pbEth1Data(), + Graffiti: ezDecode(t, "0xdeadbeefc0ffee"), + ProposerSlashings: []*eth.ProposerSlashing{pbProposerSlashing(t)}, + AttesterSlashings: []*eth.AttesterSlashing{pbAttesterSlashing(t)}, + Attestations: []*eth.Attestation{pbAttestation(t)}, + Deposits: []*eth.Deposit{pbDeposit(t)}, + VoluntaryExits: []*eth.SignedVoluntaryExit{pbSignedVoluntaryExit(t)}, + SyncAggregate: pbSyncAggregate(), + ExecutionPayloadHeader: pbExecutionPayloadHeaderCapella(t), + }, + }} + m, err := json.Marshal(b) + require.NoError(t, err) + // string error output is easier to deal with + // -1 end slice index on expected is to get rid of trailing newline + // if you update this fixture and this test breaks, you probably removed the trailing newline + require.Equal(t, string(expected[0:len(expected)-1]), string(m)) +} + func TestRoundTripUint256(t *testing.T) { vs := "4523128485832663883733241601901871400518358776001584532791311875309106626" u, err := stringToUint256(vs) @@ -818,6 +1279,16 @@ func TestExecutionPayloadHeaderRoundtrip(t *testing.T) { require.DeepEqual(t, string(expected[0:len(expected)-1]), string(m)) } +func TestExecutionPayloadHeaderCapellaRoundtrip(t *testing.T) { + expected, err := os.ReadFile("testdata/execution-payload-capella.json") + require.NoError(t, err) + hu := &ExecutionPayloadHeaderCapella{} + require.NoError(t, json.Unmarshal(expected, hu)) + m, err := json.Marshal(hu) + require.NoError(t, err) + require.DeepEqual(t, string(expected[0:len(expected)-1]), string(m)) +} + func TestErrorMessage_non200Err(t *testing.T) { mockRequest := &http.Request{ URL: &url.URL{Path: "example.com"}, @@ -904,5 +1375,4 @@ func TestErrorMessage_non200Err(t *testing.T) { } }) } - } diff --git a/beacon-chain/builder/BUILD.bazel b/beacon-chain/builder/BUILD.bazel index 3e5bc36777d6..241fe1e635d1 100644 --- a/beacon-chain/builder/BUILD.bazel +++ b/beacon-chain/builder/BUILD.bazel @@ -14,9 +14,9 @@ go_library( "//beacon-chain/blockchain:go_default_library", "//beacon-chain/db:go_default_library", "//cmd/beacon-chain/flags:go_default_library", + "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", - "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", diff --git a/beacon-chain/builder/service.go b/beacon-chain/builder/service.go index fe32bade5a3d..2afbc02510f7 100644 --- a/beacon-chain/builder/service.go +++ b/beacon-chain/builder/service.go @@ -9,9 +9,9 @@ import ( "github.com/prysmaticlabs/prysm/v3/api/client/builder" "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v3/beacon-chain/db" + "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" - v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" log "github.com/sirupsen/logrus" "go.opencensus.io/trace" @@ -22,8 +22,8 @@ var ErrNoBuilder = errors.New("builder endpoint not configured") // BlockBuilder defines the interface for interacting with the block builder type BlockBuilder interface { - SubmitBlindedBlock(ctx context.Context, block *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) - GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubKey [48]byte) (*ethpb.SignedBuilderBid, error) + SubmitBlindedBlock(ctx context.Context, block interfaces.SignedBeaconBlock) (interfaces.ExecutionData, error) + GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubKey [48]byte) (builder.SignedBid, error) RegisterValidator(ctx context.Context, reg []*ethpb.SignedValidatorRegistrationV1) error Configured() bool } @@ -82,7 +82,7 @@ func (*Service) Stop() error { } // SubmitBlindedBlock submits a blinded block to the builder relay network. -func (s *Service) SubmitBlindedBlock(ctx context.Context, b *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) { +func (s *Service) SubmitBlindedBlock(ctx context.Context, b interfaces.SignedBeaconBlock) (interfaces.ExecutionData, error) { ctx, span := trace.StartSpan(ctx, "builder.SubmitBlindedBlock") defer span.End() start := time.Now() @@ -94,7 +94,7 @@ func (s *Service) SubmitBlindedBlock(ctx context.Context, b *ethpb.SignedBlinded } // GetHeader retrieves the header for a given slot and parent hash from the builder relay network. -func (s *Service) GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubKey [48]byte) (*ethpb.SignedBuilderBid, error) { +func (s *Service) GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubKey [48]byte) (builder.SignedBid, error) { ctx, span := trace.StartSpan(ctx, "builder.GetHeader") defer span.End() start := time.Now() diff --git a/beacon-chain/builder/testing/BUILD.bazel b/beacon-chain/builder/testing/BUILD.bazel index 17288ae773f5..617896074dbf 100644 --- a/beacon-chain/builder/testing/BUILD.bazel +++ b/beacon-chain/builder/testing/BUILD.bazel @@ -7,8 +7,12 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/builder/testing", visibility = ["//visibility:public"], deps = [ + "//api/client/builder:go_default_library", + "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "@com_github_pkg_errors//:go_default_library", ], ) diff --git a/beacon-chain/builder/testing/mock.go b/beacon-chain/builder/testing/mock.go index 702491165718..36a8f1feb21e 100644 --- a/beacon-chain/builder/testing/mock.go +++ b/beacon-chain/builder/testing/mock.go @@ -3,6 +3,10 @@ package testing import ( "context" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v3/api/client/builder" + "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" @@ -24,13 +28,21 @@ func (s *MockBuilderService) Configured() bool { } // SubmitBlindedBlock for mocking. -func (s *MockBuilderService) SubmitBlindedBlock(context.Context, *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) { - return s.Payload, s.ErrSubmitBlindedBlock +func (s *MockBuilderService) SubmitBlindedBlock(_ context.Context, _ interfaces.SignedBeaconBlock) (interfaces.ExecutionData, error) { + w, err := blocks.WrappedExecutionPayload(s.Payload) + if err != nil { + return nil, errors.Wrap(err, "could not wrap payload") + } + return w, s.ErrSubmitBlindedBlock } // GetHeader for mocking. -func (s *MockBuilderService) GetHeader(context.Context, types.Slot, [32]byte, [48]byte) (*ethpb.SignedBuilderBid, error) { - return s.Bid, s.ErrGetHeader +func (s *MockBuilderService) GetHeader(context.Context, types.Slot, [32]byte, [48]byte) (builder.SignedBid, error) { + w, err := builder.WrappedSignedBuilderBid(s.Bid) + if err != nil { + return nil, errors.Wrap(err, "could not wrap bid") + } + return w, s.ErrGetHeader } // RegisterValidator for mocking. diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel b/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel index 38b80d8d98e6..80a4dbb1014f 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel @@ -29,6 +29,7 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/prysm/v1alpha1/validator", visibility = ["//beacon-chain:__subpackages__"], deps = [ + "//api/client/builder:go_default_library", "//async/event:go_default_library", "//beacon-chain/blockchain:go_default_library", "//beacon-chain/builder:go_default_library", diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go index f0e04ad69a2a..338874182213 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prysmaticlabs/prysm/v3/api/client/builder" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state" @@ -90,15 +91,22 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Sl ctx, cancel := context.WithTimeout(ctx, blockBuilderTimeout) defer cancel() - bid, err := vs.BlockBuilder.GetHeader(ctx, slot, bytesutil.ToBytes32(h.BlockHash()), pk) + signedBid, err := vs.BlockBuilder.GetHeader(ctx, slot, bytesutil.ToBytes32(h.BlockHash()), pk) if err != nil { return nil, err } - if bid == nil || bid.Message == nil { + if signedBid.IsNil() { + return nil, errors.New("builder returned nil bid") + } + bid, err := signedBid.Message() + if err != nil { + return nil, errors.Wrap(err, "could not get bid") + } + if bid.IsNil() { return nil, errors.New("builder returned nil bid") } - v := bytesutil.LittleEndianBytesToBigInt(bid.Message.Value) + v := bytesutil.LittleEndianBytesToBigInt(bid.Value()) if v.String() == "0" { return nil, errors.New("builder returned header with 0 bid amount") } @@ -108,32 +116,40 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Sl return nil, err } - if bytesutil.ToBytes32(bid.Message.Header.TransactionsRoot) == emptyRoot { + header, err := bid.Header() + if err != nil { + return nil, errors.Wrap(err, "could not get bid header") + } + txRoot, err := header.TransactionsRoot() + if err != nil { + return nil, errors.Wrap(err, "could not get transaction root") + } + if bytesutil.ToBytes32(txRoot) == emptyRoot { return nil, errors.New("builder returned header with an empty tx root") } - if !bytes.Equal(bid.Message.Header.ParentHash, h.BlockHash()) { - return nil, fmt.Errorf("incorrect parent hash %#x != %#x", bid.Message.Header.ParentHash, h.BlockHash()) + if !bytes.Equal(header.ParentHash(), h.BlockHash()) { + return nil, fmt.Errorf("incorrect parent hash %#x != %#x", header.ParentHash(), h.BlockHash()) } t, err := slots.ToTime(uint64(vs.TimeFetcher.GenesisTime().Unix()), slot) if err != nil { return nil, err } - if bid.Message.Header.Timestamp != uint64(t.Unix()) { - return nil, fmt.Errorf("incorrect timestamp %d != %d", bid.Message.Header.Timestamp, uint64(t.Unix())) + if header.Timestamp() != uint64(t.Unix()) { + return nil, fmt.Errorf("incorrect timestamp %d != %d", header.Timestamp(), uint64(t.Unix())) } - if err := validateBuilderSignature(bid); err != nil { + if err := validateBuilderSignature(signedBid); err != nil { return nil, errors.Wrap(err, "could not validate builder signature") } log.WithFields(logrus.Fields{ "value": v.String(), - "builderPubKey": fmt.Sprintf("%#x", bid.Message.Pubkey), - "blockHash": fmt.Sprintf("%#x", bid.Message.Header.BlockHash), + "builderPubKey": fmt.Sprintf("%#x", bid.Pubkey()), + "blockHash": fmt.Sprintf("%#x", header.BlockHash()), }).Info("Received header with bid") - return consensusblocks.WrappedExecutionPayloadHeader(bid.Message.Header) + return header, nil } // This function retrieves the full payload block using the input blind block. This input must be versioned as @@ -170,7 +186,7 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe randaoReveal := b.Block().Body().RandaoReveal() graffiti := b.Block().Body().Graffiti() sig := b.Signature() - sb := ðpb.SignedBlindedBeaconBlockBellatrix{ + psb := ðpb.SignedBlindedBeaconBlockBellatrix{ Block: ðpb.BlindedBeaconBlockBellatrix{ Slot: b.Block().Slot(), ProposerIndex: b.Block().ProposerIndex(), @@ -192,6 +208,10 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe Signature: sig[:], } + sb, err := consensusblocks.NewSignedBeaconBlock(psb) + if err != nil { + return nil, errors.Wrap(err, "could not create signed block") + } payload, err := vs.BlockBuilder.SubmitBlindedBlock(ctx, sb) if err != nil { return nil, err @@ -210,53 +230,68 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe "%#x != %#x", headerRoot, payloadRoot) } + pbPayload, err := payload.PbBellatrix() + if err != nil { + return nil, errors.Wrap(err, "could not get payload") + } bb := ðpb.SignedBeaconBlockBellatrix{ Block: ðpb.BeaconBlockBellatrix{ - Slot: sb.Block.Slot, - ProposerIndex: sb.Block.ProposerIndex, - ParentRoot: sb.Block.ParentRoot, - StateRoot: sb.Block.StateRoot, + Slot: psb.Block.Slot, + ProposerIndex: psb.Block.ProposerIndex, + ParentRoot: psb.Block.ParentRoot, + StateRoot: psb.Block.StateRoot, Body: ðpb.BeaconBlockBodyBellatrix{ - RandaoReveal: sb.Block.Body.RandaoReveal, - Eth1Data: sb.Block.Body.Eth1Data, - Graffiti: sb.Block.Body.Graffiti, - ProposerSlashings: sb.Block.Body.ProposerSlashings, - AttesterSlashings: sb.Block.Body.AttesterSlashings, - Attestations: sb.Block.Body.Attestations, - Deposits: sb.Block.Body.Deposits, - VoluntaryExits: sb.Block.Body.VoluntaryExits, + RandaoReveal: psb.Block.Body.RandaoReveal, + Eth1Data: psb.Block.Body.Eth1Data, + Graffiti: psb.Block.Body.Graffiti, + ProposerSlashings: psb.Block.Body.ProposerSlashings, + AttesterSlashings: psb.Block.Body.AttesterSlashings, + Attestations: psb.Block.Body.Attestations, + Deposits: psb.Block.Body.Deposits, + VoluntaryExits: psb.Block.Body.VoluntaryExits, SyncAggregate: agg, - ExecutionPayload: payload, + ExecutionPayload: pbPayload, }, }, - Signature: sb.Signature, + Signature: psb.Signature, } wb, err := consensusblocks.NewSignedBeaconBlock(bb) if err != nil { return nil, err } + txs, err := payload.Transactions() + if err != nil { + return nil, errors.Wrap(err, "could not get transactions from payload") + } log.WithFields(logrus.Fields{ "blockHash": fmt.Sprintf("%#x", h.BlockHash()), "feeRecipient": fmt.Sprintf("%#x", h.FeeRecipient()), "gasUsed": h.GasUsed, "slot": b.Block().Slot(), - "txs": len(payload.Transactions), + "txs": len(txs), }).Info("Retrieved full payload from builder") return wb, nil } // Validates builder signature and returns an error if the signature is invalid. -func validateBuilderSignature(bid *ethpb.SignedBuilderBid) error { +func validateBuilderSignature(signedBid builder.SignedBid) error { d, err := signing.ComputeDomain(params.BeaconConfig().DomainApplicationBuilder, nil, /* fork version */ nil /* genesis val root */) if err != nil { return err } - if bid == nil || bid.Message == nil { + if signedBid.IsNil() { return errors.New("nil builder bid") } - return signing.VerifySigningRoot(bid.Message, bid.Message.Pubkey, bid.Signature, d) + bid, err := signedBid.Message() + if err != nil { + return errors.Wrap(err, "could not get bid") + } + if bid.IsNil() { + return errors.New("builder returned nil bid") + } + return signing.VerifySigningRoot(bid, bid.Pubkey(), signedBid.Signature(), d) } diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix_test.go b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix_test.go index 02b65ebbfb38..fc9ccde256ce 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix_test.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v3/api/client/builder" blockchainTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing" builderTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/builder/testing" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing" @@ -81,6 +82,7 @@ func TestServer_getPayloadHeader(t *testing.T) { name: "get header failed", mock: &builderTest.MockBuilderService{ ErrGetHeader: errors.New("can't get header"), + Bid: sBid, }, fetcher: &blockchainTest.ChainService{ Block: func() interfaces.SignedBeaconBlock { @@ -224,6 +226,7 @@ func TestServer_getBuilderBlock(t *testing.T) { return wb }(), mock: &builderTest.MockBuilderService{ + Payload: &v1.ExecutionPayload{}, HasConfigured: true, ErrSubmitBlindedBlock: errors.New("can't submit"), }, @@ -331,12 +334,16 @@ func TestServer_validateBuilderSignature(t *testing.T) { require.NoError(t, err) sr, err := signing.ComputeSigningRoot(bid, domain) require.NoError(t, err) - sBid := ðpb.SignedBuilderBid{ + pbBid := ðpb.SignedBuilderBid{ Message: bid, Signature: sk.Sign(sr[:]).Marshal(), } + sBid, err := builder.WrappedSignedBuilderBid(pbBid) + require.NoError(t, err) require.NoError(t, validateBuilderSignature(sBid)) - sBid.Message.Value = make([]byte, 32) + pbBid.Message.Value = make([]byte, 32) + sBid, err = builder.WrappedSignedBuilderBid(pbBid) + require.NoError(t, err) require.ErrorIs(t, validateBuilderSignature(sBid), signing.ErrSigFailedToVerify) } diff --git a/proto/prysm/v1alpha1/BUILD.bazel b/proto/prysm/v1alpha1/BUILD.bazel index b8dcb04ec145..73792b49f124 100644 --- a/proto/prysm/v1alpha1/BUILD.bazel +++ b/proto/prysm/v1alpha1/BUILD.bazel @@ -120,6 +120,7 @@ ssz_gen_marshal( "BLSToExecutionChange", "SignedBLSToExecutionChange", "BuilderBid", + "BuilderBidCapella", ], ) @@ -211,9 +212,9 @@ ssz_proto_files( "attestation.proto", "beacon_block.proto", "beacon_state.proto", + "blobs.proto", "sync_committee.proto", "withdrawals.proto", - "blobs.proto", ], config = select({ "//conditions:default": "mainnet", diff --git a/proto/prysm/v1alpha1/beacon_block.pb.go b/proto/prysm/v1alpha1/beacon_block.pb.go index 9cc81ec06171..a451d2837095 100755 --- a/proto/prysm/v1alpha1/beacon_block.pb.go +++ b/proto/prysm/v1alpha1/beacon_block.pb.go @@ -31,6 +31,7 @@ type GenericSignedBeaconBlock struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Block: + // // *GenericSignedBeaconBlock_Phase0 // *GenericSignedBeaconBlock_Altair // *GenericSignedBeaconBlock_Bellatrix @@ -167,6 +168,7 @@ type GenericBeaconBlock struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Block: + // // *GenericBeaconBlock_Phase0 // *GenericBeaconBlock_Altair // *GenericBeaconBlock_Bellatrix @@ -2743,6 +2745,124 @@ func (x *SignedBuilderBid) GetSignature() []byte { return nil } +type BuilderBidCapella struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Header *v1.ExecutionPayloadHeaderCapella `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty" ssz-size:"32"` + Pubkey []byte `protobuf:"bytes,3,opt,name=pubkey,proto3" json:"pubkey,omitempty" ssz-size:"48"` +} + +func (x *BuilderBidCapella) Reset() { + *x = BuilderBidCapella{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BuilderBidCapella) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BuilderBidCapella) ProtoMessage() {} + +func (x *BuilderBidCapella) ProtoReflect() protoreflect.Message { + mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BuilderBidCapella.ProtoReflect.Descriptor instead. +func (*BuilderBidCapella) Descriptor() ([]byte, []int) { + return file_proto_prysm_v1alpha1_beacon_block_proto_rawDescGZIP(), []int{36} +} + +func (x *BuilderBidCapella) GetHeader() *v1.ExecutionPayloadHeaderCapella { + if x != nil { + return x.Header + } + return nil +} + +func (x *BuilderBidCapella) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +func (x *BuilderBidCapella) GetPubkey() []byte { + if x != nil { + return x.Pubkey + } + return nil +} + +type SignedBuilderBidCapella struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message *BuilderBidCapella `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty" ssz-size:"96"` +} + +func (x *SignedBuilderBidCapella) Reset() { + *x = SignedBuilderBidCapella{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignedBuilderBidCapella) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignedBuilderBidCapella) ProtoMessage() {} + +func (x *SignedBuilderBidCapella) ProtoReflect() protoreflect.Message { + mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignedBuilderBidCapella.ProtoReflect.Descriptor instead. +func (*SignedBuilderBidCapella) Descriptor() ([]byte, []int) { + return file_proto_prysm_v1alpha1_beacon_block_proto_rawDescGZIP(), []int{37} +} + +func (x *SignedBuilderBidCapella) GetMessage() *BuilderBidCapella { + if x != nil { + return x.Message + } + return nil +} + +func (x *SignedBuilderBidCapella) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + type Deposit_Data struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2757,7 +2877,7 @@ type Deposit_Data struct { func (x *Deposit_Data) Reset() { *x = Deposit_Data{} if protoimpl.UnsafeEnabled { - mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[36] + mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2770,7 +2890,7 @@ func (x *Deposit_Data) String() string { func (*Deposit_Data) ProtoMessage() {} func (x *Deposit_Data) ProtoReflect() protoreflect.Message { - mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[36] + mi := &file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3560,17 +3680,36 @@ var file_proto_prysm_v1alpha1_beacon_block_proto_rawDesc = []byte{ 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x42, 0x69, 0x64, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x9b, 0x01, 0x0a, 0x19, 0x6f, 0x72, 0x67, - 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x10, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x31, 0x3b, 0x65, 0x74, 0x68, 0xaa, 0x02, 0x15, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, - 0x6d, 0x2e, 0x45, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, - 0x15, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x74, 0x68, 0x5c, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x9c, 0x01, 0x0a, 0x11, 0x42, 0x75, 0x69, + 0x6c, 0x64, 0x65, 0x72, 0x42, 0x69, 0x64, 0x43, 0x61, 0x70, 0x65, 0x6c, 0x6c, 0x61, 0x12, 0x49, + 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, + 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x61, 0x70, 0x65, 0x6c, 0x6c, + 0x61, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1e, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x34, 0x38, 0x52, + 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x83, 0x01, 0x0a, 0x17, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x42, 0x69, 0x64, 0x43, 0x61, 0x70, 0x65, + 0x6c, 0x6c, 0x61, 0x12, 0x42, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, + 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x75, 0x69, + 0x6c, 0x64, 0x65, 0x72, 0x42, 0x69, 0x64, 0x43, 0x61, 0x70, 0x65, 0x6c, 0x6c, 0x61, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, + 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x9b, 0x01, + 0x0a, 0x19, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, + 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x10, 0x42, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, + 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, + 0x76, 0x33, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x65, 0x74, 0x68, 0xaa, 0x02, 0x15, 0x45, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x31, 0xca, 0x02, 0x15, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, + 0x74, 0x68, 0x5c, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -3585,7 +3724,7 @@ func file_proto_prysm_v1alpha1_beacon_block_proto_rawDescGZIP() []byte { return file_proto_prysm_v1alpha1_beacon_block_proto_rawDescData } -var file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes = make([]protoimpl.MessageInfo, 37) +var file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes = make([]protoimpl.MessageInfo, 39) var file_proto_prysm_v1alpha1_beacon_block_proto_goTypes = []interface{}{ (*GenericSignedBeaconBlock)(nil), // 0: ethereum.eth.v1alpha1.GenericSignedBeaconBlock (*GenericBeaconBlock)(nil), // 1: ethereum.eth.v1alpha1.GenericBeaconBlock @@ -3623,15 +3762,17 @@ var file_proto_prysm_v1alpha1_beacon_block_proto_goTypes = []interface{}{ (*SignedValidatorRegistrationV1)(nil), // 33: ethereum.eth.v1alpha1.SignedValidatorRegistrationV1 (*BuilderBid)(nil), // 34: ethereum.eth.v1alpha1.BuilderBid (*SignedBuilderBid)(nil), // 35: ethereum.eth.v1alpha1.SignedBuilderBid - (*Deposit_Data)(nil), // 36: ethereum.eth.v1alpha1.Deposit.Data - (*Attestation)(nil), // 37: ethereum.eth.v1alpha1.Attestation - (*AttestationData)(nil), // 38: ethereum.eth.v1alpha1.AttestationData - (*v1.ExecutionPayload)(nil), // 39: ethereum.engine.v1.ExecutionPayload - (*v1.ExecutionPayloadHeader)(nil), // 40: ethereum.engine.v1.ExecutionPayloadHeader - (*BlobsSidecar)(nil), // 41: ethereum.eth.v1alpha1.BlobsSidecar - (*v1.ExecutionPayloadCapella)(nil), // 42: ethereum.engine.v1.ExecutionPayloadCapella - (*SignedBLSToExecutionChange)(nil), // 43: ethereum.eth.v1alpha1.SignedBLSToExecutionChange - (*v1.ExecutionPayloadHeaderCapella)(nil), // 44: ethereum.engine.v1.ExecutionPayloadHeaderCapella + (*BuilderBidCapella)(nil), // 36: ethereum.eth.v1alpha1.BuilderBidCapella + (*SignedBuilderBidCapella)(nil), // 37: ethereum.eth.v1alpha1.SignedBuilderBidCapella + (*Deposit_Data)(nil), // 38: ethereum.eth.v1alpha1.Deposit.Data + (*Attestation)(nil), // 39: ethereum.eth.v1alpha1.Attestation + (*AttestationData)(nil), // 40: ethereum.eth.v1alpha1.AttestationData + (*v1.ExecutionPayload)(nil), // 41: ethereum.engine.v1.ExecutionPayload + (*v1.ExecutionPayloadHeader)(nil), // 42: ethereum.engine.v1.ExecutionPayloadHeader + (*BlobsSidecar)(nil), // 43: ethereum.eth.v1alpha1.BlobsSidecar + (*v1.ExecutionPayloadCapella)(nil), // 44: ethereum.engine.v1.ExecutionPayloadCapella + (*SignedBLSToExecutionChange)(nil), // 45: ethereum.eth.v1alpha1.SignedBLSToExecutionChange + (*v1.ExecutionPayloadHeaderCapella)(nil), // 46: ethereum.engine.v1.ExecutionPayloadHeaderCapella } var file_proto_prysm_v1alpha1_beacon_block_proto_depIdxs = []int32{ 3, // 0: ethereum.eth.v1alpha1.GenericSignedBeaconBlock.phase0:type_name -> ethereum.eth.v1alpha1.SignedBeaconBlock @@ -3653,13 +3794,13 @@ var file_proto_prysm_v1alpha1_beacon_block_proto_depIdxs = []int32{ 13, // 16: ethereum.eth.v1alpha1.BeaconBlockBody.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data 8, // 17: ethereum.eth.v1alpha1.BeaconBlockBody.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing 9, // 18: ethereum.eth.v1alpha1.BeaconBlockBody.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashing - 37, // 19: ethereum.eth.v1alpha1.BeaconBlockBody.attestations:type_name -> ethereum.eth.v1alpha1.Attestation + 39, // 19: ethereum.eth.v1alpha1.BeaconBlockBody.attestations:type_name -> ethereum.eth.v1alpha1.Attestation 10, // 20: ethereum.eth.v1alpha1.BeaconBlockBody.deposits:type_name -> ethereum.eth.v1alpha1.Deposit 12, // 21: ethereum.eth.v1alpha1.BeaconBlockBody.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit 13, // 22: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data 8, // 23: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing 9, // 24: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashing - 37, // 25: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.attestations:type_name -> ethereum.eth.v1alpha1.Attestation + 39, // 25: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.attestations:type_name -> ethereum.eth.v1alpha1.Attestation 10, // 26: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.deposits:type_name -> ethereum.eth.v1alpha1.Deposit 12, // 27: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit 17, // 28: ethereum.eth.v1alpha1.BeaconBlockBodyAltair.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate @@ -3667,63 +3808,65 @@ var file_proto_prysm_v1alpha1_beacon_block_proto_depIdxs = []int32{ 15, // 30: ethereum.eth.v1alpha1.ProposerSlashing.header_2:type_name -> ethereum.eth.v1alpha1.SignedBeaconBlockHeader 16, // 31: ethereum.eth.v1alpha1.AttesterSlashing.attestation_1:type_name -> ethereum.eth.v1alpha1.IndexedAttestation 16, // 32: ethereum.eth.v1alpha1.AttesterSlashing.attestation_2:type_name -> ethereum.eth.v1alpha1.IndexedAttestation - 36, // 33: ethereum.eth.v1alpha1.Deposit.data:type_name -> ethereum.eth.v1alpha1.Deposit.Data + 38, // 33: ethereum.eth.v1alpha1.Deposit.data:type_name -> ethereum.eth.v1alpha1.Deposit.Data 11, // 34: ethereum.eth.v1alpha1.SignedVoluntaryExit.exit:type_name -> ethereum.eth.v1alpha1.VoluntaryExit 14, // 35: ethereum.eth.v1alpha1.SignedBeaconBlockHeader.header:type_name -> ethereum.eth.v1alpha1.BeaconBlockHeader - 38, // 36: ethereum.eth.v1alpha1.IndexedAttestation.data:type_name -> ethereum.eth.v1alpha1.AttestationData + 40, // 36: ethereum.eth.v1alpha1.IndexedAttestation.data:type_name -> ethereum.eth.v1alpha1.AttestationData 19, // 37: ethereum.eth.v1alpha1.SignedBeaconBlockBellatrix.block:type_name -> ethereum.eth.v1alpha1.BeaconBlockBellatrix 20, // 38: ethereum.eth.v1alpha1.BeaconBlockBellatrix.body:type_name -> ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix 13, // 39: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data 8, // 40: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing 9, // 41: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashing - 37, // 42: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.attestations:type_name -> ethereum.eth.v1alpha1.Attestation + 39, // 42: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.attestations:type_name -> ethereum.eth.v1alpha1.Attestation 10, // 43: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.deposits:type_name -> ethereum.eth.v1alpha1.Deposit 12, // 44: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit 17, // 45: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate - 39, // 46: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.execution_payload:type_name -> ethereum.engine.v1.ExecutionPayload + 41, // 46: ethereum.eth.v1alpha1.BeaconBlockBodyBellatrix.execution_payload:type_name -> ethereum.engine.v1.ExecutionPayload 22, // 47: ethereum.eth.v1alpha1.SignedBlindedBeaconBlockBellatrix.block:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockBellatrix 23, // 48: ethereum.eth.v1alpha1.BlindedBeaconBlockBellatrix.body:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix 13, // 49: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data 8, // 50: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing 9, // 51: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashing - 37, // 52: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.attestations:type_name -> ethereum.eth.v1alpha1.Attestation + 39, // 52: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.attestations:type_name -> ethereum.eth.v1alpha1.Attestation 10, // 53: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.deposits:type_name -> ethereum.eth.v1alpha1.Deposit 12, // 54: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit 17, // 55: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate - 40, // 56: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.execution_payload_header:type_name -> ethereum.engine.v1.ExecutionPayloadHeader + 42, // 56: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyBellatrix.execution_payload_header:type_name -> ethereum.engine.v1.ExecutionPayloadHeader 25, // 57: ethereum.eth.v1alpha1.SignedBeaconBlockAndBlobsSidecar.beacon_block:type_name -> ethereum.eth.v1alpha1.SignedBeaconBlockCapella - 41, // 58: ethereum.eth.v1alpha1.SignedBeaconBlockAndBlobsSidecar.blobs_sidecar:type_name -> ethereum.eth.v1alpha1.BlobsSidecar + 43, // 58: ethereum.eth.v1alpha1.SignedBeaconBlockAndBlobsSidecar.blobs_sidecar:type_name -> ethereum.eth.v1alpha1.BlobsSidecar 26, // 59: ethereum.eth.v1alpha1.SignedBeaconBlockCapella.block:type_name -> ethereum.eth.v1alpha1.BeaconBlockCapella 27, // 60: ethereum.eth.v1alpha1.BeaconBlockCapella.body:type_name -> ethereum.eth.v1alpha1.BeaconBlockBodyCapella 13, // 61: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data 8, // 62: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing 9, // 63: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashing - 37, // 64: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.attestations:type_name -> ethereum.eth.v1alpha1.Attestation + 39, // 64: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.attestations:type_name -> ethereum.eth.v1alpha1.Attestation 10, // 65: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.deposits:type_name -> ethereum.eth.v1alpha1.Deposit 12, // 66: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit 17, // 67: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate - 42, // 68: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.execution_payload:type_name -> ethereum.engine.v1.ExecutionPayloadCapella - 43, // 69: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange + 44, // 68: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.execution_payload:type_name -> ethereum.engine.v1.ExecutionPayloadCapella + 45, // 69: ethereum.eth.v1alpha1.BeaconBlockBodyCapella.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange 29, // 70: ethereum.eth.v1alpha1.SignedBlindedBeaconBlockCapella.block:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockCapella 30, // 71: ethereum.eth.v1alpha1.BlindedBeaconBlockCapella.body:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella 13, // 72: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data 8, // 73: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing 9, // 74: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashing - 37, // 75: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.attestations:type_name -> ethereum.eth.v1alpha1.Attestation + 39, // 75: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.attestations:type_name -> ethereum.eth.v1alpha1.Attestation 10, // 76: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.deposits:type_name -> ethereum.eth.v1alpha1.Deposit 12, // 77: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit 17, // 78: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate - 44, // 79: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.execution_payload_header:type_name -> ethereum.engine.v1.ExecutionPayloadHeaderCapella - 43, // 80: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange + 46, // 79: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.execution_payload_header:type_name -> ethereum.engine.v1.ExecutionPayloadHeaderCapella + 45, // 80: ethereum.eth.v1alpha1.BlindedBeaconBlockBodyCapella.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange 33, // 81: ethereum.eth.v1alpha1.SignedValidatorRegistrationsV1.messages:type_name -> ethereum.eth.v1alpha1.SignedValidatorRegistrationV1 31, // 82: ethereum.eth.v1alpha1.SignedValidatorRegistrationV1.message:type_name -> ethereum.eth.v1alpha1.ValidatorRegistrationV1 - 40, // 83: ethereum.eth.v1alpha1.BuilderBid.header:type_name -> ethereum.engine.v1.ExecutionPayloadHeader + 42, // 83: ethereum.eth.v1alpha1.BuilderBid.header:type_name -> ethereum.engine.v1.ExecutionPayloadHeader 34, // 84: ethereum.eth.v1alpha1.SignedBuilderBid.message:type_name -> ethereum.eth.v1alpha1.BuilderBid - 85, // [85:85] is the sub-list for method output_type - 85, // [85:85] is the sub-list for method input_type - 85, // [85:85] is the sub-list for extension type_name - 85, // [85:85] is the sub-list for extension extendee - 0, // [0:85] is the sub-list for field type_name + 46, // 85: ethereum.eth.v1alpha1.BuilderBidCapella.header:type_name -> ethereum.engine.v1.ExecutionPayloadHeaderCapella + 36, // 86: ethereum.eth.v1alpha1.SignedBuilderBidCapella.message:type_name -> ethereum.eth.v1alpha1.BuilderBidCapella + 87, // [87:87] is the sub-list for method output_type + 87, // [87:87] is the sub-list for method input_type + 87, // [87:87] is the sub-list for extension type_name + 87, // [87:87] is the sub-list for extension extendee + 0, // [0:87] is the sub-list for field type_name } func init() { file_proto_prysm_v1alpha1_beacon_block_proto_init() } @@ -4168,6 +4311,30 @@ func file_proto_prysm_v1alpha1_beacon_block_proto_init() { } } file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BuilderBidCapella); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignedBuilderBidCapella); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_prysm_v1alpha1_beacon_block_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Deposit_Data); i { case 0: return &v.state @@ -4202,7 +4369,7 @@ func file_proto_prysm_v1alpha1_beacon_block_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_prysm_v1alpha1_beacon_block_proto_rawDesc, NumEnums: 0, - NumMessages: 37, + NumMessages: 39, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/prysm/v1alpha1/beacon_block.proto b/proto/prysm/v1alpha1/beacon_block.proto index 4f25266f1727..51a4be73fe2d 100644 --- a/proto/prysm/v1alpha1/beacon_block.proto +++ b/proto/prysm/v1alpha1/beacon_block.proto @@ -572,10 +572,10 @@ message BlindedBeaconBlockBodyCapella { } message ValidatorRegistrationV1 { - bytes fee_recipient = 1 [(ethereum.eth.ext.ssz_size) = "20"]; - uint64 gas_limit = 2; - uint64 timestamp = 3; - bytes pubkey = 4 [(ethereum.eth.ext.ssz_size) = "48"]; + bytes fee_recipient = 1 [(ethereum.eth.ext.ssz_size) = "20"]; + uint64 gas_limit = 2; + uint64 timestamp = 3; + bytes pubkey = 4 [(ethereum.eth.ext.ssz_size) = "48"]; } message SignedValidatorRegistrationsV1 { @@ -583,17 +583,28 @@ message SignedValidatorRegistrationsV1 { } message SignedValidatorRegistrationV1 { - ValidatorRegistrationV1 message = 1 ; - bytes signature = 2 [(ethereum.eth.ext.ssz_size) = "96"]; + ValidatorRegistrationV1 message = 1 ; + bytes signature = 2 [(ethereum.eth.ext.ssz_size) = "96"]; } message BuilderBid { - ethereum.engine.v1.ExecutionPayloadHeader header = 1 ; + ethereum.engine.v1.ExecutionPayloadHeader header = 1; bytes value = 2 [(ethereum.eth.ext.ssz_size) = "32"]; - bytes pubkey = 3 [(ethereum.eth.ext.ssz_size) = "48"]; + bytes pubkey = 3 [(ethereum.eth.ext.ssz_size) = "48"]; } message SignedBuilderBid { - BuilderBid message = 1 ; - bytes signature = 2 [(ethereum.eth.ext.ssz_size) = "96"]; + BuilderBid message = 1 ; + bytes signature = 2 [(ethereum.eth.ext.ssz_size) = "96"]; +} + +message BuilderBidCapella { + ethereum.engine.v1.ExecutionPayloadHeaderCapella header = 1 ; + bytes value = 2 [(ethereum.eth.ext.ssz_size) = "32"]; + bytes pubkey = 3 [(ethereum.eth.ext.ssz_size) = "48"]; +} + +message SignedBuilderBidCapella { + BuilderBidCapella message = 1 ; + bytes signature = 2 [(ethereum.eth.ext.ssz_size) = "96"]; } diff --git a/proto/prysm/v1alpha1/generated.ssz.go b/proto/prysm/v1alpha1/generated.ssz.go index 2fe3d1d411fa..d5ffbe223fdf 100644 --- a/proto/prysm/v1alpha1/generated.ssz.go +++ b/proto/prysm/v1alpha1/generated.ssz.go @@ -1,5 +1,5 @@ // Code generated by fastssz. DO NOT EDIT. -// Hash: cd84f61a2f07139241137aeaa7b8bca4ff86118ce0fd0bd523c77c30518db21f +// Hash: 7e32b259c438fd7514a400a345ba5c1bbdaf7dfb681c2608a94431700f2d606e package eth import ( @@ -6615,6 +6615,139 @@ func (b *BuilderBid) HashTreeRootWith(hh *ssz.Hasher) (err error) { return } +// MarshalSSZ ssz marshals the BuilderBidCapella object +func (b *BuilderBidCapella) MarshalSSZ() ([]byte, error) { + return ssz.MarshalSSZ(b) +} + +// MarshalSSZTo ssz marshals the BuilderBidCapella object to a target array +func (b *BuilderBidCapella) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + offset := int(84) + + // Offset (0) 'Header' + dst = ssz.WriteOffset(dst, offset) + if b.Header == nil { + b.Header = new(v1.ExecutionPayloadHeaderCapella) + } + offset += b.Header.SizeSSZ() + + // Field (1) 'Value' + if size := len(b.Value); size != 32 { + err = ssz.ErrBytesLengthFn("--.Value", size, 32) + return + } + dst = append(dst, b.Value...) + + // Field (2) 'Pubkey' + if size := len(b.Pubkey); size != 48 { + err = ssz.ErrBytesLengthFn("--.Pubkey", size, 48) + return + } + dst = append(dst, b.Pubkey...) + + // Field (0) 'Header' + if dst, err = b.Header.MarshalSSZTo(dst); err != nil { + return + } + + return +} + +// UnmarshalSSZ ssz unmarshals the BuilderBidCapella object +func (b *BuilderBidCapella) UnmarshalSSZ(buf []byte) error { + var err error + size := uint64(len(buf)) + if size < 84 { + return ssz.ErrSize + } + + tail := buf + var o0 uint64 + + // Offset (0) 'Header' + if o0 = ssz.ReadOffset(buf[0:4]); o0 > size { + return ssz.ErrOffset + } + + if o0 < 84 { + return ssz.ErrInvalidVariableOffset + } + + // Field (1) 'Value' + if cap(b.Value) == 0 { + b.Value = make([]byte, 0, len(buf[4:36])) + } + b.Value = append(b.Value, buf[4:36]...) + + // Field (2) 'Pubkey' + if cap(b.Pubkey) == 0 { + b.Pubkey = make([]byte, 0, len(buf[36:84])) + } + b.Pubkey = append(b.Pubkey, buf[36:84]...) + + // Field (0) 'Header' + { + buf = tail[o0:] + if b.Header == nil { + b.Header = new(v1.ExecutionPayloadHeaderCapella) + } + if err = b.Header.UnmarshalSSZ(buf); err != nil { + return err + } + } + return err +} + +// SizeSSZ returns the ssz encoded size in bytes for the BuilderBidCapella object +func (b *BuilderBidCapella) SizeSSZ() (size int) { + size = 84 + + // Field (0) 'Header' + if b.Header == nil { + b.Header = new(v1.ExecutionPayloadHeaderCapella) + } + size += b.Header.SizeSSZ() + + return +} + +// HashTreeRoot ssz hashes the BuilderBidCapella object +func (b *BuilderBidCapella) HashTreeRoot() ([32]byte, error) { + return ssz.HashWithDefaultHasher(b) +} + +// HashTreeRootWith ssz hashes the BuilderBidCapella object with a hasher +func (b *BuilderBidCapella) HashTreeRootWith(hh *ssz.Hasher) (err error) { + indx := hh.Index() + + // Field (0) 'Header' + if err = b.Header.HashTreeRootWith(hh); err != nil { + return + } + + // Field (1) 'Value' + if size := len(b.Value); size != 32 { + err = ssz.ErrBytesLengthFn("--.Value", size, 32) + return + } + hh.PutBytes(b.Value) + + // Field (2) 'Pubkey' + if size := len(b.Pubkey); size != 48 { + err = ssz.ErrBytesLengthFn("--.Pubkey", size, 48) + return + } + hh.PutBytes(b.Pubkey) + + if ssz.EnableVectorizedHTR { + hh.MerkleizeVectorizedHTR(indx) + } else { + hh.Merkleize(indx) + } + return +} + // MarshalSSZ ssz marshals the Deposit_Data object func (d *Deposit_Data) MarshalSSZ() ([]byte, error) { return ssz.MarshalSSZ(d)