all: implement eip-7251 consolidation requests

Co-authored-by: Mario Vega <marioevz@gmail.com>
Co-authored-by: lightclient <lightclient@protonmail.com>
pull/29052/head
Mario Vega 3 months ago committed by lightclient
parent dbdecb55dc
commit 3aae627db3
No known key found for this signature in database
GPG Key ID: 75C916AFEE20183E
  1. 86
      beacon/engine/gen_ed.go
  2. 56
      beacon/engine/types.go
  3. 76
      cmd/evm/internal/t8ntool/execution.go
  4. 116
      core/blockchain_test.go
  5. 2
      core/chain_makers.go
  6. 43
      core/state_processor.go
  7. 79
      core/types/consolidation_request.go
  8. 56
      core/types/gen_consolidation_request_json.go
  9. 7
      core/types/request.go
  10. 28
      eth/catalyst/api.go
  11. 41
      eth/catalyst/api_test.go
  12. 3
      miner/worker.go
  13. 2
      params/protocol_params.go

@ -17,26 +17,27 @@ var _ = (*executableDataMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (e ExecutableData) MarshalJSON() ([]byte, error) { func (e ExecutableData) MarshalJSON() ([]byte, error) {
type ExecutableData struct { type ExecutableData struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"` ParentHash common.Hash `json:"parentHash" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
StateRoot common.Hash `json:"stateRoot" gencodec:"required"` StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
Random common.Hash `json:"prevRandao" gencodec:"required"` Random common.Hash `json:"prevRandao" gencodec:"required"`
Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"` Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
BlockHash common.Hash `json:"blockHash" gencodec:"required"` BlockHash common.Hash `json:"blockHash" gencodec:"required"`
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"` Deposits types.Deposits `json:"depositRequests"`
WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests"` WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ConsolidationRequests types.ConsolidationRequests `json:"consolidationRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
var enc ExecutableData var enc ExecutableData
enc.ParentHash = e.ParentHash enc.ParentHash = e.ParentHash
@ -63,6 +64,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
enc.Deposits = e.Deposits enc.Deposits = e.Deposits
enc.WithdrawalRequests = e.WithdrawalRequests enc.WithdrawalRequests = e.WithdrawalRequests
enc.ConsolidationRequests = e.ConsolidationRequests
enc.ExecutionWitness = e.ExecutionWitness enc.ExecutionWitness = e.ExecutionWitness
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -70,26 +72,27 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (e *ExecutableData) UnmarshalJSON(input []byte) error { func (e *ExecutableData) UnmarshalJSON(input []byte) error {
type ExecutableData struct { type ExecutableData struct {
ParentHash *common.Hash `json:"parentHash" gencodec:"required"` ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
Random *common.Hash `json:"prevRandao" gencodec:"required"` Random *common.Hash `json:"prevRandao" gencodec:"required"`
Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"` Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
BlockHash *common.Hash `json:"blockHash" gencodec:"required"` BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits *types.Deposits `json:"depositRequests"` Deposits *types.Deposits `json:"depositRequests"`
WithdrawalRequests *types.WithdrawalRequests `json:"withdrawalRequests"` WithdrawalRequests *types.WithdrawalRequests `json:"withdrawalRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ConsolidationRequests *types.ConsolidationRequests `json:"consolidationRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
var dec ExecutableData var dec ExecutableData
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
@ -169,6 +172,9 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.WithdrawalRequests != nil { if dec.WithdrawalRequests != nil {
e.WithdrawalRequests = *dec.WithdrawalRequests e.WithdrawalRequests = *dec.WithdrawalRequests
} }
if dec.ConsolidationRequests != nil {
e.ConsolidationRequests = *dec.ConsolidationRequests
}
if dec.ExecutionWitness != nil { if dec.ExecutionWitness != nil {
e.ExecutionWitness = dec.ExecutionWitness e.ExecutionWitness = dec.ExecutionWitness
} }

@ -60,26 +60,27 @@ type payloadAttributesMarshaling struct {
// ExecutableData is the data necessary to execute an EL payload. // ExecutableData is the data necessary to execute an EL payload.
type ExecutableData struct { type ExecutableData struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"` ParentHash common.Hash `json:"parentHash" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
StateRoot common.Hash `json:"stateRoot" gencodec:"required"` StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
LogsBloom []byte `json:"logsBloom" gencodec:"required"` LogsBloom []byte `json:"logsBloom" gencodec:"required"`
Random common.Hash `json:"prevRandao" gencodec:"required"` Random common.Hash `json:"prevRandao" gencodec:"required"`
Number uint64 `json:"blockNumber" gencodec:"required"` Number uint64 `json:"blockNumber" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"` GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"` GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Timestamp uint64 `json:"timestamp" gencodec:"required"` Timestamp uint64 `json:"timestamp" gencodec:"required"`
ExtraData []byte `json:"extraData" gencodec:"required"` ExtraData []byte `json:"extraData" gencodec:"required"`
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
BlockHash common.Hash `json:"blockHash" gencodec:"required"` BlockHash common.Hash `json:"blockHash" gencodec:"required"`
Transactions [][]byte `json:"transactions" gencodec:"required"` Transactions [][]byte `json:"transactions" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *uint64 `json:"blobGasUsed"` BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"` ExcessBlobGas *uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"` Deposits types.Deposits `json:"depositRequests"`
WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests"` WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ConsolidationRequests types.ConsolidationRequests `json:"consolidationRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
// JSON type overrides for executableData. // JSON type overrides for executableData.
@ -252,6 +253,9 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
requests = append(requests, types.NewRequest(w)) requests = append(requests, types.NewRequest(w))
} }
} }
if data.ConsolidationRequests != nil {
requests = append(requests, data.ConsolidationRequests.Requests()...)
}
if requests != nil { if requests != nil {
h := types.DeriveSha(requests, trie.NewStackTrie(nil)) h := types.DeriveSha(requests, trie.NewStackTrie(nil))
requestsHash = &h requestsHash = &h
@ -335,6 +339,7 @@ func setRequests(requests types.Requests, data *ExecutableData) {
// we should return an empty slice instead of nil. // we should return an empty slice instead of nil.
data.Deposits = make(types.Deposits, 0) data.Deposits = make(types.Deposits, 0)
data.WithdrawalRequests = make(types.WithdrawalRequests, 0) data.WithdrawalRequests = make(types.WithdrawalRequests, 0)
data.ConsolidationRequests = make(types.ConsolidationRequests, 0)
} }
for _, r := range requests { for _, r := range requests {
switch v := r.Inner().(type) { switch v := r.Inner().(type) {
@ -342,16 +347,19 @@ func setRequests(requests types.Requests, data *ExecutableData) {
data.Deposits = append(data.Deposits, v) data.Deposits = append(data.Deposits, v)
case *types.WithdrawalRequest: case *types.WithdrawalRequest:
data.WithdrawalRequests = append(data.WithdrawalRequests, v) data.WithdrawalRequests = append(data.WithdrawalRequests, v)
case *types.ConsolidationRequest:
data.ConsolidationRequests = append(data.ConsolidationRequests, v)
} }
} }
} }
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange // ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
type ExecutionPayloadBody struct { type ExecutionPayloadBody struct {
TransactionData []hexutil.Bytes `json:"transactions"` TransactionData []hexutil.Bytes `json:"transactions"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
Deposits types.Deposits `json:"depositRequests"` Deposits types.Deposits `json:"depositRequests"`
WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests"` WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests"`
ConsolidationRequests types.ConsolidationRequests `json:"consolidationRequests"`
} }
// Client identifiers to support ClientVersionV1. // Client identifiers to support ClientVersionV1.

@ -53,22 +53,23 @@ type Prestate struct {
// ExecutionResult contains the execution status after running a state test, any // ExecutionResult contains the execution status after running a state test, any
// error that might have occurred and a dump of the final state if requested. // error that might have occurred and a dump of the final state if requested.
type ExecutionResult struct { type ExecutionResult struct {
StateRoot common.Hash `json:"stateRoot"` StateRoot common.Hash `json:"stateRoot"`
TxRoot common.Hash `json:"txRoot"` TxRoot common.Hash `json:"txRoot"`
ReceiptRoot common.Hash `json:"receiptsRoot"` ReceiptRoot common.Hash `json:"receiptsRoot"`
LogsHash common.Hash `json:"logsHash"` LogsHash common.Hash `json:"logsHash"`
Bloom types.Bloom `json:"logsBloom" gencodec:"required"` Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
Receipts types.Receipts `json:"receipts"` Receipts types.Receipts `json:"receipts"`
Rejected []*rejectedTx `json:"rejected,omitempty"` Rejected []*rejectedTx `json:"rejected,omitempty"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"` GasUsed math.HexOrDecimal64 `json:"gasUsed"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsRoot,omitempty"` RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
DepositRequests types.Deposits `json:"depositRequests,omitempty"` DepositRequests types.Deposits `json:"depositRequests,omitempty"`
WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests,omitempty"` WithdrawalRequests types.WithdrawalRequests `json:"withdrawalRequests,omitempty"`
ConsolidationRequests types.ConsolidationRequests `json:"consolidationRequests,omitempty"`
} }
type ommer struct { type ommer struct {
@ -357,9 +358,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
} }
// Retrieve deposit and withdrawal requests // Retrieve deposit and withdrawal requests
var ( var (
depositRequests types.Deposits depositRequests types.Deposits
withdrawalRequests types.WithdrawalRequests withdrawalRequests types.WithdrawalRequests
requestsHash *common.Hash consolidationRequests types.ConsolidationRequests
requestsHash *common.Hash
) )
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) { if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
// Parse deposit requests from the logs // Parse deposit requests from the logs
@ -375,18 +377,25 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
vmenv := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) vmenv := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
wxs := core.ProcessDequeueWithdrawalRequests(vmenv, statedb) wxs := core.ProcessDequeueWithdrawalRequests(vmenv, statedb)
requests = append(requests, wxs...) requests = append(requests, wxs...)
// Process the consolidation requests contract execution
cxs := core.ProcessDequeueConsolidationRequests(vmenv, statedb)
requests = append(requests, cxs...)
// Calculate the requests root // Calculate the requests root
h := types.DeriveSha(requests, trie.NewStackTrie(nil)) h := types.DeriveSha(requests, trie.NewStackTrie(nil))
requestsHash = &h requestsHash = &h
// Get the deposits from the requests
// Break out individual request types.
depositRequests = make(types.Deposits, 0) depositRequests = make(types.Deposits, 0)
withdrawalRequests = make(types.WithdrawalRequests, 0) withdrawalRequests = make(types.WithdrawalRequests, 0)
consolidationRequests = make(types.ConsolidationRequests, 0)
for _, req := range requests { for _, req := range requests {
switch v := req.Inner().(type) { switch v := req.Inner().(type) {
case *types.Deposit: case *types.Deposit:
depositRequests = append(depositRequests, v) depositRequests = append(depositRequests, v)
case *types.WithdrawalRequest: case *types.WithdrawalRequest:
withdrawalRequests = append(withdrawalRequests, v) withdrawalRequests = append(withdrawalRequests, v)
case *types.ConsolidationRequest:
consolidationRequests = append(consolidationRequests, v)
} }
} }
} }
@ -396,19 +405,20 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
} }
execRs := &ExecutionResult{ execRs := &ExecutionResult{
StateRoot: root, StateRoot: root,
TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)), TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)),
ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)), ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)),
Bloom: types.CreateBloom(receipts), Bloom: types.CreateBloom(receipts),
LogsHash: rlpHash(statedb.Logs()), LogsHash: rlpHash(statedb.Logs()),
Receipts: receipts, Receipts: receipts,
Rejected: rejectedTxs, Rejected: rejectedTxs,
Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty), Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty),
GasUsed: (math.HexOrDecimal64)(gasUsed), GasUsed: (math.HexOrDecimal64)(gasUsed),
BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee), BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee),
RequestsHash: requestsHash, RequestsHash: requestsHash,
DepositRequests: depositRequests, DepositRequests: depositRequests,
WithdrawalRequests: withdrawalRequests, WithdrawalRequests: withdrawalRequests,
ConsolidationRequests: consolidationRequests,
} }
if pre.Env.Withdrawals != nil { if pre.Env.Withdrawals != nil {
h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil)) h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil))

