Skip to content

Commit 3e51f81

Browse files
committed
all: implement 6110
1 parent a30e0dc commit 3e51f81

28 files changed

+775
-144
lines changed

beacon/engine/gen_ed.go

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

beacon/engine/types.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ type ExecutableData struct {
7777
Withdrawals []*types.Withdrawal `json:"withdrawals"`
7878
BlobGasUsed *uint64 `json:"blobGasUsed"`
7979
ExcessBlobGas *uint64 `json:"excessBlobGas"`
80-
Deposits []*types.Deposit `json:"depositReceipts"`
80+
Deposits types.Deposits `json:"depositRequests"`
8181
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
8282
}
8383

@@ -233,10 +233,18 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
233233
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
234234
withdrawalsRoot = &h
235235
}
236-
var depositsRoot *common.Hash
236+
// Compute requestsHash if any requests are non-nil.
237+
var (
238+
requestsHash *common.Hash
239+
requests types.Requests
240+
)
237241
if data.Deposits != nil {
238-
h := types.DeriveSha(types.Deposits(data.Deposits), trie.NewStackTrie(nil))
239-
depositsRoot = &h
242+
requests = make(types.Requests, 0)
243+
for _, d := range data.Deposits {
244+
requests = append(requests, types.NewRequest(d))
245+
}
246+
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
247+
requestsHash = &h
240248
}
241249
header := &types.Header{
242250
ParentHash: data.ParentHash,
@@ -258,10 +266,10 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
258266
ExcessBlobGas: data.ExcessBlobGas,
259267
BlobGasUsed: data.BlobGasUsed,
260268
ParentBeaconRoot: beaconRoot,
261-
DepositsHash: depositsRoot,
269+
RequestsHash: requestsHash,
262270
}
263271
block := types.NewBlockWithHeader(header)
264-
block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Deposits: data.Deposits})
272+
block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests})
265273
block = block.WithWitness(data.ExecutionWitness)
266274
if block.Hash() != data.BlockHash {
267275
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
@@ -290,7 +298,6 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
290298
Withdrawals: block.Withdrawals(),
291299
BlobGasUsed: block.BlobGasUsed(),
292300
ExcessBlobGas: block.ExcessBlobGas(),
293-
Deposits: block.Deposits(),
294301
ExecutionWitness: block.ExecutionWitness(),
295302
}
296303
bundle := BlobsBundleV1{
@@ -305,13 +312,30 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
305312
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
306313
}
307314
}
315+
setRequests(block.Requests(), data)
308316
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
309317
}
310318

311-
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
312-
type ExecutionPayloadBodyV1 struct {
319+
// setRequests differentiates the different request types and
320+
// assigns them to the associated fields in ExecutableData.
321+
func setRequests(requests types.Requests, data *ExecutableData) {
322+
if requests != nil {
323+
// If requests is non-nil, it means deposits are available in block and we
324+
// should return an empty slice instead of nil if there are no deposits.
325+
data.Deposits = make(types.Deposits, 0)
326+
}
327+
for _, r := range requests {
328+
if d, ok := r.Inner().(*types.Deposit); ok {
329+
data.Deposits = append(data.Deposits, d)
330+
}
331+
}
332+
}
333+
334+
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
335+
type ExecutionPayloadBody struct {
313336
TransactionData []hexutil.Bytes `json:"transactions"`
314337
Withdrawals []*types.Withdrawal `json:"withdrawals"`
338+
Deposits types.Deposits `json:"depositRequests"`
315339
}
316340

317341
// Client identifiers to support ClientVersionV1.

cmd/evm/internal/t8ntool/execution.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ 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"`
70+
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
6971
}
7072

7173
type ommer struct {
@@ -377,6 +379,28 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
377379
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
378380
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
379381
}
382+
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
383+
// Parse the requests from the logs
384+
var allLogs []*types.Log
385+
for _, receipt := range receipts {
386+
allLogs = append(allLogs, receipt.Logs...)
387+
}
388+
requests, err := core.ParseDepositLogs(allLogs, chainConfig)
389+
if err != nil {
390+
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
391+
}
392+
// Calculate the requests root
393+
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
394+
execRs.RequestsHash = &h
395+
// Get the deposits from the requests
396+
deposits := make(types.Deposits, 0)
397+
for _, req := range requests {
398+
if dep, ok := req.Inner().(*types.Deposit); ok {
399+
deposits = append(deposits, dep)
400+
}
401+
}
402+
execRs.DepositRequests = &deposits
403+
}
380404
// Re-create statedb instance with new root upon the updated database
381405
// for accessing latest states.
382406
statedb, err = state.New(root, statedb.Database(), nil)

