diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index b2e5f70714..98b7d9e337 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -18,6 +18,7 @@ package t8ntool import ( "fmt" + gomath "math" "math/big" "github.com/ethereum/go-ethereum/common" @@ -347,7 +348,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, for _, w := range pre.Env.Withdrawals { // Amount is in gwei, turn into wei amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) - statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal) + if w.Validator != gomath.MaxUint64 { + statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal) + } } // Gather the execution-layer triggered requests. @@ -362,6 +365,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, if err := core.ParseDepositLogs(&requests, allLogs, chainConfig); err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err)) } + if len(pre.Env.Withdrawals) > 0 { + w := pre.Env.Withdrawals[0] + if w.Validator == gomath.MaxUint64 { + amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) + if err := core.ProcessStakingDistribution(evm, w.Address, amount); err != nil { + log.Error("could not process staking distribution", "err", err) + } + } + } // EIP-7002 if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not process withdrawal requests: %v", err)) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 01390c40a3..7963b9df17 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -19,6 +19,7 @@ package beacon import ( "errors" "fmt" + "math" "math/big" "github.com/ethereum/go-ethereum/common" @@ -347,7 +348,9 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // Convert amount from gwei to wei. amount := new(uint256.Int).SetUint64(w.Amount) amount = amount.Mul(amount, uint256.NewInt(params.GWei)) - state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal) + if w.Validator != math.MaxUint64 { + state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal) + } } // No block reward which is issued by consensus layer instead. } diff --git a/core/chain_makers.go b/core/chain_makers.go index 37bddcfda5..90a28cf92c 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -18,6 +18,7 @@ package core import ( "fmt" + "math" "math/big" "github.com/ethereum/go-ethereum/common" @@ -30,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-verkle" @@ -327,6 +329,15 @@ func (b *BlockGen) collectRequests(readonly bool) (requests [][]byte) { // create EVM for system calls blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) evm := vm.NewEVM(blockContext, statedb, b.cm.config, vm.Config{}) + if len(b.withdrawals) > 0 { + w := b.withdrawals[0] + if w.Validator == math.MaxUint64 { + amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) + if err := ProcessStakingDistribution(evm, w.Address, amount); err != nil { + log.Error("could not process staking distribution", "err", err) + } + } + } // EIP-7002 if err := ProcessWithdrawalQueue(&requests, evm); err != nil { panic(fmt.Sprintf("could not process withdrawal requests: %v", err)) diff --git a/core/state_processor.go b/core/state_processor.go index 322bd24f41..1197559258 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -18,6 +18,7 @@ package core import ( "fmt" + "math" "math/big" "github.com/ethereum/go-ethereum/common" @@ -27,7 +28,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -112,6 +115,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil { return nil, err } + if len(block.Withdrawals()) > 0 { + w := block.Withdrawals()[0] + if w.Validator == math.MaxUint64 { + amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) + if err := ProcessStakingDistribution(evm, w.Address, amount); err != nil { + log.Error("could not process staking distribution", "err", err) + } + } + } // EIP-7002 if err := ProcessWithdrawalQueue(&requests, evm); err != nil { return nil, err @@ -279,6 +291,41 @@ func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) error { return processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress) } +// ProcessStakingDistribution +func ProcessStakingDistribution(evm *vm.EVM, address common.Address, amount *big.Int) error { + if tracer := evm.Config.Tracer; tracer != nil { + onSystemCallStart(tracer, evm.GetVMContext()) + if tracer.OnSystemCallEnd != nil { + defer tracer.OnSystemCallEnd() + } + } + input := make([]byte, 32) + copy(input[12:], address.Bytes()) + addr := params.StakingContractAddress + msg := &Message{ + From: params.SystemAddress, + GasLimit: 30_000_000, + GasPrice: common.Big0, + GasFeeCap: common.Big0, + GasTipCap: common.Big0, + To: &addr, + Data: append(params.StakingContractCallData, input...), + } + evm.SetTxContext(NewEVMTxContext(msg)) + evm.StateDB.AddAddressToAccessList(addr) + evm.StateDB.AddBalance( + params.StakingContractAddress, + uint256.NewInt(0).SetBytes(amount.Bytes()), + tracing.BalanceIncreaseRewardMineBlock, + ) + _, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) + evm.StateDB.Finalise(true) + if err != nil { + return fmt.Errorf("system call failed to execute: %v", err) + } + return nil +} + func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error { if tracer := evm.Config.Tracer; tracer != nil { onSystemCallStart(tracer, evm.GetVMContext()) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index b997cf297b..cde74747db 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -21,6 +21,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "math/big" "time" @@ -34,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/internal/ethapi/override" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -332,6 +334,15 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if err := core.ParseDepositLogs(&requests, allLogs, sim.chainConfig); err != nil { return nil, nil, nil, err } + if block.BlockOverrides.Withdrawals != nil && len(*block.BlockOverrides.Withdrawals) > 0 { + w := (*block.BlockOverrides.Withdrawals)[0] + if w.Validator == math.MaxUint64 { + amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) + if err := core.ProcessStakingDistribution(evm, w.Address, amount); err != nil { + log.Error("could not process staking distribution", "err", err) + } + } + } // EIP-7002 if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { return nil, nil, nil, err diff --git a/miner/worker.go b/miner/worker.go index b5db6180cf..d22edc812f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -19,6 +19,7 @@ package miner import ( "errors" "fmt" + "math" "math/big" "sync/atomic" "time" @@ -34,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + ethparams "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -126,6 +128,15 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo if err := core.ParseDepositLogs(&requests, allLogs, miner.chainConfig); err != nil { return &newPayloadResult{err: err} } + if len(params.withdrawals) > 0 { + w := params.withdrawals[0] + if w.Validator == math.MaxUint64 { + amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(ethparams.GWei)) + if err := core.ProcessStakingDistribution(work.evm, w.Address, amount); err != nil { + log.Error("could not process staking distribution", "err", err) + } + } + } // EIP-7002 if err := core.ProcessWithdrawalQueue(&requests, work.evm); err != nil { return &newPayloadResult{err: err} diff --git a/params/protocol_params.go b/params/protocol_params.go index 6b06dadaef..c5bde58510 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -211,4 +211,8 @@ var ( // EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE ConsolidationQueueAddress = common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251") ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd") + + StakingContractAddress = common.HexToAddress("0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512") + // StakingContractCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500") + StakingContractCallData = common.FromHex("1de9d9b6") )