@ -4316,9 +4316,8 @@ func TestEIP6110(t *testing.T) {
} }
} }
// TestEIP7002 verifies that withdrawal requests are processed correctly in the // TestRequests verifies that Prague requests are processed correctly.
// pre-deploy and parsed out correctly via the system call. func TestRequests(t *testing.T) {
func TestEIP7002(t *testing.T) {
var ( var (
engine = beacon.NewFaker() engine = beacon.NewFaker()
@ -4330,8 +4329,9 @@ func TestEIP7002(t *testing.T) {
gspec = &Genesis{ gspec = &Genesis{
Config: &config, Config: &config,
Alloc: types.GenesisAlloc{ Alloc: types.GenesisAlloc{
addr: {Balance: funds}, addr: {Balance: funds},
params.WithdrawalRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd")}, params.WithdrawalRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd")},
params.ConsolidationRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd")},
}, },
} }
) )
@ -4357,29 +4357,67 @@ func TestEIP7002(t *testing.T) {
Amount: 1337, Amount: 1337,
}, },
} }
cxs := types.ConsolidationRequests{
{
Source: addr,
SourcePublicKey: [48]byte{13, 37},
TargetPublicKey: [48]byte{11, 11},
},
{
Source: addr,
SourcePublicKey: [48]byte{42, 42},
TargetPublicKey: [48]byte{11, 11},
},
}
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 3, func(i int, b *BlockGen) {
for i, wx := range wxs { switch i {
data := make([]byte, 56) case 0:
copy(data, wx.PublicKey[:]) // Block 1: submit withdrawal requests
binary.BigEndian.PutUint64(data[48:], wx.Amount) for _, wx := range wxs {
txdata := &types.DynamicFeeTx{ data := make([]byte, 56)
ChainID: gspec.Config.ChainID, copy(data, wx.PublicKey[:])
Nonce: uint64(i), binary.BigEndian.PutUint64(data[48:], wx.Amount)
To: &params.WithdrawalRequestsAddress, txdata := &types.DynamicFeeTx{
Value: big.NewInt(1), ChainID: gspec.Config.ChainID,
Gas: 500000, Nonce: b.TxNonce(addr),
GasFeeCap: newGwei(5), To: &params.WithdrawalRequestsAddress,
GasTipCap: big.NewInt(2), Value: big.NewInt(1),
AccessList: nil, Gas: 500000,
Data: data, GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
AccessList: nil,
Data: data,
}
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key)
b.AddTx(tx)
}
case 1:
// Block 2: submit consolidation requests
for _, cx := range cxs {
data := make([]byte, 96)
copy(data, cx.SourcePublicKey[:])
copy(data[48:], cx.TargetPublicKey[:])
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: b.TxNonce(addr),
To: &params.ConsolidationRequestsAddress,
Value: big.NewInt(1),
Gas: 500000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
AccessList: nil,
Data: data,
}
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key)
b.AddTx(tx)
} }
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key)
b.AddTx(tx)
} }
}) })
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil)
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -4387,6 +4425,8 @@ func TestEIP7002(t *testing.T) {
if n, err := chain.InsertChain(blocks); err != nil { if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err) t.Fatalf("block %d: failed to insert into chain: %v", n, err)
} }
// Verify the withdrawal requests match.
block := chain.GetBlockByNumber(1) block := chain.GetBlockByNumber(1)
if block == nil { if block == nil {
t.Fatalf("failed to retrieve block 1") t.Fatalf("failed to retrieve block 1")
@ -4395,7 +4435,7 @@ func TestEIP7002(t *testing.T) {
// Verify the withdrawal requests match. // Verify the withdrawal requests match.
got := block.Requests() got := block.Requests()
if len(got) != 2 { if len(got) != 2 {
t.Fatalf("wrong number of withdrawal requests: wanted 2, got %d", len(wxs)) t.Fatalf("wrong number of withdrawal requests: wanted 2, got %d", len(got))
} }
for i, want := range wxs { for i, want := range wxs {
got, ok := got[i].Inner().(*types.WithdrawalRequest) got, ok := got[i].Inner().(*types.WithdrawalRequest)
@ -4412,4 +4452,30 @@ func TestEIP7002(t *testing.T) {
t.Fatalf("wrong amount: want %d, got %d", want.Amount, got.Amount) t.Fatalf("wrong amount: want %d, got %d", want.Amount, got.Amount)
} }
} }
// Verify the consolidation requests match. Even though both requests are sent
// in block two, only one is dequeued at a time.
for i, want := range cxs {
block := chain.GetBlockByNumber(uint64(i + 2))
if block == nil {
t.Fatalf("failed to retrieve block")
}
requests := block.Requests()
if len(requests) != 1 {
t.Fatalf("wrong number of consolidation requests: wanted 1, got %d", len(got))
}
got, ok := requests[0].Inner().(*types.ConsolidationRequest)
if !ok {
t.Fatalf("expected consolidation request")
}
if want.Source != got.Source {
t.Fatalf("wrong source address: want %s, got %s", want.Source, got.Source)
}
if want.SourcePublicKey != got.SourcePublicKey {
t.Fatalf("wrong source public key: want %s, got %s", common.Bytes2Hex(want.SourcePublicKey[:]), common.Bytes2Hex(got.SourcePublicKey[:]))
}
if want.TargetPublicKey != got.TargetPublicKey {
t.Fatalf("wrong target public key: want %s, got %s", common.Bytes2Hex(want.TargetPublicKey[:]), common.Bytes2Hex(got.TargetPublicKey[:]))
}
}
} }

