Skip to content

Commit 7c8cfdd

Browse files
MariusVanDerWijdenlightclientmarioevzholimanfjl
authored andcommitted
all: implement withdrawals (EIP-4895) (ethereum#26484)
This change implements withdrawals as specified in EIP-4895. Co-authored-by: [email protected] <[email protected]> Co-authored-by: marioevz <[email protected]> Co-authored-by: Martin Holst Swende <[email protected]> Co-authored-by: Felix Lange <[email protected]>
1 parent 7dbc020 commit 7c8cfdd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1236
-439
lines changed

cmd/evm/internal/t8ntool/block.go

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,23 @@ import (
3838

3939
//go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go
4040
type header struct {
41-
ParentHash common.Hash `json:"parentHash"`
42-
OmmerHash *common.Hash `json:"sha3Uncles"`
43-
Coinbase *common.Address `json:"miner"`
44-
Root common.Hash `json:"stateRoot" gencodec:"required"`
45-
TxHash *common.Hash `json:"transactionsRoot"`
46-
ReceiptHash *common.Hash `json:"receiptsRoot"`
47-
Bloom types.Bloom `json:"logsBloom"`
48-
Difficulty *big.Int `json:"difficulty"`
49-
Number *big.Int `json:"number" gencodec:"required"`
50-
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
51-
GasUsed uint64 `json:"gasUsed"`
52-
Time uint64 `json:"timestamp" gencodec:"required"`
53-
Extra []byte `json:"extraData"`
54-
MixDigest common.Hash `json:"mixHash"`
55-
Nonce *types.BlockNonce `json:"nonce"`
56-
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
41+
ParentHash common.Hash `json:"parentHash"`
42+
OmmerHash *common.Hash `json:"sha3Uncles"`
43+
Coinbase *common.Address `json:"miner"`
44+
Root common.Hash `json:"stateRoot" gencodec:"required"`
45+
TxHash *common.Hash `json:"transactionsRoot"`
46+
ReceiptHash *common.Hash `json:"receiptsRoot"`
47+
Bloom types.Bloom `json:"logsBloom"`
48+
Difficulty *big.Int `json:"difficulty"`
49+
Number *big.Int `json:"number" gencodec:"required"`
50+
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
51+
GasUsed uint64 `json:"gasUsed"`
52+
Time uint64 `json:"timestamp" gencodec:"required"`
53+
Extra []byte `json:"extraData"`
54+
MixDigest common.Hash `json:"mixHash"`
55+
Nonce *types.BlockNonce `json:"nonce"`
56+
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
57+
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
5758
}
5859

5960
type headerMarshaling struct {
@@ -67,10 +68,11 @@ type headerMarshaling struct {
6768
}
6869

6970
type bbInput struct {
70-
Header *header `json:"header,omitempty"`
71-
OmmersRlp []string `json:"ommers,omitempty"`
72-
TxRlp string `json:"txs,omitempty"`
73-
Clique *cliqueInput `json:"clique,omitempty"`
71+
Header *header `json:"header,omitempty"`
72+
OmmersRlp []string `json:"ommers,omitempty"`
73+
TxRlp string `json:"txs,omitempty"`
74+
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
75+
Clique *cliqueInput `json:"clique,omitempty"`
7476

7577
Ethash bool `json:"-"`
7678
EthashDir string `json:"-"`
@@ -114,21 +116,22 @@ func (c *cliqueInput) UnmarshalJSON(input []byte) error {
114116
// ToBlock converts i into a *types.Block
115117
func (i *bbInput) ToBlock() *types.Block {
116118
header := &types.Header{
117-
ParentHash: i.Header.ParentHash,
118-
UncleHash: types.EmptyUncleHash,
119-
Coinbase: common.Address{},
120-
Root: i.Header.Root,
121-
TxHash: types.EmptyRootHash,
122-
ReceiptHash: types.EmptyRootHash,
123-
Bloom: i.Header.Bloom,
124-
Difficulty: common.Big0,
125-
Number: i.Header.Number,
126-
GasLimit: i.Header.GasLimit,
127-
GasUsed: i.Header.GasUsed,
128-
Time: i.Header.Time,
129-
Extra: i.Header.Extra,
130-
MixDigest: i.Header.MixDigest,
131-
BaseFee: i.Header.BaseFee,
119+
ParentHash: i.Header.ParentHash,
120+
UncleHash: types.EmptyUncleHash,
121+
Coinbase: common.Address{},
122+
Root: i.Header.Root,
123+
TxHash: types.EmptyRootHash,
124+
ReceiptHash: types.EmptyRootHash,
125+
Bloom: i.Header.Bloom,
126+
Difficulty: common.Big0,
127+
Number: i.Header.Number,
128+
GasLimit: i.Header.GasLimit,
129+
GasUsed: i.Header.GasUsed,
130+
Time: i.Header.Time,
131+
Extra: i.Header.Extra,
132+
MixDigest: i.Header.MixDigest,
133+
BaseFee: i.Header.BaseFee,
134+
WithdrawalsHash: i.Header.WithdrawalsHash,
132135
}
133136

134137
// Fill optional values.
@@ -153,7 +156,7 @@ func (i *bbInput) ToBlock() *types.Block {
153156
if header.Difficulty != nil {
154157
header.Difficulty = i.Header.Difficulty
155158
}
156-
return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers)
159+
return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers).WithWithdrawals(i.Withdrawals)
157160
}
158161

159162
// SealBlock seals the given block using the configured engine.
@@ -259,14 +262,15 @@ func BuildBlock(ctx *cli.Context) error {
259262

260263
func readInput(ctx *cli.Context) (*bbInput, error) {
261264
var (
262-
headerStr = ctx.String(InputHeaderFlag.Name)
263-
ommersStr = ctx.String(InputOmmersFlag.Name)
264-
txsStr = ctx.String(InputTxsRlpFlag.Name)
265-
cliqueStr = ctx.String(SealCliqueFlag.Name)
266-
ethashOn = ctx.Bool(SealEthashFlag.Name)
267-
ethashDir = ctx.String(SealEthashDirFlag.Name)
268-
ethashMode = ctx.String(SealEthashModeFlag.Name)
269-
inputData = &bbInput{}
265+
headerStr = ctx.String(InputHeaderFlag.Name)
266+
ommersStr = ctx.String(InputOmmersFlag.Name)
267+
withdrawalsStr = ctx.String(InputWithdrawalsFlag.Name)
268+
txsStr = ctx.String(InputTxsRlpFlag.Name)
269+
cliqueStr = ctx.String(SealCliqueFlag.Name)
270+
ethashOn = ctx.Bool(SealEthashFlag.Name)
271+
ethashDir = ctx.String(SealEthashDirFlag.Name)
272+
ethashMode = ctx.String(SealEthashModeFlag.Name)
273+
inputData = &bbInput{}
270274
)
271275
if ethashOn && cliqueStr != "" {
272276
return nil, NewError(ErrorConfig, fmt.Errorf("both ethash and clique sealing specified, only one may be chosen"))
@@ -312,6 +316,13 @@ func readInput(ctx *cli.Context) (*bbInput, error) {
312316
}
313317
inputData.OmmersRlp = ommers
314318
}
319+
if withdrawalsStr != stdinSelector && withdrawalsStr != "" {
320+
var withdrawals []*types.Withdrawal
321+
if err := readFile(withdrawalsStr, "withdrawals", &withdrawals); err != nil {
322+
return nil, err
323+
}
324+
inputData.Withdrawals = withdrawals
325+
}
315326
if txsStr != stdinSelector {
316327
var txs string
317328
if err := readFile(txsStr, "txs", &txs); err != nil {
@@ -351,15 +362,14 @@ func readInput(ctx *cli.Context) (*bbInput, error) {
351362
// files
352363
func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error {
353364
raw, _ := rlp.EncodeToBytes(block)
354-
355365
type blockInfo struct {
356366
Rlp hexutil.Bytes `json:"rlp"`
357367
Hash common.Hash `json:"hash"`
358368
}
359-
var enc blockInfo
360-
enc.Rlp = raw
361-
enc.Hash = block.Hash()
362-
369+
enc := blockInfo{
370+
Rlp: raw,
371+
Hash: block.Hash(),
372+
}
363373
b, err := json.MarshalIndent(enc, "", " ")
364374
if err != nil {
365375
return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))

cmd/evm/internal/t8ntool/execution.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ type Prestate struct {
4747
// ExecutionResult contains the execution status after running a state test, any
4848
// error that might have occurred and a dump of the final state if requested.
4949
type ExecutionResult struct {
50-
StateRoot common.Hash `json:"stateRoot"`
51-
TxRoot common.Hash `json:"txRoot"`
52-
ReceiptRoot common.Hash `json:"receiptsRoot"`
53-
LogsHash common.Hash `json:"logsHash"`
54-
Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
55-
Receipts types.Receipts `json:"receipts"`
56-
Rejected []*rejectedTx `json:"rejected,omitempty"`
57-
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
58-
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
59-
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
50+
StateRoot common.Hash `json:"stateRoot"`
51+
TxRoot common.Hash `json:"txRoot"`
52+
ReceiptRoot common.Hash `json:"receiptsRoot"`
53+
LogsHash common.Hash `json:"logsHash"`
54+
Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
55+
Receipts types.Receipts `json:"receipts"`
56+
Rejected []*rejectedTx `json:"rejected,omitempty"`
57+
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
58+
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
59+
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
60+
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
6061
}
6162

6263
type ommer struct {
@@ -79,6 +80,7 @@ type stEnv struct {
7980
ParentTimestamp uint64 `json:"parentTimestamp,omitempty"`
8081
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
8182
Ommers []ommer `json:"ommers,omitempty"`
83+
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
8284
BaseFee *big.Int `json:"currentBaseFee,omitempty"`
8385
ParentUncleHash common.Hash `json:"parentUncleHash"`
8486
}
@@ -254,6 +256,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
254256
}
255257
statedb.AddBalance(pre.Env.Coinbase, minerReward)
256258
}
259+
// Apply withdrawals
260+
for _, w := range pre.Env.Withdrawals {
261+
// Amount is in gwei, turn into wei
262+
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
263+
statedb.AddBalance(w.Address, amount)
264+
}
257265
// Commit block
258266
root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber))
259267
if err != nil {
@@ -272,6 +280,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
272280
GasUsed: (math.HexOrDecimal64)(gasUsed),
273281
BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee),
274282
}
283+
if pre.Env.Withdrawals != nil {
284+
h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil))
285+
execRs.WithdrawalsRoot = &h
286+
}
275287
return statedb, execRs, nil
276288
}
277289

cmd/evm/internal/t8ntool/flags.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ var (
112112
Name: "input.ommers",
113113
Usage: "`stdin` or file name of where to find the list of ommer header RLPs to use.",
114114
}
115+
InputWithdrawalsFlag = &cli.StringFlag{
116+
Name: "input.withdrawals",
117+
Usage: "`stdin` or file name of where to find the list of withdrawals to use.",
118+
}
115119
InputTxsRlpFlag = &cli.StringFlag{
116120
Name: "input.txs",
117121
Usage: "`stdin` or file name of where to find the transactions list in RLP form.",

cmd/evm/internal/t8ntool/gen_header.go

Lines changed: 38 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/evm/internal/t8ntool/gen_stenv.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/evm/internal/t8ntool/transition.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ func Transition(ctx *cli.Context) error {
262262
return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section"))
263263
}
264264
}
265+
if chainConfig.IsShanghai(prestate.Env.Number) && prestate.Env.Withdrawals == nil {
266+
return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section"))
267+
}
265268
isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0
266269
env := prestate.Env
267270
if isMerged {

cmd/evm/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ var blockBuilderCommand = &cli.Command{
176176
t8ntool.OutputBlockFlag,
177177
t8ntool.InputHeaderFlag,
178178
t8ntool.InputOmmersFlag,
179+
t8ntool.InputWithdrawalsFlag,
179180
t8ntool.InputTxsRlpFlag,
180181
t8ntool.SealCliqueFlag,
181182
t8ntool.SealEthashFlag,

0 commit comments

Comments
 (0)