mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
60 Commits
sleep-with
...
engine-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fac371616 | ||
|
|
2dd2f7b59b | ||
|
|
09a257af5c | ||
|
|
bfe8941dde | ||
|
|
09180cab28 | ||
|
|
7fd4a7f3e0 | ||
|
|
3744481132 | ||
|
|
86a82c59e6 | ||
|
|
362a6f66de | ||
|
|
072b65e564 | ||
|
|
398e78992d | ||
|
|
1b380b6105 | ||
|
|
61963c7d5e | ||
|
|
520637e225 | ||
|
|
2213fa9322 | ||
|
|
e448296acf | ||
|
|
25a0c50ae2 | ||
|
|
d911da694f | ||
|
|
a146245c23 | ||
|
|
5a308b71c8 | ||
|
|
cb343d586d | ||
|
|
501282cb9f | ||
|
|
f705134ba4 | ||
|
|
588aafaf06 | ||
|
|
ee94b939e1 | ||
|
|
c06367e0af | ||
|
|
928d60c5c5 | ||
|
|
19a476f767 | ||
|
|
91490c7f65 | ||
|
|
fe90a9ba9e | ||
|
|
c43bfc6614 | ||
|
|
181bc56476 | ||
|
|
3a567ccbdd | ||
|
|
700ddb3fb3 | ||
|
|
bea6022ff4 | ||
|
|
33e41d6a8a | ||
|
|
a4e966f890 | ||
|
|
948d30f691 | ||
|
|
1f79b34d13 | ||
|
|
3c91ce1358 | ||
|
|
f57dd0c268 | ||
|
|
d10f761b91 | ||
|
|
fe8e82363d | ||
|
|
f5f6e23432 | ||
|
|
f207887300 | ||
|
|
be274b16e7 | ||
|
|
90010b7db7 | ||
|
|
5761a44da2 | ||
|
|
ff819037bd | ||
|
|
2fefd798cd | ||
|
|
a3f5422f84 | ||
|
|
54d9595dc0 | ||
|
|
56f856c8ce | ||
|
|
e5b41dd8ed | ||
|
|
1fc9006294 | ||
|
|
3a5f4f7451 | ||
|
|
cd5de3e203 | ||
|
|
290daf2e78 | ||
|
|
fdf1b9756b | ||
|
|
0616f953e0 |
@@ -1,4 +1,4 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -11,6 +11,21 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["client_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/pkg/errors"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
||||
// GetPayloadMethod v1 request string for JSON-RPC.
|
||||
GetPayloadMethod = "engine_getPayloadV1"
|
||||
// ExecutionBlockByHashMethod request string for JSON-RPC.
|
||||
ExecutionBlockByHashMethod = "eth_blockByHash"
|
||||
// LatestExecutionBlockMethod request string for JSON-RPC.
|
||||
LatestExecutionBlockMethod = "eth_blockByNumber"
|
||||
// DefaultTimeout for HTTP.
|
||||
DefaultTimeout = time.Second * 5
|
||||
)
|
||||
@@ -27,8 +32,8 @@ const (
|
||||
// ForkchoiceUpdatedResponse is the response kind received by the
|
||||
// engine_forkchoiceUpdatedV1 endpoint.
|
||||
type ForkchoiceUpdatedResponse struct {
|
||||
Status *pb.PayloadStatus `json:"status"`
|
||||
PayloadId [8]byte `json:"payloadId"`
|
||||
Status *pb.PayloadStatus `json:"status"`
|
||||
PayloadId *pb.PayloadIDBytes `json:"payloadId"`
|
||||
}
|
||||
|
||||
// Client defines a new engine API client for the Prysm consensus node
|
||||
@@ -67,19 +72,75 @@ func New(ctx context.Context, endpoint string, opts ...Option) (*Client, error)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewPayload --
|
||||
func (*Client) NewPayload(_ context.Context, _ *pb.ExecutionPayload) (*pb.PayloadStatus, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
||||
func (c *Client) NewPayload(ctx context.Context, payload *pb.ExecutionPayload) (*pb.PayloadStatus, error) {
|
||||
result := &pb.PayloadStatus{}
|
||||
err := c.rpc.CallContext(ctx, result, NewPayloadMethod, payload)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// ForkchoiceUpdated --
|
||||
func (*Client) ForkchoiceUpdated(
|
||||
_ context.Context, _ *pb.ForkchoiceState, _ *pb.PayloadAttributes,
|
||||
// ForkchoiceUpdated calls the engine_forkchoiceUpdatedV1 method via JSON-RPC.
|
||||
func (c *Client) ForkchoiceUpdated(
|
||||
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
result := &ForkchoiceUpdatedResponse{}
|
||||
err := c.rpc.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, attrs)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// GetPayload --
|
||||
func (*Client) GetPayload(_ context.Context, _ [8]byte) (*pb.ExecutionPayload, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
// GetPayload calls the engine_getPayloadV1 method via JSON-RPC.
|
||||
func (c *Client) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error) {
|
||||
result := &pb.ExecutionPayload{}
|
||||
err := c.rpc.CallContext(ctx, result, GetPayloadMethod, pb.PayloadIDBytes(payloadId))
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// LatestExecutionBlock fetches the latest execution engine block by calling
|
||||
// eth_blockByNumber via JSON-RPC.
|
||||
func (c *Client) LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock, error) {
|
||||
result := &pb.ExecutionBlock{}
|
||||
err := c.rpc.CallContext(ctx, result, LatestExecutionBlockMethod)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// ExecutionBlockByHash fetches an execution engine block by hash by calling
|
||||
// eth_blockByHash via JSON-RPC.
|
||||
func (c *Client) ExecutionBlockByHash(ctx context.Context, hash common.Hash) (*pb.ExecutionBlock, error) {
|
||||
result := &pb.ExecutionBlock{}
|
||||
err := c.rpc.CallContext(ctx, result, ExecutionBlockByHashMethod, hash)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// Handles errors received from the RPC server according to the specification.
|
||||
func handleRPCError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
e, ok := err.(rpc.Error)
|
||||
if !ok {
|
||||
return errors.Wrap(err, "got an unexpected error")
|
||||
}
|
||||
switch e.ErrorCode() {
|
||||
case -32700:
|
||||
return ErrParse
|
||||
case -32600:
|
||||
return ErrInvalidRequest
|
||||
case -32601:
|
||||
return ErrMethodNotFound
|
||||
case -32602:
|
||||
return ErrInvalidParams
|
||||
case -32603:
|
||||
return ErrInternal
|
||||
case -32001:
|
||||
return ErrUnknownPayload
|
||||
case -32000:
|
||||
// Only -32000 status codes are data errors in the RPC specification.
|
||||
errWithData, ok := err.(rpc.DataError)
|
||||
if !ok {
|
||||
return errors.Wrap(err, "got an unexpected error")
|
||||
}
|
||||
return errors.Wrapf(ErrServer, "%v", errWithData.ErrorData())
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
511
beacon-chain/powchain/engine-api-client/v1/client_test.go
Normal file
511
beacon-chain/powchain/engine-api-client/v1/client_test.go
Normal file
@@ -0,0 +1,511 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestClient_IPC(t *testing.T) {
|
||||
server := newTestIPCServer(t)
|
||||
defer server.Stop()
|
||||
rpcClient := rpc.DialInProc(server)
|
||||
defer rpcClient.Close()
|
||||
client := &Client{}
|
||||
client.rpc = rpcClient
|
||||
ctx := context.Background()
|
||||
fix := fixtures()
|
||||
|
||||
t.Run(GetPayloadMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
payloadId := [8]byte{1}
|
||||
resp, err := client.GetPayload(ctx, payloadId)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
|
||||
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
||||
require.Equal(t, true, ok)
|
||||
resp, err := client.ForkchoiceUpdated(ctx, &pb.ForkchoiceState{}, &pb.PayloadAttributes{})
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want.Status, resp.Status)
|
||||
require.DeepEqual(t, want.PayloadId, resp.PayloadId)
|
||||
})
|
||||
t.Run(NewPayloadMethod, func(t *testing.T) {
|
||||
want, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
|
||||
require.Equal(t, true, ok)
|
||||
req, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
resp, err := client.NewPayload(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(LatestExecutionBlockMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
require.Equal(t, true, ok)
|
||||
resp, err := client.LatestExecutionBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ExecutionBlockByHashMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
require.Equal(t, true, ok)
|
||||
arg := common.BytesToHash([]byte("foo"))
|
||||
resp, err := client.ExecutionBlockByHash(ctx, arg)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_HTTP(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
fix := fixtures()
|
||||
|
||||
t.Run(GetPayloadMethod, func(t *testing.T) {
|
||||
payloadId := [8]byte{1}
|
||||
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
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 := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
|
||||
reqArg, err := json.Marshal(pb.PayloadIDBytes(payloadId))
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Println(jsonRequestString)
|
||||
|
||||
// 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 := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.GetPayload(ctx, payloadId)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
|
||||
forkChoiceState := &pb.ForkchoiceState{
|
||||
HeadBlockHash: []byte("head"),
|
||||
SafeBlockHash: []byte("safe"),
|
||||
FinalizedBlockHash: []byte("finalized"),
|
||||
}
|
||||
payloadAttributes := &pb.PayloadAttributes{
|
||||
Timestamp: 1,
|
||||
Random: []byte("random"),
|
||||
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
|
||||
}
|
||||
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
||||
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 := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
|
||||
forkChoiceStateReq, err := json.Marshal(forkChoiceState)
|
||||
require.NoError(t, err)
|
||||
payloadAttrsReq, err := json.Marshal(payloadAttributes)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the JSON string RPC request contains the right arguments.
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, string(forkChoiceStateReq),
|
||||
))
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, string(payloadAttrsReq),
|
||||
))
|
||||
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 := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want.Status, resp.Status)
|
||||
require.DeepEqual(t, want.PayloadId, resp.PayloadId)
|
||||
})
|
||||
t.Run(NewPayloadMethod, func(t *testing.T) {
|
||||
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
want, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
|
||||
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 := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
|
||||
reqArg, err := json.Marshal(execPayload)
|
||||
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 := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.NewPayload(ctx, execPayload)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(LatestExecutionBlockMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
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())
|
||||
}()
|
||||
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 := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.LatestExecutionBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ExecutionBlockByHashMethod, func(t *testing.T) {
|
||||
arg := common.BytesToHash([]byte("foo"))
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
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 := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
// We expect the JSON string RPC request contains the right arguments.
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, fmt.Sprintf("%#x", arg),
|
||||
))
|
||||
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 := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.ExecutionBlockByHash(ctx, arg)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
}
|
||||
|
||||
type customError struct {
|
||||
code int
|
||||
}
|
||||
|
||||
func (c *customError) ErrorCode() int {
|
||||
return c.code
|
||||
}
|
||||
|
||||
func (*customError) Error() string {
|
||||
return "something went wrong"
|
||||
}
|
||||
|
||||
type dataError struct {
|
||||
code int
|
||||
data interface{}
|
||||
}
|
||||
|
||||
func (c *dataError) ErrorCode() int {
|
||||
return c.code
|
||||
}
|
||||
|
||||
func (*dataError) Error() string {
|
||||
return "something went wrong"
|
||||
}
|
||||
|
||||
func (c *dataError) ErrorData() interface{} {
|
||||
return c.data
|
||||
}
|
||||
|
||||
func Test_handleRPCError(t *testing.T) {
|
||||
got := handleRPCError(nil)
|
||||
require.Equal(t, true, got == nil)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
expected error
|
||||
expectedContains string
|
||||
given error
|
||||
}{
|
||||
{
|
||||
name: "not an rpc error",
|
||||
expectedContains: "got an unexpected error",
|
||||
given: errors.New("foo"),
|
||||
},
|
||||
{
|
||||
name: "ErrParse",
|
||||
expectedContains: ErrParse.Error(),
|
||||
given: &customError{code: -32700},
|
||||
},
|
||||
{
|
||||
name: "ErrInvalidRequest",
|
||||
expectedContains: ErrInvalidRequest.Error(),
|
||||
given: &customError{code: -32600},
|
||||
},
|
||||
{
|
||||
name: "ErrMethodNotFound",
|
||||
expectedContains: ErrMethodNotFound.Error(),
|
||||
given: &customError{code: -32601},
|
||||
},
|
||||
{
|
||||
name: "ErrInvalidParams",
|
||||
expectedContains: ErrInvalidParams.Error(),
|
||||
given: &customError{code: -32602},
|
||||
},
|
||||
{
|
||||
name: "ErrInternal",
|
||||
expectedContains: ErrInternal.Error(),
|
||||
given: &customError{code: -32603},
|
||||
},
|
||||
{
|
||||
name: "ErrUnknownPayload",
|
||||
expectedContains: ErrUnknownPayload.Error(),
|
||||
given: &customError{code: -32001},
|
||||
},
|
||||
{
|
||||
name: "ErrServer unexpected no data",
|
||||
expectedContains: "got an unexpected error",
|
||||
given: &customError{code: -32000},
|
||||
},
|
||||
{
|
||||
name: "ErrServer with data",
|
||||
expectedContains: ErrServer.Error(),
|
||||
given: &dataError{code: -32000, data: 5},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := handleRPCError(tt.given)
|
||||
require.ErrorContains(t, tt.expectedContains, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newTestIPCServer(t *testing.T) *rpc.Server {
|
||||
server := rpc.NewServer()
|
||||
err := server.RegisterName("engine", new(testEngineService))
|
||||
require.NoError(t, err)
|
||||
err = server.RegisterName("eth", new(testEngineService))
|
||||
require.NoError(t, err)
|
||||
return server
|
||||
}
|
||||
|
||||
func fixtures() map[string]interface{} {
|
||||
foo := bytesutil.ToBytes32([]byte("foo"))
|
||||
bar := bytesutil.PadTo([]byte("bar"), 20)
|
||||
baz := bytesutil.PadTo([]byte("baz"), 256)
|
||||
executionPayloadFixture := &pb.ExecutionPayload{
|
||||
ParentHash: foo[:],
|
||||
FeeRecipient: bar,
|
||||
StateRoot: foo[:],
|
||||
ReceiptsRoot: foo[:],
|
||||
LogsBloom: baz,
|
||||
Random: foo[:],
|
||||
BlockNumber: 1,
|
||||
GasLimit: 1,
|
||||
GasUsed: 1,
|
||||
Timestamp: 1,
|
||||
ExtraData: foo[:],
|
||||
BaseFeePerGas: foo[:],
|
||||
BlockHash: foo[:],
|
||||
Transactions: [][]byte{foo[:]},
|
||||
}
|
||||
executionBlock := &pb.ExecutionBlock{
|
||||
Number: []byte("100"),
|
||||
Hash: []byte("hash"),
|
||||
ParentHash: []byte("parentHash"),
|
||||
Sha3Uncles: []byte("sha3Uncles"),
|
||||
Miner: []byte("miner"),
|
||||
StateRoot: []byte("sha3Uncles"),
|
||||
TransactionsRoot: []byte("transactionsRoot"),
|
||||
ReceiptsRoot: []byte("receiptsRoot"),
|
||||
LogsBloom: []byte("logsBloom"),
|
||||
Difficulty: []byte("1"),
|
||||
TotalDifficulty: []byte("2"),
|
||||
GasLimit: 3,
|
||||
GasUsed: 4,
|
||||
Timestamp: 5,
|
||||
Size: []byte("6"),
|
||||
ExtraData: []byte("extraData"),
|
||||
BaseFeePerGas: []byte("baseFeePerGas"),
|
||||
Transactions: [][]byte{foo[:]},
|
||||
Uncles: [][]byte{foo[:]},
|
||||
}
|
||||
status := &pb.PayloadStatus{
|
||||
Status: pb.PayloadStatus_ACCEPTED,
|
||||
LatestValidHash: foo[:],
|
||||
ValidationError: "",
|
||||
}
|
||||
id := pb.PayloadIDBytes([8]byte{1, 0, 0, 0, 0, 0, 0, 0})
|
||||
forkChoiceResp := &ForkchoiceUpdatedResponse{
|
||||
Status: status,
|
||||
PayloadId: &id,
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"ExecutionBlock": executionBlock,
|
||||
"ExecutionPayload": executionPayloadFixture,
|
||||
"PayloadStatus": status,
|
||||
"ForkchoiceUpdatedResponse": forkChoiceResp,
|
||||
}
|
||||
}
|
||||
|
||||
type testEngineService struct{}
|
||||
|
||||
func (*testEngineService) NoArgsRets() {}
|
||||
|
||||
func (*testEngineService) BlockByHash(
|
||||
_ context.Context, _ common.Hash,
|
||||
) *pb.ExecutionBlock {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) BlockByNumber(
|
||||
_ context.Context, _ *big.Int,
|
||||
) *pb.ExecutionBlock {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) GetPayloadV1(
|
||||
_ context.Context, _ pb.PayloadIDBytes,
|
||||
) *pb.ExecutionPayload {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) ForkchoiceUpdatedV1(
|
||||
_ context.Context, _ *pb.ForkchoiceState, _ *pb.PayloadAttributes,
|
||||
) *ForkchoiceUpdatedResponse {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) NewPayloadV1(
|
||||
_ context.Context, _ *pb.ExecutionPayload,
|
||||
) *pb.PayloadStatus {
|
||||
fix := fixtures()
|
||||
item, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
@@ -1,105 +1,91 @@
|
||||
package enginev1
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
// HexBytes implements a custom json.Marshaler/Unmarshaler for byte slices that encodes them as
|
||||
// hex strings per the Ethereum JSON-RPC specification.
|
||||
type HexBytes []byte
|
||||
|
||||
// Quantity implements a custom json.Marshaler/Unmarshaler for uint64 that encodes them as
|
||||
// big-endian hex strings per the Ethereum JSON-RPC specification.
|
||||
type Quantity uint64
|
||||
// PayloadIDBytes defines a custom type for Payload IDs used by the engine API
|
||||
// client with proper JSON Marshal and Unmarshal methods to hex.
|
||||
type PayloadIDBytes [8]byte
|
||||
|
||||
// MarshalJSON --
|
||||
func (b HexBytes) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(hexutil.Encode(b))
|
||||
func (b PayloadIDBytes) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(hexutil.Bytes(b[:]))
|
||||
}
|
||||
|
||||
// UnmarshalJSON --
|
||||
func (b *HexBytes) UnmarshalJSON(enc []byte) error {
|
||||
if len(enc) == 0 {
|
||||
*b = make([]byte, 0)
|
||||
return nil
|
||||
}
|
||||
var hexString string
|
||||
if err := json.Unmarshal(enc, &hexString); err != nil {
|
||||
func (b *PayloadIDBytes) UnmarshalJSON(enc []byte) error {
|
||||
hexBytes := hexutil.Bytes(make([]byte, 0))
|
||||
if err := json.Unmarshal(enc, &hexBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
dst, err := hexutil.Decode(hexString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*b = dst
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
func (q Quantity) MarshalJSON() ([]byte, error) {
|
||||
enc := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(enc, uint64(q))
|
||||
return json.Marshal(hexutil.Encode(enc))
|
||||
}
|
||||
|
||||
// UnmarshalJSON --
|
||||
func (q *Quantity) UnmarshalJSON(enc []byte) error {
|
||||
if len(enc) == 0 {
|
||||
*q = 0
|
||||
return nil
|
||||
}
|
||||
var hexString string
|
||||
if err := json.Unmarshal(enc, &hexString); err != nil {
|
||||
return err
|
||||
}
|
||||
dst, err := hexutil.Decode(hexString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*q = Quantity(binary.BigEndian.Uint64(dst))
|
||||
res := [8]byte{}
|
||||
copy(res[:], hexBytes)
|
||||
*b = res
|
||||
return nil
|
||||
}
|
||||
|
||||
type executionBlockJSON struct {
|
||||
Number HexBytes `json:"number"`
|
||||
Hash HexBytes `json:"hash"`
|
||||
ParentHash HexBytes `json:"parentHash"`
|
||||
Sha3Uncles HexBytes `json:"sha3Uncles"`
|
||||
Miner HexBytes `json:"miner"`
|
||||
StateRoot HexBytes `json:"stateRoot"`
|
||||
TransactionsRoot HexBytes `json:"transactionsRoot"`
|
||||
ReceiptsRoot HexBytes `json:"receiptsRoot"`
|
||||
LogsBloom HexBytes `json:"logsBloom"`
|
||||
Difficulty HexBytes `json:"difficulty"`
|
||||
TotalDifficulty HexBytes `json:"totalDifficulty"`
|
||||
GasLimit Quantity `json:"gasLimit"`
|
||||
GasUsed Quantity `json:"gasUsed"`
|
||||
Timestamp Quantity `json:"timestamp"`
|
||||
BaseFeePerGas HexBytes `json:"baseFeePerGas"`
|
||||
ExtraData HexBytes `json:"extraData"`
|
||||
MixHash HexBytes `json:"mixHash"`
|
||||
Nonce HexBytes `json:"nonce"`
|
||||
Size HexBytes `json:"size"`
|
||||
Transactions []HexBytes `json:"transactions"`
|
||||
Uncles []HexBytes `json:"uncles"`
|
||||
Number *big.Int `json:"number"`
|
||||
Hash hexutil.Bytes `json:"hash"`
|
||||
ParentHash hexutil.Bytes `json:"parentHash"`
|
||||
Sha3Uncles hexutil.Bytes `json:"sha3Uncles"`
|
||||
Miner hexutil.Bytes `json:"miner"`
|
||||
StateRoot hexutil.Bytes `json:"stateRoot"`
|
||||
TransactionsRoot hexutil.Bytes `json:"transactionsRoot"`
|
||||
ReceiptsRoot hexutil.Bytes `json:"receiptsRoot"`
|
||||
LogsBloom hexutil.Bytes `json:"logsBloom"`
|
||||
Difficulty *big.Int `json:"difficulty"`
|
||||
TotalDifficulty *big.Int `json:"totalDifficulty"`
|
||||
GasLimit hexutil.Uint64 `json:"gasLimit"`
|
||||
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
||||
Timestamp hexutil.Uint64 `json:"timestamp"`
|
||||
BaseFeePerGas *big.Int `json:"baseFeePerGas"`
|
||||
ExtraData hexutil.Bytes `json:"extraData"`
|
||||
MixHash hexutil.Bytes `json:"mixHash"`
|
||||
Nonce hexutil.Bytes `json:"nonce"`
|
||||
Size *big.Int `json:"size"`
|
||||
Transactions []hexutil.Bytes `json:"transactions"`
|
||||
Uncles []hexutil.Bytes `json:"uncles"`
|
||||
}
|
||||
|
||||
// MarshalJSON defines a custom json.Marshaler interface implementation
|
||||
// that uses custom json.Marshalers for the HexBytes and Quantity types.
|
||||
// that uses custom json.Marshalers for the hexutil.Bytes and hexutil.Uint64 types.
|
||||
func (e *ExecutionBlock) MarshalJSON() ([]byte, error) {
|
||||
transactions := make([]HexBytes, len(e.Transactions))
|
||||
transactions := make([]hexutil.Bytes, len(e.Transactions))
|
||||
for i, tx := range e.Transactions {
|
||||
transactions[i] = tx
|
||||
}
|
||||
uncles := make([]HexBytes, len(e.Uncles))
|
||||
uncles := make([]hexutil.Bytes, len(e.Uncles))
|
||||
for i, ucl := range e.Uncles {
|
||||
uncles[i] = ucl
|
||||
}
|
||||
num, err := hexutil.DecodeBig(fmt.Sprintf("%#x", e.Number))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diff, err := hexutil.DecodeBig(fmt.Sprintf("%#x", e.Difficulty))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalDiff, err := hexutil.DecodeBig(fmt.Sprintf("%#x", e.TotalDifficulty))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
size, err := hexutil.DecodeBig(fmt.Sprintf("%#x", e.Size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
baseFee, err := hexutil.DecodeBig(fmt.Sprintf("%#x", e.BaseFeePerGas))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(executionBlockJSON{
|
||||
Number: e.Number,
|
||||
Number: num,
|
||||
Hash: e.Hash,
|
||||
ParentHash: e.ParentHash,
|
||||
Sha3Uncles: e.Sha3Uncles,
|
||||
@@ -108,30 +94,30 @@ func (e *ExecutionBlock) MarshalJSON() ([]byte, error) {
|
||||
TransactionsRoot: e.TransactionsRoot,
|
||||
ReceiptsRoot: e.ReceiptsRoot,
|
||||
LogsBloom: e.LogsBloom,
|
||||
Difficulty: e.Difficulty,
|
||||
TotalDifficulty: e.TotalDifficulty,
|
||||
GasLimit: Quantity(e.GasLimit),
|
||||
GasUsed: Quantity(e.GasUsed),
|
||||
Timestamp: Quantity(e.Timestamp),
|
||||
Difficulty: diff,
|
||||
TotalDifficulty: totalDiff,
|
||||
GasLimit: hexutil.Uint64(e.GasLimit),
|
||||
GasUsed: hexutil.Uint64(e.GasUsed),
|
||||
Timestamp: hexutil.Uint64(e.Timestamp),
|
||||
ExtraData: e.ExtraData,
|
||||
MixHash: e.MixHash,
|
||||
Nonce: e.Nonce,
|
||||
Size: e.Size,
|
||||
BaseFeePerGas: e.BaseFeePerGas,
|
||||
Size: size,
|
||||
BaseFeePerGas: baseFee,
|
||||
Transactions: transactions,
|
||||
Uncles: uncles,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON defines a custom json.Unmarshaler interface implementation
|
||||
// that uses custom json.Unmarshalers for the HexBytes and Quantity types.
|
||||
// that uses custom json.Unmarshalers for the hexutil.Bytes and hexutil.Uint64 types.
|
||||
func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
|
||||
dec := executionBlockJSON{}
|
||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
*e = ExecutionBlock{}
|
||||
e.Number = dec.Number
|
||||
e.Number = dec.Number.Bytes()
|
||||
e.Hash = dec.Hash
|
||||
e.ParentHash = dec.ParentHash
|
||||
e.Sha3Uncles = dec.Sha3Uncles
|
||||
@@ -140,16 +126,16 @@ func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
|
||||
e.TransactionsRoot = dec.TransactionsRoot
|
||||
e.ReceiptsRoot = dec.ReceiptsRoot
|
||||
e.LogsBloom = dec.LogsBloom
|
||||
e.Difficulty = dec.Difficulty
|
||||
e.TotalDifficulty = dec.TotalDifficulty
|
||||
e.Difficulty = dec.Difficulty.Bytes()
|
||||
e.TotalDifficulty = dec.TotalDifficulty.Bytes()
|
||||
e.GasLimit = uint64(dec.GasLimit)
|
||||
e.GasUsed = uint64(dec.GasUsed)
|
||||
e.Timestamp = uint64(dec.Timestamp)
|
||||
e.ExtraData = dec.ExtraData
|
||||
e.MixHash = dec.MixHash
|
||||
e.Nonce = dec.Nonce
|
||||
e.Size = dec.Size
|
||||
e.BaseFeePerGas = dec.BaseFeePerGas
|
||||
e.Size = dec.Size.Bytes()
|
||||
e.BaseFeePerGas = dec.BaseFeePerGas.Bytes()
|
||||
transactions := make([][]byte, len(dec.Transactions))
|
||||
for i, tx := range dec.Transactions {
|
||||
transactions[i] = tx
|
||||
@@ -164,28 +150,32 @@ func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
|
||||
}
|
||||
|
||||
type executionPayloadJSON struct {
|
||||
ParentHash HexBytes `json:"parentHash"`
|
||||
FeeRecipient HexBytes `json:"feeRecipient"`
|
||||
StateRoot HexBytes `json:"stateRoot"`
|
||||
ReceiptsRoot HexBytes `json:"receiptsRoot"`
|
||||
LogsBloom HexBytes `json:"logsBloom"`
|
||||
Random HexBytes `json:"random"`
|
||||
BlockNumber Quantity `json:"blockNumber"`
|
||||
GasLimit Quantity `json:"gasLimit"`
|
||||
GasUsed Quantity `json:"gasUsed"`
|
||||
Timestamp Quantity `json:"timestamp"`
|
||||
ExtraData HexBytes `json:"extraData"`
|
||||
BaseFeePerGas HexBytes `json:"baseFeePerGas"`
|
||||
BlockHash HexBytes `json:"blockHash"`
|
||||
Transactions []HexBytes `json:"transactions"`
|
||||
ParentHash hexutil.Bytes `json:"parentHash"`
|
||||
FeeRecipient hexutil.Bytes `json:"feeRecipient"`
|
||||
StateRoot hexutil.Bytes `json:"stateRoot"`
|
||||
ReceiptsRoot hexutil.Bytes `json:"receiptsRoot"`
|
||||
LogsBloom hexutil.Bytes `json:"logsBloom"`
|
||||
Random hexutil.Bytes `json:"random"`
|
||||
BlockNumber hexutil.Uint64 `json:"blockNumber"`
|
||||
GasLimit hexutil.Uint64 `json:"gasLimit"`
|
||||
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
||||
Timestamp hexutil.Uint64 `json:"timestamp"`
|
||||
ExtraData hexutil.Bytes `json:"extraData"`
|
||||
BaseFeePerGas hexutil.Big `json:"baseFeePerGas"`
|
||||
BlockHash hexutil.Bytes `json:"blockHash"`
|
||||
Transactions []hexutil.Bytes `json:"transactions"`
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
||||
transactions := make([]HexBytes, len(e.Transactions))
|
||||
transactions := make([]hexutil.Bytes, len(e.Transactions))
|
||||
for i, tx := range e.Transactions {
|
||||
transactions[i] = tx
|
||||
}
|
||||
var b hexutil.Big
|
||||
if err := b.UnmarshalText(e.BaseFeePerGas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(executionPayloadJSON{
|
||||
ParentHash: e.ParentHash,
|
||||
FeeRecipient: e.FeeRecipient,
|
||||
@@ -193,12 +183,12 @@ func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
||||
ReceiptsRoot: e.ReceiptsRoot,
|
||||
LogsBloom: e.LogsBloom,
|
||||
Random: e.Random,
|
||||
BlockNumber: Quantity(e.BlockNumber),
|
||||
GasLimit: Quantity(e.GasLimit),
|
||||
GasUsed: Quantity(e.GasUsed),
|
||||
Timestamp: Quantity(e.Timestamp),
|
||||
BlockNumber: hexutil.Uint64(e.BlockNumber),
|
||||
GasLimit: hexutil.Uint64(e.GasLimit),
|
||||
GasUsed: hexutil.Uint64(e.GasUsed),
|
||||
Timestamp: hexutil.Uint64(e.Timestamp),
|
||||
ExtraData: e.ExtraData,
|
||||
BaseFeePerGas: e.BaseFeePerGas,
|
||||
BaseFeePerGas: b,
|
||||
BlockHash: e.BlockHash,
|
||||
Transactions: transactions,
|
||||
})
|
||||
@@ -208,6 +198,7 @@ func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
||||
func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
||||
dec := executionPayloadJSON{}
|
||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||
fmt.Println("got weird err")
|
||||
return err
|
||||
}
|
||||
*e = ExecutionPayload{}
|
||||
@@ -222,7 +213,11 @@ func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
||||
e.GasUsed = uint64(dec.GasUsed)
|
||||
e.Timestamp = uint64(dec.Timestamp)
|
||||
e.ExtraData = dec.ExtraData
|
||||
e.BaseFeePerGas = dec.BaseFeePerGas
|
||||
baseFee, err := dec.BaseFeePerGas.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.BaseFeePerGas = baseFee
|
||||
e.BlockHash = dec.BlockHash
|
||||
transactions := make([][]byte, len(dec.Transactions))
|
||||
for i, tx := range dec.Transactions {
|
||||
@@ -233,15 +228,15 @@ func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
||||
}
|
||||
|
||||
type payloadAttributesJSON struct {
|
||||
Timestamp Quantity `json:"timestamp"`
|
||||
Random HexBytes `json:"random"`
|
||||
SuggestedFeeRecipient HexBytes `json:"suggestedFeeRecipient"`
|
||||
Timestamp hexutil.Uint64 `json:"timestamp"`
|
||||
Random hexutil.Bytes `json:"random"`
|
||||
SuggestedFeeRecipient hexutil.Bytes `json:"suggestedFeeRecipient"`
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
func (p *PayloadAttributes) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(payloadAttributesJSON{
|
||||
Timestamp: Quantity(p.Timestamp),
|
||||
Timestamp: hexutil.Uint64(p.Timestamp),
|
||||
Random: p.Random,
|
||||
SuggestedFeeRecipient: p.SuggestedFeeRecipient,
|
||||
})
|
||||
@@ -261,9 +256,9 @@ func (p *PayloadAttributes) UnmarshalJSON(enc []byte) error {
|
||||
}
|
||||
|
||||
type payloadStatusJSON struct {
|
||||
LatestValidHash HexBytes `json:"latestValidHash"`
|
||||
Status string `json:"status"`
|
||||
ValidationError string `json:"validationError"`
|
||||
LatestValidHash hexutil.Bytes `json:"latestValidHash"`
|
||||
Status string `json:"status"`
|
||||
ValidationError string `json:"validationError"`
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
@@ -289,9 +284,9 @@ func (p *PayloadStatus) UnmarshalJSON(enc []byte) error {
|
||||
}
|
||||
|
||||
type forkchoiceStateJSON struct {
|
||||
HeadBlockHash HexBytes `json:"headBlockHash"`
|
||||
SafeBlockHash HexBytes `json:"safeBlockHash"`
|
||||
FinalizedBlockHash HexBytes `json:"finalizedBlockHash"`
|
||||
HeadBlockHash hexutil.Bytes `json:"headBlockHash"`
|
||||
SafeBlockHash hexutil.Bytes `json:"safeBlockHash"`
|
||||
FinalizedBlockHash hexutil.Bytes `json:"finalizedBlockHash"`
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
|
||||
@@ -2,7 +2,6 @@ package enginev1_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
@@ -140,62 +139,13 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestHexBytes_MarshalUnmarshalJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
b enginev1.HexBytes
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
b: []byte{},
|
||||
},
|
||||
{
|
||||
name: "foo",
|
||||
b: []byte("foo"),
|
||||
},
|
||||
{
|
||||
name: "bytes",
|
||||
b: []byte{1, 2, 3, 4},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.b.MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
var dec enginev1.HexBytes
|
||||
err = dec.UnmarshalJSON(got)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, tt.b, dec)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuantity_MarshalUnmarshalJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
b enginev1.Quantity
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
b: 0,
|
||||
},
|
||||
{
|
||||
name: "num",
|
||||
b: 5,
|
||||
},
|
||||
{
|
||||
name: "max",
|
||||
b: math.MaxUint64,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.b.MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
var dec enginev1.Quantity
|
||||
err = dec.UnmarshalJSON(got)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, tt.b, dec)
|
||||
})
|
||||
}
|
||||
func TestPayloadIDBytes_MarshalUnmarshalJSON(t *testing.T) {
|
||||
item := [8]byte{1, 0, 0, 0, 0, 0, 0, 0}
|
||||
enc, err := json.Marshal(enginev1.PayloadIDBytes(item))
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, "\"0x0100000000000000\"", string(enc))
|
||||
res := &enginev1.PayloadIDBytes{}
|
||||
err = res.UnmarshalJSON(enc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, item == *res)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user