@ -362,6 +362,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
) )
wxs := ProcessDequeueWithdrawalRequests(vmenv, statedb) wxs := ProcessDequeueWithdrawalRequests(vmenv, statedb)
requests = append(requests, wxs...) requests = append(requests, wxs...)
cxs := ProcessDequeueConsolidationRequests(vmenv, statedb)
requests = append(requests, cxs...)
} }
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests} body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests}

@ -106,6 +106,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
wxs := ProcessDequeueWithdrawalRequests(vmenv, statedb) wxs := ProcessDequeueWithdrawalRequests(vmenv, statedb)
requests = append(requests, wxs...) requests = append(requests, wxs...)
cxs := ProcessDequeueConsolidationRequests(vmenv, statedb)
requests = append(requests, cxs...)
} }
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
@ -315,3 +317,44 @@ func ProcessDequeueWithdrawalRequests(vmenv *vm.EVM, statedb *state.StateDB) typ
} }
return reqs return reqs
} }
// ProcessDequeueConsolidationRequests applies the EIP-7251 system call to the consolidation requests contract.
func ProcessDequeueConsolidationRequests(vmenv *vm.EVM, statedb *state.StateDB) types.Requests {
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil {
vmenv.Config.Tracer.OnSystemCallStart()
}
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil {
defer vmenv.Config.Tracer.OnSystemCallEnd()
}
msg := &Message{
From: params.SystemAddress,
GasLimit: 30_000_000,
GasPrice: common.Big0,
GasFeeCap: common.Big0,
GasTipCap: common.Big0,
To: &params.ConsolidationRequestsAddress,
}
vmenv.Reset(NewEVMTxContext(msg), statedb)
statedb.AddAddressToAccessList(params.ConsolidationRequestsAddress)
ret, _, _ := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
statedb.Finalise(true)
// Parse out the exits.
var reqs types.Requests
for i := 0; i < len(ret)/116; i++ {
start := i * 116
var (
sourcePubkey [48]byte
targetPubkey [48]byte
)
copy(sourcePubkey[:], ret[start+20:start+20+48])
copy(targetPubkey[:], ret[start+20+48:start+20+48+48])
cx := &types.ConsolidationRequest{
Source: common.BytesToAddress(ret[start : start+20]),
SourcePublicKey: sourcePubkey,
TargetPublicKey: targetPubkey,
}
reqs = append(reqs, types.NewRequest(cx))
}
return reqs
}

