Skip to content

Commit 3a5313f

Browse files
fjllightclient
andauthored
all: implement EIP-7002 & EIP-7251 (ethereum#30571)
This is a redo of ethereum#29052 based on newer specs. Here we implement EIPs scheduled for the Prague fork: - EIP-7002: Execution layer triggerable withdrawals - EIP-7251: Increase the MAX_EFFECTIVE_BALANCE Co-authored-by: lightclient <[email protected]>
1 parent 16bf471 commit 3a5313f

24 files changed

+216
-41
lines changed

cmd/evm/internal/t8ntool/execution.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ type ExecutionResult struct {
6666
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
6767
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
6868
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
69-
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
69+
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
7070
Requests [][]byte `json:"requests,omitempty"`
7171
}
7272

@@ -379,8 +379,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
379379
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
380380
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
381381
}
382+
383+
var requests [][]byte
382384
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
383-
// Parse the requests from the logs
385+
// EIP-6110 deposits
384386
var allLogs []*types.Log
385387
for _, receipt := range receipts {
386388
allLogs = append(allLogs, receipt.Logs...)
@@ -389,12 +391,23 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
389391
if err != nil {
390392
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
391393
}
392-
requests := [][]byte{depositRequests}
393-
// Calculate the requests root
394+
requests = append(requests, depositRequests)
395+
// create EVM for system calls
396+
vmenv := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
397+
// EIP-7002 withdrawals
398+
withdrawalRequests := core.ProcessWithdrawalQueue(vmenv, statedb)
399+
requests = append(requests, withdrawalRequests)
400+
// EIP-7251 consolidations
401+
consolidationRequests := core.ProcessConsolidationQueue(vmenv, statedb)
402+
requests = append(requests, consolidationRequests)
403+
}
404+
if requests != nil {
405+
// Set requestsHash on block.
394406
h := types.CalcRequestsHash(requests)
395407
execRs.RequestsHash = &h
396408
execRs.Requests = requests
397409
}
410+
398411
// Re-create statedb instance with new root upon the updated database
399412
// for accessing latest states.
400413
statedb, err = state.New(root, statedb.Database())

core/blockchain_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4227,3 +4227,87 @@ func TestEIP3651(t *testing.T) {
42274227
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
42284228
}
42294229
}
4230+
4231+
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
4232+
var depositsGeneratorCode = common.FromHex("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033")
4233+
4234+
// This is a smoke test for EIP-7685 requests added in the Prague fork. The test first
4235+
// creates a block containing requests, and then inserts it into the chain to run
4236+
// validation.
4237+
func TestPragueRequests(t *testing.T) {
4238+
var (
4239+
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
4240+
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
4241+
config = *params.MergedTestChainConfig
4242+
signer = types.LatestSigner(&config)
4243+
engine = beacon.NewFaker()
4244+
)
4245+
gspec := &Genesis{
4246+
Config: &config,
4247+
Alloc: types.GenesisAlloc{
4248+
addr1: {Balance: big.NewInt(9999900000000000)},
4249+
config.DepositContractAddress: {Code: depositsGeneratorCode},
4250+
params.WithdrawalQueueAddress: {Code: params.WithdrawalQueueCode},
4251+
params.ConsolidationQueueAddress: {Code: params.ConsolidationQueueCode},
4252+
},
4253+
}
4254+
4255+
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
4256+
// create deposit
4257+
depositTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
4258+
ChainID: gspec.Config.ChainID,
4259+
Nonce: 0,
4260+
To: &config.DepositContractAddress,
4261+
Gas: 500_000,
4262+
GasFeeCap: newGwei(5),
4263+
GasTipCap: big.NewInt(2),
4264+
})
4265+
b.AddTx(depositTx)
4266+
4267+
// create withdrawal request
4268+
withdrawalTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
4269+
ChainID: gspec.Config.ChainID,
4270+
Nonce: 1,
4271+
To: &params.WithdrawalQueueAddress,
4272+
Gas: 500_000,
4273+
GasFeeCap: newGwei(5),
4274+
GasTipCap: big.NewInt(2),
4275+
Value: newGwei(1),
4276+
Data: common.FromHex("b917cfdc0d25b72d55cf94db328e1629b7f4fde2c30cdacf873b664416f76a0c7f7cc50c9f72a3cb84be88144cde91250000000000000d80"),
4277+
})
4278+
b.AddTx(withdrawalTx)
4279+
4280+
// create consolidation request
4281+
consolidationTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
4282+
ChainID: gspec.Config.ChainID,
4283+
Nonce: 2,
4284+
To: &params.ConsolidationQueueAddress,
4285+
Gas: 500_000,
4286+
GasFeeCap: newGwei(5),
4287+
GasTipCap: big.NewInt(2),
4288+
Value: newGwei(1),
4289+
Data: common.FromHex("b917cfdc0d25b72d55cf94db328e1629b7f4fde2c30cdacf873b664416f76a0c7f7cc50c9f72a3cb84be88144cde9125b9812f7d0b1f2f969b52bbb2d316b0c2fa7c9dba85c428c5e6c27766bcc4b0c6e874702ff1eb1c7024b08524a9771601"),
4290+
})
4291+
b.AddTx(consolidationTx)
4292+
})
4293+
4294+
// Check block has the correct requests hash.
4295+
rh := blocks[0].RequestsHash()
4296+
if rh == nil {
4297+
t.Fatal("block has nil requests hash")
4298+
}
4299+
expectedRequestsHash := common.HexToHash("0x06ffb72b9f0823510b128bca6cd4f96f59b745de6791e9fc350b596e7605101e")
4300+
if *rh != expectedRequestsHash {
4301+
t.Fatalf("block has wrong requestsHash %v, want %v", *rh, expectedRequestsHash)
4302+
}
4303+
4304+
// Insert block to check validation.
4305+
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
4306+
if err != nil {
4307+
t.Fatalf("failed to create tester chain: %v", err)
4308+
}
4309+
defer chain.Stop()
4310+
if n, err := chain.InsertChain(blocks); err != nil {
4311+
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
4312+
}
4313+
}