core/block_validator.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
121121

122122
// ValidateState validates the various changes that happen after a state transition,
123123
// such as amount of used gas, the receipt roots and the state root itself.
124-
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error {
124+
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
125+
if res == nil {
126+
return fmt.Errorf("nil ProcessResult value")
127+
}
125128
header := block.Header()
126-
if block.GasUsed() != usedGas {
127-
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
129+
if block.GasUsed() != res.GasUsed {
130+
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed)
128131
}
129132
// Validate the received block's bloom with the one derived from the generated receipts.
130133
// For valid blocks this should always validate to true.
131-
rbloom := types.CreateBloom(receipts)
134+
rbloom := types.CreateBloom(res.Receipts)
132135
if rbloom != header.Bloom {
133136
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
134137
}
@@ -138,10 +141,17 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
138141
return nil
139142
}
140143
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
141-
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
144+
receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
142145
if receiptSha != header.ReceiptHash {
143146
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
144147
}
148+
// Validate the parsed requests match the expected header value.
149+
if header.RequestsHash != nil {
150+
depositSha := types.DeriveSha(res.Requests, trie.NewStackTrie(nil))
151+
if depositSha != *header.RequestsHash {
152+
return fmt.Errorf("invalid deposit root hash (remote: %x local: %x)", *header.RequestsHash, depositSha)
153+
}
154+
}
145155
// Validate the state root against the received state root and throw
146156
// an error if they don't match.
147157
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {

core/blockchain.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,23 +1927,23 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
19271927

19281928
// Process block using the parent state as reference point
19291929
pstart := time.Now()
1930-
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
1930+
res, err := bc.processor.Process(block, statedb, bc.vmConfig)
19311931
if err != nil {
1932-
bc.reportBlock(block, receipts, err)
1932+
bc.reportBlock(block, res, err)
19331933
return nil, err
19341934
}
19351935
ptime := time.Since(pstart)
19361936

19371937
vstart := time.Now()
1938-
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
1939-
bc.reportBlock(block, receipts, err)
1938+
if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
1939+
bc.reportBlock(block, res, err)
19401940
return nil, err
19411941
}
19421942
vtime := time.Since(vstart)
19431943

19441944
if witness := statedb.Witness(); witness != nil {
19451945
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
1946-
bc.reportBlock(block, receipts, err)
1946+
bc.reportBlock(block, res, err)
19471947
return nil, fmt.Errorf("cross verification failed: %v", err)
19481948
}
19491949
}
@@ -1978,9 +1978,9 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
19781978
)
19791979
if !setHead {
19801980
// Don't set the head, only insert the block
1981-
err = bc.writeBlockWithState(block, receipts, statedb)
1981+
err = bc.writeBlockWithState(block, res.Receipts, statedb)
19821982
} else {
1983-
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
1983+
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
19841984
}
19851985
if err != nil {
19861986
return nil, err
@@ -1994,7 +1994,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
19941994
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
19951995
blockInsertTimer.UpdateSince(start)
19961996

1997-
return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil
1997+
return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil
19981998
}
19991999

20002000
// insertSideChain is called when an import batch hits upon a pruned ancestor
@@ -2491,7 +2491,11 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
24912491
}
24922492

24932493
// reportBlock logs a bad block error.
2494-
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
2494+
func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err error) {
2495+
var receipts types.Receipts
2496+
if res != nil {
2497+
receipts = res.Receipts
2498+
}
24952499
rawdb.WriteBadBlock(bc.db, block)
24962500
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
24972501
}

core/blockchain_test.go

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,14 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
163163
if err != nil {
164164
return err
165165
}
166-
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
166+
res, err := blockchain.processor.Process(block, statedb, vm.Config{})
167167
if err != nil {
168-
blockchain.reportBlock(block, receipts, err)
168+
blockchain.reportBlock(block, res, err)
169169
return err
170170
}
171-
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
172-
blockchain.reportBlock(block, receipts, err)
171+
err = blockchain.validator.ValidateState(block, statedb, res, false)
172+
if err != nil {
173+
blockchain.reportBlock(block, res, err)
173174
return err
174175
}
175176