@ -0,0 +1,79 @@
// Copyright 2024 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
import (
"bytes"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
)
//go:generate go run github.com/fjl/gencodec -type ConsolidationRequest -field-override consolidationRequestMarshaling -out gen_consolidation_request_json.go
// ConsolidationRequest represents an EIP-7251 consolidation request from source for
// the validator associated with the source public key to a target public key.
type ConsolidationRequest struct {
Source common.Address `json:"sourceAddress"`
SourcePublicKey [48]byte `json:"sourcePubkey"`
TargetPublicKey [48]byte `json:"targetPubkey"`
}
// field type overrides for gencodec
type consolidationRequestMarshaling struct {
SourcePublicKey hexutil.Bytes
TargetPublicKey hexutil.Bytes
}
func (c *ConsolidationRequest) Bytes() []byte {
out := make([]byte, 116)
copy(out, c.Source.Bytes())
copy(out[20:], c.SourcePublicKey[:])
copy(out[68:], c.TargetPublicKey[:])
return out
}
// ConsolidationRequests implements DerivableList for consolidation requests.
type ConsolidationRequests []*ConsolidationRequest
// Len returns the length of s.
func (s ConsolidationRequests) Len() int { return len(s) }
// EncodeIndex encodes the i'th consolidation request to c.
func (s ConsolidationRequests) EncodeIndex(i int, c *bytes.Buffer) {
rlp.Encode(c, s[i])
}
// Requests creates a deep copy of each deposit and returns a slice of the
// withdrwawal requests as Request objects.
func (s ConsolidationRequests) Requests() (reqs Requests) {
for _, d := range s {
reqs = append(reqs, NewRequest(d))
}
return
}
func (c *ConsolidationRequest) requestType() byte { return ConsolidationRequestType }
func (c *ConsolidationRequest) encode(b *bytes.Buffer) error { return rlp.Encode(b, c) }
func (c *ConsolidationRequest) decode(input []byte) error { return rlp.DecodeBytes(input, c) }
func (c *ConsolidationRequest) copy() RequestData {
return &ConsolidationRequest{
Source: c.Source,
SourcePublicKey: c.SourcePublicKey,
TargetPublicKey: c.TargetPublicKey,
}
}

