mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 05:47:59 -05:00
Merge branch 'develop' of github.com:prysmaticlabs/prysm into kintsugi
This commit is contained in:
@@ -70,6 +70,7 @@ go_library(
|
||||
"//proto/eth/ext:go_default_library",
|
||||
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
|
||||
"@com_github_golang_protobuf//proto:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
|
||||
"@go_googleapis//google/api:annotations_go_proto",
|
||||
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
|
||||
@@ -88,5 +89,6 @@ go_test(
|
||||
":go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,47 +1,215 @@
|
||||
package enginev1
|
||||
|
||||
import "google.golang.org/protobuf/encoding/protojson"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
|
||||
"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
|
||||
|
||||
func (b HexBytes) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(hexutil.Encode(b))
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
dst, err := hexutil.Decode(hexString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*b = dst
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q Quantity) MarshalJSON() ([]byte, error) {
|
||||
enc := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(enc, uint64(q))
|
||||
return json.Marshal(hexutil.Encode(enc))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
// MarshalJSON defines a custom json.Marshaler interface implementation
|
||||
// that uses protojson underneath the hood, as protojson will respect
|
||||
// proper struct tag naming conventions required for the JSON-RPC engine API to work.
|
||||
// that uses custom json.Marshalers for the HexBytes and Quantity types.
|
||||
func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
|
||||
return protojson.Marshal(e)
|
||||
transactions := make([]HexBytes, len(e.Transactions))
|
||||
for i, tx := range e.Transactions {
|
||||
transactions[i] = tx
|
||||
}
|
||||
return json.Marshal(executionPayloadJSON{
|
||||
ParentHash: e.ParentHash,
|
||||
FeeRecipient: e.FeeRecipient,
|
||||
StateRoot: e.StateRoot,
|
||||
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),
|
||||
ExtraData: e.ExtraData,
|
||||
BaseFeePerGas: e.BaseFeePerGas,
|
||||
BlockHash: e.BlockHash,
|
||||
Transactions: transactions,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON defines a custom json.Unmarshaler interface implementation
|
||||
// that uses protojson underneath the hood, as protojson will respect
|
||||
// proper struct tag naming conventions required for the JSON-RPC engine API to work.
|
||||
// that uses custom json.Unmarshalers for the HexBytes and Quantity types.
|
||||
func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
|
||||
return protojson.Unmarshal(enc, e)
|
||||
dec := executionPayloadJSON{}
|
||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
*e = ExecutionPayload{}
|
||||
e.ParentHash = dec.ParentHash
|
||||
e.FeeRecipient = dec.FeeRecipient
|
||||
e.StateRoot = dec.StateRoot
|
||||
e.ReceiptsRoot = dec.ReceiptsRoot
|
||||
e.LogsBloom = dec.LogsBloom
|
||||
e.Random = dec.Random
|
||||
e.BlockNumber = uint64(dec.BlockNumber)
|
||||
e.GasLimit = uint64(dec.GasLimit)
|
||||
e.GasUsed = uint64(dec.GasUsed)
|
||||
e.Timestamp = uint64(dec.Timestamp)
|
||||
e.ExtraData = dec.ExtraData
|
||||
e.BaseFeePerGas = dec.BaseFeePerGas
|
||||
e.BlockHash = dec.BlockHash
|
||||
transactions := make([][]byte, len(dec.Transactions))
|
||||
for i, tx := range dec.Transactions {
|
||||
transactions[i] = tx
|
||||
}
|
||||
e.Transactions = transactions
|
||||
return nil
|
||||
}
|
||||
|
||||
type payloadAttributesJSON struct {
|
||||
Timestamp Quantity `json:"timestamp"`
|
||||
Random HexBytes `json:"random"`
|
||||
SuggestedFeeRecipient HexBytes `json:"suggestedFeeRecipient"`
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
func (p *PayloadAttributes) MarshalJSON() ([]byte, error) {
|
||||
return protojson.Marshal(p)
|
||||
return json.Marshal(payloadAttributesJSON{
|
||||
Timestamp: Quantity(p.Timestamp),
|
||||
Random: p.Random,
|
||||
SuggestedFeeRecipient: p.SuggestedFeeRecipient,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON --
|
||||
func (p *PayloadAttributes) UnmarshalJSON(enc []byte) error {
|
||||
return protojson.Unmarshal(enc, p)
|
||||
dec := payloadAttributesJSON{}
|
||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
*p = PayloadAttributes{}
|
||||
p.Timestamp = uint64(dec.Timestamp)
|
||||
p.Random = dec.Random
|
||||
p.SuggestedFeeRecipient = dec.SuggestedFeeRecipient
|
||||
return nil
|
||||
}
|
||||
|
||||
type payloadStatusJSON struct {
|
||||
LatestValidHash HexBytes `json:"latestValidHash"`
|
||||
Status string `json:"status"`
|
||||
ValidationError string `json:"validationError"`
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
func (p *PayloadStatus) MarshalJSON() ([]byte, error) {
|
||||
return protojson.Marshal(p)
|
||||
return json.Marshal(payloadStatusJSON{
|
||||
LatestValidHash: p.LatestValidHash,
|
||||
Status: p.Status.String(),
|
||||
ValidationError: p.ValidationError,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON --
|
||||
func (p *PayloadStatus) UnmarshalJSON(enc []byte) error {
|
||||
return protojson.Unmarshal(enc, p)
|
||||
dec := payloadStatusJSON{}
|
||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
*p = PayloadStatus{}
|
||||
p.LatestValidHash = dec.LatestValidHash
|
||||
p.Status = PayloadStatus_Status(PayloadStatus_Status_value[dec.Status])
|
||||
p.ValidationError = dec.ValidationError
|
||||
return nil
|
||||
}
|
||||
|
||||
type forkchoiceStateJSON struct {
|
||||
HeadBlockHash HexBytes `json:"headBlockHash"`
|
||||
SafeBlockHash HexBytes `json:"safeBlockHash"`
|
||||
FinalizedBlockHash HexBytes `json:"finalizedBlockHash"`
|
||||
}
|
||||
|
||||
// MarshalJSON --
|
||||
func (f *ForkchoiceState) MarshalJSON() ([]byte, error) {
|
||||
return protojson.Marshal(f)
|
||||
return json.Marshal(forkchoiceStateJSON{
|
||||
HeadBlockHash: f.HeadBlockHash,
|
||||
SafeBlockHash: f.SafeBlockHash,
|
||||
FinalizedBlockHash: f.FinalizedBlockHash,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON --
|
||||
func (f *ForkchoiceState) UnmarshalJSON(enc []byte) error {
|
||||
return protojson.Unmarshal(enc, f)
|
||||
dec := forkchoiceStateJSON{}
|
||||
if err := json.Unmarshal(enc, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
*f = ForkchoiceState{}
|
||||
f.HeadBlockHash = dec.HeadBlockHash
|
||||
f.SafeBlockHash = dec.SafeBlockHash
|
||||
f.FinalizedBlockHash = dec.FinalizedBlockHash
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,93 +2,150 @@ package enginev1_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestJsonMarshalUnmarshal(t *testing.T) {
|
||||
foo := bytesutil.ToBytes32([]byte("foo"))
|
||||
bar := bytesutil.PadTo([]byte("bar"), 20)
|
||||
baz := bytesutil.PadTo([]byte("baz"), 256)
|
||||
t.Run("payload attributes", func(t *testing.T) {
|
||||
jsonPayload := map[string]interface{}{
|
||||
"timestamp": 1,
|
||||
"random": foo[:],
|
||||
"suggestedFeeRecipient": bar,
|
||||
jsonPayload := &enginev1.PayloadAttributes{
|
||||
Timestamp: 1,
|
||||
Random: []byte("random"),
|
||||
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
|
||||
}
|
||||
enc, err := json.Marshal(jsonPayload)
|
||||
require.NoError(t, err)
|
||||
payloadPb := &enginev1.PayloadAttributes{}
|
||||
require.NoError(t, json.Unmarshal(enc, payloadPb))
|
||||
require.DeepEqual(t, uint64(1), payloadPb.Timestamp)
|
||||
require.DeepEqual(t, foo[:], payloadPb.Random)
|
||||
require.DeepEqual(t, bar, payloadPb.SuggestedFeeRecipient)
|
||||
require.DeepEqual(t, []byte("random"), payloadPb.Random)
|
||||
require.DeepEqual(t, []byte("suggestedFeeRecipient"), payloadPb.SuggestedFeeRecipient)
|
||||
})
|
||||
t.Run("payload status", func(t *testing.T) {
|
||||
jsonPayload := map[string]interface{}{
|
||||
"status": "INVALID",
|
||||
"latestValidHash": foo[:],
|
||||
"validationError": "failed validation",
|
||||
jsonPayload := &enginev1.PayloadStatus{
|
||||
Status: enginev1.PayloadStatus_INVALID,
|
||||
LatestValidHash: []byte("latestValidHash"),
|
||||
ValidationError: "failed validation",
|
||||
}
|
||||
enc, err := json.Marshal(jsonPayload)
|
||||
require.NoError(t, err)
|
||||
payloadPb := &enginev1.PayloadStatus{}
|
||||
require.NoError(t, json.Unmarshal(enc, payloadPb))
|
||||
require.DeepEqual(t, "INVALID", payloadPb.Status.String())
|
||||
require.DeepEqual(t, foo[:], payloadPb.LatestValidHash)
|
||||
require.DeepEqual(t, []byte("latestValidHash"), payloadPb.LatestValidHash)
|
||||
require.DeepEqual(t, "failed validation", payloadPb.ValidationError)
|
||||
})
|
||||
t.Run("forkchoice state", func(t *testing.T) {
|
||||
jsonPayload := map[string]interface{}{
|
||||
"headBlockHash": foo[:],
|
||||
"safeBlockHash": foo[:],
|
||||
"finalizedBlockHash": foo[:],
|
||||
jsonPayload := &enginev1.ForkchoiceState{
|
||||
HeadBlockHash: []byte("head"),
|
||||
SafeBlockHash: []byte("safe"),
|
||||
FinalizedBlockHash: []byte("finalized"),
|
||||
}
|
||||
enc, err := json.Marshal(jsonPayload)
|
||||
require.NoError(t, err)
|
||||
payloadPb := &enginev1.ForkchoiceState{}
|
||||
require.NoError(t, json.Unmarshal(enc, payloadPb))
|
||||
require.DeepEqual(t, foo[:], payloadPb.HeadBlockHash)
|
||||
require.DeepEqual(t, foo[:], payloadPb.SafeBlockHash)
|
||||
require.DeepEqual(t, foo[:], payloadPb.FinalizedBlockHash)
|
||||
require.DeepEqual(t, []byte("head"), payloadPb.HeadBlockHash)
|
||||
require.DeepEqual(t, []byte("safe"), payloadPb.SafeBlockHash)
|
||||
require.DeepEqual(t, []byte("finalized"), payloadPb.FinalizedBlockHash)
|
||||
})
|
||||
t.Run("execution payload", func(t *testing.T) {
|
||||
jsonPayload := map[string]interface{}{
|
||||
"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[:]},
|
||||
jsonPayload := &enginev1.ExecutionPayload{
|
||||
ParentHash: []byte("parent"),
|
||||
FeeRecipient: []byte("feeRecipient"),
|
||||
StateRoot: []byte("stateRoot"),
|
||||
ReceiptsRoot: []byte("receiptsRoot"),
|
||||
LogsBloom: []byte("logsBloom"),
|
||||
Random: []byte("random"),
|
||||
BlockNumber: 1,
|
||||
GasLimit: 2,
|
||||
GasUsed: 3,
|
||||
Timestamp: 4,
|
||||
ExtraData: []byte("extraData"),
|
||||
BaseFeePerGas: []byte("baseFeePerGas"),
|
||||
BlockHash: []byte("blockHash"),
|
||||
Transactions: [][]byte{[]byte("hi")},
|
||||
}
|
||||
enc, err := json.Marshal(jsonPayload)
|
||||
require.NoError(t, err)
|
||||
payloadPb := &enginev1.ExecutionPayload{}
|
||||
require.NoError(t, json.Unmarshal(enc, payloadPb))
|
||||
require.DeepEqual(t, foo[:], payloadPb.ParentHash)
|
||||
require.DeepEqual(t, bar, payloadPb.FeeRecipient)
|
||||
require.DeepEqual(t, foo[:], payloadPb.StateRoot)
|
||||
require.DeepEqual(t, foo[:], payloadPb.ReceiptsRoot)
|
||||
require.DeepEqual(t, baz, payloadPb.LogsBloom)
|
||||
require.DeepEqual(t, foo[:], payloadPb.Random)
|
||||
require.DeepEqual(t, []byte("parent"), payloadPb.ParentHash)
|
||||
require.DeepEqual(t, []byte("feeRecipient"), payloadPb.FeeRecipient)
|
||||
require.DeepEqual(t, []byte("stateRoot"), payloadPb.StateRoot)
|
||||
require.DeepEqual(t, []byte("receiptsRoot"), payloadPb.ReceiptsRoot)
|
||||
require.DeepEqual(t, []byte("logsBloom"), payloadPb.LogsBloom)
|
||||
require.DeepEqual(t, []byte("random"), payloadPb.Random)
|
||||
require.DeepEqual(t, uint64(1), payloadPb.BlockNumber)
|
||||
require.DeepEqual(t, uint64(1), payloadPb.GasLimit)
|
||||
require.DeepEqual(t, uint64(1), payloadPb.GasUsed)
|
||||
require.DeepEqual(t, uint64(1), payloadPb.Timestamp)
|
||||
require.DeepEqual(t, foo[:], payloadPb.ExtraData)
|
||||
require.DeepEqual(t, foo[:], payloadPb.BaseFeePerGas)
|
||||
require.DeepEqual(t, foo[:], payloadPb.BlockHash)
|
||||
require.DeepEqual(t, [][]byte{foo[:]}, payloadPb.Transactions)
|
||||
require.DeepEqual(t, uint64(2), payloadPb.GasLimit)
|
||||
require.DeepEqual(t, uint64(3), payloadPb.GasUsed)
|
||||
require.DeepEqual(t, uint64(4), payloadPb.Timestamp)
|
||||
require.DeepEqual(t, []byte("extraData"), payloadPb.ExtraData)
|
||||
require.DeepEqual(t, []byte("baseFeePerGas"), payloadPb.BaseFeePerGas)
|
||||
require.DeepEqual(t, []byte("blockHash"), payloadPb.BlockHash)
|
||||
require.DeepEqual(t, [][]byte{[]byte("hi")}, payloadPb.Transactions)
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user