mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-02-01 00:28:16 -05:00
Compare commits
60 Commits
e2e-debugg
...
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(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
@@ -11,6 +11,21 @@ go_library(
|
|||||||
visibility = ["//beacon-chain:__subpackages__"],
|
visibility = ["//beacon-chain:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//proto/engine/v1:go_default_library",
|
"//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_ethereum_go_ethereum//rpc:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||||
@@ -20,6 +21,10 @@ const (
|
|||||||
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
||||||
// GetPayloadMethod v1 request string for JSON-RPC.
|
// GetPayloadMethod v1 request string for JSON-RPC.
|
||||||
GetPayloadMethod = "engine_getPayloadV1"
|
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 for HTTP.
|
||||||
DefaultTimeout = time.Second * 5
|
DefaultTimeout = time.Second * 5
|
||||||
)
|
)
|
||||||
@@ -27,8 +32,8 @@ const (
|
|||||||
// ForkchoiceUpdatedResponse is the response kind received by the
|
// ForkchoiceUpdatedResponse is the response kind received by the
|
||||||
// engine_forkchoiceUpdatedV1 endpoint.
|
// engine_forkchoiceUpdatedV1 endpoint.
|
||||||
type ForkchoiceUpdatedResponse struct {
|
type ForkchoiceUpdatedResponse struct {
|
||||||
Status *pb.PayloadStatus `json:"status"`
|
Status *pb.PayloadStatus `json:"status"`
|
||||||
PayloadId [8]byte `json:"payloadId"`
|
PayloadId *pb.PayloadIDBytes `json:"payloadId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client defines a new engine API client for the Prysm consensus node
|
// 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
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayload --
|
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
||||||
func (*Client) NewPayload(_ context.Context, _ *pb.ExecutionPayload) (*pb.PayloadStatus, error) {
|
func (c *Client) NewPayload(ctx context.Context, payload *pb.ExecutionPayload) (*pb.PayloadStatus, error) {
|
||||||
return nil, errors.New("unimplemented")
|
result := &pb.PayloadStatus{}
|
||||||
|
err := c.rpc.CallContext(ctx, result, NewPayloadMethod, payload)
|
||||||
|
return result, handleRPCError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForkchoiceUpdated --
|
// ForkchoiceUpdated calls the engine_forkchoiceUpdatedV1 method via JSON-RPC.
|
||||||
func (*Client) ForkchoiceUpdated(
|
func (c *Client) ForkchoiceUpdated(
|
||||||
_ context.Context, _ *pb.ForkchoiceState, _ *pb.PayloadAttributes,
|
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
|
||||||
) (*ForkchoiceUpdatedResponse, error) {
|
) (*ForkchoiceUpdatedResponse, error) {
|
||||||
return nil, errors.New("unimplemented")
|
result := &ForkchoiceUpdatedResponse{}
|
||||||
|
err := c.rpc.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, attrs)
|
||||||
|
return result, handleRPCError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPayload --
|
// GetPayload calls the engine_getPayloadV1 method via JSON-RPC.
|
||||||
func (*Client) GetPayload(_ context.Context, _ [8]byte) (*pb.ExecutionPayload, error) {
|
func (c *Client) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error) {
|
||||||
return nil, errors.New("unimplemented")
|
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
|
package enginev1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HexBytes implements a custom json.Marshaler/Unmarshaler for byte slices that encodes them as
|
// PayloadIDBytes defines a custom type for Payload IDs used by the engine API
|
||||||
// hex strings per the Ethereum JSON-RPC specification.
|
// client with proper JSON Marshal and Unmarshal methods to hex.
|
||||||
type HexBytes []byte
|
type PayloadIDBytes [8]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
|
|
||||||
|
|
||||||
// MarshalJSON --
|
// MarshalJSON --
|
||||||
func (b HexBytes) MarshalJSON() ([]byte, error) {
|
func (b PayloadIDBytes) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(hexutil.Encode(b))
|
return json.Marshal(hexutil.Bytes(b[:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON --
|
// UnmarshalJSON --
|
||||||
func (b *HexBytes) UnmarshalJSON(enc []byte) error {
|
func (b *PayloadIDBytes) UnmarshalJSON(enc []byte) error {
|
||||||
if len(enc) == 0 {
|
hexBytes := hexutil.Bytes(make([]byte, 0))
|
||||||
*b = make([]byte, 0)
|
if err := json.Unmarshal(enc, &hexBytes); err != nil {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var hexString string
|
|
||||||
if err := json.Unmarshal(enc, &hexString); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dst, err := hexutil.Decode(hexString)
|
res := [8]byte{}
|
||||||
if err != nil {
|
copy(res[:], hexBytes)
|
||||||
return err
|
*b = res
|
||||||
}
|
|
||||||
*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))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type executionBlockJSON struct {
|
type executionBlockJSON struct {
|
||||||
Number HexBytes `json:"number"`
|
Number *big.Int `json:"number"`
|
||||||
Hash HexBytes `json:"hash"`
|
Hash hexutil.Bytes `json:"hash"`
|
||||||
ParentHash HexBytes `json:"parentHash"`
|
ParentHash hexutil.Bytes `json:"parentHash"`
|
||||||
Sha3Uncles HexBytes `json:"sha3Uncles"`
|
Sha3Uncles hexutil.Bytes `json:"sha3Uncles"`
|
||||||
Miner HexBytes `json:"miner"`
|
Miner hexutil.Bytes `json:"miner"`
|
||||||
StateRoot HexBytes `json:"stateRoot"`
|
StateRoot hexutil.Bytes `json:"stateRoot"`
|
||||||
TransactionsRoot HexBytes `json:"transactionsRoot"`
|
TransactionsRoot hexutil.Bytes `json:"transactionsRoot"`
|
||||||
ReceiptsRoot HexBytes `json:"receiptsRoot"`
|
ReceiptsRoot hexutil.Bytes `json:"receiptsRoot"`
|
||||||
LogsBloom HexBytes `json:"logsBloom"`
|
LogsBloom hexutil.Bytes `json:"logsBloom"`
|
||||||
Difficulty HexBytes `json:"difficulty"`
|
Difficulty *big.Int `json:"difficulty"`
|
||||||
TotalDifficulty HexBytes `json:"totalDifficulty"`
|
TotalDifficulty *big.Int `json:"totalDifficulty"`
|
||||||
GasLimit Quantity `json:"gasLimit"`
|
GasLimit hexutil.Uint64 `json:"gasLimit"`
|
||||||
GasUsed Quantity `json:"gasUsed"`
|
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
||||||
Timestamp Quantity `json:"timestamp"`
|
Timestamp hexutil.Uint64 `json:"timestamp"`
|
||||||
BaseFeePerGas HexBytes `json:"baseFeePerGas"`
|
BaseFeePerGas *big.Int `json:"baseFeePerGas"`
|
||||||
ExtraData HexBytes `json:"extraData"`
|
ExtraData hexutil.Bytes `json:"extraData"`
|
||||||
MixHash HexBytes `json:"mixHash"`
|
MixHash hexutil.Bytes `json:"mixHash"`
|
||||||
Nonce HexBytes `json:"nonce"`
|
Nonce hexutil.Bytes `json:"nonce"`
|
||||||
Size HexBytes `json:"size"`
|
Size *big.Int `json:"size"`
|
||||||
Transactions []HexBytes `json:"transactions"`
|
Transactions []hexutil.Bytes `json:"transactions"`
|
||||||
Uncles []HexBytes `json:"uncles"`
|
Uncles []hexutil.Bytes `json:"uncles"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON defines a custom json.Marshaler interface implementation
|
// 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) {
|
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 {
|
for i, tx := range e.Transactions {
|
||||||
transactions[i] = tx
|
transactions[i] = tx
|
||||||
}
|
}
|
||||||
uncles := make([]HexBytes, len(e.Uncles))
|
uncles := make([]hexutil.Bytes, len(e.Uncles))
|
||||||
for i, ucl := range e.Uncles {
|
for i, ucl := range e.Uncles {
|
||||||
uncles[i] = ucl
|
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{
|
return json.Marshal(executionBlockJSON{
|
||||||
Number: e.Number,
|
Number: num,
|
||||||
Hash: e.Hash,
|
Hash: e.Hash,
|
||||||
ParentHash: e.ParentHash,
|
ParentHash: e.ParentHash,
|
||||||
Sha3Uncles: e.Sha3Uncles,
|
Sha3Uncles: e.Sha3Uncles,
|
||||||
@@ -108,30 +94,30 @@ func (e *ExecutionBlock) MarshalJSON() ([]byte, error) {
|
|||||||
TransactionsRoot: e.TransactionsRoot,
|
TransactionsRoot: e.TransactionsRoot,
|
||||||
ReceiptsRoot: e.ReceiptsRoot,
|
ReceiptsRoot: e.ReceiptsRoot,
|
||||||
LogsBloom: e.LogsBloom,
|
LogsBloom: e.LogsBloom,
|
||||||
Difficulty: e.Difficulty,
|
Difficulty: diff,
|
||||||
TotalDifficulty: e.TotalDifficulty,
|
TotalDifficulty: totalDiff,
|
||||||
GasLimit: Quantity(e.GasLimit),
|
GasLimit: hexutil.Uint64(e.GasLimit),
|
||||||
GasUsed: Quantity(e.GasUsed),
|
GasUsed: hexutil.Uint64(e.GasUsed),
|
||||||
Timestamp: Quantity(e.Timestamp),
|
Timestamp: hexutil.Uint64(e.Timestamp),
|
||||||
ExtraData: e.ExtraData,
|
ExtraData: e.ExtraData,
|
||||||
MixHash: e.MixHash,
|
MixHash: e.MixHash,
|
||||||
Nonce: e.Nonce,
|
Nonce: e.Nonce,
|
||||||
Size: e.Size,
|
Size: size,
|
||||||
BaseFeePerGas: e.BaseFeePerGas,
|
BaseFeePerGas: baseFee,
|
||||||
Transactions: transactions,
|
Transactions: transactions,
|
||||||
Uncles: uncles,
|
Uncles: uncles,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON defines a custom json.Unmarshaler interface implementation
|
// 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 {
|
func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
|
||||||
dec := executionBlockJSON{}
|
dec := executionBlockJSON{}
|
||||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
*e = ExecutionBlock{}
|
*e = ExecutionBlock{}
|
||||||
e.Number = dec.Number
|
e.Number = dec.Number.Bytes()
|
||||||
e.Hash = dec.Hash
|
e.Hash = dec.Hash
|
||||||
e.ParentHash = dec.ParentHash
|
e.ParentHash = dec.ParentHash
|
||||||
e.Sha3Uncles = dec.Sha3Uncles
|
e.Sha3Uncles = dec.Sha3Uncles
|
||||||
@@ -140,16 +126,16 @@ func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
|
|||||||
e.TransactionsRoot = dec.TransactionsRoot
|
e.TransactionsRoot = dec.TransactionsRoot
|
||||||
e.ReceiptsRoot = dec.ReceiptsRoot
|
e.ReceiptsRoot = dec.ReceiptsRoot
|
||||||
e.LogsBloom = dec.LogsBloom
|
e.LogsBloom = dec.LogsBloom
|
||||||
e.Difficulty = dec.Difficulty
|
e.Difficulty = dec.Difficulty.Bytes()
|
||||||
e.TotalDifficulty = dec.TotalDifficulty
|
e.TotalDifficulty = dec.TotalDifficulty.Bytes()
|
||||||
e.GasLimit = uint64(dec.GasLimit)
|
e.GasLimit = uint64(dec.GasLimit)
|
||||||
e.GasUsed = uint64(dec.GasUsed)
|
e.GasUsed = uint64(dec.GasUsed)
|
||||||
e.Timestamp = uint64(dec.Timestamp)
|
e.Timestamp = uint64(dec.Timestamp)
|
||||||
e.ExtraData = dec.ExtraData
|
e.ExtraData = dec.ExtraData
|
||||||
e.MixHash = dec.MixHash
|
e.MixHash = dec.MixHash
|
||||||
e.Nonce = dec.Nonce
|
e.Nonce = dec.Nonce
|
||||||
e.Size = dec.Size
|
e.Size = dec.Size.Bytes()
|
||||||
e.BaseFeePerGas = dec.BaseFeePerGas
|
e.BaseFeePerGas = dec.BaseFeePerGas.Bytes()
|
||||||
transactions := make([][]byte, len(dec.Transactions))
|
transactions := make([][]byte, len(dec.Transactions))
|
||||||
for i, tx := range dec.Transactions {
|
for i, tx := range dec.Transactions {
|
||||||
transactions[i] = tx
|
transactions[i] = tx
|
||||||
@@ -164,28 +150,32 @@ func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type executionPayloadJSON struct {
|
type executionPayloadJSON struct {
|
||||||
ParentHash HexBytes `json:"parentHash"`
|
ParentHash hexutil.Bytes `json:"parentHash"`
|
||||||
FeeRecipient HexBytes `json:"feeRecipient"`
|
FeeRecipient hexutil.Bytes `json:"feeRecipient"`
|
||||||
StateRoot HexBytes `json:"stateRoot"`
|
StateRoot hexutil.Bytes `json:"stateRoot"`
|
||||||
ReceiptsRoot HexBytes `json:"receiptsRoot"`
|
ReceiptsRoot hexutil.Bytes `json:"receiptsRoot"`
|
||||||
LogsBloom HexBytes `json:"logsBloom"`
|
LogsBloom hexutil.Bytes `json:"logsBloom"`
|
||||||
Random HexBytes `json:"random"`
|
Random hexutil.Bytes `json:"random"`
|
||||||
BlockNumber Quantity `json:"blockNumber"`
|
BlockNumber hexutil.Uint64 `json:"blockNumber"`
|
||||||
GasLimit Quantity `json:"gasLimit"`
|
GasLimit hexutil.Uint64 `json:"gasLimit"`
|
||||||
GasUsed Quantity `json:"gasUsed"`
|
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
||||||
Timestamp Quantity `json:"timestamp"`
|
Timestamp hexutil.Uint64 `json:"timestamp"`
|
||||||
ExtraData HexBytes `json:"extraData"`
|
ExtraData hexutil.Bytes `json:"extraData"`
|
||||||
BaseFeePerGas HexBytes `json:"baseFeePerGas"`
|
BaseFeePerGas hexutil.Big `json:"baseFeePerGas"`
|
||||||
BlockHash HexBytes `json:"blockHash"`
|
BlockHash hexutil.Bytes `json:"blockHash"`
|
||||||
Transactions []HexBytes `json:"transactions"`
|
Transactions []hexutil.Bytes `json:"transactions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON --
|
// MarshalJSON --
|
||||||
func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
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 {
|
for i, tx := range e.Transactions {
|
||||||
transactions[i] = tx
|
transactions[i] = tx
|
||||||
}
|
}
|
||||||
|
var b hexutil.Big
|
||||||
|
if err := b.UnmarshalText(e.BaseFeePerGas); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return json.Marshal(executionPayloadJSON{
|
return json.Marshal(executionPayloadJSON{
|
||||||
ParentHash: e.ParentHash,
|
ParentHash: e.ParentHash,
|
||||||
FeeRecipient: e.FeeRecipient,
|
FeeRecipient: e.FeeRecipient,
|
||||||
@@ -193,12 +183,12 @@ func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
|||||||
ReceiptsRoot: e.ReceiptsRoot,
|
ReceiptsRoot: e.ReceiptsRoot,
|
||||||
LogsBloom: e.LogsBloom,
|
LogsBloom: e.LogsBloom,
|
||||||
Random: e.Random,
|
Random: e.Random,
|
||||||
BlockNumber: Quantity(e.BlockNumber),
|
BlockNumber: hexutil.Uint64(e.BlockNumber),
|
||||||
GasLimit: Quantity(e.GasLimit),
|
GasLimit: hexutil.Uint64(e.GasLimit),
|
||||||
GasUsed: Quantity(e.GasUsed),
|
GasUsed: hexutil.Uint64(e.GasUsed),
|
||||||
Timestamp: Quantity(e.Timestamp),
|
Timestamp: hexutil.Uint64(e.Timestamp),
|
||||||
ExtraData: e.ExtraData,
|
ExtraData: e.ExtraData,
|
||||||
BaseFeePerGas: e.BaseFeePerGas,
|
BaseFeePerGas: b,
|
||||||
BlockHash: e.BlockHash,
|
BlockHash: e.BlockHash,
|
||||||
Transactions: transactions,
|
Transactions: transactions,
|
||||||
})
|
})
|
||||||
@@ -208,6 +198,7 @@ func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
|||||||
func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
||||||
dec := executionPayloadJSON{}
|
dec := executionPayloadJSON{}
|
||||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||||
|
fmt.Println("got weird err")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
*e = ExecutionPayload{}
|
*e = ExecutionPayload{}
|
||||||
@@ -222,7 +213,11 @@ func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
|||||||
e.GasUsed = uint64(dec.GasUsed)
|
e.GasUsed = uint64(dec.GasUsed)
|
||||||
e.Timestamp = uint64(dec.Timestamp)
|
e.Timestamp = uint64(dec.Timestamp)
|
||||||
e.ExtraData = dec.ExtraData
|
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
|
e.BlockHash = dec.BlockHash
|
||||||
transactions := make([][]byte, len(dec.Transactions))
|
transactions := make([][]byte, len(dec.Transactions))
|
||||||
for i, tx := range dec.Transactions {
|
for i, tx := range dec.Transactions {
|
||||||
@@ -233,15 +228,15 @@ func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type payloadAttributesJSON struct {
|
type payloadAttributesJSON struct {
|
||||||
Timestamp Quantity `json:"timestamp"`
|
Timestamp hexutil.Uint64 `json:"timestamp"`
|
||||||
Random HexBytes `json:"random"`
|
Random hexutil.Bytes `json:"random"`
|
||||||
SuggestedFeeRecipient HexBytes `json:"suggestedFeeRecipient"`
|
SuggestedFeeRecipient hexutil.Bytes `json:"suggestedFeeRecipient"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON --
|
// MarshalJSON --
|
||||||
func (p *PayloadAttributes) MarshalJSON() ([]byte, error) {
|
func (p *PayloadAttributes) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(payloadAttributesJSON{
|
return json.Marshal(payloadAttributesJSON{
|
||||||
Timestamp: Quantity(p.Timestamp),
|
Timestamp: hexutil.Uint64(p.Timestamp),
|
||||||
Random: p.Random,
|
Random: p.Random,
|
||||||
SuggestedFeeRecipient: p.SuggestedFeeRecipient,
|
SuggestedFeeRecipient: p.SuggestedFeeRecipient,
|
||||||
})
|
})
|
||||||
@@ -261,9 +256,9 @@ func (p *PayloadAttributes) UnmarshalJSON(enc []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type payloadStatusJSON struct {
|
type payloadStatusJSON struct {
|
||||||
LatestValidHash HexBytes `json:"latestValidHash"`
|
LatestValidHash hexutil.Bytes `json:"latestValidHash"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
ValidationError string `json:"validationError"`
|
ValidationError string `json:"validationError"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON --
|
// MarshalJSON --
|
||||||
@@ -289,9 +284,9 @@ func (p *PayloadStatus) UnmarshalJSON(enc []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type forkchoiceStateJSON struct {
|
type forkchoiceStateJSON struct {
|
||||||
HeadBlockHash HexBytes `json:"headBlockHash"`
|
HeadBlockHash hexutil.Bytes `json:"headBlockHash"`
|
||||||
SafeBlockHash HexBytes `json:"safeBlockHash"`
|
SafeBlockHash hexutil.Bytes `json:"safeBlockHash"`
|
||||||
FinalizedBlockHash HexBytes `json:"finalizedBlockHash"`
|
FinalizedBlockHash hexutil.Bytes `json:"finalizedBlockHash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON --
|
// MarshalJSON --
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package enginev1_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||||
@@ -140,62 +139,13 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHexBytes_MarshalUnmarshalJSON(t *testing.T) {
|
func TestPayloadIDBytes_MarshalUnmarshalJSON(t *testing.T) {
|
||||||
tests := []struct {
|
item := [8]byte{1, 0, 0, 0, 0, 0, 0, 0}
|
||||||
name string
|
enc, err := json.Marshal(enginev1.PayloadIDBytes(item))
|
||||||
b enginev1.HexBytes
|
require.NoError(t, err)
|
||||||
}{
|
require.DeepEqual(t, "\"0x0100000000000000\"", string(enc))
|
||||||
{
|
res := &enginev1.PayloadIDBytes{}
|
||||||
name: "empty",
|
err = res.UnmarshalJSON(enc)
|
||||||
b: []byte{},
|
require.NoError(t, err)
|
||||||
},
|
require.Equal(t, true, item == *res)
|
||||||
{
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user