core/chain_makers.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
348348

349349
var requests [][]byte
350350
if config.IsPrague(b.header.Number, b.header.Time) {
351+
// EIP-6110 deposits
351352
var blockLogs []*types.Log
352353
for _, r := range b.receipts {
353354
blockLogs = append(blockLogs, r.Logs...)
@@ -357,6 +358,15 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
357358
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
358359
}
359360
requests = append(requests, depositRequests)
361+
// create EVM for system calls
362+
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
363+
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, cm.config, vm.Config{})
364+
// EIP-7002 withdrawals
365+
withdrawalRequests := ProcessWithdrawalQueue(vmenv, statedb)
366+
requests = append(requests, withdrawalRequests)
367+
// EIP-7251 consolidations
368+
consolidationRequests := ProcessConsolidationQueue(vmenv, statedb)
369+
requests = append(requests, consolidationRequests)
360370
}
361371
if requests != nil {
362372
reqHash := types.CalcRequestsHash(requests)

core/genesis.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
472472
}
473473
}
474474
if conf.IsPrague(num, g.Timestamp) {
475-
emptyRequests := [][]byte{{0}}
475+
emptyRequests := [][]byte{{0x00}, {0x01}, {0x02}}
476476
rhash := types.CalcRequestsHash(emptyRequests)
477477
head.RequestsHash = &rhash
478478
}
@@ -588,10 +588,11 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
588588
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
589589
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
590590
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
591-
// Pre-deploy EIP-4788 system contract
592-
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
593-
// Pre-deploy EIP-2935 history contract.
594-
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
591+
// Pre-deploy system contracts
592+
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
593+
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
594+
params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0},
595+
params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0},
595596
},
596597
}
597598
if faucet != nil {

core/state_processor.go

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,18 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
102102
// Read requests if Prague is enabled.
103103
var requests [][]byte
104104
if p.config.IsPrague(block.Number(), block.Time()) {
105+
// EIP-6110 deposits
105106
depositRequests, err := ParseDepositLogs(allLogs, p.config)
106107
if err != nil {
107108
return nil, err
108109
}
109110
requests = append(requests, depositRequests)
111+
// EIP-7002 withdrawals
112+
withdrawalRequests := ProcessWithdrawalQueue(vmenv, statedb)
113+
requests = append(requests, withdrawalRequests)
114+
// EIP-7251 consolidations
115+
consolidationRequests := ProcessConsolidationQueue(vmenv, statedb)
116+
requests = append(requests, consolidationRequests)
110117
}
111118

112119
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
@@ -219,9 +226,6 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
219226
defer tracer.OnSystemCallEnd()
220227
}
221228
}
222-
223-
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
224-
// the new root
225229
msg := &Message{
226230
From: params.SystemAddress,
227231
GasLimit: 30_000_000,
@@ -248,7 +252,6 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.
248252
defer tracer.OnSystemCallEnd()
249253
}
250254
}
251-
252255
msg := &Message{
253256
From: params.SystemAddress,
254257
GasLimit: 30_000_000,
@@ -264,6 +267,48 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.
264267
statedb.Finalise(true)
265268
}
266269

