Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add header & block fields for Withdrawals #45

Merged
merged 2 commits into from
Nov 8, 2022
Merged
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
77 changes: 40 additions & 37 deletions cmd/evm/internal/t8ntool/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,24 @@ import (

//go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go
type header struct {
ParentHash common.Hash `json:"parentHash"`
OmmerHash *common.Hash `json:"sha3Uncles"`
Coinbase *common.Address `json:"miner"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash *common.Hash `json:"transactionsRoot"`
ReceiptHash *common.Hash `json:"receiptsRoot"`
Bloom types.Bloom `json:"logsBloom"`
Difficulty *big.Int `json:"difficulty"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed"`
Time uint64 `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData"`
MixDigest common.Hash `json:"mixHash"`
Nonce *types.BlockNonce `json:"nonce"`
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`
ParentHash common.Hash `json:"parentHash"`
OmmerHash *common.Hash `json:"sha3Uncles"`
Coinbase *common.Address `json:"miner"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash *common.Hash `json:"transactionsRoot"`
ReceiptHash *common.Hash `json:"receiptsRoot"`
Bloom types.Bloom `json:"logsBloom"`
Difficulty *big.Int `json:"difficulty"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed"`
Time uint64 `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData"`
MixDigest common.Hash `json:"mixHash"`
Nonce *types.BlockNonce `json:"nonce"`
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`
}

type headerMarshaling struct {
Expand All @@ -68,10 +69,11 @@ type headerMarshaling struct {
}

type bbInput struct {
Header *header `json:"header,omitempty"`
OmmersRlp []string `json:"ommers,omitempty"`
TxRlp string `json:"txs,omitempty"`
Clique *cliqueInput `json:"clique,omitempty"`
Header *header `json:"header,omitempty"`
OmmersRlp []string `json:"ommers,omitempty"`
TxRlp string `json:"txs,omitempty"`
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
Clique *cliqueInput `json:"clique,omitempty"`

Ethash bool `json:"-"`
EthashDir string `json:"-"`
Expand Down Expand Up @@ -115,22 +117,23 @@ func (c *cliqueInput) UnmarshalJSON(input []byte) error {
// ToBlock converts i into a *types.Block
func (i *bbInput) ToBlock() *types.Block {
header := &types.Header{
ParentHash: i.Header.ParentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address{},
Root: i.Header.Root,
TxHash: types.EmptyRootHash,
ReceiptHash: types.EmptyRootHash,
Bloom: i.Header.Bloom,
Difficulty: common.Big0,
Number: i.Header.Number,
GasLimit: i.Header.GasLimit,
GasUsed: i.Header.GasUsed,
Time: i.Header.Time,
Extra: i.Header.Extra,
MixDigest: i.Header.MixDigest,
BaseFee: i.Header.BaseFee,
ExcessDataGas: i.Header.ExcessDataGas,
ParentHash: i.Header.ParentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address{},
Root: i.Header.Root,
TxHash: types.EmptyRootHash,
ReceiptHash: types.EmptyRootHash,
Bloom: i.Header.Bloom,
Difficulty: common.Big0,
Number: i.Header.Number,
GasLimit: i.Header.GasLimit,
GasUsed: i.Header.GasUsed,
Time: i.Header.Time,
Extra: i.Header.Extra,
MixDigest: i.Header.MixDigest,
BaseFee: i.Header.BaseFee,
WithdrawalsHash: i.Header.WithdrawalsHash,
ExcessDataGas: i.Header.ExcessDataGas,
}

// Fill optional values.
Expand Down
74 changes: 40 additions & 34 deletions cmd/evm/internal/t8ntool/gen_header.go

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

86 changes: 79 additions & 7 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package types
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"math/big"
Expand Down Expand Up @@ -88,6 +89,9 @@ type Header struct {
// BaseFee was added by EIP-1559 and is ignored in legacy headers.
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`

// WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers.
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`

// ExcessDataGas was added by EIP-4844 and is ignored in legacy headers.
ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`

Expand Down Expand Up @@ -117,6 +121,10 @@ func (h *Header) SetExcessDataGas(v *big.Int) {
if v != nil {
h.ExcessDataGas.Set(v)
}
if h.WithdrawalsHash == nil {
Copy link
Collaborator

@Inphi Inphi Nov 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is totally OK for now. In the future, a more robust solution would be to have the rlp codec automatically populate preceeding optional fields for us.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that idea. I had tried to change rlpencode to throw an error in these cases, but the maintainers were worried about unintended consequences with so much outside code depending on the rlp package. This might be less risky of an approach.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they really need to start versioning their software 🙂

// leaving this nil would result in a buggy encoding
h.WithdrawalsHash = &EmptyRootHash
}
}

// Hash returns the block hash of the header, which is simply the keccak256 hash of its
Expand Down Expand Up @@ -184,6 +192,7 @@ type Block struct {
header *Header
uncles []*Header
transactions Transactions
withdrawals []*Withdrawal

// caches
hash atomic.Value
Expand Down Expand Up @@ -271,9 +280,10 @@ func (txs *extBlockTxs) EncodeRLP(w io.Writer) error {

// "external" block encoding. used for eth protocol, etc.
type extblock struct {
Header *Header
Txs *extBlockTxs
Uncles []*Header
Header *Header
Txs *extBlockTxs
Uncles []*Header
Withdrawals []*Withdrawal `rlp:"optional"`
}

// NewBlock creates a new block. The input data is copied,
Expand Down Expand Up @@ -315,6 +325,31 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
return b
}

// NewBlock2 creates a new block with withdrawals. The input data
// is copied, changes to header and to the field values will not
// affect the block.
//
// The values of TxHash, UncleHash, ReceiptHash and Bloom in header
// are ignored and set to values derived from the given txs, uncles
// and receipts.
func NewBlock2(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, withdrawals []*Withdrawal, hasher TrieHasher) *Block {
b := NewBlock(header, txs, uncles, receipts, hasher)
if withdrawals == nil {
return b
}

b.withdrawals = make([]*Withdrawal, len(withdrawals))
copy(b.withdrawals, withdrawals)

if len(withdrawals) == 0 {
b.header.WithdrawalsHash = &EmptyRootHash
} else {
h := DeriveSha(Withdrawals(withdrawals), hasher)
b.header.WithdrawalsHash = &h
}
return b
}

// NewBlockWithHeader creates a block with the given header data. The
// header data is copied, changes to header and to the field values
// will not affect the block.
Expand Down Expand Up @@ -342,6 +377,10 @@ func CopyHeader(h *Header) *Header {
cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra)
}
if h.WithdrawalsHash != nil {
cpy.WithdrawalsHash = new(common.Hash)
cpy.WithdrawalsHash.SetBytes(h.WithdrawalsHash.Bytes())
}
return &cpy
}

Expand All @@ -357,17 +396,24 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error {
return fmt.Errorf("transactions in blocks must not contain wrap-data, tx %d is bad", i)
}
}
b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, []*Transaction(*eb.Txs)
b.header, b.uncles, b.transactions, b.withdrawals = eb.Header, eb.Uncles, []*Transaction(*eb.Txs), eb.Withdrawals
b.size.Store(rlp.ListSize(size))
return nil
}

