Skip to content

Commit

Permalink
all: implement eip-7251 consolidation requests
Browse files Browse the repository at this point in the history
Co-authored-by: Mario Vega <marioevz@gmail.com>
Co-authored-by: lightclient <lightclient@protonmail.com>
  • Loading branch information
marioevz and lightclient committed Jul 1, 2024
1 parent 2654728 commit ed02a33
Show file tree
Hide file tree
Showing 10 changed files with 343 additions and 60 deletions.
73 changes: 41 additions & 32 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,23 @@ type Prestate struct {
// 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.
type ExecutionResult struct {
StateRoot common.Hash `json:"stateRoot"`
TxRoot common.Hash `json:"txRoot"`
ReceiptRoot common.Hash `json:"receiptsRoot"`
LogsHash common.Hash `json:"logsHash"`
Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
Receipts types.Receipts `json:"receipts"`
Rejected []*rejectedTx `json:"rejected,omitempty"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
WithdrawalRequests *types.WithdrawalRequests `json:"withdrawalRequests,omitempty"`
StateRoot common.Hash `json:"stateRoot"`
TxRoot common.Hash `json:"txRoot"`
ReceiptRoot common.Hash `json:"receiptsRoot"`
LogsHash common.Hash `json:"logsHash"`
Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
Receipts types.Receipts `json:"receipts"`
Rejected []*rejectedTx `json:"rejected,omitempty"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
WithdrawalRequests *types.WithdrawalRequests `json:"withdrawalRequests,omitempty"`
ConsolidationRequests *types.ConsolidationRequests `json:"consolidationRequests,omitempty"`
}

type ommer struct {
Expand Down Expand Up @@ -350,9 +351,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
}
// Retrieve deposit and withdrawal requests
var (
depositRequests *types.Deposits
withdrawalRequests *types.WithdrawalRequests
requestsHash *common.Hash
depositRequests *types.Deposits
withdrawalRequests *types.WithdrawalRequests
consolidationRequests *types.ConsolidationRequests
requestsHash *common.Hash
)
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
// Parse deposit requests from the logs
Expand All @@ -368,6 +370,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
vmenv := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
wxs := core.ProcessDequeueWithdrawalRequests(vmenv, statedb)
requests = append(requests, wxs...)
// Process the consolidation requests contract execution
cxs := core.ProcessDequeueConsolidationRequests(vmenv, statedb)
requests = append(requests, cxs...)
// Calculate the requests root
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
requestsHash = &h
Expand All @@ -377,26 +382,30 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
// Get the withdrawals from the requests
withdrawals := requests.Withdrawals()
withdrawalRequests = &withdrawals
// Get the consolidations from the requests
consolidations := requests.Consolidations()
consolidationRequests = &consolidations
}
// Commit block
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
if err != nil {
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
}
execRs := &ExecutionResult{
StateRoot: root,
TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)),
ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)),
Bloom: types.CreateBloom(receipts),
LogsHash: rlpHash(statedb.Logs()),
Receipts: receipts,
Rejected: rejectedTxs,
Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty),
GasUsed: (math.HexOrDecimal64)(gasUsed),
BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee),
RequestsHash: requestsHash,
DepositRequests: depositRequests,
WithdrawalRequests: withdrawalRequests,
StateRoot: root,
TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)),
ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)),
Bloom: types.CreateBloom(receipts),
LogsHash: rlpHash(statedb.Logs()),
Receipts: receipts,
Rejected: rejectedTxs,
Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty),
GasUsed: (math.HexOrDecimal64)(gasUsed),
BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee),
RequestsHash: requestsHash,
DepositRequests: depositRequests,
WithdrawalRequests: withdrawalRequests,
ConsolidationRequests: consolidationRequests,
}
if pre.Env.Withdrawals != nil {
h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil))
Expand Down
2 changes: 2 additions & 0 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
)
wxs := ProcessDequeueWithdrawalRequests(vmenv, statedb)
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}
Expand Down
111 changes: 85 additions & 26 deletions core/requests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ import (
"github.com/ethereum/go-ethereum/params"
)

// TestEIP7002 verifies that withdrawal requests are processed correctly in the
// pre-deploy and parsed out correctly via the system call.
func TestEIP7002(t *testing.T) {
// TestRequests verifies that Prague requests are processed correctly.
func TestRequests(t *testing.T) {
var (
engine = beacon.NewFaker()

Expand All @@ -32,8 +31,9 @@ func TestEIP7002(t *testing.T) {
gspec = &Genesis{
Config: &config,
Alloc: types.GenesisAlloc{
addr: {Balance: funds},
params.WithdrawalRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd")},
addr: {Balance: funds},
params.WithdrawalRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd")},
params.ConsolidationRequestsAddress: {Code: common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd")},
},
}
)
Expand All @@ -59,28 +59,66 @@ func TestEIP7002(t *testing.T) {
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) {
for i, wx := range wxs {
data := make([]byte, 56)
copy(data, wx.PublicKey[:])
binary.BigEndian.PutUint64(data[48:], wx.Amount)
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: uint64(i),
To: &params.WithdrawalRequestsAddress,
Value: big.NewInt(1),
Gas: 500000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
AccessList: nil,
Data: data,
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 3, func(i int, b *BlockGen) {
switch i {
case 0:
// Block 1: submit withdrawal requests
for _, wx := range wxs {
data := make([]byte, 56)
copy(data, wx.PublicKey[:])
binary.BigEndian.PutUint64(data[48:], wx.Amount)
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: b.TxNonce(addr),
To: &params.WithdrawalRequestsAddress,
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)
}
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)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
Expand All @@ -89,15 +127,15 @@ func TestEIP7002(t *testing.T) {
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}

// Verify the withdrawal requests match.
block := chain.GetBlockByNumber(1)
if block == nil {
t.Fatalf("failed to retrieve block 1")
}

// Verify the withdrawal requests match.
got := block.WithdrawalRequests()
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 {
if want.Source != got[i].Source {
Expand All @@ -110,4 +148,25 @@ func TestEIP7002(t *testing.T) {
t.Fatalf("wrong amount: want %d, got %d", want.Amount, got[i].Amount)
}
}

// Verify the consolidation requests match.
for i, want := range cxs {
block := chain.GetBlockByNumber(uint64(i + 2))
if block == nil {
t.Fatalf("failed to retrieve block 2")
}
if got := block.ConsolidationRequests(); len(got) != 1 {
t.Fatalf("wrong number of consolidation requests: wanted 1, got %d", len(got))
}
got := block.ConsolidationRequests()[0]
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[:]))
}
}
}
44 changes: 44 additions & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
}
wxs := ProcessDequeueWithdrawalRequests(vmenv, statedb)
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)
Expand Down Expand Up @@ -278,3 +280,45 @@ func ProcessDequeueWithdrawalRequests(vmenv *vm.EVM, statedb *state.StateDB) typ
}
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)

fmt.Println("consolidation requests", ret)
// 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
}
15 changes: 15 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,21 @@ func (b *Block) WithdrawalRequests() WithdrawalRequests {
return wxs
}

func (b *Block) ConsolidationRequests() ConsolidationRequests {
var cxs ConsolidationRequests
if b.requests != nil {
// 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.
cxs = make(ConsolidationRequests, 0)
}
for _, r := range b.requests {
if c, ok := r.inner.(*ConsolidationRequest); ok {
cxs = append(cxs, c)
}
}
return cxs
}

func (b *Block) Transaction(hash common.Hash) *Transaction {
for _, transaction := range b.transactions {
if transaction.Hash() == hash {
Expand Down
Loading

0 comments on commit ed02a33

Please sign in to comment.