@ -0,0 +1,56 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package types
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var _ = (*consolidationRequestMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (c ConsolidationRequest) MarshalJSON() ([]byte, error) {
type ConsolidationRequest struct {
Source common.Address `json:"sourceAddress"`
SourcePublicKey hexutil.Bytes `json:"sourcePubkey"`
TargetPublicKey hexutil.Bytes `json:"targetPubkey"`
}
var enc ConsolidationRequest
enc.Source = c.Source
enc.SourcePublicKey = c.SourcePublicKey[:]
enc.TargetPublicKey = c.TargetPublicKey[:]
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (c *ConsolidationRequest) UnmarshalJSON(input []byte) error {
type ConsolidationRequest struct {
Source *common.Address `json:"sourceAddress"`
SourcePublicKey *hexutil.Bytes `json:"sourcePubkey"`
TargetPublicKey *hexutil.Bytes `json:"targetPubkey"`
}
var dec ConsolidationRequest
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Source != nil {
c.Source = *dec.Source
}
if dec.SourcePublicKey != nil {
if len(*dec.SourcePublicKey) != len(c.SourcePublicKey) {
return errors.New("field 'sourcePubkey' has wrong length, need 48 items")
}
copy(c.SourcePublicKey[:], *dec.SourcePublicKey)
}
if dec.TargetPublicKey != nil {
if len(*dec.TargetPublicKey) != len(c.TargetPublicKey) {
return errors.New("field 'targetPubkey' has wrong length, need 48 items")
}
copy(c.TargetPublicKey[:], *dec.TargetPublicKey)
}
return nil
}

@ -32,8 +32,9 @@ var (
// Request types. // Request types.
const ( const (
DepositRequestType = 0x00 DepositRequestType = 0x00
WithdrawalRequestType = 0x01 WithdrawalRequestType = 0x01
ConsolidationRequestType = 0x02
) )
// Request is an EIP-7685 request object. It represents execution layer // Request is an EIP-7685 request object. It represents execution layer
@ -152,6 +153,8 @@ func (r *Request) decode(b []byte) (RequestData, error) {
inner = new(Deposit) inner = new(Deposit)
case WithdrawalRequestType: case WithdrawalRequestType:
inner = new(WithdrawalRequest) inner = new(WithdrawalRequest)
case ConsolidationRequestType:
inner = new(ConsolidationRequest)
default: default:
return nil, ErrRequestTypeNotSupported return nil, ErrRequestTypeNotSupported
} }

@ -877,6 +877,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engin
if body != nil { if body != nil {
body.Deposits = nil body.Deposits = nil
bodies[i].WithdrawalRequests = nil bodies[i].WithdrawalRequests = nil
bodies[i].ConsolidationRequests = nil
bodies[i] = body bodies[i] = body
} }
} }
@ -907,6 +908,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64)
if bodies[i] != nil { if bodies[i] != nil {
bodies[i].Deposits = nil bodies[i].Deposits = nil
bodies[i].WithdrawalRequests = nil bodies[i].WithdrawalRequests = nil
bodies[i].ConsolidationRequests = nil
} }
} }
return bodies, nil return bodies, nil
@ -945,11 +947,12 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBody {
} }
var ( var (
body = block.Body() body = block.Body()
txs = make([]hexutil.Bytes, len(body.Transactions)) txs = make([]hexutil.Bytes, len(body.Transactions))
withdrawals = body.Withdrawals withdrawals = body.Withdrawals
depositRequests types.Deposits depositRequests types.Deposits
withdrawalRequests types.WithdrawalRequests withdrawalRequests types.WithdrawalRequests
consolidationRequests types.ConsolidationRequests
) )
for j, tx := range body.Transactions { for j, tx := range body.Transactions {
@ -965,19 +968,26 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBody {
// TODO: this isn't future proof because we can't determine if a request // TODO: this isn't future proof because we can't determine if a request
// type has activated yet or if there are just no requests of that type from // type has activated yet or if there are just no requests of that type from
// only the block. // only the block.
depositRequests = make(types.Deposits, 0)
withdrawalRequests = make(types.WithdrawalRequests, 0)
consolidationRequests = make(types.ConsolidationRequests, 0)
for _, req := range block.Requests() { for _, req := range block.Requests() {
switch v := req.Inner().(type) { switch v := req.Inner().(type) {
case *types.Deposit: case *types.Deposit:
depositRequests = append(depositRequests, v) depositRequests = append(depositRequests, v)
case *types.WithdrawalRequest: case *types.WithdrawalRequest:
withdrawalRequests = append(withdrawalRequests, v) withdrawalRequests = append(withdrawalRequests, v)
case *types.ConsolidationRequest:
consolidationRequests = append(consolidationRequests, v)
} }
} }
} }
return &engine.ExecutionPayloadBody{ return &engine.ExecutionPayloadBody{
TransactionData: txs, TransactionData: txs,
Withdrawals: withdrawals, Withdrawals: withdrawals,
Deposits: depositRequests, Deposits: depositRequests,
WithdrawalRequests: withdrawalRequests, WithdrawalRequests: withdrawalRequests,
ConsolidationRequests: consolidationRequests,
} }
} }