// EncodeRLP serializes b into the Ethereum RLP block format.
func (b *Block) EncodeRLP(w io.Writer) error {
if b.header.ExcessDataGas != nil && b.header.WithdrawalsHash == nil {
// This situation should not arise, but if it does (due to a bug) you'd silently produce an
// encoding that would fail to decode. ref:
// https://github.com/ethereum/go-ethereum/pull/26077
return errors.New("nil WithdrawalsHash in header with non-nil ExcessDataGas")
}
return rlp.Encode(w, extblock{
Header: b.header,
Txs: (*extBlockTxs)(&b.transactions),
Uncles: b.uncles,
Header: b.header,
Txs: (*extBlockTxs)(&b.transactions),
Uncles: b.uncles,
Withdrawals: b.withdrawals,
})
}

Expand Down Expand Up @@ -410,6 +456,19 @@ func (b *Block) BaseFee() *big.Int {
return new(big.Int).Set(b.header.BaseFee)
}

func (b *Block) WithdrawalsHash() *common.Hash {
if b.header.WithdrawalsHash == nil {
return nil
}
var h common.Hash
h.SetBytes(b.header.WithdrawalsHash.Bytes())
return &h
}

func (b *Block) Withdrawals() Withdrawals {
return b.withdrawals
}

func (b *Block) ExcessDataGas() *big.Int {
if b.header.ExcessDataGas == nil {
return nil
Expand Down Expand Up @@ -463,6 +522,7 @@ func (b *Block) WithSeal(header *Header) *Block {
header: &cpy,
transactions: b.transactions,
uncles: b.uncles,
withdrawals: b.withdrawals,
}
}

Expand All @@ -480,6 +540,18 @@ func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block {
return block
}

// WithBody2 returns a new block with the given transaction, uncle, and
// withdrawal contents.
func (b *Block) WithBody2(transactions []*Transaction, uncles []*Header, withdrawals []*Withdrawal) *Block {
block := b.WithBody(transactions, uncles)
if withdrawals == nil {
return block
}
block.withdrawals = make([]*Withdrawal, len(withdrawals))
copy(block.withdrawals, withdrawals)
return block
}

// Hash returns the keccak256 hash of b's header.
// The hash is computed on the first call and cached thereafter.
func (b *Block) Hash() common.Hash {
Expand Down
Loading