270+
// ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
271+
// It returns the opaque request data returned by the contract.
272+
func ProcessWithdrawalQueue(vmenv *vm.EVM, statedb *state.StateDB) []byte {
273+
return processRequestsSystemCall(vmenv, statedb, 0x01, params.WithdrawalQueueAddress)
274+
}
275+
276+
// ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
277+
// It returns the opaque request data returned by the contract.
278+
func ProcessConsolidationQueue(vmenv *vm.EVM, statedb *state.StateDB) []byte {
279+
return processRequestsSystemCall(vmenv, statedb, 0x02, params.ConsolidationQueueAddress)
280+
}
281+
282+
func processRequestsSystemCall(vmenv *vm.EVM, statedb *state.StateDB, requestType byte, addr common.Address) []byte {
283+
if tracer := vmenv.Config.Tracer; tracer != nil {
284+
if tracer.OnSystemCallStart != nil {
285+
tracer.OnSystemCallStart()
286+
}
287+
if tracer.OnSystemCallEnd != nil {
288+
defer tracer.OnSystemCallEnd()
289+
}
290+
}
291+
292+
msg := &Message{
293+
From: params.SystemAddress,
294+
GasLimit: 30_000_000,
295+
GasPrice: common.Big0,
296+
GasFeeCap: common.Big0,
297+
GasTipCap: common.Big0,
298+
To: &addr,
299+
}
300+
vmenv.Reset(NewEVMTxContext(msg), statedb)
301+
statedb.AddAddressToAccessList(addr)
302+
ret, _, _ := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
303+
statedb.Finalise(true)
304+
305+
// Create withdrawals requestsData with prefix 0x01
306+
requestsData := make([]byte, len(ret)+1)
307+
requestsData[0] = requestType
308+
copy(requestsData[1:], ret)
309+
return requestsData
310+
}
311+
267312
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
268313
// BeaconDepositContract.
269314
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, error) {

core/types/block.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ func (b *Block) BaseFee() *big.Int {
402402
return new(big.Int).Set(b.header.BaseFee)
403403
}
404404

405-
func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot }
405+
func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot }
406+
func (b *Block) RequestsHash() *common.Hash { return b.header.RequestsHash }
406407

407408
func (b *Block) ExcessBlobGas() *uint64 {
408409
var excessBlobGas *uint64

eth/catalyst/simulated_beacon.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
220220
}
221221
}
222222
// Mark the payload as canon
223-
if _, err = c.engineAPI.NewPayloadV3(*payload, blobHashes, &common.Hash{}); err != nil {
223+
if _, err = c.engineAPI.NewPayloadV4(*payload, blobHashes, &common.Hash{}, envelope.Requests); err != nil {
224224
return err
225225
}
226226
c.setCurrentState(payload.BlockHash, finalizedHash)

eth/catalyst/simulated_beacon_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis, period
4040

4141
n, err := node.New(&node.Config{
4242
P2P: p2p.Config{
43-
ListenAddr: "127.0.0.1:8545",
43+
ListenAddr: "127.0.0.1:0",
4444
NoDiscovery: true,
4545
MaxPeers: 0,
4646
},

eth/tracers/internal/tracetest/supply_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func TestSupplyOmittedFields(t *testing.T) {
8686

8787
expected := supplyInfo{
8888
Number: 0,
89-
Hash: common.HexToHash("0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703"),
89+
Hash: common.HexToHash("0xc02ee8ee5b54a40e43f0fa827d431e1bd4f217e941790dda10b2521d1925a20b"),
9090
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
9191
}
9292
actual := out[expected.Number]

internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{
33
"blobGasPrice": "0x1",
44
"blobGasUsed": "0x20000",
5-
"blockHash": "0xd1392771155ce83f6403c6af275efd22bed567030c21168fcc9dbad5004eb245",
5+
"blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d",
66
"blockNumber": "0x6",
77
"contractAddress": null,
88
"cumulativeGasUsed": "0x5208",

0 commit comments

Comments
 (0)