diff --git a/beacon-chain/execution/BUILD.bazel b/beacon-chain/execution/BUILD.bazel index 32eeea60d3..c3eaf23521 100644 --- a/beacon-chain/execution/BUILD.bazel +++ b/beacon-chain/execution/BUILD.bazel @@ -37,6 +37,7 @@ go_library( "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", "//beacon-chain/state/stategen:go_default_library", + "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", @@ -107,6 +108,7 @@ go_test( "//beacon-chain/execution/types:go_default_library", "//beacon-chain/forkchoice/doubly-linked-tree:go_default_library", "//beacon-chain/state/stategen:go_default_library", + "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", diff --git a/beacon-chain/execution/engine_client.go b/beacon-chain/execution/engine_client.go index f3b1557185..751bbc02a7 100644 --- a/beacon-chain/execution/engine_client.go +++ b/beacon-chain/execution/engine_client.go @@ -15,6 +15,7 @@ import ( "github.com/holiman/uint256" "github.com/pkg/errors" "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/types" + "github.com/prysmaticlabs/prysm/v3/config/features" fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" @@ -48,6 +49,10 @@ const ( ExecutionBlockByHashMethod = "eth_getBlockByHash" // ExecutionBlockByNumberMethod request string for JSON-RPC. ExecutionBlockByNumberMethod = "eth_getBlockByNumber" + // GetPayloadBodiesByHashV1 v1 request string for JSON-RPC. + GetPayloadBodiesByHashV1 = "engine_getPayloadBodiesByHashV1" + // GetPayloadBodiesByRangeV1 v1 request string for JSON-RPC. + GetPayloadBodiesByRangeV1 = "engine_getPayloadBodiesByRangeV1" // Defines the seconds before timing out engine endpoints with non-block execution semantics. defaultEngineTimeout = time.Second ) @@ -437,6 +442,50 @@ func (s *Service) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H return hdr, err } +// GetPayloadBodiesByHash returns the relevant payload bodies for the provided block hash. +func (s *Service) GetPayloadBodiesByHash(ctx context.Context, executionBlockHashes []common.Hash) ([]*pb.ExecutionPayloadBodyV1, error) { + if !features.Get().EnableOptionalEngineMethods { + return nil, errors.New("optional engine methods not enabled") + } + ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayloadBodiesByHashV1") + defer span.End() + + result := make([]*pb.ExecutionPayloadBodyV1, 0) + err := s.rpcClient.CallContext(ctx, &result, GetPayloadBodiesByHashV1, executionBlockHashes) + + for i, item := range result { + if item == nil { + result[i] = &pb.ExecutionPayloadBodyV1{ + Transactions: make([][]byte, 0), + Withdrawals: make([]*pb.Withdrawal, 0), + } + } + } + return result, handleRPCError(err) +} + +// GetPayloadBodiesByRange returns the relevant payload bodies for the provided range. +func (s *Service) GetPayloadBodiesByRange(ctx context.Context, start, count uint64) ([]*pb.ExecutionPayloadBodyV1, error) { + if !features.Get().EnableOptionalEngineMethods { + return nil, errors.New("optional engine methods not enabled") + } + ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayloadBodiesByRangeV1") + defer span.End() + + result := make([]*pb.ExecutionPayloadBodyV1, 0) + err := s.rpcClient.CallContext(ctx, &result, GetPayloadBodiesByRangeV1, start, count) + + for i, item := range result { + if item == nil { + result[i] = &pb.ExecutionPayloadBodyV1{ + Transactions: make([][]byte, 0), + Withdrawals: make([]*pb.Withdrawal, 0), + } + } + } + return result, handleRPCError(err) +} + // ReconstructFullBlock takes in a blinded beacon block and reconstructs // a beacon block with a full execution payload via the engine API. func (s *Service) ReconstructFullBlock( @@ -669,6 +718,9 @@ func handleRPCError(err error) error { case -38003: errInvalidPayloadAttributesCount.Inc() return ErrInvalidPayloadAttributes + case -38004: + errRequestTooLargeCount.Inc() + return ErrRequestTooLarge case -32000: errServerErrorCount.Inc() // Only -32000 status codes are data errors in the RPC specification. diff --git a/beacon-chain/execution/engine_client_test.go b/beacon-chain/execution/engine_client_test.go index 63c0d8418d..acc2a58a2a 100644 --- a/beacon-chain/execution/engine_client_test.go +++ b/beacon-chain/execution/engine_client_test.go @@ -20,6 +20,7 @@ import ( "github.com/holiman/uint256" "github.com/pkg/errors" mocks "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing" + "github.com/prysmaticlabs/prysm/v3/config/features" fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" @@ -1817,3 +1818,505 @@ func newPayloadV2Setup(t *testing.T, status *pb.PayloadStatus, payload *pb.Execu service.rpcClient = rpcClient return service } + +func TestCapella_PayloadBodiesByHash(t *testing.T) { + resetFn := features.InitWithReset(&features.Flags{ + EnableOptionalEngineMethods: true, + }) + defer resetFn() + t.Run("empty response works", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 0) + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{}) + require.NoError(t, err) + require.Equal(t, 0, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("single element response null works", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) + executionPayloadBodies[0] = nil + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{}) + require.NoError(t, err) + require.Equal(t, 1, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("empty, null, full works", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{}, + Withdrawals: []*pb.Withdrawal{}, + } + executionPayloadBodies[1] = nil + executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 1, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{}) + require.NoError(t, err) + require.Equal(t, 3, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("full works, single item", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 1, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{}) + require.NoError(t, err) + require.Equal(t, 1, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("full works, multiple items", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 2) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 1, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + executionPayloadBodies[1] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 2, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{}) + require.NoError(t, err) + require.Equal(t, 2, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("returning empty, null, empty should work properly", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + // [A, B, C] but no B in the server means + // we get [Abody, null, Cbody]. + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{}, + Withdrawals: []*pb.Withdrawal{}, + } + executionPayloadBodies[1] = nil + executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{}, + Withdrawals: []*pb.Withdrawal{}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{}) + require.NoError(t, err) + require.Equal(t, 3, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) +} + +func TestCapella_PayloadBodiesByRange(t *testing.T) { + resetFn := features.InitWithReset(&features.Flags{ + EnableOptionalEngineMethods: true, + }) + defer resetFn() + t.Run("empty response works", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 0) + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + require.NoError(t, err) + require.Equal(t, 0, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("single element response null works", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) + executionPayloadBodies[0] = nil + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + require.NoError(t, err) + require.Equal(t, 1, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("empty, null, full works", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{}, + Withdrawals: []*pb.Withdrawal{}, + } + executionPayloadBodies[1] = nil + executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 1, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + require.NoError(t, err) + require.Equal(t, 3, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("full works, single item", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 1, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + require.NoError(t, err) + require.Equal(t, 1, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("full works, multiple items", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 2) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 1, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + executionPayloadBodies[1] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, + Withdrawals: []*pb.Withdrawal{{ + Index: 2, + ValidatorIndex: 1, + Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), + Amount: 1, + }}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + require.NoError(t, err) + require.Equal(t, 2, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) + t.Run("returning empty, null, empty should work properly", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(t, r.Body.Close()) + }() + // [A, B, C] but no B in the server means + // we get [Abody, null, Cbody]. + executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) + executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{}, + Withdrawals: []*pb.Withdrawal{}, + } + executionPayloadBodies[1] = nil + executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ + Transactions: [][]byte{}, + Withdrawals: []*pb.Withdrawal{}, + } + + resp := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "result": executionPayloadBodies, + } + err := json.NewEncoder(w).Encode(resp) + require.NoError(t, err) + })) + ctx := context.Background() + + rpcClient, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + + service := &Service{} + service.rpcClient = rpcClient + + results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + require.NoError(t, err) + require.Equal(t, 3, len(results)) + + for _, item := range results { + require.NotNil(t, item) + } + }) +} diff --git a/beacon-chain/execution/errors.go b/beacon-chain/execution/errors.go index 88acaf3d7f..c27329c101 100644 --- a/beacon-chain/execution/errors.go +++ b/beacon-chain/execution/errors.go @@ -34,4 +34,6 @@ var ( ErrInvalidBlockHashPayloadStatus = errors.New("payload status is INVALID_BLOCK_HASH") // ErrNilResponse when the response is nil. ErrNilResponse = errors.New("nil response") + // ErrRequestTooLarge when the request is too large + ErrRequestTooLarge = errors.New("request too large") ) diff --git a/beacon-chain/execution/metrics.go b/beacon-chain/execution/metrics.go index 218318e5a5..a187891220 100644 --- a/beacon-chain/execution/metrics.go +++ b/beacon-chain/execution/metrics.go @@ -71,4 +71,8 @@ var ( Name: "reconstructed_execution_payload_count", Help: "Count the number of execution payloads that are reconstructed using JSON-RPC from payload headers", }) + errRequestTooLargeCount = promauto.NewCounter(prometheus.CounterOpts{ + Name: "execution_payload_bodies_count", + Help: "The number of requested payload bodies is too large", + }) ) diff --git a/config/features/config.go b/config/features/config.go index bd276a75c5..f9aa199b19 100644 --- a/config/features/config.go +++ b/config/features/config.go @@ -74,6 +74,7 @@ type Flags struct { DisableStakinContractCheck bool // Disables check for deposit contract when proposing blocks EnableVerboseSigVerification bool // EnableVerboseSigVerification specifies whether to verify individual signature if batch verification fails + EnableOptionalEngineMethods bool // EnableOptionalEngineMethods specifies whether to activate capella specific engine methods // KeystoreImportDebounceInterval specifies the time duration the validator waits to reload new keys if they have // changed on disk. This feature is for advanced use cases only. @@ -255,6 +256,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error { logEnabled(enableVerboseSigVerification) cfg.EnableVerboseSigVerification = true } + if ctx.IsSet(EnableOptionalEngineMethods.Name) { + logEnabled(EnableOptionalEngineMethods) + cfg.EnableOptionalEngineMethods = true + } Init(cfg) return nil } diff --git a/config/features/flags.go b/config/features/flags.go index 39bd4c09db..8f3cc8ee86 100644 --- a/config/features/flags.go +++ b/config/features/flags.go @@ -135,6 +135,10 @@ var ( Name: "enable-verbose-sig-verification", Usage: "Enables identifying invalid signatures if batch verification fails when processing block", } + EnableOptionalEngineMethods = &cli.BoolFlag{ + Name: "enable-optional-engine-methods", + Usage: "Enables the optional engine methods", + } ) // devModeFlags holds list of flags that are set when development mode is on. @@ -182,6 +186,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c disableDefensivePull, enableFullSSZDataLogging, enableVerboseSigVerification, + EnableOptionalEngineMethods, }...)...) // E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E. diff --git a/proto/engine/v1/execution_engine.pb.go b/proto/engine/v1/execution_engine.pb.go index d58c7c58b5..392f2da271 100755 --- a/proto/engine/v1/execution_engine.pb.go +++ b/proto/engine/v1/execution_engine.pb.go @@ -78,7 +78,7 @@ func (x PayloadStatus_Status) Number() protoreflect.EnumNumber { // Deprecated: Use PayloadStatus_Status.Descriptor instead. func (PayloadStatus_Status) EnumDescriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{8, 0} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{9, 0} } type ExecutionPayload struct { @@ -232,6 +232,61 @@ func (x *ExecutionPayload) GetTransactions() [][]byte { return nil } +type ExecutionPayloadBodyV1 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Transactions [][]byte `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"` + Withdrawals []*Withdrawal `protobuf:"bytes,2,rep,name=withdrawals,proto3" json:"withdrawals,omitempty"` +} + +func (x *ExecutionPayloadBodyV1) Reset() { + *x = ExecutionPayloadBodyV1{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExecutionPayloadBodyV1) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecutionPayloadBodyV1) ProtoMessage() {} + +func (x *ExecutionPayloadBodyV1) ProtoReflect() protoreflect.Message { + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] + 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 ExecutionPayloadBodyV1.ProtoReflect.Descriptor instead. +func (*ExecutionPayloadBodyV1) Descriptor() ([]byte, []int) { + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{1} +} + +func (x *ExecutionPayloadBodyV1) GetTransactions() [][]byte { + if x != nil { + return x.Transactions + } + return nil +} + +func (x *ExecutionPayloadBodyV1) GetWithdrawals() []*Withdrawal { + if x != nil { + return x.Withdrawals + } + return nil +} + type ExecutionPayloadCapella struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -257,7 +312,7 @@ type ExecutionPayloadCapella struct { func (x *ExecutionPayloadCapella) Reset() { *x = ExecutionPayloadCapella{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -270,7 +325,7 @@ func (x *ExecutionPayloadCapella) String() string { func (*ExecutionPayloadCapella) ProtoMessage() {} func (x *ExecutionPayloadCapella) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -283,7 +338,7 @@ func (x *ExecutionPayloadCapella) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadCapella.ProtoReflect.Descriptor instead. func (*ExecutionPayloadCapella) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{1} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{2} } func (x *ExecutionPayloadCapella) GetParentHash() []byte { @@ -403,7 +458,7 @@ type ExecutionPayloadCapellaWithValue struct { func (x *ExecutionPayloadCapellaWithValue) Reset() { *x = ExecutionPayloadCapellaWithValue{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -416,7 +471,7 @@ func (x *ExecutionPayloadCapellaWithValue) String() string { func (*ExecutionPayloadCapellaWithValue) ProtoMessage() {} func (x *ExecutionPayloadCapellaWithValue) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -429,7 +484,7 @@ func (x *ExecutionPayloadCapellaWithValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadCapellaWithValue.ProtoReflect.Descriptor instead. func (*ExecutionPayloadCapellaWithValue) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{2} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{3} } func (x *ExecutionPayloadCapellaWithValue) GetPayload() *ExecutionPayloadCapella { @@ -470,7 +525,7 @@ type ExecutionPayloadHeader struct { func (x *ExecutionPayloadHeader) Reset() { *x = ExecutionPayloadHeader{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -483,7 +538,7 @@ func (x *ExecutionPayloadHeader) String() string { func (*ExecutionPayloadHeader) ProtoMessage() {} func (x *ExecutionPayloadHeader) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -496,7 +551,7 @@ func (x *ExecutionPayloadHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadHeader.ProtoReflect.Descriptor instead. func (*ExecutionPayloadHeader) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{3} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{4} } func (x *ExecutionPayloadHeader) GetParentHash() []byte { @@ -622,7 +677,7 @@ type ExecutionPayloadHeaderCapella struct { func (x *ExecutionPayloadHeaderCapella) Reset() { *x = ExecutionPayloadHeaderCapella{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -635,7 +690,7 @@ func (x *ExecutionPayloadHeaderCapella) String() string { func (*ExecutionPayloadHeaderCapella) ProtoMessage() {} func (x *ExecutionPayloadHeaderCapella) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -648,7 +703,7 @@ func (x *ExecutionPayloadHeaderCapella) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadHeaderCapella.ProtoReflect.Descriptor instead. func (*ExecutionPayloadHeaderCapella) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{4} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{5} } func (x *ExecutionPayloadHeaderCapella) GetParentHash() []byte { @@ -769,7 +824,7 @@ type TransitionConfiguration struct { func (x *TransitionConfiguration) Reset() { *x = TransitionConfiguration{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -782,7 +837,7 @@ func (x *TransitionConfiguration) String() string { func (*TransitionConfiguration) ProtoMessage() {} func (x *TransitionConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -795,7 +850,7 @@ func (x *TransitionConfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use TransitionConfiguration.ProtoReflect.Descriptor instead. func (*TransitionConfiguration) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{5} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{6} } func (x *TransitionConfiguration) GetTerminalTotalDifficulty() string { @@ -832,7 +887,7 @@ type PayloadAttributes struct { func (x *PayloadAttributes) Reset() { *x = PayloadAttributes{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -845,7 +900,7 @@ func (x *PayloadAttributes) String() string { func (*PayloadAttributes) ProtoMessage() {} func (x *PayloadAttributes) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -858,7 +913,7 @@ func (x *PayloadAttributes) ProtoReflect() protoreflect.Message { // Deprecated: Use PayloadAttributes.ProtoReflect.Descriptor instead. func (*PayloadAttributes) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{6} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{7} } func (x *PayloadAttributes) GetTimestamp() uint64 { @@ -896,7 +951,7 @@ type PayloadAttributesV2 struct { func (x *PayloadAttributesV2) Reset() { *x = PayloadAttributesV2{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -909,7 +964,7 @@ func (x *PayloadAttributesV2) String() string { func (*PayloadAttributesV2) ProtoMessage() {} func (x *PayloadAttributesV2) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -922,7 +977,7 @@ func (x *PayloadAttributesV2) ProtoReflect() protoreflect.Message { // Deprecated: Use PayloadAttributesV2.ProtoReflect.Descriptor instead. func (*PayloadAttributesV2) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{7} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{8} } func (x *PayloadAttributesV2) GetTimestamp() uint64 { @@ -966,7 +1021,7 @@ type PayloadStatus struct { func (x *PayloadStatus) Reset() { *x = PayloadStatus{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -979,7 +1034,7 @@ func (x *PayloadStatus) String() string { func (*PayloadStatus) ProtoMessage() {} func (x *PayloadStatus) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -992,7 +1047,7 @@ func (x *PayloadStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use PayloadStatus.ProtoReflect.Descriptor instead. func (*PayloadStatus) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{8} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{9} } func (x *PayloadStatus) GetStatus() PayloadStatus_Status { @@ -1029,7 +1084,7 @@ type ForkchoiceState struct { func (x *ForkchoiceState) Reset() { *x = ForkchoiceState{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1042,7 +1097,7 @@ func (x *ForkchoiceState) String() string { func (*ForkchoiceState) ProtoMessage() {} func (x *ForkchoiceState) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1055,7 +1110,7 @@ func (x *ForkchoiceState) ProtoReflect() protoreflect.Message { // Deprecated: Use ForkchoiceState.ProtoReflect.Descriptor instead. func (*ForkchoiceState) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{9} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{10} } func (x *ForkchoiceState) GetHeadBlockHash() []byte { @@ -1093,7 +1148,7 @@ type Withdrawal struct { func (x *Withdrawal) Reset() { *x = Withdrawal{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1106,7 +1161,7 @@ func (x *Withdrawal) String() string { func (*Withdrawal) ProtoMessage() {} func (x *Withdrawal) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1119,7 +1174,7 @@ func (x *Withdrawal) ProtoReflect() protoreflect.Message { // Deprecated: Use Withdrawal.ProtoReflect.Descriptor instead. func (*Withdrawal) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{10} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{11} } func (x *Withdrawal) GetIndex() uint64 { @@ -1164,7 +1219,7 @@ type BlobsBundle struct { func (x *BlobsBundle) Reset() { *x = BlobsBundle{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1177,7 +1232,7 @@ func (x *BlobsBundle) String() string { func (*BlobsBundle) ProtoMessage() {} func (x *BlobsBundle) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1190,7 +1245,7 @@ func (x *BlobsBundle) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobsBundle.ProtoReflect.Descriptor instead. func (*BlobsBundle) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{11} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{12} } func (x *BlobsBundle) GetBlockHash() []byte { @@ -1232,7 +1287,7 @@ type Blob struct { func (x *Blob) Reset() { *x = Blob{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1245,7 +1300,7 @@ func (x *Blob) String() string { func (*Blob) ProtoMessage() {} func (x *Blob) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1258,7 +1313,7 @@ func (x *Blob) ProtoReflect() protoreflect.Message { // Deprecated: Use Blob.ProtoReflect.Descriptor instead. func (*Blob) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{12} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{13} } func (x *Blob) GetData() []byte { @@ -1313,7 +1368,15 @@ var file_proto_engine_v1_execution_engine_proto_rawDesc = []byte{ 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x1d, 0x8a, 0xb5, 0x18, 0x03, 0x3f, 0x2c, 0x3f, 0x92, 0xb5, 0x18, 0x12, 0x31, 0x30, 0x34, 0x38, 0x35, 0x37, 0x36, 0x2c, 0x31, 0x30, 0x37, 0x33, 0x37, 0x34, 0x31, 0x38, 0x32, 0x34, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x99, 0x05, 0x0a, 0x17, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7e, 0x0a, 0x16, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x42, 0x6f, 0x64, 0x79, 0x56, 0x31, 0x12, 0x22, + 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x40, 0x0a, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x69, 0x74, + 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x61, 0x6c, 0x73, 0x22, 0x99, 0x05, 0x0a, 0x17, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x61, 0x70, 0x65, 0x6c, 0x6c, 0x61, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0a, 0x70, @@ -1559,34 +1622,36 @@ func file_proto_engine_v1_execution_engine_proto_rawDescGZIP() []byte { } var file_proto_engine_v1_execution_engine_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_engine_v1_execution_engine_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_proto_engine_v1_execution_engine_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_proto_engine_v1_execution_engine_proto_goTypes = []interface{}{ (PayloadStatus_Status)(0), // 0: ethereum.engine.v1.PayloadStatus.Status (*ExecutionPayload)(nil), // 1: ethereum.engine.v1.ExecutionPayload - (*ExecutionPayloadCapella)(nil), // 2: ethereum.engine.v1.ExecutionPayloadCapella - (*ExecutionPayloadCapellaWithValue)(nil), // 3: ethereum.engine.v1.ExecutionPayloadCapellaWithValue - (*ExecutionPayloadHeader)(nil), // 4: ethereum.engine.v1.ExecutionPayloadHeader - (*ExecutionPayloadHeaderCapella)(nil), // 5: ethereum.engine.v1.ExecutionPayloadHeaderCapella - (*TransitionConfiguration)(nil), // 6: ethereum.engine.v1.TransitionConfiguration - (*PayloadAttributes)(nil), // 7: ethereum.engine.v1.PayloadAttributes - (*PayloadAttributesV2)(nil), // 8: ethereum.engine.v1.PayloadAttributesV2 - (*PayloadStatus)(nil), // 9: ethereum.engine.v1.PayloadStatus - (*ForkchoiceState)(nil), // 10: ethereum.engine.v1.ForkchoiceState - (*Withdrawal)(nil), // 11: ethereum.engine.v1.Withdrawal - (*BlobsBundle)(nil), // 12: ethereum.engine.v1.BlobsBundle - (*Blob)(nil), // 13: ethereum.engine.v1.Blob + (*ExecutionPayloadBodyV1)(nil), // 2: ethereum.engine.v1.ExecutionPayloadBodyV1 + (*ExecutionPayloadCapella)(nil), // 3: ethereum.engine.v1.ExecutionPayloadCapella + (*ExecutionPayloadCapellaWithValue)(nil), // 4: ethereum.engine.v1.ExecutionPayloadCapellaWithValue + (*ExecutionPayloadHeader)(nil), // 5: ethereum.engine.v1.ExecutionPayloadHeader + (*ExecutionPayloadHeaderCapella)(nil), // 6: ethereum.engine.v1.ExecutionPayloadHeaderCapella + (*TransitionConfiguration)(nil), // 7: ethereum.engine.v1.TransitionConfiguration + (*PayloadAttributes)(nil), // 8: ethereum.engine.v1.PayloadAttributes + (*PayloadAttributesV2)(nil), // 9: ethereum.engine.v1.PayloadAttributesV2 + (*PayloadStatus)(nil), // 10: ethereum.engine.v1.PayloadStatus + (*ForkchoiceState)(nil), // 11: ethereum.engine.v1.ForkchoiceState + (*Withdrawal)(nil), // 12: ethereum.engine.v1.Withdrawal + (*BlobsBundle)(nil), // 13: ethereum.engine.v1.BlobsBundle + (*Blob)(nil), // 14: ethereum.engine.v1.Blob } var file_proto_engine_v1_execution_engine_proto_depIdxs = []int32{ - 11, // 0: ethereum.engine.v1.ExecutionPayloadCapella.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 2, // 1: ethereum.engine.v1.ExecutionPayloadCapellaWithValue.payload:type_name -> ethereum.engine.v1.ExecutionPayloadCapella - 11, // 2: ethereum.engine.v1.PayloadAttributesV2.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 0, // 3: ethereum.engine.v1.PayloadStatus.status:type_name -> ethereum.engine.v1.PayloadStatus.Status - 13, // 4: ethereum.engine.v1.BlobsBundle.blobs:type_name -> ethereum.engine.v1.Blob - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 12, // 0: ethereum.engine.v1.ExecutionPayloadBodyV1.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 12, // 1: ethereum.engine.v1.ExecutionPayloadCapella.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 3, // 2: ethereum.engine.v1.ExecutionPayloadCapellaWithValue.payload:type_name -> ethereum.engine.v1.ExecutionPayloadCapella + 12, // 3: ethereum.engine.v1.PayloadAttributesV2.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 0, // 4: ethereum.engine.v1.PayloadStatus.status:type_name -> ethereum.engine.v1.PayloadStatus.Status + 14, // 5: ethereum.engine.v1.BlobsBundle.blobs:type_name -> ethereum.engine.v1.Blob + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_proto_engine_v1_execution_engine_proto_init() } @@ -1608,7 +1673,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionPayloadCapella); i { + switch v := v.(*ExecutionPayloadBodyV1); i { case 0: return &v.state case 1: @@ -1620,7 +1685,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionPayloadCapellaWithValue); i { + switch v := v.(*ExecutionPayloadCapella); i { case 0: return &v.state case 1: @@ -1632,7 +1697,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionPayloadHeader); i { + switch v := v.(*ExecutionPayloadCapellaWithValue); i { case 0: return &v.state case 1: @@ -1644,7 +1709,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionPayloadHeaderCapella); i { + switch v := v.(*ExecutionPayloadHeader); i { case 0: return &v.state case 1: @@ -1656,7 +1721,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransitionConfiguration); i { + switch v := v.(*ExecutionPayloadHeaderCapella); i { case 0: return &v.state case 1: @@ -1668,7 +1733,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PayloadAttributes); i { + switch v := v.(*TransitionConfiguration); i { case 0: return &v.state case 1: @@ -1680,7 +1745,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PayloadAttributesV2); i { + switch v := v.(*PayloadAttributes); i { case 0: return &v.state case 1: @@ -1692,7 +1757,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PayloadStatus); i { + switch v := v.(*PayloadAttributesV2); i { case 0: return &v.state case 1: @@ -1704,7 +1769,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ForkchoiceState); i { + switch v := v.(*PayloadStatus); i { case 0: return &v.state case 1: @@ -1716,7 +1781,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Withdrawal); i { + switch v := v.(*ForkchoiceState); i { case 0: return &v.state case 1: @@ -1728,7 +1793,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlobsBundle); i { + switch v := v.(*Withdrawal); i { case 0: return &v.state case 1: @@ -1740,6 +1805,18 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlobsBundle); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_engine_v1_execution_engine_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Blob); i { case 0: return &v.state @@ -1758,7 +1835,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_engine_v1_execution_engine_proto_rawDesc, NumEnums: 1, - NumMessages: 13, + NumMessages: 14, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/engine/v1/execution_engine.proto b/proto/engine/v1/execution_engine.proto index b988c4b817..5a4bceea14 100644 --- a/proto/engine/v1/execution_engine.proto +++ b/proto/engine/v1/execution_engine.proto @@ -41,6 +41,11 @@ message ExecutionPayload { repeated bytes transactions = 14 [(ethereum.eth.ext.ssz_size) = "?,?", (ethereum.eth.ext.ssz_max) = "1048576,1073741824"]; } +message ExecutionPayloadBodyV1 { + repeated bytes transactions = 1; + repeated Withdrawal withdrawals = 2; +} + message ExecutionPayloadCapella { bytes parent_hash = 1 [(ethereum.eth.ext.ssz_size) = "32"]; bytes fee_recipient = 2 [(ethereum.eth.ext.ssz_size) = "20"]; diff --git a/proto/engine/v1/json_marshal_unmarshal.go b/proto/engine/v1/json_marshal_unmarshal.go index f8af7a9740..fec0fb18da 100644 --- a/proto/engine/v1/json_marshal_unmarshal.go +++ b/proto/engine/v1/json_marshal_unmarshal.go @@ -638,3 +638,42 @@ func (f *ForkchoiceState) UnmarshalJSON(enc []byte) error { f.FinalizedBlockHash = dec.FinalizedBlockHash return nil } + +type executionPayloadBodyV1JSON struct { + Transactions []hexutil.Bytes `json:"transactions"` + Withdrawals []*Withdrawal `json:"withdrawals"` +} + +func (b *ExecutionPayloadBodyV1) MarshalJSON() ([]byte, error) { + transactions := make([]hexutil.Bytes, len(b.Transactions)) + for i, tx := range b.Transactions { + transactions[i] = tx + } + if len(b.Withdrawals) == 0 { + b.Withdrawals = make([]*Withdrawal, 0) + } + return json.Marshal(executionPayloadBodyV1JSON{ + Transactions: transactions, + Withdrawals: b.Withdrawals, + }) +} + +func (b *ExecutionPayloadBodyV1) UnmarshalJSON(enc []byte) error { + var decoded *executionPayloadBodyV1JSON + err := json.Unmarshal(enc, &decoded) + if err != nil { + return err + } + if len(decoded.Transactions) == 0 { + b.Transactions = make([][]byte, 0) + } + if len(decoded.Withdrawals) == 0 { + b.Withdrawals = make([]*Withdrawal, 0) + } + transactions := make([][]byte, len(decoded.Transactions)) + for i, tx := range decoded.Transactions { + transactions[i] = tx + } + b.Transactions = transactions + return nil +}