@@ -4220,3 +4221,90 @@ func TestEIP3651(t *testing.T) {
42204221
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
42214222
}
42224223
}
4224+
4225+
func TestEIP6110(t *testing.T) {
4226+
var (
4227+
engine = beacon.NewFaker()
4228+
4229+
// A sender who makes transactions, has some funds
4230+
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
4231+
addr = crypto.PubkeyToAddress(key.PublicKey)
4232+
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
4233+
config = *params.AllEthashProtocolChanges
4234+
gspec = &Genesis{
4235+
Config: &config,
4236+
Alloc: types.GenesisAlloc{
4237+
addr: {Balance: funds},
4238+
config.DepositContractAddress: {
4239+
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
4240+
Code: common.Hex2Bytes("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033"),
4241+
Nonce: 0,
4242+
Balance: big.NewInt(0),
4243+
},
4244+
},
4245+
}
4246+
)
4247+
4248+
gspec.Config.BerlinBlock = common.Big0
4249+
gspec.Config.LondonBlock = common.Big0
4250+
gspec.Config.TerminalTotalDifficulty = common.Big0
4251+
gspec.Config.TerminalTotalDifficultyPassed = true
4252+
gspec.Config.ShanghaiTime = u64(0)
4253+
gspec.Config.CancunTime = u64(0)
4254+
gspec.Config.PragueTime = u64(0)
4255+
signer := types.LatestSigner(gspec.Config)
4256+
4257+
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
4258+
for i := 0; i < 5; i++ {
4259+
txdata := &types.DynamicFeeTx{
4260+
ChainID: gspec.Config.ChainID,
4261+
Nonce: uint64(i),
4262+
To: &config.DepositContractAddress,
4263+
Gas: 500000,
4264+
GasFeeCap: newGwei(5),
4265+
GasTipCap: big.NewInt(2),
4266+
AccessList: nil,
4267+
Data: []byte{},
4268+
}
4269+
tx := types.NewTx(txdata)
4270+
tx, _ = types.SignTx(tx, signer, key)
4271+
b.AddTx(tx)
4272+
}
4273+
})
4274+
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{DisableStack: true}, os.Stderr).Hooks()}, nil, nil)
4275+
if err != nil {
4276+
t.Fatalf("failed to create tester chain: %v", err)
4277+
}
4278+
defer chain.Stop()
4279+
if n, err := chain.InsertChain(blocks); err != nil {
4280+
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
4281+
}
4282+
4283+
block := chain.GetBlockByNumber(1)
4284+
if len(block.Requests()) != 5 {
4285+
t.Fatalf("failed to retrieve deposits: have %d, want %d", len(block.Requests()), 5)
4286+
}
4287+
4288+
// Verify each index is correct.
4289+
for want, req := range block.Requests() {
4290+
d, ok := req.Inner().(*types.Deposit)
4291+
if !ok {
4292+
t.Fatalf("expected deposit object")
4293+
}
4294+
if got := int(d.PublicKey[0]); got != want {
4295+
t.Fatalf("invalid pubkey: have %d, want %d", got, want)
4296+
}
4297+
if got := int(d.WithdrawalCredentials[0]); got != want {
4298+
t.Fatalf("invalid withdrawal credentials: have %d, want %d", got, want)
4299+
}
4300+
if d.Amount != uint64(want) {
4301+
t.Fatalf("invalid amounbt: have %d, want %d", d.Amount, want)
4302+
}
4303+
if got := int(d.Signature[0]); got != want {
4304+
t.Fatalf("invalid signature: have %d, want %d", got, want)
4305+
}
4306+
if d.Index != uint64(want) {
4307+
t.Fatalf("invalid index: have %d, want %d", d.Index, want)
4308+
}
4309+
}
4310+
}

core/chain_makers.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,18 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
346346
gen(i, b)
347347
}
348348

349-
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals}
349+
var requests types.Requests
350+
if config.IsPrague(b.header.Number, b.header.Time) {
351+
for _, r := range b.receipts {
352+
d, err := ParseDepositLogs(r.Logs, config)
353+
if err != nil {
354+
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
355+
}
356+
requests = append(requests, d...)
357+
}
358+
}
359+
360+
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests}
350361
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
351362
if err != nil {
352363
panic(err)

0 commit comments

Comments
 (0)