Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,37 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
}

type HeaderSerializer interface {
EncodeRLP(h *Header, w io.Writer) error
DecodeRLP(h *Header, s *rlp.Stream) error
}

var RegisteredHeaderSerializer HeaderSerializer

// XXX: JSON marshalling should be handled as well.
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
//go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go
//go:generate go run ../../rlp/rlpgen -type HeaderWithExtraPayload -out gen_header_rlp.go

// Header represents a block header in the Ethereum blockchain.
type Header struct {
type Header HeaderWithExtraPayload

func (obj *Header) EncodeRLP(w io.Writer) error {
if RegisteredHeaderSerializer != nil {
return RegisteredHeaderSerializer.EncodeRLP(obj, w)
}
return rlp.Encode(w, (*HeaderWithExtraPayload)(obj))
}

func (obj *Header) DecodeRLP(s *rlp.Stream) error {
if RegisteredHeaderSerializer != nil {
return RegisteredHeaderSerializer.DecodeRLP(obj, s)
}
return s.Decode((*HeaderWithExtraPayload)(obj))
}

type HeaderWithExtraPayload struct { // Note this name must be exported if we want to use rlpgen
ExtraPayload interface{} `json:"-" rlp:"-"`

ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner"`
Expand Down
6 changes: 6 additions & 0 deletions core/types/gen_header_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/types/gen_header_rlp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

145 changes: 145 additions & 0 deletions core/types_ext/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// Package types contains data types related to Ethereum consensus.
package types_ext

import (
"io"
"math/big"

"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/core/types"
"github.com/ava-labs/libevm/rlp"
)

type (
BlockNonce = types.BlockNonce
Bloom = types.Bloom
)

func init() {
// Register the header type for RLP serialization
types.RegisteredHeaderSerializer = headerSerializable{}
}

//go:generate go run ../../rlp/rlpgen -type headerSerializable -out gen_header_rlp.go
type Header = types.Header

func (headerSerializable) EncodeRLP(h *types.Header, w io.Writer) error {
var hs headerSerializable

// Set the shared fields with upstream
hs.ParentHash = h.ParentHash
hs.UncleHash = h.UncleHash
hs.Coinbase = h.Coinbase
hs.Root = h.Root
hs.TxHash = h.TxHash
hs.ReceiptHash = h.ReceiptHash
hs.Bloom = h.Bloom
hs.Difficulty = h.Difficulty
hs.Number = h.Number
hs.GasLimit = h.GasLimit
hs.GasUsed = h.GasUsed
hs.Time = h.Time
hs.Extra = h.Extra
hs.MixDigest = h.MixDigest

// Set the extra payload
if h.ExtraPayload != nil {
hs.AddedStuff = h.ExtraPayload.(*headerExtra).AddedStuff
}

return rlp.Encode(w, &hs)
}

func (headerSerializable) DecodeRLP(h *types.Header, s *rlp.Stream) error {
var hs headerSerializable
if err := s.Decode(&hs); err != nil {
return err
}

// Set the shared fields with upstream
h.ParentHash = hs.ParentHash
h.UncleHash = hs.UncleHash
h.Coinbase = hs.Coinbase
h.Root = hs.Root
h.TxHash = hs.TxHash
h.ReceiptHash = hs.ReceiptHash
h.Bloom = hs.Bloom
h.Difficulty = hs.Difficulty
h.Number = hs.Number
h.GasLimit = hs.GasLimit
h.GasUsed = hs.GasUsed
h.Time = hs.Time
h.Extra = hs.Extra
h.MixDigest = hs.MixDigest
h.Nonce = hs.Nonce
h.BaseFee = hs.BaseFee
h.BlobGasUsed = hs.BlobGasUsed
h.ExcessBlobGas = hs.ExcessBlobGas
h.ParentBeaconRoot = hs.ParentBeaconRoot

// Set the extra payload
h.ExtraPayload = &headerExtra{
AddedStuff: hs.AddedStuff,
}
return nil
}

// Separate the extra payload from the header, so there is no duplicate of
// shared fields.
type headerExtra struct {
AddedStuff *common.Hash
}

// The purpose of this struct is to specify the exact RLP serialization of the
// header, including shared fields and fields related to the extra payload.
type headerSerializable struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time uint64 `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash"`
Nonce BlockNonce `json:"nonce"`

// Added stuff in the middle of the header
AddedStuff *common.Hash `json:"addedStuff" rlp:"optional"`

// BaseFee was added by EIP-1559 and is ignored in legacy headers.
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`

// BlobGasUsed was added by EIP-4844 and is ignored in legacy headers.
BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`

// ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers.
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`

// ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers.
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
}

// XXX: Need to support size too in upstream code
// var headerSize = common.StorageSize(reflect.TypeOf(Header{}).Size())
36 changes: 36 additions & 0 deletions core/types_ext/block_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package types_ext

import (
"math/big"
"testing"

"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/rlp"
"github.com/stretchr/testify/require"
)

func TestRLP(t *testing.T) {
// expected (eg, from network or disk)
added := common.Hash{111}
asIs := headerSerializable{
Number: big.NewInt(10), // Shared field
AddedStuff: &added, // Added field
}

rlpAsIs, err := rlp.EncodeToBytes(&asIs)
require.NoError(t, err)

// now parse it via upstream type
var upstream Header
err = rlp.DecodeBytes(rlpAsIs, &upstream)
require.NoError(t, err)

// check that the fields are the same
require.Equal(t, asIs.Number, upstream.Number)
require.Equal(t, asIs.AddedStuff, upstream.ExtraPayload.(*headerExtra).AddedStuff)

// now encode the upstream type
rlpUpstream, err := rlp.EncodeToBytes(&upstream)
require.NoError(t, err)
require.Equal(t, rlpAsIs, rlpUpstream)
}
Loading