mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Engine API: new/get_payload for Capella (#11775)
* Engine API: new/get_payload for Capella * Fix build * Use switch for payload type check * Fix bad tests * Rm redundant arg Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
@@ -42,6 +42,7 @@ go_library(
|
|||||||
"//consensus-types/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
"//consensus-types/interfaces:go_default_library",
|
"//consensus-types/interfaces:go_default_library",
|
||||||
"//consensus-types/payload-attribute:go_default_library",
|
"//consensus-types/payload-attribute:go_default_library",
|
||||||
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//container/trie:go_default_library",
|
"//container/trie:go_default_library",
|
||||||
"//contracts/deposit:go_default_library",
|
"//contracts/deposit:go_default_library",
|
||||||
"//crypto/hash:go_default_library",
|
"//crypto/hash:go_default_library",
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
|
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
|
||||||
|
prysmType "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
)
|
)
|
||||||
@@ -30,12 +32,16 @@ import (
|
|||||||
const (
|
const (
|
||||||
// NewPayloadMethod v1 request string for JSON-RPC.
|
// NewPayloadMethod v1 request string for JSON-RPC.
|
||||||
NewPayloadMethod = "engine_newPayloadV1"
|
NewPayloadMethod = "engine_newPayloadV1"
|
||||||
|
// NewPayloadMethodV2 v2 request string for JSON-RPC.
|
||||||
|
NewPayloadMethodV2 = "engine_newPayloadV2"
|
||||||
// ForkchoiceUpdatedMethod v1 request string for JSON-RPC.
|
// ForkchoiceUpdatedMethod v1 request string for JSON-RPC.
|
||||||
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
||||||
// ForkchoiceUpdatedMethodV2 v2 request string for JSON-RPC.
|
// ForkchoiceUpdatedMethodV2 v2 request string for JSON-RPC.
|
||||||
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
|
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
|
||||||
// GetPayloadMethod v1 request string for JSON-RPC.
|
// GetPayloadMethod v1 request string for JSON-RPC.
|
||||||
GetPayloadMethod = "engine_getPayloadV1"
|
GetPayloadMethod = "engine_getPayloadV1"
|
||||||
|
// GetPayloadMethodV2 v2 request string for JSON-RPC.
|
||||||
|
GetPayloadMethodV2 = "engine_getPayloadV2"
|
||||||
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
|
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
|
||||||
ExchangeTransitionConfigurationMethod = "engine_exchangeTransitionConfigurationV1"
|
ExchangeTransitionConfigurationMethod = "engine_exchangeTransitionConfigurationV1"
|
||||||
// ExecutionBlockByHashMethod request string for JSON-RPC.
|
// ExecutionBlockByHashMethod request string for JSON-RPC.
|
||||||
@@ -72,7 +78,7 @@ type EngineCaller interface {
|
|||||||
ForkchoiceUpdated(
|
ForkchoiceUpdated(
|
||||||
ctx context.Context, state *pb.ForkchoiceState, attrs payloadattribute.Attributer,
|
ctx context.Context, state *pb.ForkchoiceState, attrs payloadattribute.Attributer,
|
||||||
) (*pb.PayloadIDBytes, []byte, error)
|
) (*pb.PayloadIDBytes, []byte, error)
|
||||||
GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error)
|
GetPayload(ctx context.Context, payloadId [8]byte, slot prysmType.Slot) (interfaces.ExecutionData, error)
|
||||||
ExchangeTransitionConfiguration(
|
ExchangeTransitionConfiguration(
|
||||||
ctx context.Context, cfg *pb.TransitionConfiguration,
|
ctx context.Context, cfg *pb.TransitionConfiguration,
|
||||||
) error
|
) error
|
||||||
@@ -80,7 +86,7 @@ type EngineCaller interface {
|
|||||||
GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error)
|
GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
// NewPayload calls the engine_newPayloadVX method via JSON-RPC.
|
||||||
func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionData) ([]byte, error) {
|
func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionData) ([]byte, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.NewPayload")
|
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.NewPayload")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -93,13 +99,28 @@ func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionDa
|
|||||||
ctx, cancel := context.WithDeadline(ctx, d)
|
ctx, cancel := context.WithDeadline(ctx, d)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
result := &pb.PayloadStatus{}
|
result := &pb.PayloadStatus{}
|
||||||
payloadPb, ok := payload.Proto().(*pb.ExecutionPayload)
|
|
||||||
if !ok {
|
switch payload.Proto().(type) {
|
||||||
return nil, errors.New("execution data must be an execution payload")
|
case *pb.ExecutionPayload:
|
||||||
}
|
payloadPb, ok := payload.Proto().(*pb.ExecutionPayload)
|
||||||
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payloadPb)
|
if !ok {
|
||||||
if err != nil {
|
return nil, errors.New("execution data must be a Bellatrix or Capella execution payload")
|
||||||
return nil, handleRPCError(err)
|
}
|
||||||
|
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payloadPb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, handleRPCError(err)
|
||||||
|
}
|
||||||
|
case *pb.ExecutionPayloadCapella:
|
||||||
|
payloadPb, ok := payload.Proto().(*pb.ExecutionPayloadCapella)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("execution data must be a Capella execution payload")
|
||||||
|
}
|
||||||
|
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethodV2, payloadPb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, handleRPCError(err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unknown execution data type")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch result.Status {
|
switch result.Status {
|
||||||
@@ -174,8 +195,8 @@ func (s *Service) ForkchoiceUpdated(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPayload calls the engine_getPayloadV1 method via JSON-RPC.
|
// GetPayload calls the engine_getPayloadVX method via JSON-RPC.
|
||||||
func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error) {
|
func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte, slot prysmType.Slot) (interfaces.ExecutionData, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayload")
|
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayload")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
@@ -186,9 +207,22 @@ func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.Execut
|
|||||||
d := time.Now().Add(defaultEngineTimeout)
|
d := time.Now().Add(defaultEngineTimeout)
|
||||||
ctx, cancel := context.WithDeadline(ctx, d)
|
ctx, cancel := context.WithDeadline(ctx, d)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
if slots.ToEpoch(slot) >= params.BeaconConfig().CapellaForkEpoch {
|
||||||
|
result := &pb.ExecutionPayloadCapella{}
|
||||||
|
err := s.rpcClient.CallContext(ctx, result, GetPayloadMethodV2, pb.PayloadIDBytes(payloadId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, handleRPCError(err)
|
||||||
|
}
|
||||||
|
return blocks.WrappedExecutionPayloadCapella(result)
|
||||||
|
}
|
||||||
|
|
||||||
result := &pb.ExecutionPayload{}
|
result := &pb.ExecutionPayload{}
|
||||||
err := s.rpcClient.CallContext(ctx, result, GetPayloadMethod, pb.PayloadIDBytes(payloadId))
|
err := s.rpcClient.CallContext(ctx, result, GetPayloadMethod, pb.PayloadIDBytes(payloadId))
|
||||||
return result, handleRPCError(err)
|
if err != nil {
|
||||||
|
return nil, handleRPCError(err)
|
||||||
|
}
|
||||||
|
return blocks.WrappedExecutionPayload(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExchangeTransitionConfiguration calls the engine_exchangeTransitionConfigurationV1 method via JSON-RPC.
|
// ExchangeTransitionConfiguration calls the engine_exchangeTransitionConfigurationV1 method via JSON-RPC.
|
||||||
|
|||||||
@@ -63,13 +63,30 @@ func TestClient_IPC(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
fix := fixtures()
|
fix := fixtures()
|
||||||
|
|
||||||
|
params.SetupTestConfigCleanup(t)
|
||||||
|
cfg := params.BeaconConfig().Copy()
|
||||||
|
cfg.CapellaForkEpoch = 1
|
||||||
|
params.OverrideBeaconConfig(cfg)
|
||||||
|
|
||||||
t.Run(GetPayloadMethod, func(t *testing.T) {
|
t.Run(GetPayloadMethod, func(t *testing.T) {
|
||||||
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||||
require.Equal(t, true, ok)
|
require.Equal(t, true, ok)
|
||||||
payloadId := [8]byte{1}
|
payloadId := [8]byte{1}
|
||||||
resp, err := srv.GetPayload(ctx, payloadId)
|
resp, err := srv.GetPayload(ctx, payloadId, 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.DeepEqual(t, want, resp)
|
resPb, err := resp.PbBellatrix()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, want, resPb)
|
||||||
|
})
|
||||||
|
t.Run(GetPayloadMethodV2, func(t *testing.T) {
|
||||||
|
want, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
payloadId := [8]byte{1}
|
||||||
|
resp, err := srv.GetPayload(ctx, payloadId, params.BeaconConfig().SlotsPerEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
resPb, err := resp.PbCapella()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, want, resPb)
|
||||||
})
|
})
|
||||||
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
|
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
|
||||||
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
||||||
@@ -102,6 +119,17 @@ func TestClient_IPC(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.DeepEqual(t, bytesutil.ToBytes32(want.LatestValidHash), bytesutil.ToBytes32(latestValidHash))
|
require.DeepEqual(t, bytesutil.ToBytes32(want.LatestValidHash), bytesutil.ToBytes32(latestValidHash))
|
||||||
})
|
})
|
||||||
|
t.Run(NewPayloadMethodV2, func(t *testing.T) {
|
||||||
|
want, ok := fix["ValidPayloadStatus"].(*pb.PayloadStatus)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
req, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
wrappedPayload, err := blocks.WrappedExecutionPayloadCapella(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
latestValidHash, err := srv.NewPayload(ctx, wrappedPayload)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, bytesutil.ToBytes32(want.LatestValidHash), bytesutil.ToBytes32(latestValidHash))
|
||||||
|
})
|
||||||
t.Run(ExchangeTransitionConfigurationMethod, func(t *testing.T) {
|
t.Run(ExchangeTransitionConfigurationMethod, func(t *testing.T) {
|
||||||
want, ok := fix["TransitionConfiguration"].(*pb.TransitionConfiguration)
|
want, ok := fix["TransitionConfiguration"].(*pb.TransitionConfiguration)
|
||||||
require.Equal(t, true, ok)
|
require.Equal(t, true, ok)
|
||||||
@@ -129,6 +157,11 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
fix := fixtures()
|
fix := fixtures()
|
||||||
|
|
||||||
|
params.SetupTestConfigCleanup(t)
|
||||||
|
cfg := params.BeaconConfig().Copy()
|
||||||
|
cfg.CapellaForkEpoch = 1
|
||||||
|
params.OverrideBeaconConfig(cfg)
|
||||||
|
|
||||||
t.Run(GetPayloadMethod, func(t *testing.T) {
|
t.Run(GetPayloadMethod, func(t *testing.T) {
|
||||||
payloadId := [8]byte{1}
|
payloadId := [8]byte{1}
|
||||||
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||||
@@ -167,9 +200,55 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
client.rpcClient = rpcClient
|
client.rpcClient = rpcClient
|
||||||
|
|
||||||
// We call the RPC method via HTTP and expect a proper result.
|
// We call the RPC method via HTTP and expect a proper result.
|
||||||
resp, err := client.GetPayload(ctx, payloadId)
|
resp, err := client.GetPayload(ctx, payloadId, 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.DeepEqual(t, want, resp)
|
pb, err := resp.PbBellatrix()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, want, pb)
|
||||||
|
})
|
||||||
|
t.Run(GetPayloadMethodV2, func(t *testing.T) {
|
||||||
|
payloadId := [8]byte{1}
|
||||||
|
want, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
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())
|
||||||
|
}()
|
||||||
|
enc, err := io.ReadAll(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
jsonRequestString := string(enc)
|
||||||
|
|
||||||
|
reqArg, err := json.Marshal(pb.PayloadIDBytes(payloadId))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We expect the JSON string RPC request contains the right arguments.
|
||||||
|
require.Equal(t, true, strings.Contains(
|
||||||
|
jsonRequestString, string(reqArg),
|
||||||
|
))
|
||||||
|
resp := map[string]interface{}{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"result": want,
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer rpcClient.Close()
|
||||||
|
|
||||||
|
client := &Service{}
|
||||||
|
client.rpcClient = rpcClient
|
||||||
|
|
||||||
|
// We call the RPC method via HTTP and expect a proper result.
|
||||||
|
resp, err := client.GetPayload(ctx, payloadId, params.BeaconConfig().SlotsPerEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
pb, err := resp.PbCapella()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, want, pb)
|
||||||
})
|
})
|
||||||
t.Run(ForkchoiceUpdatedMethod+" VALID status", func(t *testing.T) {
|
t.Run(ForkchoiceUpdatedMethod+" VALID status", func(t *testing.T) {
|
||||||
forkChoiceState := &pb.ForkchoiceState{
|
forkChoiceState := &pb.ForkchoiceState{
|
||||||
@@ -325,6 +404,20 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.DeepEqual(t, want.LatestValidHash, resp)
|
require.DeepEqual(t, want.LatestValidHash, resp)
|
||||||
})
|
})
|
||||||
|
t.Run(NewPayloadMethodV2+" VALID status", func(t *testing.T) {
|
||||||
|
execPayload, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
want, ok := fix["ValidPayloadStatus"].(*pb.PayloadStatus)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
client := newPayloadV2Setup(t, want, execPayload)
|
||||||
|
|
||||||
|
// We call the RPC method via HTTP and expect a proper result.
|
||||||
|
wrappedPayload, err := blocks.WrappedExecutionPayloadCapella(execPayload)
|
||||||
|
require.NoError(t, err)
|
||||||
|
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, want.LatestValidHash, resp)
|
||||||
|
})
|
||||||
t.Run(NewPayloadMethod+" SYNCING status", func(t *testing.T) {
|
t.Run(NewPayloadMethod+" SYNCING status", func(t *testing.T) {
|
||||||
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||||
require.Equal(t, true, ok)
|
require.Equal(t, true, ok)
|
||||||
@@ -339,6 +432,20 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
require.ErrorIs(t, ErrAcceptedSyncingPayloadStatus, err)
|
require.ErrorIs(t, ErrAcceptedSyncingPayloadStatus, err)
|
||||||
require.DeepEqual(t, []uint8(nil), resp)
|
require.DeepEqual(t, []uint8(nil), resp)
|
||||||
})
|
})
|
||||||
|
t.Run(NewPayloadMethodV2+" SYNCING status", func(t *testing.T) {
|
||||||
|
execPayload, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
want, ok := fix["SyncingStatus"].(*pb.PayloadStatus)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
client := newPayloadV2Setup(t, want, execPayload)
|
||||||
|
|
||||||
|
// We call the RPC method via HTTP and expect a proper result.
|
||||||
|
wrappedPayload, err := blocks.WrappedExecutionPayloadCapella(execPayload)
|
||||||
|
require.NoError(t, err)
|
||||||
|
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||||
|
require.ErrorIs(t, ErrAcceptedSyncingPayloadStatus, err)
|
||||||
|
require.DeepEqual(t, []uint8(nil), resp)
|
||||||
|
})
|
||||||
t.Run(NewPayloadMethod+" INVALID_BLOCK_HASH status", func(t *testing.T) {
|
t.Run(NewPayloadMethod+" INVALID_BLOCK_HASH status", func(t *testing.T) {
|
||||||
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||||
require.Equal(t, true, ok)
|
require.Equal(t, true, ok)
|
||||||
@@ -353,6 +460,20 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
require.ErrorIs(t, ErrInvalidBlockHashPayloadStatus, err)
|
require.ErrorIs(t, ErrInvalidBlockHashPayloadStatus, err)
|
||||||
require.DeepEqual(t, []uint8(nil), resp)
|
require.DeepEqual(t, []uint8(nil), resp)
|
||||||
})
|
})
|
||||||
|
t.Run(NewPayloadMethodV2+" INVALID_BLOCK_HASH status", func(t *testing.T) {
|
||||||
|
execPayload, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
want, ok := fix["InvalidBlockHashStatus"].(*pb.PayloadStatus)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
client := newPayloadV2Setup(t, want, execPayload)
|
||||||
|
|
||||||
|
// We call the RPC method via HTTP and expect a proper result.
|
||||||
|
wrappedPayload, err := blocks.WrappedExecutionPayloadCapella(execPayload)
|
||||||
|
require.NoError(t, err)
|
||||||
|
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||||
|
require.ErrorIs(t, ErrInvalidBlockHashPayloadStatus, err)
|
||||||
|
require.DeepEqual(t, []uint8(nil), resp)
|
||||||
|
})
|
||||||
t.Run(NewPayloadMethod+" INVALID status", func(t *testing.T) {
|
t.Run(NewPayloadMethod+" INVALID status", func(t *testing.T) {
|
||||||
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||||
require.Equal(t, true, ok)
|
require.Equal(t, true, ok)
|
||||||
@@ -367,6 +488,20 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
require.ErrorIs(t, ErrInvalidPayloadStatus, err)
|
require.ErrorIs(t, ErrInvalidPayloadStatus, err)
|
||||||
require.DeepEqual(t, want.LatestValidHash, resp)
|
require.DeepEqual(t, want.LatestValidHash, resp)
|
||||||
})
|
})
|
||||||
|
t.Run(NewPayloadMethodV2+" INVALID status", func(t *testing.T) {
|
||||||
|
execPayload, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
want, ok := fix["InvalidStatus"].(*pb.PayloadStatus)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
client := newPayloadV2Setup(t, want, execPayload)
|
||||||
|
|
||||||
|
// We call the RPC method via HTTP and expect a proper result.
|
||||||
|
wrappedPayload, err := blocks.WrappedExecutionPayloadCapella(execPayload)
|
||||||
|
require.NoError(t, err)
|
||||||
|
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||||
|
require.ErrorIs(t, ErrInvalidPayloadStatus, err)
|
||||||
|
require.DeepEqual(t, want.LatestValidHash, resp)
|
||||||
|
})
|
||||||
t.Run(NewPayloadMethod+" UNKNOWN status", func(t *testing.T) {
|
t.Run(NewPayloadMethod+" UNKNOWN status", func(t *testing.T) {
|
||||||
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||||
require.Equal(t, true, ok)
|
require.Equal(t, true, ok)
|
||||||
@@ -1142,6 +1277,23 @@ func fixtures() map[string]interface{} {
|
|||||||
BlockHash: foo[:],
|
BlockHash: foo[:],
|
||||||
Transactions: [][]byte{foo[:]},
|
Transactions: [][]byte{foo[:]},
|
||||||
}
|
}
|
||||||
|
executionPayloadFixtureCapella := &pb.ExecutionPayloadCapella{
|
||||||
|
ParentHash: foo[:],
|
||||||
|
FeeRecipient: bar,
|
||||||
|
StateRoot: foo[:],
|
||||||
|
ReceiptsRoot: foo[:],
|
||||||
|
LogsBloom: baz,
|
||||||
|
PrevRandao: foo[:],
|
||||||
|
BlockNumber: 1,
|
||||||
|
GasLimit: 1,
|
||||||
|
GasUsed: 1,
|
||||||
|
Timestamp: 1,
|
||||||
|
ExtraData: foo[:],
|
||||||
|
BaseFeePerGas: bytesutil.PadTo(baseFeePerGas.Bytes(), fieldparams.RootLength),
|
||||||
|
BlockHash: foo[:],
|
||||||
|
Transactions: [][]byte{foo[:]},
|
||||||
|
Withdrawals: []*pb.Withdrawal{},
|
||||||
|
}
|
||||||
parent := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength)
|
parent := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength)
|
||||||
sha3Uncles := bytesutil.PadTo([]byte("sha3Uncles"), fieldparams.RootLength)
|
sha3Uncles := bytesutil.PadTo([]byte("sha3Uncles"), fieldparams.RootLength)
|
||||||
miner := bytesutil.PadTo([]byte("miner"), fieldparams.FeeRecipientLength)
|
miner := bytesutil.PadTo([]byte("miner"), fieldparams.FeeRecipientLength)
|
||||||
@@ -1236,6 +1388,7 @@ func fixtures() map[string]interface{} {
|
|||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"ExecutionBlock": executionBlock,
|
"ExecutionBlock": executionBlock,
|
||||||
"ExecutionPayload": executionPayloadFixture,
|
"ExecutionPayload": executionPayloadFixture,
|
||||||
|
"ExecutionPayloadCapella": executionPayloadFixtureCapella,
|
||||||
"ValidPayloadStatus": validStatus,
|
"ValidPayloadStatus": validStatus,
|
||||||
"InvalidBlockHashStatus": inValidBlockHashStatus,
|
"InvalidBlockHashStatus": inValidBlockHashStatus,
|
||||||
"AcceptedStatus": acceptedStatus,
|
"AcceptedStatus": acceptedStatus,
|
||||||
@@ -1419,6 +1572,17 @@ func (*testEngineService) GetPayloadV1(
|
|||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*testEngineService) GetPayloadV2(
|
||||||
|
_ context.Context, _ pb.PayloadIDBytes,
|
||||||
|
) *pb.ExecutionPayloadCapella {
|
||||||
|
fix := fixtures()
|
||||||
|
item, ok := fix["ExecutionPayloadCapella"].(*pb.ExecutionPayloadCapella)
|
||||||
|
if !ok {
|
||||||
|
panic("not found")
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
func (*testEngineService) ExchangeTransitionConfigurationV1(
|
func (*testEngineService) ExchangeTransitionConfigurationV1(
|
||||||
_ context.Context, _ *pb.TransitionConfiguration,
|
_ context.Context, _ *pb.TransitionConfiguration,
|
||||||
) *pb.TransitionConfiguration {
|
) *pb.TransitionConfiguration {
|
||||||
@@ -1465,6 +1629,17 @@ func (*testEngineService) NewPayloadV1(
|
|||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*testEngineService) NewPayloadV2(
|
||||||
|
_ context.Context, _ *pb.ExecutionPayloadCapella,
|
||||||
|
) *pb.PayloadStatus {
|
||||||
|
fix := fixtures()
|
||||||
|
item, ok := fix["ValidPayloadStatus"].(*pb.PayloadStatus)
|
||||||
|
if !ok {
|
||||||
|
panic("not found")
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
func forkchoiceUpdateSetup(t *testing.T, fcs *pb.ForkchoiceState, att *pb.PayloadAttributes, res *ForkchoiceUpdatedResponse) *Service {
|
func forkchoiceUpdateSetup(t *testing.T, fcs *pb.ForkchoiceState, att *pb.PayloadAttributes, res *ForkchoiceUpdatedResponse) *Service {
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -1576,3 +1751,37 @@ func newPayloadSetup(t *testing.T, status *pb.PayloadStatus, payload *pb.Executi
|
|||||||
service.rpcClient = rpcClient
|
service.rpcClient = rpcClient
|
||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newPayloadV2Setup(t *testing.T, status *pb.PayloadStatus, payload *pb.ExecutionPayloadCapella) *Service {
|
||||||
|
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())
|
||||||
|
}()
|
||||||
|
enc, err := io.ReadAll(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
jsonRequestString := string(enc)
|
||||||
|
|
||||||
|
reqArg, err := json.Marshal(payload)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We expect the JSON string RPC request contains the right arguments.
|
||||||
|
require.Equal(t, true, strings.Contains(
|
||||||
|
jsonRequestString, string(reqArg),
|
||||||
|
))
|
||||||
|
resp := map[string]interface{}{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"result": status,
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}))
|
||||||
|
|
||||||
|
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
service := &Service{}
|
||||||
|
service.rpcClient = rpcClient
|
||||||
|
return service
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ go_library(
|
|||||||
"//consensus-types/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
"//consensus-types/interfaces:go_default_library",
|
"//consensus-types/interfaces:go_default_library",
|
||||||
"//consensus-types/payload-attribute:go_default_library",
|
"//consensus-types/payload-attribute:go_default_library",
|
||||||
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
|
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
)
|
)
|
||||||
@@ -53,8 +54,12 @@ func (e *EngineClient) ForkchoiceUpdated(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPayload --
|
// GetPayload --
|
||||||
func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte) (*pb.ExecutionPayload, error) {
|
func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte, _ types.Slot) (interfaces.ExecutionData, error) {
|
||||||
return e.ExecutionPayload, e.ErrGetPayload
|
p, err := blocks.WrappedExecutionPayload(e.ExecutionPayload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return p, e.ErrGetPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExchangeTransitionConfiguration --
|
// ExchangeTransitionConfiguration --
|
||||||
|
|||||||
@@ -68,11 +68,15 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
|||||||
var pid [8]byte
|
var pid [8]byte
|
||||||
copy(pid[:], payloadId[:])
|
copy(pid[:], payloadId[:])
|
||||||
payloadIDCacheHit.Inc()
|
payloadIDCacheHit.Inc()
|
||||||
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, pid)
|
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, pid, slot)
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
pb, err := payload.PbBellatrix()
|
||||||
return payload, nil
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
warnIfFeeRecipientDiffers(pb, feeRecipient)
|
||||||
|
return pb, nil
|
||||||
case errors.Is(err, context.DeadlineExceeded):
|
case errors.Is(err, context.DeadlineExceeded):
|
||||||
default:
|
default:
|
||||||
return nil, errors.Wrap(err, "could not get cached payload from execution client")
|
return nil, errors.Wrap(err, "could not get cached payload from execution client")
|
||||||
@@ -168,12 +172,16 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
|||||||
if payloadID == nil {
|
if payloadID == nil {
|
||||||
return nil, fmt.Errorf("nil payload with block hash: %#x", parentHash)
|
return nil, fmt.Errorf("nil payload with block hash: %#x", parentHash)
|
||||||
}
|
}
|
||||||
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID)
|
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID, slot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
pb, err := payload.PbBellatrix()
|
||||||
return payload, nil
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
warnIfFeeRecipientDiffers(pb, feeRecipient)
|
||||||
|
return pb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// warnIfFeeRecipientDiffers logs a warning if the fee recipient in the included payload does not
|
// warnIfFeeRecipientDiffers logs a warning if the fee recipient in the included payload does not
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
|||||||
params.OverrideBeaconConfig(cfg)
|
params.OverrideBeaconConfig(cfg)
|
||||||
|
|
||||||
vs := &Server{
|
vs := &Server{
|
||||||
ExecutionEngineCaller: &powtesting.EngineClient{PayloadIDBytes: tt.payloadID, ErrForkchoiceUpdated: tt.forkchoiceErr},
|
ExecutionEngineCaller: &powtesting.EngineClient{PayloadIDBytes: tt.payloadID, ErrForkchoiceUpdated: tt.forkchoiceErr, ExecutionPayload: &pb.ExecutionPayload{}},
|
||||||
HeadFetcher: &chainMock.ChainService{State: tt.st},
|
HeadFetcher: &chainMock.ChainService{State: tt.st},
|
||||||
BeaconDB: beaconDB,
|
BeaconDB: beaconDB,
|
||||||
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
||||||
@@ -153,7 +153,7 @@ func TestServer_getExecutionPayloadContextTimeout(t *testing.T) {
|
|||||||
params.OverrideBeaconConfig(cfg)
|
params.OverrideBeaconConfig(cfg)
|
||||||
|
|
||||||
vs := &Server{
|
vs := &Server{
|
||||||
ExecutionEngineCaller: &powtesting.EngineClient{PayloadIDBytes: &pb.PayloadIDBytes{}, ErrGetPayload: context.DeadlineExceeded},
|
ExecutionEngineCaller: &powtesting.EngineClient{PayloadIDBytes: &pb.PayloadIDBytes{}, ErrGetPayload: context.DeadlineExceeded, ExecutionPayload: &pb.ExecutionPayload{}},
|
||||||
HeadFetcher: &chainMock.ChainService{State: nonTransitionSt},
|
HeadFetcher: &chainMock.ChainService{State: nonTransitionSt},
|
||||||
BeaconDB: beaconDB,
|
BeaconDB: beaconDB,
|
||||||
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
|
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
@@ -77,12 +78,10 @@ type engineMock struct {
|
|||||||
payloadStatus error
|
payloadStatus error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *engineMock) GetPayload(context.Context, [8]byte) (*pb.ExecutionPayload, error) {
|
func (m *engineMock) GetPayload(context.Context, [8]byte, types.Slot) (interfaces.ExecutionData, error) {
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
func (m *engineMock) GetPayloadV2(context.Context, [8]byte) (*pb.ExecutionPayloadCapella, error) {
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *engineMock) ForkchoiceUpdated(context.Context, *pb.ForkchoiceState, payloadattribute.Attributer) (*pb.PayloadIDBytes, []byte, error) {
|
func (m *engineMock) ForkchoiceUpdated(context.Context, *pb.ForkchoiceState, payloadattribute.Attributer) (*pb.PayloadIDBytes, []byte, error) {
|
||||||
return nil, m.latestValidHash, m.payloadStatus
|
return nil, m.latestValidHash, m.payloadStatus
|
||||||
}
|
}
|
||||||
@@ -90,7 +89,7 @@ func (m *engineMock) NewPayload(context.Context, interfaces.ExecutionData) ([]by
|
|||||||
return m.latestValidHash, m.payloadStatus
|
return m.latestValidHash, m.payloadStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *engineMock) LatestExecutionBlock(context.Context) (*pb.ExecutionBlock, error) {
|
func (m *engineMock) LatestExecutionBlock() (*pb.ExecutionBlock, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user