@ -80,6 +80,8 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) {
Nonce: 0, Nonce: 0,
Balance: big.NewInt(0), Balance: big.NewInt(0),
}, },
params.WithdrawalRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd")},
params.ConsolidationRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd")},
}, },
ExtraData: []byte("test genesis"), ExtraData: []byte("test genesis"),
Timestamp: 9000, Timestamp: 9000,
@ -1313,15 +1315,23 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
// Each block, this callback will include two txs that generate body values like logs and requests. // Each block, this callback will include two txs that generate body values like logs and requests.
callback := func(parent *types.Header) { callback := func(parent *types.Header) {
if parent.Number.Cmp(big.NewInt(10)) == 0 {
// Make a block with empty requests to ensure nil / non-nil distinction is
// being maintained.
return
}
var ( var (
statedb, _ = ethservice.BlockChain().StateAt(parent.Root) statedb, _ = ethservice.BlockChain().StateAt(parent.Root)
// Create tx to trigger log generator. // Create tx to trigger log generator.
tx1, _ = types.SignTx(types.NewContractCreation(statedb.GetNonce(testAddr), new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) tx1, _ = types.SignTx(types.NewContractCreation(statedb.GetNonce(testAddr), new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
// Create tx to trigger deposit generator. // Create tx to trigger deposit generator.
tx2, _ = types.SignTx(types.NewTransaction(statedb.GetNonce(testAddr)+1, ethservice.APIBackend.ChainConfig().DepositContractAddress, new(big.Int), 500000, big.NewInt(2*params.InitialBaseFee), nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey) tx2, _ = types.SignTx(types.NewTransaction(statedb.GetNonce(testAddr)+1, ethservice.APIBackend.ChainConfig().DepositContractAddress, new(big.Int), 500000, big.NewInt(2*params.InitialBaseFee), nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
// Create tx to trigger withdrawal request.
tx3, _ = types.SignTx(types.NewTransaction(statedb.GetNonce(testAddr)+2, params.WithdrawalRequestsAddress, big.NewInt(42), 500000, big.NewInt(2*params.InitialBaseFee), make([]byte, 56)), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
// Create tx to trigger consolidation request.
tx4, _ = types.SignTx(types.NewTransaction(statedb.GetNonce(testAddr)+3, params.ConsolidationRequestsAddress, big.NewInt(42), 500000, big.NewInt(2*params.InitialBaseFee), make([]byte, 96)), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
) )
ethservice.TxPool().Add([]*types.Transaction{tx1}, false, false) ethservice.TxPool().Add([]*types.Transaction{tx1, tx2, tx3, tx4}, false, false)
ethservice.TxPool().Add([]*types.Transaction{tx2}, false, false)
} }
// Make some withdrawals to include. // Make some withdrawals to include.
@ -1569,18 +1579,31 @@ func equalBody(a *types.Body, b *engine.ExecutionPayloadBody) bool {
return false return false
} }
var deposits types.Deposits var (
dxs types.Deposits
wxs types.WithdrawalRequests
cxs types.ConsolidationRequests
)
if a.Requests != nil { if a.Requests != nil {
// If requests is non-nil, it means deposits are available in block and we // If requests is non-nil, it means deposits are available in block and we
// should return an empty slice instead of nil if there are no deposits. // should return an empty slice instead of nil if there are no deposits.
deposits = make(types.Deposits, 0) dxs = make(types.Deposits, 0)
} wxs = make(types.WithdrawalRequests, 0)
for _, r := range a.Requests { cxs = make(types.ConsolidationRequests, 0)
if d, ok := r.Inner().(*types.Deposit); ok { }
deposits = append(deposits, d) for _, req := range a.Requests {
switch v := req.Inner().(type) {
case *types.Deposit:
dxs = append(dxs, v)
case *types.WithdrawalRequest:
wxs = append(wxs, v)
case *types.ConsolidationRequest:
cxs = append(cxs, v)
} }
} }
return reflect.DeepEqual(deposits, b.Deposits) return reflect.DeepEqual(dxs, b.Deposits) &&
reflect.DeepEqual(wxs, b.WithdrawalRequests) &&
reflect.DeepEqual(cxs, b.ConsolidationRequests)
} }
func TestBlockToPayloadWithBlobs(t *testing.T) { func TestBlockToPayloadWithBlobs(t *testing.T) {

@ -125,6 +125,9 @@ func (miner *Miner) generateWork(params *generateParams) *newPayloadResult {
vmenv := vm.NewEVM(context, vm.TxContext{}, work.state, miner.chainConfig, vm.Config{}) vmenv := vm.NewEVM(context, vm.TxContext{}, work.state, miner.chainConfig, vm.Config{})
wxs := core.ProcessDequeueWithdrawalRequests(vmenv, work.state) wxs := core.ProcessDequeueWithdrawalRequests(vmenv, work.state)
requests = append(requests, wxs...) requests = append(requests, wxs...)
// Process ConsolidationRequests
cxs := core.ProcessDequeueConsolidationRequests(vmenv, work.state)
requests = append(requests, cxs...)
body.Requests = requests body.Requests = requests
} }
block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts) block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts)

@ -193,6 +193,8 @@ var (
BeaconRootsCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500") BeaconRootsCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500")
// WithdrawalRequests is the address where the EIP-7002 withdrawal requests queue is maintained. // WithdrawalRequests is the address where the EIP-7002 withdrawal requests queue is maintained.
WithdrawalRequestsAddress = common.HexToAddress("0x00A3ca265EBcb825B45F985A16CEFB49958cE017") WithdrawalRequestsAddress = common.HexToAddress("0x00A3ca265EBcb825B45F985A16CEFB49958cE017")
// ConsolidationRequests is the address where the EIP-7251 consolidation requests queue is maintained.
ConsolidationRequestsAddress = common.HexToAddress("0x00b42dbF2194e931E80326D950320f7d9Dbeac02")
// SystemAddress is where the system-transaction is sent from as per EIP-4788 // SystemAddress is where the system-transaction is sent from as per EIP-4788
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
// HistoryStorageAddress is where the historical block hashes are stored. // HistoryStorageAddress is where the historical block hashes are stored.

Loading…
Cancel
Save