From 0ae7e7b6a1545e6c0001c889e4751c217be7a02a Mon Sep 17 00:00:00 2001 From: mralj Date: Wed, 25 Sep 2024 19:08:40 +0200 Subject: [PATCH 01/26] dial L1 RPC client passed via required flag --- cmd/geth/main.go | 6 ++++++ cmd/utils/flags.go | 22 +++++++++++++++++++++- core/vm/interpreter.go | 10 +++++++++- eth/backend.go | 13 ++++++++++++- eth/ethconfig/config.go | 3 +++ internal/flags/categories.go | 1 + 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 2675a616759c..cbf71c151d8f 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -206,6 +206,11 @@ var ( utils.MetricsInfluxDBBucketFlag, utils.MetricsInfluxDBOrganizationFlag, } + + //[rollup-geth] + rollupFlags = []cli.Flag{ + utils.L1NodeRPCEndpointFlag, + } ) var app = flags.NewApp("the go-ethereum command line interface") @@ -257,6 +262,7 @@ func init() { consoleFlags, debug.Flags, metricsFlags, + rollupFlags, //[rollup-geth] ) flags.AutoEnvVars(app.Flags, "GETH") diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 6db88ff66183..dccf4981340c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -951,6 +951,14 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. Value: metrics.DefaultConfig.InfluxDBOrganization, Category: flags.MetricsCategory, } + + //[rollup-geth] + L1NodeRPCEndpointFlag = &cli.StringFlag{ + Name: "rollup.l1.rpc_endpoint", + Usage: "L1 node RPC endpoint eg. http://0.0.0.0:8545", + Category: flags.RollupCategory, + Required: true, + } ) var ( @@ -1251,6 +1259,15 @@ func setLes(ctx *cli.Context, cfg *ethconfig.Config) { } } +// [rollup-geth] +func setRollupEthConfig(ctx *cli.Context, cfg *ethconfig.Config) { + if ctx.IsSet(L1NodeRPCEndpointFlag.Name) { + cfg.L1NodeRPCEndpoint = ctx.String(L1NodeRPCEndpointFlag.Name) + } else { + log.Crit("L1 node RPC endpoint URL not set", "flag", L1NodeRPCEndpointFlag.Name) + } +} + // MakeDatabaseHandles raises out the number of allowed file handles per process // for Geth and returns half of the allowance to assign to the database. func MakeDatabaseHandles(max int) int { @@ -1651,6 +1668,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { setRequiredBlocks(ctx, cfg) setLes(ctx, cfg) + //[rollup-geth] + setRollupEthConfig(ctx, cfg) + // Cap the cache allowance and tune the garbage collector mem, err := gopsutil.VirtualMemory() if err == nil { @@ -1861,7 +1881,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) { cfg.Genesis = nil // fallback to db content - //validate genesis has PoS enabled in block 0 + // validate genesis has PoS enabled in block 0 genesis, err := core.ReadGenesis(chaindb) if err != nil { Fatalf("Could not read genesis from database: %v", err) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 793f398367a7..adbf8632d6e6 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -17,7 +17,9 @@ package vm import ( + "context" "fmt" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -34,7 +36,13 @@ type Config struct { EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled - StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) + StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) + L1RpcClient L1Client //[rollup-geth] +} + +// [rollup-geth] +type L1Client interface { + StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/eth/backend.go b/eth/backend.go index f10d99c3a70b..f8762ffc3f7b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -43,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -164,7 +165,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } bcVersion := rawdb.ReadDatabaseVersion(chainDb) - var dbVer = "" + dbVer := "" if bcVersion != nil { dbVer = fmt.Sprintf("%d", *bcVersion) } @@ -215,6 +216,16 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle } + + //[rollup-geth] + l1Client, err := ethclient.Dial(config.L1NodeRPCEndpoint) + if err != nil { + log.Crit("Unable to connect to L1 RPC endpoint at", "URL", config.L1NodeRPCEndpoint, "error", err) + } else { + vmConfig.L1RpcClient = l1Client + log.Info("Initialized L1 RPC client", "endpoint", config.L1NodeRPCEndpoint) + } + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory) if err != nil { return nil, err diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index c781a639408a..5719ef16a3ab 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -156,6 +156,9 @@ type Config struct { // OverrideVerkle (TODO: remove after the fork) OverrideVerkle *uint64 `toml:",omitempty"` + + //[rollup-geth] + L1NodeRPCEndpoint string } // CreateConsensusEngine creates a consensus engine for the given chain config. diff --git a/internal/flags/categories.go b/internal/flags/categories.go index d426add55b10..7f28f24f9097 100644 --- a/internal/flags/categories.go +++ b/internal/flags/categories.go @@ -37,6 +37,7 @@ const ( MiscCategory = "MISC" TestingCategory = "TESTING" DeprecatedCategory = "ALIASED (deprecated)" + RollupCategory = "ROLLUP" //[rollup-geth] ) func init() { From 1974d9268529e545582096bccec47fab4083518a Mon Sep 17 00:00:00 2001 From: mralj Date: Thu, 26 Sep 2024 13:22:58 +0200 Subject: [PATCH 02/26] added L1SLoad sekelton --- core/vm/contracts_rollup.go | 75 +++++++++++++++++++++++++++ core/vm/contracts_rollup_overrides.go | 25 +++++++++ core/vm/evm.go | 11 +++- params/config.go | 2 + 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 core/vm/contracts_rollup.go create mode 100644 core/vm/contracts_rollup_overrides.go diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go new file mode 100644 index 000000000000..d633e368905d --- /dev/null +++ b/core/vm/contracts_rollup.go @@ -0,0 +1,75 @@ +//[rollup-geth] +// These are rollup-geth specific precompiled contracts + +package vm + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" +) + +type RollupPrecompiledContractsOverrides struct { + l1SLoadGetLatestL1Block func() *big.Int +} + +func GenerateRollupPrecompiledContractsOverrides(evm *EVM) RollupPrecompiledContractsOverrides { + return RollupPrecompiledContractsOverrides{ + l1SLoadGetLatestL1Block: getLatestL1BlockNumber(evm), + } +} + +var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) + +var PrecompiledContractsRollupR0 = PrecompiledContracts{ + rollupL1SloadAddress: &l1SLoad{}, +} + +func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { + switch rules.IsR0 { + case rules.IsR0: + return PrecompiledContractsRollupR0 + default: + return nil + } +} + +func (evm *EVM) activateRollupPrecompiledContracts() { + activeRollupPrecompiles := activeRollupPrecompiledContracts(evm.chainRules) + for k, v := range activeRollupPrecompiles { + evm.precompiles[k] = v + } + + // NOTE: if L1SLoad was not activated via chain rules this is no-op + evm.precompiles.activateL1SLoad(evm.Config.L1RpcClient, evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block) +} + +type l1SLoad struct { + l1RpcClient L1Client + getLatestL1BlockNumber func() *big.Int +} + +func (c *l1SLoad) RequiredGas(input []byte) uint64 { return 0 } + +func (c *l1SLoad) Run(input []byte) ([]byte, error) { + if !c.isL1SLoadActive() { + return nil, errors.New("L1SLoad precompile not active") + } + + return nil, nil +} + +func (c *l1SLoad) isL1SLoadActive() bool { + return c.getLatestL1BlockNumber != nil && c.l1RpcClient != nil +} + +func (pc *PrecompiledContracts) activateL1SLoad(l1RpcClient L1Client, getLatestL1BlockNumber func() *big.Int) { + if (*pc)[rollupL1SloadAddress] != nil { + (*pc)[rollupL1SloadAddress] = &l1SLoad{ + l1RpcClient: l1RpcClient, + getLatestL1BlockNumber: getLatestL1BlockNumber, + } + } +} diff --git a/core/vm/contracts_rollup_overrides.go b/core/vm/contracts_rollup_overrides.go new file mode 100644 index 000000000000..56c70990b029 --- /dev/null +++ b/core/vm/contracts_rollup_overrides.go @@ -0,0 +1,25 @@ +//[rollup-geth] +// These are rollup-geth specific precompiled contracts + +package vm + +import "math/big" + +type RollupPrecompiledContractsOverrides struct { + l1SLoadGetLatestL1Block func() *big.Int +} + +func GenerateRollupPrecompiledContractsOverrides(evm *EVM) RollupPrecompiledContractsOverrides { + return RollupPrecompiledContractsOverrides{ + l1SLoadGetLatestL1Block: getLatestL1BlockNumber(evm), + } +} + +// [OVERRIDE] getLatestL1BlockNumber +// Each rollup should override this function so that it returns +// correct latest L1 block number +func getLatestL1BlockNumber(evm *EVM) func() *big.Int { + return func() *big.Int { + return evm.Context.BlockNumber + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 616668d565cc..8292dc30b1eb 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -113,7 +113,11 @@ type EVM struct { // applied in opCall*. callGasTemp uint64 // precompiles holds the precompiled contracts for the current epoch - precompiles map[common.Address]PrecompiledContract + precompiles PrecompiledContracts + + //[rollup-geth] + // Overrides specific to precompiled contracts for rollups + rollupPrecompileOverrides RollupPrecompiledContractsOverrides } // NewEVM returns a new EVM. The returned EVM is not thread safe and should @@ -128,6 +132,11 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } evm.precompiles = activePrecompiledContracts(evm.chainRules) + + //[rollup-geth] + evm.rollupPrecompileOverrides = GenerateRollupPrecompiledContractsOverrides(evm) + evm.activateRollupPrecompiledContracts() + evm.interpreter = NewEVMInterpreter(evm) return evm } diff --git a/params/config.go b/params/config.go index 9ecf465bb67a..f405622951ec 100644 --- a/params/config.go +++ b/params/config.go @@ -894,6 +894,7 @@ type Rules struct { IsBerlin, IsLondon bool IsMerge, IsShanghai, IsCancun, IsPrague bool IsVerkle bool + IsR0 bool // [rollup-geth] } // Rules ensures c's ChainID is not nil. @@ -924,5 +925,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsPrague: isMerge && c.IsPrague(num, timestamp), IsVerkle: isVerkle, IsEIP4762: isVerkle, + IsR0: true, // [rollup-geth] } } From 99ccaf73a55eb655f91c764e00c8a411d7317b55 Mon Sep 17 00:00:00 2001 From: mralj Date: Thu, 26 Sep 2024 13:26:08 +0200 Subject: [PATCH 03/26] bugfix --- core/vm/contracts.go | 28 ++++++++++++++++++++-------- core/vm/contracts_rollup.go | 15 --------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 104d2ba814b2..2a2561121e13 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -174,22 +174,31 @@ func init() { } func activePrecompiledContracts(rules params.Rules) PrecompiledContracts { + var activePrecompiles PrecompiledContracts switch { case rules.IsVerkle: - return PrecompiledContractsVerkle + activePrecompiles = PrecompiledContractsVerkle case rules.IsPrague: - return PrecompiledContractsPrague + activePrecompiles = PrecompiledContractsPrague case rules.IsCancun: - return PrecompiledContractsCancun + activePrecompiles = PrecompiledContractsCancun case rules.IsBerlin: - return PrecompiledContractsBerlin + activePrecompiles = PrecompiledContractsBerlin case rules.IsIstanbul: - return PrecompiledContractsIstanbul + activePrecompiles = PrecompiledContractsIstanbul case rules.IsByzantium: - return PrecompiledContractsByzantium + activePrecompiles = PrecompiledContractsByzantium default: - return PrecompiledContractsHomestead + activePrecompiles = PrecompiledContractsHomestead } + + // [rollup-geth] + activeRollupPrecompiles := activeRollupPrecompiledContracts(rules) + for k, v := range activeRollupPrecompiles { + activePrecompiles[k] = v + } + + return activePrecompiles } // ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration. @@ -281,6 +290,7 @@ type sha256hash struct{} func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } + func (c *sha256hash) Run(input []byte) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil @@ -296,6 +306,7 @@ type ripemd160hash struct{} func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } + func (c *ripemd160hash) Run(input []byte) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) @@ -312,6 +323,7 @@ type dataCopy struct{} func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } + func (c *dataCopy) Run(in []byte) ([]byte, error) { return common.CopyBytes(in), nil } @@ -461,7 +473,7 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { // Modulo 0 is undefined, return zero return common.LeftPadBytes([]byte{}, int(modLen)), nil case base.BitLen() == 1: // a bit length of 1 means it's 1 (or -1). - //If base == 1, then we can just return base % mod (if mod >= 1, which it is) + // If base == 1, then we can just return base % mod (if mod >= 1, which it is) v = base.Mod(base, mod).Bytes() default: v = base.Exp(base, exp, mod).Bytes() diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index d633e368905d..875a15bdacad 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -11,16 +11,6 @@ import ( "github.com/ethereum/go-ethereum/params" ) -type RollupPrecompiledContractsOverrides struct { - l1SLoadGetLatestL1Block func() *big.Int -} - -func GenerateRollupPrecompiledContractsOverrides(evm *EVM) RollupPrecompiledContractsOverrides { - return RollupPrecompiledContractsOverrides{ - l1SLoadGetLatestL1Block: getLatestL1BlockNumber(evm), - } -} - var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) var PrecompiledContractsRollupR0 = PrecompiledContracts{ @@ -37,11 +27,6 @@ func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { } func (evm *EVM) activateRollupPrecompiledContracts() { - activeRollupPrecompiles := activeRollupPrecompiledContracts(evm.chainRules) - for k, v := range activeRollupPrecompiles { - evm.precompiles[k] = v - } - // NOTE: if L1SLoad was not activated via chain rules this is no-op evm.precompiles.activateL1SLoad(evm.Config.L1RpcClient, evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block) } From a24608eef1bd36176b6a6596c0d7c973400ead1f Mon Sep 17 00:00:00 2001 From: mralj Date: Thu, 26 Sep 2024 19:48:47 +0200 Subject: [PATCH 04/26] added ability to activate rollup precompiles from eth/internal and eth/tracers --- core/vm/contracts_rollup.go | 43 ++++++++++++++++++++++++------------- core/vm/interpreter.go | 6 +++--- eth/api_backend.go | 5 +++++ eth/tracers/api.go | 9 ++++++++ internal/ethapi/api.go | 12 ++++++++--- internal/ethapi/backend.go | 3 +++ internal/ethapi/simulate.go | 9 +++++++- 7 files changed, 65 insertions(+), 22 deletions(-) diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index 875a15bdacad..d18e5f92bf29 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -14,7 +14,11 @@ import ( var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) var PrecompiledContractsRollupR0 = PrecompiledContracts{ - rollupL1SloadAddress: &l1SLoad{}, + rollupL1SloadAddress: &L1SLoad{}, +} + +type RollupPrecompileActivationConfig struct { + L1SLoad } func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { @@ -26,19 +30,25 @@ func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { } } -func (evm *EVM) activateRollupPrecompiledContracts() { +func (pc *PrecompiledContracts) ActivateRollupPrecompiledContracts(config RollupPrecompileActivationConfig) { // NOTE: if L1SLoad was not activated via chain rules this is no-op - evm.precompiles.activateL1SLoad(evm.Config.L1RpcClient, evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block) + pc.activateL1SLoad(config.L1RpcClient, config.GetLatestL1BlockNumber) } -type l1SLoad struct { - l1RpcClient L1Client - getLatestL1BlockNumber func() *big.Int +func (evm *EVM) activateRollupPrecompiledContracts() { + evm.precompiles.ActivateRollupPrecompiledContracts(RollupPrecompileActivationConfig{ + L1SLoad{L1RpcClient: evm.Config.L1RpcClient, GetLatestL1BlockNumber: evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block}, + }) } -func (c *l1SLoad) RequiredGas(input []byte) uint64 { return 0 } +type L1SLoad struct { + L1RpcClient L1RpcClient + GetLatestL1BlockNumber func() *big.Int +} + +func (c *L1SLoad) RequiredGas(input []byte) uint64 { return 0 } -func (c *l1SLoad) Run(input []byte) ([]byte, error) { +func (c *L1SLoad) Run(input []byte) ([]byte, error) { if !c.isL1SLoadActive() { return nil, errors.New("L1SLoad precompile not active") } @@ -46,15 +56,18 @@ func (c *l1SLoad) Run(input []byte) ([]byte, error) { return nil, nil } -func (c *l1SLoad) isL1SLoadActive() bool { - return c.getLatestL1BlockNumber != nil && c.l1RpcClient != nil +func (c *L1SLoad) isL1SLoadActive() bool { + return c.GetLatestL1BlockNumber != nil && c.L1RpcClient != nil } -func (pc *PrecompiledContracts) activateL1SLoad(l1RpcClient L1Client, getLatestL1BlockNumber func() *big.Int) { - if (*pc)[rollupL1SloadAddress] != nil { - (*pc)[rollupL1SloadAddress] = &l1SLoad{ - l1RpcClient: l1RpcClient, - getLatestL1BlockNumber: getLatestL1BlockNumber, +func (pc *PrecompiledContracts) activateL1SLoad(l1RpcClient L1RpcClient, getLatestL1BlockNumber func() *big.Int) { + rulesSayContractShouldBeActive := (*pc)[rollupL1SloadAddress] != nil + paramsNotNil := l1RpcClient != nil && getLatestL1BlockNumber != nil + + if shouldActivateL1SLoad := rulesSayContractShouldBeActive && paramsNotNil; shouldActivateL1SLoad { + (*pc)[rollupL1SloadAddress] = &L1SLoad{ + L1RpcClient: l1RpcClient, + GetLatestL1BlockNumber: getLatestL1BlockNumber, } } } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index adbf8632d6e6..ebb07b8b8b5a 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -36,12 +36,12 @@ type Config struct { EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled - StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) - L1RpcClient L1Client //[rollup-geth] + StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) + L1RpcClient L1RpcClient //[rollup-geth] } // [rollup-geth] -type L1Client interface { +type L1RpcClient interface { StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) } diff --git a/eth/api_backend.go b/eth/api_backend.go index 8a9898b956f3..4960be76211f 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -431,3 +431,8 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } + +// [rollup-geth] +func (b *EthAPIBackend) GetL1RpcClient() vm.L1RpcClient { + return b.eth.BlockChain().GetVMConfig().L1RpcClient +} diff --git a/eth/tracers/api.go b/eth/tracers/api.go index a8289512069b..44d0abf99be4 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -88,6 +88,9 @@ type Backend interface { ChainDb() ethdb.Database StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) + + // [rollup-geth] + GetL1RpcClient() vm.L1RpcClient } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -960,6 +963,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time) precompiles := vm.ActivePrecompiledContracts(rules) + + //[rollup-geth] This is optional for rollups + precompiles.ActivateRollupPrecompiledContracts(vm.RollupPrecompileActivationConfig{ + vm.L1SLoad{L1RpcClient: api.backend.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return vmctx.BlockNumber }}, + }) + if err := config.StateOverrides.Apply(statedb, precompiles); err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a50295289340..d0ab0ab0a888 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -256,7 +256,7 @@ func (api *TxPoolAPI) Inspect() map[string]map[string]map[string]string { pending, queue := api.b.TxPoolContent() // Define a formatter to flatten a transaction into a string - var format = func(tx *types.Transaction) string { + format := func(tx *types.Transaction) string { if to := tx.To(); to != nil { return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice()) } @@ -1166,6 +1166,12 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S } rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules)) + + //[rollup-geth] This is optional for rollups + precompiles.ActivateRollupPrecompiledContracts(vm.RollupPrecompileActivationConfig{ + vm.L1SLoad{L1RpcClient: b.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return blockCtx.BlockNumber }}, + }) + if err := overrides.Apply(state, precompiles); err != nil { return nil, err } @@ -2092,11 +2098,11 @@ func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, matchTx := sendArgs.ToTransaction(types.LegacyTxType) // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. - var price = matchTx.GasPrice() + price := matchTx.GasPrice() if gasPrice != nil { price = gasPrice.ToInt() } - var gas = matchTx.Gas() + gas := matchTx.Gas() if gasLimit != nil { gas = uint64(*gasLimit) } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 0e991592b4b3..671e5017ac05 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -96,6 +96,9 @@ type Backend interface { SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) + + //[rollup-geth] + GetL1RpcClient() vm.L1RpcClient } func GetAPIs(apiBackend Backend) []rpc.API { diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 4371a4246480..82a7d8a4cf57 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -286,7 +286,14 @@ func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContra isMerge = (base.Difficulty.Sign() == 0) rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) ) - return maps.Clone(vm.ActivePrecompiledContracts(rules)) + precompiles := vm.ActivePrecompiledContracts(rules) + + //[rollup-geth] This is optional for rollups + precompiles.ActivateRollupPrecompiledContracts(vm.RollupPrecompileActivationConfig{ + vm.L1SLoad{L1RpcClient: sim.b.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return base.Number }}, + }) + + return maps.Clone(precompiles) } // sanitizeChain checks the chain integrity. Specifically it checks that From 204ef24a5f5c992013862f62f05fab36dbe35e3f Mon Sep 17 00:00:00 2001 From: mralj Date: Thu, 26 Sep 2024 20:21:47 +0200 Subject: [PATCH 05/26] added example how code in overrides would change --- core/vm/contracts_rollup_overrides.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/core/vm/contracts_rollup_overrides.go b/core/vm/contracts_rollup_overrides.go index 56c70990b029..df7b4c3c6c30 100644 --- a/core/vm/contracts_rollup_overrides.go +++ b/core/vm/contracts_rollup_overrides.go @@ -3,7 +3,9 @@ package vm -import "math/big" +import ( + "math/big" +) type RollupPrecompiledContractsOverrides struct { l1SLoadGetLatestL1Block func() *big.Int @@ -23,3 +25,16 @@ func getLatestL1BlockNumber(evm *EVM) func() *big.Int { return evm.Context.BlockNumber } } + +// [OVERRIDE] getLatestL1BlockNumber +// Each rollup should override this function so that it returns +// correct latest L1 block number +// +// EXAMPLE 2 +// func getLatestL1BlockNumber(evm *EVM) func() *big.Int { +// return func() *big.Int { +// addressOfL1BlockContract := common.Address{} +// slotInContractRepresentingL1BlockNumber := common.Hash{} +// return evm.StateDB.GetState(addressOfL1BlockContract, slotInContractRepresentingL1BlockNumber).Big() +// } +// } From 759dda71cec8a5d1353c67fa46bb81dce7ac94b8 Mon Sep 17 00:00:00 2001 From: mralj Date: Thu, 26 Sep 2024 13:22:58 +0200 Subject: [PATCH 06/26] added L1SLoad sekelton --- core/vm/contracts_rollup.go | 58 ++++++++++++++------------- core/vm/contracts_rollup_overrides.go | 17 +------- 2 files changed, 31 insertions(+), 44 deletions(-) diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index d18e5f92bf29..d633e368905d 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -11,14 +11,20 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) +type RollupPrecompiledContractsOverrides struct { + l1SLoadGetLatestL1Block func() *big.Int +} -var PrecompiledContractsRollupR0 = PrecompiledContracts{ - rollupL1SloadAddress: &L1SLoad{}, +func GenerateRollupPrecompiledContractsOverrides(evm *EVM) RollupPrecompiledContractsOverrides { + return RollupPrecompiledContractsOverrides{ + l1SLoadGetLatestL1Block: getLatestL1BlockNumber(evm), + } } -type RollupPrecompileActivationConfig struct { - L1SLoad +var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) + +var PrecompiledContractsRollupR0 = PrecompiledContracts{ + rollupL1SloadAddress: &l1SLoad{}, } func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { @@ -30,25 +36,24 @@ func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { } } -func (pc *PrecompiledContracts) ActivateRollupPrecompiledContracts(config RollupPrecompileActivationConfig) { - // NOTE: if L1SLoad was not activated via chain rules this is no-op - pc.activateL1SLoad(config.L1RpcClient, config.GetLatestL1BlockNumber) -} - func (evm *EVM) activateRollupPrecompiledContracts() { - evm.precompiles.ActivateRollupPrecompiledContracts(RollupPrecompileActivationConfig{ - L1SLoad{L1RpcClient: evm.Config.L1RpcClient, GetLatestL1BlockNumber: evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block}, - }) + activeRollupPrecompiles := activeRollupPrecompiledContracts(evm.chainRules) + for k, v := range activeRollupPrecompiles { + evm.precompiles[k] = v + } + + // NOTE: if L1SLoad was not activated via chain rules this is no-op + evm.precompiles.activateL1SLoad(evm.Config.L1RpcClient, evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block) } -type L1SLoad struct { - L1RpcClient L1RpcClient - GetLatestL1BlockNumber func() *big.Int +type l1SLoad struct { + l1RpcClient L1Client + getLatestL1BlockNumber func() *big.Int } -func (c *L1SLoad) RequiredGas(input []byte) uint64 { return 0 } +func (c *l1SLoad) RequiredGas(input []byte) uint64 { return 0 } -func (c *L1SLoad) Run(input []byte) ([]byte, error) { +func (c *l1SLoad) Run(input []byte) ([]byte, error) { if !c.isL1SLoadActive() { return nil, errors.New("L1SLoad precompile not active") } @@ -56,18 +61,15 @@ func (c *L1SLoad) Run(input []byte) ([]byte, error) { return nil, nil } -func (c *L1SLoad) isL1SLoadActive() bool { - return c.GetLatestL1BlockNumber != nil && c.L1RpcClient != nil +func (c *l1SLoad) isL1SLoadActive() bool { + return c.getLatestL1BlockNumber != nil && c.l1RpcClient != nil } -func (pc *PrecompiledContracts) activateL1SLoad(l1RpcClient L1RpcClient, getLatestL1BlockNumber func() *big.Int) { - rulesSayContractShouldBeActive := (*pc)[rollupL1SloadAddress] != nil - paramsNotNil := l1RpcClient != nil && getLatestL1BlockNumber != nil - - if shouldActivateL1SLoad := rulesSayContractShouldBeActive && paramsNotNil; shouldActivateL1SLoad { - (*pc)[rollupL1SloadAddress] = &L1SLoad{ - L1RpcClient: l1RpcClient, - GetLatestL1BlockNumber: getLatestL1BlockNumber, +func (pc *PrecompiledContracts) activateL1SLoad(l1RpcClient L1Client, getLatestL1BlockNumber func() *big.Int) { + if (*pc)[rollupL1SloadAddress] != nil { + (*pc)[rollupL1SloadAddress] = &l1SLoad{ + l1RpcClient: l1RpcClient, + getLatestL1BlockNumber: getLatestL1BlockNumber, } } } diff --git a/core/vm/contracts_rollup_overrides.go b/core/vm/contracts_rollup_overrides.go index df7b4c3c6c30..56c70990b029 100644 --- a/core/vm/contracts_rollup_overrides.go +++ b/core/vm/contracts_rollup_overrides.go @@ -3,9 +3,7 @@ package vm -import ( - "math/big" -) +import "math/big" type RollupPrecompiledContractsOverrides struct { l1SLoadGetLatestL1Block func() *big.Int @@ -25,16 +23,3 @@ func getLatestL1BlockNumber(evm *EVM) func() *big.Int { return evm.Context.BlockNumber } } - -// [OVERRIDE] getLatestL1BlockNumber -// Each rollup should override this function so that it returns -// correct latest L1 block number -// -// EXAMPLE 2 -// func getLatestL1BlockNumber(evm *EVM) func() *big.Int { -// return func() *big.Int { -// addressOfL1BlockContract := common.Address{} -// slotInContractRepresentingL1BlockNumber := common.Hash{} -// return evm.StateDB.GetState(addressOfL1BlockContract, slotInContractRepresentingL1BlockNumber).Big() -// } -// } From f0dd2170c62121c7bdc1ba47389b6f1b790d9807 Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 27 Sep 2024 13:10:01 +0200 Subject: [PATCH 07/26] implements L1SLOAD contract --- core/vm/contracts_rollup.go | 105 +++++++++++++++++++++---------- core/vm/contracts_rollup_test.go | 32 ++++++++++ core/vm/contracts_test.go | 4 +- params/protocol_params_rollup.go | 7 +++ 4 files changed, 114 insertions(+), 34 deletions(-) create mode 100644 core/vm/contracts_rollup_test.go create mode 100644 params/protocol_params_rollup.go diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index d633e368905d..2b6140423ebc 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -4,27 +4,23 @@ package vm import ( + "context" "errors" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) -type RollupPrecompiledContractsOverrides struct { - l1SLoadGetLatestL1Block func() *big.Int -} - -func GenerateRollupPrecompiledContractsOverrides(evm *EVM) RollupPrecompiledContractsOverrides { - return RollupPrecompiledContractsOverrides{ - l1SLoadGetLatestL1Block: getLatestL1BlockNumber(evm), - } -} - var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) var PrecompiledContractsRollupR0 = PrecompiledContracts{ - rollupL1SloadAddress: &l1SLoad{}, + rollupL1SloadAddress: &L1SLoad{}, +} + +type RollupPrecompileActivationConfig struct { + L1SLoad } func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { @@ -36,40 +32,85 @@ func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { } } -func (evm *EVM) activateRollupPrecompiledContracts() { - activeRollupPrecompiles := activeRollupPrecompiledContracts(evm.chainRules) - for k, v := range activeRollupPrecompiles { - evm.precompiles[k] = v - } - +func (pc *PrecompiledContracts) ActivateRollupPrecompiledContracts(config RollupPrecompileActivationConfig) { // NOTE: if L1SLoad was not activated via chain rules this is no-op - evm.precompiles.activateL1SLoad(evm.Config.L1RpcClient, evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block) + pc.activateL1SLoad(config.L1RpcClient, config.GetLatestL1BlockNumber) +} + +func (evm *EVM) activateRollupPrecompiledContracts() { + evm.precompiles.ActivateRollupPrecompiledContracts(RollupPrecompileActivationConfig{ + L1SLoad{L1RpcClient: evm.Config.L1RpcClient, GetLatestL1BlockNumber: evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block}, + }) } -type l1SLoad struct { - l1RpcClient L1Client - getLatestL1BlockNumber func() *big.Int +//INPUT SPECS: +//Byte range Name Description +//------------------------------------------------------------ +//[0: 19] (20 bytes) address The contract address +//[20: 51] (32 bytes) key1 The storage key +//... ... ... +//[k*32-12: k*32+19] (32 bytes) key_k The storage key + +type L1SLoad struct { + L1RpcClient L1RpcClient + GetLatestL1BlockNumber func() *big.Int } -func (c *l1SLoad) RequiredGas(input []byte) uint64 { return 0 } +func (c *L1SLoad) RequiredGas(input []byte) uint64 { + storageSlotsToLoad := len(input[common.AddressLength-1:]) / common.HashLength + storageSlotsToLoad = min(storageSlotsToLoad, params.L1SLoadMaxNumStorageSlots) -func (c *l1SLoad) Run(input []byte) ([]byte, error) { + return params.L1SLoadBaseGas + uint64(storageSlotsToLoad)*params.L1SLoadPerLoadGas +} + +func (c *L1SLoad) Run(input []byte) ([]byte, error) { if !c.isL1SLoadActive() { - return nil, errors.New("L1SLoad precompile not active") + log.Error("L1SLOAD called, but not activated", "client", c.L1RpcClient, "and latest block number function", c.GetLatestL1BlockNumber) + return nil, errors.New("L1SLOAD precompile not active") + } + + if len(input) < common.AddressLength+common.HashLength { + return nil, errors.New("L1SLOAD input too short") + } + + countOfStorageKeysToRead := (len(input) - common.AddressLength) / common.HashLength + thereIsAtLeast1StorageKeyToRead := countOfStorageKeysToRead > 0 + allStorageKeysAreExactly32Bytes := countOfStorageKeysToRead*common.HashLength == len(input)-common.AddressLength + + if inputIsValid := thereIsAtLeast1StorageKeyToRead && allStorageKeysAreExactly32Bytes; !inputIsValid { + return nil, errors.New("L1SLOAD input is malformed") + } + + contractAddress := common.BytesToAddress(input[:common.AddressLength]) + input = input[common.AddressLength-1:] + contractStorageKeys := make([]common.Hash, countOfStorageKeysToRead) + for k := 0; k < countOfStorageKeysToRead; k++ { + contractStorageKeys[k] = common.BytesToHash(input[k*common.HashLength : (k+1)*common.HashLength]) } - return nil, nil + // TODO: + // 1. Batch multiple storage slots + // 2. What about timeout strategy here? + res, err := c.L1RpcClient.StorageAt(context.Background(), contractAddress, contractStorageKeys[0], c.GetLatestL1BlockNumber()) + if err != nil { + return nil, err + } + + return res, nil } -func (c *l1SLoad) isL1SLoadActive() bool { - return c.getLatestL1BlockNumber != nil && c.l1RpcClient != nil +func (c *L1SLoad) isL1SLoadActive() bool { + return c.GetLatestL1BlockNumber != nil && c.L1RpcClient != nil } -func (pc *PrecompiledContracts) activateL1SLoad(l1RpcClient L1Client, getLatestL1BlockNumber func() *big.Int) { - if (*pc)[rollupL1SloadAddress] != nil { - (*pc)[rollupL1SloadAddress] = &l1SLoad{ - l1RpcClient: l1RpcClient, - getLatestL1BlockNumber: getLatestL1BlockNumber, +func (pc PrecompiledContracts) activateL1SLoad(l1RpcClient L1RpcClient, getLatestL1BlockNumber func() *big.Int) { + rulesSayContractShouldBeActive := pc[rollupL1SloadAddress] != nil + paramsNotNil := l1RpcClient != nil && getLatestL1BlockNumber != nil + + if shouldActivateL1SLoad := rulesSayContractShouldBeActive && paramsNotNil; shouldActivateL1SLoad { + pc[rollupL1SloadAddress] = &L1SLoad{ + L1RpcClient: l1RpcClient, + GetLatestL1BlockNumber: getLatestL1BlockNumber, } } } diff --git a/core/vm/contracts_rollup_test.go b/core/vm/contracts_rollup_test.go new file mode 100644 index 000000000000..cbca8188c9f6 --- /dev/null +++ b/core/vm/contracts_rollup_test.go @@ -0,0 +1,32 @@ +package vm + +import ( + "context" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +type MockL1RPCClient struct{} + +func (m MockL1RPCClient) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { + return common.Hex2Bytes("abab"), nil +} + +func TestPrecompiledL1SLOAD(t *testing.T) { + mockL1RPCClient := MockL1RPCClient{} + + allPrecompiles[rollupL1SloadAddress] = &L1SLoad{} + allPrecompiles.activateL1SLoad(mockL1RPCClient, func() *big.Int { return big1 }) + + l1SLoadTestcase := precompiledTest{ + Name: "L1SLOAD", + Input: "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e864", + Expected: "abab", + Gas: 4000, + NoBenchmark: true, + } + + testPrecompiled(rollupL1SloadAddress.Hex(), l1SLoadTestcase, t) +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index fff5c966f34f..23035e0eeec2 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -45,7 +45,7 @@ type precompiledFailureTest struct { // allPrecompiles does not map to the actual set of precompiles, as it also contains // repriced versions of precompiles at certain slots -var allPrecompiles = map[common.Address]PrecompiledContract{ +var allPrecompiles = PrecompiledContracts{ common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{3}): &ripemd160hash{}, @@ -181,7 +181,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { // Keep it as uint64, multiply 100 to get two digit float later mgasps := (100 * 1000 * gasUsed) / elapsed bench.ReportMetric(float64(mgasps)/100, "mgas/s") - //Check if it is correct + // Check if it is correct if err != nil { bench.Error(err) return diff --git a/params/protocol_params_rollup.go b/params/protocol_params_rollup.go new file mode 100644 index 000000000000..3ac56c6f63d2 --- /dev/null +++ b/params/protocol_params_rollup.go @@ -0,0 +1,7 @@ +package params + +const ( + L1SLoadBaseGas uint64 = 2000 // Base price for L1Sload + L1SLoadPerLoadGas uint64 = 2000 // Per-load price for loading one storage slot + L1SLoadMaxNumStorageSlots = 5 // Max number of storage slots requested in L1Sload precompile +) From c4b24af69ac7940ca9c0fe09a12b55e52564367b Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 27 Sep 2024 13:32:52 +0200 Subject: [PATCH 08/26] added rpc call timeout strategy --- core/vm/contracts_rollup.go | 13 +++++++++++-- params/protocol_params_rollup.go | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index 2b6140423ebc..8dee19ed6f4f 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -7,6 +7,7 @@ import ( "context" "errors" "math/big" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" @@ -90,8 +91,16 @@ func (c *L1SLoad) Run(input []byte) ([]byte, error) { // TODO: // 1. Batch multiple storage slots - // 2. What about timeout strategy here? - res, err := c.L1RpcClient.StorageAt(context.Background(), contractAddress, contractStorageKeys[0], c.GetLatestL1BlockNumber()) + var ctx context.Context + if params.L1SLoadRPCTimeoutInSec > 0 { + c, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(params.L1SLoadRPCTimeoutInSec)) + ctx = c + defer cancel() + } else { + ctx = context.Background() + } + + res, err := c.L1RpcClient.StorageAt(ctx, contractAddress, contractStorageKeys[0], c.GetLatestL1BlockNumber()) if err != nil { return nil, err } diff --git a/params/protocol_params_rollup.go b/params/protocol_params_rollup.go index 3ac56c6f63d2..46a0c9f570a9 100644 --- a/params/protocol_params_rollup.go +++ b/params/protocol_params_rollup.go @@ -5,3 +5,5 @@ const ( L1SLoadPerLoadGas uint64 = 2000 // Per-load price for loading one storage slot L1SLoadMaxNumStorageSlots = 5 // Max number of storage slots requested in L1Sload precompile ) + +var L1SLoadRPCTimeoutInSec = MainnetChainConfig.Clique.Period // After how many ms will RPC call timeout From bea23a3c5fca4f2bda610ec235e252373f3d762c Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 27 Sep 2024 22:40:37 +0200 Subject: [PATCH 09/26] added batch call for StoragesAt as well as tests --- core/vm/contracts_rollup.go | 2 +- core/vm/contracts_rollup_test.go | 22 +++++------ core/vm/interpreter.go | 2 +- .../vm/testdata/precompiles/fail-l1sload.json | 16 ++++++++ core/vm/testdata/precompiles/l1sload.json | 24 ++++++++++++ ethclient/ethclient_rollup.go | 38 +++++++++++++++++++ params/protocol_params_rollup.go | 3 +- 7 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 core/vm/testdata/precompiles/fail-l1sload.json create mode 100644 core/vm/testdata/precompiles/l1sload.json create mode 100644 ethclient/ethclient_rollup.go diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index 8dee19ed6f4f..b1b2f17b4cc3 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -100,7 +100,7 @@ func (c *L1SLoad) Run(input []byte) ([]byte, error) { ctx = context.Background() } - res, err := c.L1RpcClient.StorageAt(ctx, contractAddress, contractStorageKeys[0], c.GetLatestL1BlockNumber()) + res, err := c.L1RpcClient.StoragesAt(ctx, contractAddress, contractStorageKeys, c.GetLatestL1BlockNumber()) if err != nil { return nil, err } diff --git a/core/vm/contracts_rollup_test.go b/core/vm/contracts_rollup_test.go index cbca8188c9f6..b798b5a24535 100644 --- a/core/vm/contracts_rollup_test.go +++ b/core/vm/contracts_rollup_test.go @@ -10,8 +10,15 @@ import ( type MockL1RPCClient struct{} -func (m MockL1RPCClient) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { - return common.Hex2Bytes("abab"), nil +func (m MockL1RPCClient) StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) { + // testcase is in format "abab", this makes output lenght 2 bytes + const mockedRespValueSize = 2 + mockResp := make([]byte, mockedRespValueSize*len(keys)) + for i := range keys { + copy(mockResp[mockedRespValueSize*i:], common.Hex2Bytes("abab")) + } + + return mockResp, nil } func TestPrecompiledL1SLOAD(t *testing.T) { @@ -20,13 +27,6 @@ func TestPrecompiledL1SLOAD(t *testing.T) { allPrecompiles[rollupL1SloadAddress] = &L1SLoad{} allPrecompiles.activateL1SLoad(mockL1RPCClient, func() *big.Int { return big1 }) - l1SLoadTestcase := precompiledTest{ - Name: "L1SLOAD", - Input: "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e864", - Expected: "abab", - Gas: 4000, - NoBenchmark: true, - } - - testPrecompiled(rollupL1SloadAddress.Hex(), l1SLoadTestcase, t) + testJson("l1sload", rollupL1SloadAddress.Hex(), t) + testJsonFail("l1sload", rollupL1SloadAddress.Hex(), t) } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index ebb07b8b8b5a..0872dfde4048 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -42,7 +42,7 @@ type Config struct { // [rollup-geth] type L1RpcClient interface { - StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) + StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/core/vm/testdata/precompiles/fail-l1sload.json b/core/vm/testdata/precompiles/fail-l1sload.json new file mode 100644 index 000000000000..2128bec29b86 --- /dev/null +++ b/core/vm/testdata/precompiles/fail-l1sload.json @@ -0,0 +1,16 @@ +[ + { + "Name": "L1SLOAD FAIL: input contains only address", + "Input": "a83114A443dA1CecEFC50368531cACE9F37fCCcb", + "ExpectedError": "L1SLOAD input too short", + "Gas": 4000, + "NoBenchmark": true + }, + { + "Name": "L1SLOAD FAIL: input key not 32 bytes", + "Input": "a83114A443dA1CecEFC50368531cACE9F37fCCcb112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7122", + "ExpectedError": "L1SLOAD input is malformed", + "Gas": 4000, + "NoBenchmark": true + } +] diff --git a/core/vm/testdata/precompiles/l1sload.json b/core/vm/testdata/precompiles/l1sload.json new file mode 100644 index 000000000000..b0debfd3b49a --- /dev/null +++ b/core/vm/testdata/precompiles/l1sload.json @@ -0,0 +1,24 @@ +[ + { + "Name": "L1SLOAD: 1 key", + "Input": "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e864", + "Expected": "abab", + "Gas": 4000, + "NoBenchmark": true + }, + { + "Name": "L1SLOAD: 2 keys", + "Input": "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e8640112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a", + "Expected": "abababab", + "Gas": 6000, + "NoBenchmark": true + }, + + { + "Name": "L1SLOAD: 5 keys", + "Input": "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e8640112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a", + "Expected": "abababababababababab", + "Gas": 12000, + "NoBenchmark": true + } +] diff --git a/ethclient/ethclient_rollup.go b/ethclient/ethclient_rollup.go new file mode 100644 index 000000000000..4571cdca8509 --- /dev/null +++ b/ethclient/ethclient_rollup.go @@ -0,0 +1,38 @@ +package ethclient + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" +) + +// StoragesAt returns the values of keys in the contract storage of the given account. +// The block number can be nil, in which case the value is taken from the latest known block. +func (ec *Client) StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) { + results := make([]hexutil.Bytes, len(keys)) + reqs := make([]rpc.BatchElem, len(keys)) + + for i := range reqs { + reqs[i] = rpc.BatchElem{ + Method: "eth_getStorageAt", + Args: []interface{}{account, keys[i], toBlockNumArg(blockNumber)}, + Result: &results[i], + } + } + if err := ec.c.BatchCallContext(ctx, reqs); err != nil { + return nil, err + } + + output := make([]byte, common.HashLength*len(keys)) + for i := range reqs { + if reqs[i].Error != nil { + return nil, reqs[i].Error + } + copy(output[i*common.HashLength:], results[i]) + } + + return output, nil +} diff --git a/params/protocol_params_rollup.go b/params/protocol_params_rollup.go index 46a0c9f570a9..d75663d81c78 100644 --- a/params/protocol_params_rollup.go +++ b/params/protocol_params_rollup.go @@ -4,6 +4,5 @@ const ( L1SLoadBaseGas uint64 = 2000 // Base price for L1Sload L1SLoadPerLoadGas uint64 = 2000 // Per-load price for loading one storage slot L1SLoadMaxNumStorageSlots = 5 // Max number of storage slots requested in L1Sload precompile + L1SLoadRPCTimeoutInSec = 3 ) - -var L1SLoadRPCTimeoutInSec = MainnetChainConfig.Clique.Period // After how many ms will RPC call timeout From e9a5c283a73f7775ae7b63eba3bcf355bd09eb9b Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 27 Sep 2024 22:44:44 +0200 Subject: [PATCH 10/26] added test for too long input edgecase --- core/vm/contracts_rollup.go | 2 -- core/vm/testdata/precompiles/fail-l1sload.json | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index b1b2f17b4cc3..7de2f59a9e04 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -89,8 +89,6 @@ func (c *L1SLoad) Run(input []byte) ([]byte, error) { contractStorageKeys[k] = common.BytesToHash(input[k*common.HashLength : (k+1)*common.HashLength]) } - // TODO: - // 1. Batch multiple storage slots var ctx context.Context if params.L1SLoadRPCTimeoutInSec > 0 { c, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(params.L1SLoadRPCTimeoutInSec)) diff --git a/core/vm/testdata/precompiles/fail-l1sload.json b/core/vm/testdata/precompiles/fail-l1sload.json index 2128bec29b86..43250bede45a 100644 --- a/core/vm/testdata/precompiles/fail-l1sload.json +++ b/core/vm/testdata/precompiles/fail-l1sload.json @@ -12,5 +12,13 @@ "ExpectedError": "L1SLOAD input is malformed", "Gas": 4000, "NoBenchmark": true + }, + { + "Name": "L1SLOAD FAIL: input too long", + "Input": "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e8640112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7aa83114A443dA1CecEFC50368531cACE9F37fCCcb112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7122", + "ExpectedError": "L1SLOAD input is malformed", + "Gas": 4000, + "NoBenchmark": true } + ] From 56c1f67d41e2cae55bba3e1a32a1f4bf5cabc88c Mon Sep 17 00:00:00 2001 From: mralj Date: Sat, 28 Sep 2024 13:00:06 +0200 Subject: [PATCH 11/26] added missing mocks for tests --- core/vm/contracts_rollup.go | 2 +- eth/tracers/api_rollup_test.go | 7 +++++++ internal/ethapi/api_rollup_test.go | 7 +++++++ internal/ethapi/transaction_args_rollup_test.go | 7 +++++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 eth/tracers/api_rollup_test.go create mode 100644 internal/ethapi/api_rollup_test.go create mode 100644 internal/ethapi/transaction_args_rollup_test.go diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index 7de2f59a9e04..d80bcd343782 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -78,7 +78,7 @@ func (c *L1SLoad) Run(input []byte) ([]byte, error) { thereIsAtLeast1StorageKeyToRead := countOfStorageKeysToRead > 0 allStorageKeysAreExactly32Bytes := countOfStorageKeysToRead*common.HashLength == len(input)-common.AddressLength - if inputIsValid := thereIsAtLeast1StorageKeyToRead && allStorageKeysAreExactly32Bytes; !inputIsValid { + if inputIsInvalid := !(thereIsAtLeast1StorageKeyToRead && allStorageKeysAreExactly32Bytes); inputIsInvalid { return nil, errors.New("L1SLOAD input is malformed") } diff --git a/eth/tracers/api_rollup_test.go b/eth/tracers/api_rollup_test.go new file mode 100644 index 000000000000..21581a015aef --- /dev/null +++ b/eth/tracers/api_rollup_test.go @@ -0,0 +1,7 @@ +package tracers + +import "github.com/ethereum/go-ethereum/core/vm" + +func (b *testBackend) GetL1RpcClient() vm.L1RpcClient { + return nil +} diff --git a/internal/ethapi/api_rollup_test.go b/internal/ethapi/api_rollup_test.go new file mode 100644 index 000000000000..337dca43e256 --- /dev/null +++ b/internal/ethapi/api_rollup_test.go @@ -0,0 +1,7 @@ +package ethapi + +import "github.com/ethereum/go-ethereum/core/vm" + +func (b *testBackend) GetL1RpcClient() vm.L1RpcClient { + return nil +} diff --git a/internal/ethapi/transaction_args_rollup_test.go b/internal/ethapi/transaction_args_rollup_test.go new file mode 100644 index 000000000000..5004799d10a9 --- /dev/null +++ b/internal/ethapi/transaction_args_rollup_test.go @@ -0,0 +1,7 @@ +package ethapi + +import "github.com/ethereum/go-ethereum/core/vm" + +func (b *backendMock) GetL1RpcClient() vm.L1RpcClient { + return nil +} From 6a98534271adc973fae517ae452177efb0692f60 Mon Sep 17 00:00:00 2001 From: mralj Date: Thu, 26 Sep 2024 13:22:58 +0200 Subject: [PATCH 12/26] added L1SLoad sekelton --- core/vm/contracts_rollup.go | 54 ++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index d80bcd343782..b9fa41bb83c4 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -14,43 +14,45 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) +type RollupPrecompileActivationConfig struct { + L1SLoad +} -var PrecompiledContractsRollupR0 = PrecompiledContracts{ - rollupL1SloadAddress: &L1SLoad{}, +type L1RpcClient interface { + StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) } -type RollupPrecompileActivationConfig struct { - L1SLoad +var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) +var precompiledContractsRollupR0 = PrecompiledContracts{ + rollupL1SloadAddress: &L1SLoad{}, } func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { switch rules.IsR0 { case rules.IsR0: - return PrecompiledContractsRollupR0 + return precompiledContractsRollupR0 default: return nil } } -func (pc *PrecompiledContracts) ActivateRollupPrecompiledContracts(config RollupPrecompileActivationConfig) { +// ActivateRollupPrecompiledContracts activates rollup-specific precompiles +func (pc PrecompiledContracts) ActivateRollupPrecompiledContracts(config *RollupPrecompileActivationConfig) { + if config == nil { + return + } + // NOTE: if L1SLoad was not activated via chain rules this is no-op pc.activateL1SLoad(config.L1RpcClient, config.GetLatestL1BlockNumber) } -func (evm *EVM) activateRollupPrecompiledContracts() { - evm.precompiles.ActivateRollupPrecompiledContracts(RollupPrecompileActivationConfig{ - L1SLoad{L1RpcClient: evm.Config.L1RpcClient, GetLatestL1BlockNumber: evm.rollupPrecompileOverrides.l1SLoadGetLatestL1Block}, - }) -} - //INPUT SPECS: //Byte range Name Description //------------------------------------------------------------ -//[0: 19] (20 bytes) address The contract address -//[20: 51] (32 bytes) key1 The storage key +//[0: 19] (20 bytes) address The contract address +//[20: 51] (32 bytes) key1 The storage key //... ... ... -//[k*32-12: k*32+19] (32 bytes) key_k The storage key +//[k*32-12: k*32+19] (32 bytes)key_k The storage key type L1SLoad struct { L1RpcClient L1RpcClient @@ -111,13 +113,15 @@ func (c *L1SLoad) isL1SLoadActive() bool { } func (pc PrecompiledContracts) activateL1SLoad(l1RpcClient L1RpcClient, getLatestL1BlockNumber func() *big.Int) { - rulesSayContractShouldBeActive := pc[rollupL1SloadAddress] != nil - paramsNotNil := l1RpcClient != nil && getLatestL1BlockNumber != nil - - if shouldActivateL1SLoad := rulesSayContractShouldBeActive && paramsNotNil; shouldActivateL1SLoad { - pc[rollupL1SloadAddress] = &L1SLoad{ - L1RpcClient: l1RpcClient, - GetLatestL1BlockNumber: getLatestL1BlockNumber, - } + if paramsAreNil := l1RpcClient == nil || getLatestL1BlockNumber == nil; paramsAreNil { + return } -} + if precompileNotRuleActivated := pc[rollupL1SloadAddress] == nil; precompileNotRuleActivated { + return + } + + pc[rollupL1SloadAddress] = &L1SLoad{ + L1RpcClient: l1RpcClient, + GetLatestL1BlockNumber: getLatestL1BlockNumber, + } +} \ No newline at end of file From ef91bcd578eea9e5b2a7678cb45eb892b13ec2e9 Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 27 Sep 2024 13:10:01 +0200 Subject: [PATCH 13/26] implements L1SLOAD contract --- core/vm/contracts_rollup_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/contracts_rollup_test.go b/core/vm/contracts_rollup_test.go index b798b5a24535..9bde468e659b 100644 --- a/core/vm/contracts_rollup_test.go +++ b/core/vm/contracts_rollup_test.go @@ -29,4 +29,4 @@ func TestPrecompiledL1SLOAD(t *testing.T) { testJson("l1sload", rollupL1SloadAddress.Hex(), t) testJsonFail("l1sload", rollupL1SloadAddress.Hex(), t) -} +} \ No newline at end of file From 2a7b7d7b937c167bb167f90c5adca02ebce0812f Mon Sep 17 00:00:00 2001 From: mralj Date: Sun, 29 Sep 2024 11:45:34 +0200 Subject: [PATCH 14/26] cmd - rollup specific files --- cmd/geth/main.go | 7 +------ cmd/utils/flags.go | 17 ----------------- cmd/utils/flags_rollup.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 23 deletions(-) create mode 100644 cmd/utils/flags_rollup.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index cbf71c151d8f..ff5aa67d3157 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -206,11 +206,6 @@ var ( utils.MetricsInfluxDBBucketFlag, utils.MetricsInfluxDBOrganizationFlag, } - - //[rollup-geth] - rollupFlags = []cli.Flag{ - utils.L1NodeRPCEndpointFlag, - } ) var app = flags.NewApp("the go-ethereum command line interface") @@ -262,7 +257,7 @@ func init() { consoleFlags, debug.Flags, metricsFlags, - rollupFlags, //[rollup-geth] + utils.RollupFlags, //[rollup-geth] ) flags.AutoEnvVars(app.Flags, "GETH") diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index dccf4981340c..9278b445b3aa 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -951,14 +951,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. Value: metrics.DefaultConfig.InfluxDBOrganization, Category: flags.MetricsCategory, } - - //[rollup-geth] - L1NodeRPCEndpointFlag = &cli.StringFlag{ - Name: "rollup.l1.rpc_endpoint", - Usage: "L1 node RPC endpoint eg. http://0.0.0.0:8545", - Category: flags.RollupCategory, - Required: true, - } ) var ( @@ -1259,15 +1251,6 @@ func setLes(ctx *cli.Context, cfg *ethconfig.Config) { } } -// [rollup-geth] -func setRollupEthConfig(ctx *cli.Context, cfg *ethconfig.Config) { - if ctx.IsSet(L1NodeRPCEndpointFlag.Name) { - cfg.L1NodeRPCEndpoint = ctx.String(L1NodeRPCEndpointFlag.Name) - } else { - log.Crit("L1 node RPC endpoint URL not set", "flag", L1NodeRPCEndpointFlag.Name) - } -} - // MakeDatabaseHandles raises out the number of allowed file handles per process // for Geth and returns half of the allowance to assign to the database. func MakeDatabaseHandles(max int) int { diff --git a/cmd/utils/flags_rollup.go b/cmd/utils/flags_rollup.go new file mode 100644 index 000000000000..4b6d0e0db319 --- /dev/null +++ b/cmd/utils/flags_rollup.go @@ -0,0 +1,32 @@ +package utils + +import ( + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/log" + "github.com/urfave/cli/v2" +) + +var ( + l1NodeRPCEndpointFlag = &cli.StringFlag{ + Name: "rollup.l1.rpc_endpoint", + Usage: "L1 node RPC endpoint eg. http://0.0.0.0:8545", + Category: flags.RollupCategory, + Required: true, + } +) + +var ( + RollupFlags = []cli.Flag{ + l1NodeRPCEndpointFlag, + } +) + +// [rollup-geth] +func setRollupEthConfig(ctx *cli.Context, cfg *ethconfig.Config) { + if ctx.IsSet(l1NodeRPCEndpointFlag.Name) { + cfg.L1NodeRPCEndpoint = ctx.String(l1NodeRPCEndpointFlag.Name) + } else { + log.Crit("L1 node RPC endpoint URL not set", "flag", l1NodeRPCEndpointFlag.Name) + } +} From 0f7439099439dac0fcc8b8d00b7121636206a763 Mon Sep 17 00:00:00 2001 From: mralj Date: Sun, 29 Sep 2024 13:12:00 +0200 Subject: [PATCH 15/26] cleaned up code & created more rollup specific files --- cmd/geth/config.go | 7 ++++++- cmd/utils/flags.go | 7 ++----- cmd/utils/flags_rollup.go | 15 ++------------- core/vm/interpreter.go | 7 ------- eth/api_backend.go | 5 ----- eth/api_backend_rollup.go | 7 +++++++ eth/backend.go | 14 ++++---------- eth/backend_rollup.go | 19 +++++++++++++++++++ eth/ethconfig/config.go | 3 --- internal/ethapi/simulate.go | 4 ++-- 10 files changed, 42 insertions(+), 46 deletions(-) create mode 100644 eth/api_backend_rollup.go create mode 100644 eth/backend_rollup.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index fd57ff40def4..24eddbabf167 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -192,7 +192,12 @@ func makeFullNode(ctx *cli.Context) *node.Node { cfg.Eth.OverrideVerkle = &v } - backend, eth := utils.RegisterEthService(stack, &cfg.Eth) + // [rollup-geth] + // TODO: think about if there is better solution for this (eg. rollup config file) + if !ctx.IsSet(utils.L1NodeRPCEndpointFlag.Name) { + log.Crit("L1 node RPC endpoint URL not set", "flag", utils.L1NodeRPCEndpointFlag.Name) + } + backend, eth := utils.RegisterEthService(stack, &cfg.Eth, ctx.String(utils.L1NodeRPCEndpointFlag.Name)) // Create gauge with geth system and build information if eth != nil { // The 'eth' backend may be nil in light mode diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 9278b445b3aa..c85e7e0a4196 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1651,9 +1651,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { setRequiredBlocks(ctx, cfg) setLes(ctx, cfg) - //[rollup-geth] - setRollupEthConfig(ctx, cfg) - // Cap the cache allowance and tune the garbage collector mem, err := gopsutil.VirtualMemory() if err == nil { @@ -1928,8 +1925,8 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) { // RegisterEthService adds an Ethereum client to the stack. // The second return value is the full node instance. -func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (*eth.EthAPIBackend, *eth.Ethereum) { - backend, err := eth.New(stack, cfg) +func RegisterEthService(stack *node.Node, cfg *ethconfig.Config, l1RPCClientEndpoint string) (*eth.EthAPIBackend, *eth.Ethereum) { + backend, err := eth.New(stack, cfg, l1RPCClientEndpoint) if err != nil { Fatalf("Failed to register the Ethereum service: %v", err) } diff --git a/cmd/utils/flags_rollup.go b/cmd/utils/flags_rollup.go index 4b6d0e0db319..241505d1a1fb 100644 --- a/cmd/utils/flags_rollup.go +++ b/cmd/utils/flags_rollup.go @@ -1,14 +1,12 @@ package utils import ( - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/flags" - "github.com/ethereum/go-ethereum/log" "github.com/urfave/cli/v2" ) var ( - l1NodeRPCEndpointFlag = &cli.StringFlag{ + L1NodeRPCEndpointFlag = &cli.StringFlag{ Name: "rollup.l1.rpc_endpoint", Usage: "L1 node RPC endpoint eg. http://0.0.0.0:8545", Category: flags.RollupCategory, @@ -18,15 +16,6 @@ var ( var ( RollupFlags = []cli.Flag{ - l1NodeRPCEndpointFlag, + L1NodeRPCEndpointFlag, } ) - -// [rollup-geth] -func setRollupEthConfig(ctx *cli.Context, cfg *ethconfig.Config) { - if ctx.IsSet(l1NodeRPCEndpointFlag.Name) { - cfg.L1NodeRPCEndpoint = ctx.String(l1NodeRPCEndpointFlag.Name) - } else { - log.Crit("L1 node RPC endpoint URL not set", "flag", l1NodeRPCEndpointFlag.Name) - } -} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 0872dfde4048..6e0b84067032 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -17,9 +17,7 @@ package vm import ( - "context" "fmt" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -40,11 +38,6 @@ type Config struct { L1RpcClient L1RpcClient //[rollup-geth] } -// [rollup-geth] -type L1RpcClient interface { - StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) -} - // ScopeContext contains the things that are per-call, such as stack and memory, // but not transients like pc and gas type ScopeContext struct { diff --git a/eth/api_backend.go b/eth/api_backend.go index 4960be76211f..8a9898b956f3 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -431,8 +431,3 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } - -// [rollup-geth] -func (b *EthAPIBackend) GetL1RpcClient() vm.L1RpcClient { - return b.eth.BlockChain().GetVMConfig().L1RpcClient -} diff --git a/eth/api_backend_rollup.go b/eth/api_backend_rollup.go new file mode 100644 index 000000000000..42548f2ab164 --- /dev/null +++ b/eth/api_backend_rollup.go @@ -0,0 +1,7 @@ +package eth + +import "github.com/ethereum/go-ethereum/core/vm" + +func (b *EthAPIBackend) GetL1RpcClient() vm.L1RpcClient { + return b.eth.BlockChain().GetVMConfig().L1RpcClient +} diff --git a/eth/backend.go b/eth/backend.go index f8762ffc3f7b..04b32b873dda 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -43,7 +43,6 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -101,7 +100,7 @@ type Ethereum struct { // New creates a new Ethereum object (including the initialisation of the common Ethereum object), // whose lifecycle will be managed by the provided node. -func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { +func New(stack *node.Node, config *ethconfig.Config, l1RPCEndpoint string) (*Ethereum, error) { // Ensure configuration values are compatible and sane if !config.SyncMode.IsValid() { return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) @@ -217,19 +216,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { overrides.OverrideVerkle = config.OverrideVerkle } - //[rollup-geth] - l1Client, err := ethclient.Dial(config.L1NodeRPCEndpoint) - if err != nil { - log.Crit("Unable to connect to L1 RPC endpoint at", "URL", config.L1NodeRPCEndpoint, "error", err) - } else { - vmConfig.L1RpcClient = l1Client - log.Info("Initialized L1 RPC client", "endpoint", config.L1NodeRPCEndpoint) - } + // [rollup-geth] + activateL1RPCEndpoint(l1RPCEndpoint, &vmConfig) eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory) if err != nil { return nil, err } + eth.bloomIndexer.Start(eth.blockchain) if config.BlobPool.Datadir != "" { diff --git a/eth/backend_rollup.go b/eth/backend_rollup.go new file mode 100644 index 000000000000..e9b2ba338be7 --- /dev/null +++ b/eth/backend_rollup.go @@ -0,0 +1,19 @@ +package eth + +import ( + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" +) + +// TODO: when we have clearer picture of how do we want rollup "features" (EIPs/RIPs) to be activated +// make this "rule" activated (ie. if not "rule activated" then L1 client can simply be nil) +func activateL1RPCEndpoint(l1RPCEndpoint string, vmConfig *vm.Config) { + l1Client, err := ethclient.Dial(l1RPCEndpoint) + if err != nil { + log.Crit("Unable to connect to L1 RPC endpoint at", "URL", l1RPCEndpoint, "error", err) + } else { + vmConfig.L1RpcClient = l1Client + log.Info("Initialized L1 RPC client", "endpoint", l1RPCEndpoint) + } +} diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 5719ef16a3ab..c781a639408a 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -156,9 +156,6 @@ type Config struct { // OverrideVerkle (TODO: remove after the fork) OverrideVerkle *uint64 `toml:",omitempty"` - - //[rollup-geth] - L1NodeRPCEndpoint string } // CreateConsensusEngine creates a consensus engine for the given chain config. diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 82a7d8a4cf57..441e90ae9941 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -283,14 +283,14 @@ func (sim *simulator) sanitizeCall(call *TransactionArgs, state *state.StateDB, func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContracts { var ( - isMerge = (base.Difficulty.Sign() == 0) + isMerge = base.Difficulty.Sign() == 0 rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) ) precompiles := vm.ActivePrecompiledContracts(rules) //[rollup-geth] This is optional for rollups precompiles.ActivateRollupPrecompiledContracts(vm.RollupPrecompileActivationConfig{ - vm.L1SLoad{L1RpcClient: sim.b.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return base.Number }}, + L1SLoad: vm.L1SLoad{L1RpcClient: sim.b.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return base.Number }}, }) return maps.Clone(precompiles) From 1ccbc9589134ebe72eb798f73eabf78a07250b5d Mon Sep 17 00:00:00 2001 From: mralj Date: Mon, 30 Sep 2024 10:13:45 +0200 Subject: [PATCH 16/26] simplified the code --- core/vm/contracts.go | 27 ++++++++++++++++++--------- core/vm/contracts_rollup_overrides.go | 14 +++++++------- core/vm/evm.go | 8 +------- eth/tracers/api.go | 15 +++++++++------ internal/ethapi/api.go | 13 ++++++++----- internal/ethapi/simulate.go | 15 +++++++++------ 6 files changed, 52 insertions(+), 40 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 2a2561121e13..37838c1d5f2a 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -23,6 +23,7 @@ import ( "fmt" "maps" "math/big" + "slices" "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" @@ -173,7 +174,7 @@ func init() { } } -func activePrecompiledContracts(rules params.Rules) PrecompiledContracts { +func activePrecompiledContracts(rules params.Rules, config *RollupPrecompileActivationConfig) PrecompiledContracts { var activePrecompiles PrecompiledContracts switch { case rules.IsVerkle: @@ -197,31 +198,39 @@ func activePrecompiledContracts(rules params.Rules) PrecompiledContracts { for k, v := range activeRollupPrecompiles { activePrecompiles[k] = v } + activePrecompiles.ActivateRollupPrecompiledContracts(config) return activePrecompiles } // ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration. -func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts { - return maps.Clone(activePrecompiledContracts(rules)) +func ActivePrecompiledContracts(rules params.Rules, rollupConfig *RollupPrecompileActivationConfig) PrecompiledContracts { + return maps.Clone(activePrecompiledContracts(rules, rollupConfig)) } // ActivePrecompiles returns the precompile addresses enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { + var activePrecompileAddresses []common.Address switch { case rules.IsPrague: - return PrecompiledAddressesPrague + activePrecompileAddresses = PrecompiledAddressesPrague case rules.IsCancun: - return PrecompiledAddressesCancun + activePrecompileAddresses = PrecompiledAddressesCancun case rules.IsBerlin: - return PrecompiledAddressesBerlin + activePrecompileAddresses = PrecompiledAddressesBerlin case rules.IsIstanbul: - return PrecompiledAddressesIstanbul + activePrecompileAddresses = PrecompiledAddressesIstanbul case rules.IsByzantium: - return PrecompiledAddressesByzantium + activePrecompileAddresses = PrecompiledAddressesByzantium default: - return PrecompiledAddressesHomestead + activePrecompileAddresses = PrecompiledAddressesHomestead } + + // [rollup-geth] + activePrecompileAddresses = + append(activePrecompileAddresses, slices.Collect(maps.Keys(activeRollupPrecompiledContracts(rules)))...) + + return activePrecompileAddresses } // RunPrecompiledContract runs and evaluates the output of a precompiled contract. diff --git a/core/vm/contracts_rollup_overrides.go b/core/vm/contracts_rollup_overrides.go index 56c70990b029..39541558a0e6 100644 --- a/core/vm/contracts_rollup_overrides.go +++ b/core/vm/contracts_rollup_overrides.go @@ -5,13 +5,13 @@ package vm import "math/big" -type RollupPrecompiledContractsOverrides struct { - l1SLoadGetLatestL1Block func() *big.Int -} - -func GenerateRollupPrecompiledContractsOverrides(evm *EVM) RollupPrecompiledContractsOverrides { - return RollupPrecompiledContractsOverrides{ - l1SLoadGetLatestL1Block: getLatestL1BlockNumber(evm), +// generateRollupPrecompiledContractsOverrides generates rollup precompile config inlucing L2 specific overrides +func generateRollupPrecompiledContractsOverrides(evm *EVM) *RollupPrecompileActivationConfig { + return &RollupPrecompileActivationConfig{ + L1SLoad{ + L1RpcClient: evm.Config.L1RpcClient, + GetLatestL1BlockNumber: getLatestL1BlockNumber(evm), + }, } } diff --git a/core/vm/evm.go b/core/vm/evm.go index 8292dc30b1eb..d74ede439efa 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -114,10 +114,6 @@ type EVM struct { callGasTemp uint64 // precompiles holds the precompiled contracts for the current epoch precompiles PrecompiledContracts - - //[rollup-geth] - // Overrides specific to precompiled contracts for rollups - rollupPrecompileOverrides RollupPrecompiledContractsOverrides } // NewEVM returns a new EVM. The returned EVM is not thread safe and should @@ -131,11 +127,9 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } - evm.precompiles = activePrecompiledContracts(evm.chainRules) //[rollup-geth] - evm.rollupPrecompileOverrides = GenerateRollupPrecompiledContractsOverrides(evm) - evm.activateRollupPrecompiledContracts() + evm.precompiles = activePrecompiledContracts(evm.chainRules, generateRollupPrecompiledContractsOverrides(evm)) evm.interpreter = NewEVMInterpreter(evm) return evm diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 44d0abf99be4..6d962d2340fa 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -962,12 +962,15 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time) - precompiles := vm.ActivePrecompiledContracts(rules) - - //[rollup-geth] This is optional for rollups - precompiles.ActivateRollupPrecompiledContracts(vm.RollupPrecompileActivationConfig{ - vm.L1SLoad{L1RpcClient: api.backend.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return vmctx.BlockNumber }}, - }) + //[rollup-geth] This is optional for rollups, instead we can simply do + // rollupsConfig := nil + rollupsConfig := vm.RollupPrecompileActivationConfig{ + L1SLoad: vm.L1SLoad{ + L1RpcClient: api.backend.GetL1RpcClient(), + GetLatestL1BlockNumber: func() *big.Int { return vmctx.BlockNumber } + }, + } + precompiles := vm.ActivePrecompiledContracts(rules, &rollupsConfig) if err := config.StateOverrides.Apply(statedb, precompiles); err != nil { return nil, err diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d0ab0ab0a888..5c7723324882 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1165,12 +1165,15 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S blockOverrides.Apply(&blockCtx) } rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) - precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules)) - //[rollup-geth] This is optional for rollups - precompiles.ActivateRollupPrecompiledContracts(vm.RollupPrecompileActivationConfig{ - vm.L1SLoad{L1RpcClient: b.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return blockCtx.BlockNumber }}, - }) + //[rollup-geth] This is optional for rollups, instead we can simply do + // rollupsConfig := nil + rollupConfig := vm.RollupPrecompileActivationConfig{ + L1SLoad: vm.L1SLoad{ + L1RpcClient: b.GetL1RpcClient(), + GetLatestL1BlockNumber: func() *big.Int { return blockCtx.BlockNumber }}, + } + precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules, &rollupConfig)) if err := overrides.Apply(state, precompiles); err != nil { return nil, err diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 441e90ae9941..a23dd9f44455 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -286,12 +286,15 @@ func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContra isMerge = base.Difficulty.Sign() == 0 rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) ) - precompiles := vm.ActivePrecompiledContracts(rules) - - //[rollup-geth] This is optional for rollups - precompiles.ActivateRollupPrecompiledContracts(vm.RollupPrecompileActivationConfig{ - L1SLoad: vm.L1SLoad{L1RpcClient: sim.b.GetL1RpcClient(), GetLatestL1BlockNumber: func() *big.Int { return base.Number }}, - }) + //[rollup-geth] This is optional for rollups, instead we can simply do + // rollupsConfig := nil + rollupsConfig := vm.RollupPrecompileActivationConfig{ + L1SLoad: vm.L1SLoad{ + L1RpcClient: sim.b.GetL1RpcClient(), + GetLatestL1BlockNumber: func() *big.Int { return base.Number }, + }, + } + precompiles := vm.ActivePrecompiledContracts(rules, &rollupsConfig) return maps.Clone(precompiles) } From b72098e19aca06cf2403da3f89b19cb34a44fb85 Mon Sep 17 00:00:00 2001 From: mralj Date: Mon, 30 Sep 2024 10:20:37 +0200 Subject: [PATCH 17/26] added missing "," - fixed comptime bug --- eth/tracers/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 6d962d2340fa..3afdf662fdfd 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -967,7 +967,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc rollupsConfig := vm.RollupPrecompileActivationConfig{ L1SLoad: vm.L1SLoad{ L1RpcClient: api.backend.GetL1RpcClient(), - GetLatestL1BlockNumber: func() *big.Int { return vmctx.BlockNumber } + GetLatestL1BlockNumber: func() *big.Int { return vmctx.BlockNumber }, }, } precompiles := vm.ActivePrecompiledContracts(rules, &rollupsConfig) From 76a23394bc6db848d6e24c829c24b5675c909f33 Mon Sep 17 00:00:00 2001 From: mralj Date: Tue, 1 Oct 2024 10:43:04 +0200 Subject: [PATCH 18/26] internal/ethapi and tracers use pre-existing function call --- core/vm/contracts_rollup_overrides.go | 27 +++++++++++++++++++++------ eth/tracers/api.go | 5 ++--- internal/ethapi/api.go | 8 +++++--- internal/ethapi/simulate.go | 6 +++--- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/core/vm/contracts_rollup_overrides.go b/core/vm/contracts_rollup_overrides.go index 39541558a0e6..ddbf472612d1 100644 --- a/core/vm/contracts_rollup_overrides.go +++ b/core/vm/contracts_rollup_overrides.go @@ -3,23 +3,38 @@ package vm -import "math/big" +import ( + "math/big" +) -// generateRollupPrecompiledContractsOverrides generates rollup precompile config inlucing L2 specific overrides +// generateRollupPrecompiledContractsOverrides generates rollup precompile config including L2 specific overrides func generateRollupPrecompiledContractsOverrides(evm *EVM) *RollupPrecompileActivationConfig { return &RollupPrecompileActivationConfig{ L1SLoad{ L1RpcClient: evm.Config.L1RpcClient, - GetLatestL1BlockNumber: getLatestL1BlockNumber(evm), + GetLatestL1BlockNumber: LetRPCDecideLatestL1Number(), }, } } -// [OVERRIDE] getLatestL1BlockNumber +// [OVERRIDE] LetRPCDecideLatestL1Number // Each rollup should override this function so that it returns // correct latest L1 block number -func getLatestL1BlockNumber(evm *EVM) func() *big.Int { +func LetRPCDecideLatestL1Number() func() *big.Int { return func() *big.Int { - return evm.Context.BlockNumber + return nil } } + +// [OVERRIDE] getLatestL1BlockNumber +// Each rollup should override this function so that it returns +// correct latest L1 block number +// +// EXAMPLE 2 +// func GetLatestL1BlockNumber(state *state.StateDB) func() *big.Int { +// return func() *big.Int { +// addressOfL1BlockContract := common.Address{} +// slotInContractRepresentingL1BlockNumber := common.Hash{} +// return state.GetState(addressOfL1BlockContract, slotInContractRepresentingL1BlockNumber).Big() +// } +// } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 3afdf662fdfd..f4dbc68e29f4 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -962,12 +962,11 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time) - //[rollup-geth] This is optional for rollups, instead we can simply do - // rollupsConfig := nil + //[rollup-geth] rollupsConfig := vm.RollupPrecompileActivationConfig{ L1SLoad: vm.L1SLoad{ L1RpcClient: api.backend.GetL1RpcClient(), - GetLatestL1BlockNumber: func() *big.Int { return vmctx.BlockNumber }, + GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number(), }, } precompiles := vm.ActivePrecompiledContracts(rules, &rollupsConfig) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 5c7723324882..a3d7183bceff 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1166,12 +1166,14 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S } rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) - //[rollup-geth] This is optional for rollups, instead we can simply do - // rollupsConfig := nil + //[rollup-geth] + // The way code is organized (check call to applyMessage) this config supersedes + // the evm config rollupConfig := vm.RollupPrecompileActivationConfig{ L1SLoad: vm.L1SLoad{ L1RpcClient: b.GetL1RpcClient(), - GetLatestL1BlockNumber: func() *big.Int { return blockCtx.BlockNumber }}, + GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number(), + }, } precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules, &rollupConfig)) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index a23dd9f44455..925ea014bc28 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -286,12 +286,12 @@ func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContra isMerge = base.Difficulty.Sign() == 0 rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) ) - //[rollup-geth] This is optional for rollups, instead we can simply do - // rollupsConfig := nil + + //[rollup-geth] rollupsConfig := vm.RollupPrecompileActivationConfig{ L1SLoad: vm.L1SLoad{ L1RpcClient: sim.b.GetL1RpcClient(), - GetLatestL1BlockNumber: func() *big.Int { return base.Number }, + GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number(), }, } precompiles := vm.ActivePrecompiledContracts(rules, &rollupsConfig) From bd56bdc4337b170c5f4969ad570286ebfb365bf2 Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 4 Oct 2024 17:36:36 +0200 Subject: [PATCH 19/26] code cleanup after trying to merge into arb/op-geth --- core/state_transition.go | 2 +- core/vm/contracts.go | 33 +++++++++------------------ core/vm/contracts_rollup.go | 30 +++++++++++++++++++----- core/vm/contracts_rollup_overrides.go | 8 +++---- core/vm/evm.go | 10 ++++---- core/vm/runtime/runtime.go | 9 ++++---- eth/tracers/api.go | 6 +++-- eth/tracers/js/goja.go | 10 ++++---- eth/tracers/native/4byte.go | 2 +- eth/tracers/native/call_flat.go | 2 +- internal/ethapi/api.go | 10 ++++---- internal/ethapi/simulate.go | 5 ++-- tests/state_test.go | 4 ++-- 13 files changed, 71 insertions(+), 60 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index d285d03fe245..808ed5d78cfd 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -437,7 +437,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) + st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompilesIncludingRollups(rules), msg.AccessList) var ( ret []byte diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 37838c1d5f2a..b17b8fe9f9f0 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -174,38 +174,28 @@ func init() { } } -func activePrecompiledContracts(rules params.Rules, config *RollupPrecompileActivationConfig) PrecompiledContracts { - var activePrecompiles PrecompiledContracts +func activePrecompiledContracts(rules params.Rules) PrecompiledContracts { switch { case rules.IsVerkle: - activePrecompiles = PrecompiledContractsVerkle + return PrecompiledContractsVerkle case rules.IsPrague: - activePrecompiles = PrecompiledContractsPrague + return PrecompiledContractsPrague case rules.IsCancun: - activePrecompiles = PrecompiledContractsCancun + return PrecompiledContractsCancun case rules.IsBerlin: - activePrecompiles = PrecompiledContractsBerlin + return PrecompiledContractsBerlin case rules.IsIstanbul: - activePrecompiles = PrecompiledContractsIstanbul + return PrecompiledContractsIstanbul case rules.IsByzantium: - activePrecompiles = PrecompiledContractsByzantium + return PrecompiledContractsByzantium default: - activePrecompiles = PrecompiledContractsHomestead + return PrecompiledContractsHomestead } - - // [rollup-geth] - activeRollupPrecompiles := activeRollupPrecompiledContracts(rules) - for k, v := range activeRollupPrecompiles { - activePrecompiles[k] = v - } - activePrecompiles.ActivateRollupPrecompiledContracts(config) - - return activePrecompiles } // ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration. -func ActivePrecompiledContracts(rules params.Rules, rollupConfig *RollupPrecompileActivationConfig) PrecompiledContracts { - return maps.Clone(activePrecompiledContracts(rules, rollupConfig)) +func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts { + return maps.Clone(activePrecompiledContracts(rules)) } // ActivePrecompiles returns the precompile addresses enabled with the current configuration. @@ -227,8 +217,7 @@ func ActivePrecompiles(rules params.Rules) []common.Address { } // [rollup-geth] - activePrecompileAddresses = - append(activePrecompileAddresses, slices.Collect(maps.Keys(activeRollupPrecompiledContracts(rules)))...) + activePrecompileAddresses = append(activePrecompileAddresses, slices.Collect(maps.Keys(activeRollupPrecompiledContracts(rules)))...) return activePrecompileAddresses } diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index b9fa41bb83c4..78ce71f4155c 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -22,10 +22,12 @@ type L1RpcClient interface { StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) } -var rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) -var precompiledContractsRollupR0 = PrecompiledContracts{ - rollupL1SloadAddress: &L1SLoad{}, -} +var ( + rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) + precompiledContractsRollupR0 = PrecompiledContracts{ + rollupL1SloadAddress: &L1SLoad{}, + } +) func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { switch rules.IsR0 { @@ -37,15 +39,31 @@ func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { } // ActivateRollupPrecompiledContracts activates rollup-specific precompiles -func (pc PrecompiledContracts) ActivateRollupPrecompiledContracts(config *RollupPrecompileActivationConfig) { +func (pc PrecompiledContracts) ActivateRollupPrecompiledContracts(rules params.Rules, config *RollupPrecompileActivationConfig) { if config == nil { return } + activeRollupPrecompiles := activeRollupPrecompiledContracts(rules) + for k, v := range activeRollupPrecompiles { + pc[k] = v + } + // NOTE: if L1SLoad was not activated via chain rules this is no-op pc.activateL1SLoad(config.L1RpcClient, config.GetLatestL1BlockNumber) } +func ActivePrecompilesIncludingRollups(rules params.Rules) []common.Address { + activePrecompiles := ActivePrecompiles(rules) + activeRollupPrecompiles := activeRollupPrecompiledContracts(rules) + + for k := range activeRollupPrecompiles { + activePrecompiles = append(activePrecompiles, k) + } + + return activePrecompiles +} + //INPUT SPECS: //Byte range Name Description //------------------------------------------------------------ @@ -124,4 +142,4 @@ func (pc PrecompiledContracts) activateL1SLoad(l1RpcClient L1RpcClient, getLates L1RpcClient: l1RpcClient, GetLatestL1BlockNumber: getLatestL1BlockNumber, } -} \ No newline at end of file +} diff --git a/core/vm/contracts_rollup_overrides.go b/core/vm/contracts_rollup_overrides.go index ddbf472612d1..81f4464c0d2a 100644 --- a/core/vm/contracts_rollup_overrides.go +++ b/core/vm/contracts_rollup_overrides.go @@ -12,7 +12,7 @@ func generateRollupPrecompiledContractsOverrides(evm *EVM) *RollupPrecompileActi return &RollupPrecompileActivationConfig{ L1SLoad{ L1RpcClient: evm.Config.L1RpcClient, - GetLatestL1BlockNumber: LetRPCDecideLatestL1Number(), + GetLatestL1BlockNumber: LetRPCDecideLatestL1Number, }, } } @@ -20,10 +20,8 @@ func generateRollupPrecompiledContractsOverrides(evm *EVM) *RollupPrecompileActi // [OVERRIDE] LetRPCDecideLatestL1Number // Each rollup should override this function so that it returns // correct latest L1 block number -func LetRPCDecideLatestL1Number() func() *big.Int { - return func() *big.Int { - return nil - } +func LetRPCDecideLatestL1Number() *big.Int { + return nil } // [OVERRIDE] getLatestL1BlockNumber diff --git a/core/vm/evm.go b/core/vm/evm.go index d74ede439efa..ee749b0cdc62 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -128,8 +128,10 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } + evm.precompiles = activePrecompiledContracts(evm.chainRules) + //[rollup-geth] - evm.precompiles = activePrecompiledContracts(evm.chainRules, generateRollupPrecompiledContractsOverrides(evm)) + evm.precompiles.ActivateRollupPrecompiledContracts(evm.chainRules, generateRollupPrecompiledContractsOverrides(evm)) evm.interpreter = NewEVMInterpreter(evm) return evm @@ -276,7 +278,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } - var snapshot = evm.StateDB.Snapshot() + snapshot := evm.StateDB.Snapshot() // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { @@ -327,7 +329,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } - var snapshot = evm.StateDB.Snapshot() + snapshot := evm.StateDB.Snapshot() // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { @@ -376,7 +378,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // after all empty accounts were deleted, so this is not required. However, if we omit this, // then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json. // We could change this, but for now it's left for legacy reasons - var snapshot = evm.StateDB.Snapshot() + snapshot := evm.StateDB.Snapshot() // We do an AddBalance of zero here, just in order to trigger a touch. // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index f83ed682cd13..f552f637d4fb 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -81,7 +81,8 @@ func setDefaults(cfg *Config) { TerminalTotalDifficultyPassed: true, MergeNetsplitBlock: nil, ShanghaiTime: &shanghaiTime, - CancunTime: &cancunTime} + CancunTime: &cancunTime, + } } if cfg.Difficulty == nil { cfg.Difficulty = new(big.Int) @@ -141,7 +142,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) + cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompilesIncludingRollups(rules), nil) cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. cfg.State.SetCode(address, code) @@ -177,7 +178,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) + cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompilesIncludingRollups(rules), nil) // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( sender, @@ -208,7 +209,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) + statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompilesIncludingRollups(rules), nil) // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( diff --git a/eth/tracers/api.go b/eth/tracers/api.go index f4dbc68e29f4..91babc6ede8b 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -962,14 +962,16 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time) + precompiles := vm.ActivePrecompiledContracts(rules) + //[rollup-geth] rollupsConfig := vm.RollupPrecompileActivationConfig{ L1SLoad: vm.L1SLoad{ L1RpcClient: api.backend.GetL1RpcClient(), - GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number(), + GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number, }, } - precompiles := vm.ActivePrecompiledContracts(rules, &rollupsConfig) + precompiles.ActivateRollupPrecompiledContracts(rules, &rollupsConfig) if err := config.StateOverrides.Apply(statedb, precompiles); err != nil { return nil, err diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index b823ef740a86..efc838610ed5 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -62,9 +62,11 @@ func init() { // hex strings into big ints. var bigIntProgram = goja.MustCompile("bigInt", bigIntegerJS, false) -type toBigFn = func(vm *goja.Runtime, val string) (goja.Value, error) -type toBufFn = func(vm *goja.Runtime, val []byte) (goja.Value, error) -type fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error) +type ( + toBigFn = func(vm *goja.Runtime, val string) (goja.Value, error) + toBufFn = func(vm *goja.Runtime, val []byte) (goja.Value, error) + fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error) +) func toBuf(vm *goja.Runtime, bufType goja.Value, val []byte) (goja.Value, error) { // bufType is usually Uint8Array. This is equivalent to `new Uint8Array(val)` in JS. @@ -245,7 +247,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from t.dbValue = db.setupObject() // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) + t.activePrecompiles = vm.ActivePrecompilesIncludingRollups(rules) t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64()) t.ctx["gas"] = t.vm.ToValue(tx.Gas()) gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 6cb0e433d27d..a5c1fefdef12 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -89,7 +89,7 @@ func (t *fourByteTracer) store(id []byte, size int) { func (t *fourByteTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) + t.activePrecompiles = vm.ActivePrecompilesIncludingRollups(rules) } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index a47b79f8df26..b3872b111528 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -207,7 +207,7 @@ func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction t.tracer.OnTxStart(env, tx, from) // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) + t.activePrecompiles = vm.ActivePrecompilesIncludingRollups(rules) } func (t *flatCallTracer) OnTxEnd(receipt *types.Receipt, err error) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a3d7183bceff..b652bdf29a9a 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1165,17 +1165,15 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S blockOverrides.Apply(&blockCtx) } rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) - + precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules)) //[rollup-geth] - // The way code is organized (check call to applyMessage) this config supersedes - // the evm config rollupConfig := vm.RollupPrecompileActivationConfig{ L1SLoad: vm.L1SLoad{ L1RpcClient: b.GetL1RpcClient(), - GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number(), + GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number, }, } - precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules, &rollupConfig)) + precompiles.ActivateRollupPrecompiledContracts(rules, &rollupConfig) if err := overrides.Apply(state, precompiles); err != nil { return nil, err @@ -1650,7 +1648,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH } isPostMerge := header.Difficulty.Sign() == 0 // Retrieve the precompiles since they don't need to be added to the access list - precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) + precompiles := vm.ActivePrecompilesIncludingRollups(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) // Create an initial tracer prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 925ea014bc28..0b53dda8f3da 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -291,10 +291,11 @@ func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContra rollupsConfig := vm.RollupPrecompileActivationConfig{ L1SLoad: vm.L1SLoad{ L1RpcClient: sim.b.GetL1RpcClient(), - GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number(), + GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number, }, } - precompiles := vm.ActivePrecompiledContracts(rules, &rollupsConfig) + precompiles := vm.ActivePrecompiledContracts(rules) + precompiles.ActivateRollupPrecompiledContracts(rules, &rollupsConfig) return maps.Clone(precompiles) } diff --git a/tests/state_test.go b/tests/state_test.go index 76fec97de0ee..e3e8dd6f8bce 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -262,7 +262,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.Error(err) return } - var rules = config.Rules(new(big.Int), false, 0) + rules := config.Rules(new(big.Int), false, 0) vmconfig.ExtraEips = eips block := t.genesis(config).ToBlock() @@ -319,7 +319,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.ResetTimer() for n := 0; n < b.N; n++ { snapshot := state.StateDB.Snapshot() - state.StateDB.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) + state.StateDB.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompilesIncludingRollups(rules), msg.AccessList) b.StartTimer() start := time.Now() From bdd7b7d5c90d4549b6f4a0ab57d8fb193045e3ce Mon Sep 17 00:00:00 2001 From: mralj Date: Mon, 7 Oct 2024 10:57:48 +0200 Subject: [PATCH 20/26] ethclient moved to node.Node --- cmd/geth/config.go | 11 +++++------ cmd/geth/config_rollup.go | 20 ++++++++++++++++++++ cmd/utils/flags.go | 4 ++-- eth/backend.go | 4 ++-- eth/backend_rollup.go | 19 ------------------- node/node.go | 9 +++++++++ node/node_rollup.go | 17 +++++++++++++++++ 7 files changed, 55 insertions(+), 29 deletions(-) create mode 100644 cmd/geth/config_rollup.go delete mode 100644 eth/backend_rollup.go create mode 100644 node/node_rollup.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 24eddbabf167..f5f6656d4a6d 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -192,12 +192,7 @@ func makeFullNode(ctx *cli.Context) *node.Node { cfg.Eth.OverrideVerkle = &v } - // [rollup-geth] - // TODO: think about if there is better solution for this (eg. rollup config file) - if !ctx.IsSet(utils.L1NodeRPCEndpointFlag.Name) { - log.Crit("L1 node RPC endpoint URL not set", "flag", utils.L1NodeRPCEndpointFlag.Name) - } - backend, eth := utils.RegisterEthService(stack, &cfg.Eth, ctx.String(utils.L1NodeRPCEndpointFlag.Name)) + backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Create gauge with geth system and build information if eth != nil { // The 'eth' backend may be nil in light mode @@ -255,6 +250,10 @@ func makeFullNode(ctx *cli.Context) *node.Node { utils.Fatalf("failed to register catalyst service: %v", err) } } + + //[rollup-geth] + activateL1RPCEndpoint(ctx, stack) + return stack } diff --git a/cmd/geth/config_rollup.go b/cmd/geth/config_rollup.go new file mode 100644 index 000000000000..3f19b8b1c4f3 --- /dev/null +++ b/cmd/geth/config_rollup.go @@ -0,0 +1,20 @@ +package main + +import ( + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/urfave/cli/v2" +) + +// TODO: when we have clearer picture of how do we want rollup "features" (EIPs/RIPs) to be activated +// make this "rule" activated (ie. if not "rule activated" then L1 client can simply be nil) +func activateL1RPCEndpoint(ctx *cli.Context, stack *node.Node) { + if !ctx.IsSet(utils.L1NodeRPCEndpointFlag.Name) { + log.Error("L1 node RPC endpoint URL not set", "flag", utils.L1NodeRPCEndpointFlag.Name) + return + } + + l1RPCEndpoint := ctx.String(utils.L1NodeRPCEndpointFlag.Name) + stack.RegisterEthClient(l1RPCEndpoint) +} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index c85e7e0a4196..8fe5ca0473d4 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1925,8 +1925,8 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) { // RegisterEthService adds an Ethereum client to the stack. // The second return value is the full node instance. -func RegisterEthService(stack *node.Node, cfg *ethconfig.Config, l1RPCClientEndpoint string) (*eth.EthAPIBackend, *eth.Ethereum) { - backend, err := eth.New(stack, cfg, l1RPCClientEndpoint) +func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (*eth.EthAPIBackend, *eth.Ethereum) { + backend, err := eth.New(stack, cfg) if err != nil { Fatalf("Failed to register the Ethereum service: %v", err) } diff --git a/eth/backend.go b/eth/backend.go index 04b32b873dda..6ca118777cc0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -100,7 +100,7 @@ type Ethereum struct { // New creates a new Ethereum object (including the initialisation of the common Ethereum object), // whose lifecycle will be managed by the provided node. -func New(stack *node.Node, config *ethconfig.Config, l1RPCEndpoint string) (*Ethereum, error) { +func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Ensure configuration values are compatible and sane if !config.SyncMode.IsValid() { return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) @@ -217,7 +217,7 @@ func New(stack *node.Node, config *ethconfig.Config, l1RPCEndpoint string) (*Eth } // [rollup-geth] - activateL1RPCEndpoint(l1RPCEndpoint, &vmConfig) + vmConfig.L1RpcClient = stack.EthClient() eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory) if err != nil { diff --git a/eth/backend_rollup.go b/eth/backend_rollup.go deleted file mode 100644 index e9b2ba338be7..000000000000 --- a/eth/backend_rollup.go +++ /dev/null @@ -1,19 +0,0 @@ -package eth - -import ( - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" -) - -// TODO: when we have clearer picture of how do we want rollup "features" (EIPs/RIPs) to be activated -// make this "rule" activated (ie. if not "rule activated" then L1 client can simply be nil) -func activateL1RPCEndpoint(l1RPCEndpoint string, vmConfig *vm.Config) { - l1Client, err := ethclient.Dial(l1RPCEndpoint) - if err != nil { - log.Crit("Unable to connect to L1 RPC endpoint at", "URL", l1RPCEndpoint, "error", err) - } else { - vmConfig.L1RpcClient = l1Client - log.Info("Initialized L1 RPC client", "endpoint", l1RPCEndpoint) - } -} diff --git a/node/node.go b/node/node.go index 633f88f058a1..02e0d38ec245 100644 --- a/node/node.go +++ b/node/node.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/event" @@ -67,6 +68,8 @@ type Node struct { inprocHandler *rpc.Server // In-process RPC request handler to process the API requests databases map[*closeTrackingDB]struct{} // All open databases + + ethClient *ethclient.Client } const ( @@ -708,6 +711,12 @@ func (n *Node) EventMux() *event.TypeMux { return n.eventmux } +// [rollup-geth] +// EthClient returns instance of ETH RPC client +func (n *Node) EthClient() *ethclient.Client { + return n.ethClient +} + // OpenDatabase opens an existing database with the given name (or creates one if no // previous can be found) from within the node's instance directory. If the node is // ephemeral, a memory database is returned. diff --git a/node/node_rollup.go b/node/node_rollup.go new file mode 100644 index 000000000000..5d0f0e8b042d --- /dev/null +++ b/node/node_rollup.go @@ -0,0 +1,17 @@ +package node + +import ( + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" +) + +func (n *Node) RegisterEthClient(endpoint string) { + ethClient, err := ethclient.Dial(endpoint) + if err != nil { + log.Error("Unable to connect to ETH RPC endpoint at", "URL", ethClient, "error", err) + return + } + + n.ethClient = ethClient + log.Info("Initialized ETH RPC client", "endpoint", ethClient) +} From d409ef823af742e419aec2f50f84be4f1d6aff80 Mon Sep 17 00:00:00 2001 From: mralj Date: Mon, 7 Oct 2024 12:02:42 +0200 Subject: [PATCH 21/26] bugfixes - l1rpc activated at proper point and precompile address --- cmd/geth/config.go | 6 +++--- core/vm/contracts_rollup.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index f5f6656d4a6d..9a245c171426 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -177,6 +177,9 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } applyMetricConfig(ctx, &cfg) + //[rollup-geth] + activateL1RPCEndpoint(ctx, stack) + return stack, cfg } @@ -251,9 +254,6 @@ func makeFullNode(ctx *cli.Context) *node.Node { } } - //[rollup-geth] - activateL1RPCEndpoint(ctx, stack) - return stack } diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index 78ce71f4155c..caf1b757a978 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -23,7 +23,7 @@ type L1RpcClient interface { } var ( - rollupL1SloadAddress = common.BytesToAddress([]byte{0x10, 0x01}) + rollupL1SloadAddress = common.BytesToAddress([]byte{0x01, 0x01}) precompiledContractsRollupR0 = PrecompiledContracts{ rollupL1SloadAddress: &L1SLoad{}, } From ee58cfe525ab1b80fbf6955fcad44a8db81879a0 Mon Sep 17 00:00:00 2001 From: mralj Date: Mon, 7 Oct 2024 13:00:42 +0200 Subject: [PATCH 22/26] missed cleanup of ActivePrecompiles --- core/vm/contracts.go | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index b17b8fe9f9f0..0712c43f98bb 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -200,26 +200,20 @@ func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts { // ActivePrecompiles returns the precompile addresses enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { - var activePrecompileAddresses []common.Address switch { case rules.IsPrague: - activePrecompileAddresses = PrecompiledAddressesPrague + return PrecompiledAddressesPrague case rules.IsCancun: - activePrecompileAddresses = PrecompiledAddressesCancun + return PrecompiledAddressesCancun case rules.IsBerlin: - activePrecompileAddresses = PrecompiledAddressesBerlin + return PrecompiledAddressesBerlin case rules.IsIstanbul: - activePrecompileAddresses = PrecompiledAddressesIstanbul + return PrecompiledAddressesIstanbul case rules.IsByzantium: - activePrecompileAddresses = PrecompiledAddressesByzantium + return PrecompiledAddressesByzantium default: - activePrecompileAddresses = PrecompiledAddressesHomestead + return PrecompiledAddressesHomestead } - - // [rollup-geth] - activePrecompileAddresses = append(activePrecompileAddresses, slices.Collect(maps.Keys(activeRollupPrecompiledContracts(rules)))...) - - return activePrecompileAddresses } // RunPrecompiledContract runs and evaluates the output of a precompiled contract. From 128b1200798968dcfdacf6b2c981348555c6b6b3 Mon Sep 17 00:00:00 2001 From: mralj Date: Mon, 7 Oct 2024 14:00:57 +0200 Subject: [PATCH 23/26] removed unused import - popped up after rebasing --- core/vm/contracts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 0712c43f98bb..d9ee58d25a17 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -23,7 +23,6 @@ import ( "fmt" "maps" "math/big" - "slices" "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" From 42855aea63d390570b5164cc46b7c7a6603610a9 Mon Sep 17 00:00:00 2001 From: mralj Date: Wed, 9 Oct 2024 10:10:44 +0200 Subject: [PATCH 24/26] concurrent map r/w bugfix --- core/vm/evm.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index ee749b0cdc62..cc4b207e4e5d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -128,9 +128,8 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } - evm.precompiles = activePrecompiledContracts(evm.chainRules) - //[rollup-geth] + evm.precompiles = ActivePrecompiledContracts(evm.chainRules) evm.precompiles.ActivateRollupPrecompiledContracts(evm.chainRules, generateRollupPrecompiledContractsOverrides(evm)) evm.interpreter = NewEVMInterpreter(evm) From d4cd646fef9c8d9a1a0d94f5361608efe7c6aaa3 Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 11 Oct 2024 12:16:24 +0200 Subject: [PATCH 25/26] rollup precompile config is glob. variable I decided to implement it this way after trying to integrate code with Arbitrum and having a better understanding of the calls that are made to the NewEvm This approach makes it easier to both override the default config, and to have the option to "not to think about it" --- cmd/geth/config.go | 2 +- cmd/geth/config_rollup.go | 20 ----------- cmd/utils/flags_rollup.go | 35 ++++++++++++------- core/vm/contracts_rollup.go | 17 ++++----- core/vm/contracts_rollup_overrides.go | 14 ++++++-- eth/api_backend_rollup.go | 7 ---- eth/backend.go | 2 +- eth/tracers/api.go | 11 +----- eth/tracers/api_rollup_test.go | 7 ---- internal/ethapi/api.go | 10 ++---- internal/ethapi/backend.go | 3 -- internal/ethapi/simulate.go | 10 ++---- .../ethapi/transaction_args_rollup_test.go | 7 ---- 13 files changed, 52 insertions(+), 93 deletions(-) delete mode 100644 cmd/geth/config_rollup.go delete mode 100644 eth/api_backend_rollup.go delete mode 100644 eth/tracers/api_rollup_test.go delete mode 100644 internal/ethapi/transaction_args_rollup_test.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 9a245c171426..92dc9f8a2152 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -178,7 +178,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { applyMetricConfig(ctx, &cfg) //[rollup-geth] - activateL1RPCEndpoint(ctx, stack) + utils.ActivateL1RPCEndpoint(ctx, stack) return stack, cfg } diff --git a/cmd/geth/config_rollup.go b/cmd/geth/config_rollup.go deleted file mode 100644 index 3f19b8b1c4f3..000000000000 --- a/cmd/geth/config_rollup.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/urfave/cli/v2" -) - -// TODO: when we have clearer picture of how do we want rollup "features" (EIPs/RIPs) to be activated -// make this "rule" activated (ie. if not "rule activated" then L1 client can simply be nil) -func activateL1RPCEndpoint(ctx *cli.Context, stack *node.Node) { - if !ctx.IsSet(utils.L1NodeRPCEndpointFlag.Name) { - log.Error("L1 node RPC endpoint URL not set", "flag", utils.L1NodeRPCEndpointFlag.Name) - return - } - - l1RPCEndpoint := ctx.String(utils.L1NodeRPCEndpointFlag.Name) - stack.RegisterEthClient(l1RPCEndpoint) -} diff --git a/cmd/utils/flags_rollup.go b/cmd/utils/flags_rollup.go index 241505d1a1fb..bfb6ee3cb538 100644 --- a/cmd/utils/flags_rollup.go +++ b/cmd/utils/flags_rollup.go @@ -1,21 +1,32 @@ package utils import ( + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" "github.com/urfave/cli/v2" ) -var ( - L1NodeRPCEndpointFlag = &cli.StringFlag{ - Name: "rollup.l1.rpc_endpoint", - Usage: "L1 node RPC endpoint eg. http://0.0.0.0:8545", - Category: flags.RollupCategory, - Required: true, - } -) +var L1NodeRPCEndpointFlag = &cli.StringFlag{ + Name: "rollup.l1.rpc_endpoint", + Usage: "L1 node RPC endpoint eg. http://0.0.0.0:8545", + Category: flags.RollupCategory, +} + +var RollupFlags = []cli.Flag{ + L1NodeRPCEndpointFlag, +} -var ( - RollupFlags = []cli.Flag{ - L1NodeRPCEndpointFlag, +// TODO: when we have clearer picture of how do we want rollup "features" (EIPs/RIPs) to be activated +// make this "rule" activated (ie. if not "rule activated" then L1 client can simply be nil) +func ActivateL1RPCEndpoint(ctx *cli.Context, stack *node.Node) { + if !ctx.IsSet(L1NodeRPCEndpointFlag.Name) { + log.Error("L1 node RPC endpoint URL not set", "flag", L1NodeRPCEndpointFlag.Name) + return } -) + + l1RPCEndpoint := ctx.String(L1NodeRPCEndpointFlag.Name) + stack.RegisterEthClient(l1RPCEndpoint) + vm.SetVmL1RpcClient(stack.EthClient()) +} diff --git a/core/vm/contracts_rollup.go b/core/vm/contracts_rollup.go index caf1b757a978..3d2dfe7d5551 100644 --- a/core/vm/contracts_rollup.go +++ b/core/vm/contracts_rollup.go @@ -39,11 +39,7 @@ func activeRollupPrecompiledContracts(rules params.Rules) PrecompiledContracts { } // ActivateRollupPrecompiledContracts activates rollup-specific precompiles -func (pc PrecompiledContracts) ActivateRollupPrecompiledContracts(rules params.Rules, config *RollupPrecompileActivationConfig) { - if config == nil { - return - } - +func (pc PrecompiledContracts) ActivateRollupPrecompiledContracts(rules params.Rules, config RollupPrecompileActivationConfig) { activeRollupPrecompiles := activeRollupPrecompiledContracts(rules) for k, v := range activeRollupPrecompiles { pc[k] = v @@ -131,13 +127,18 @@ func (c *L1SLoad) isL1SLoadActive() bool { } func (pc PrecompiledContracts) activateL1SLoad(l1RpcClient L1RpcClient, getLatestL1BlockNumber func() *big.Int) { - if paramsAreNil := l1RpcClient == nil || getLatestL1BlockNumber == nil; paramsAreNil { - return - } if precompileNotRuleActivated := pc[rollupL1SloadAddress] == nil; precompileNotRuleActivated { return } + if rpcClientNotOverridenUseDefaultOne := l1RpcClient == nil; rpcClientNotOverridenUseDefaultOne { + l1RpcClient = defaultRollupPrecompilesConfig.L1RpcClient + } + + if latestBlockGetterNotOverridenUseDefaultOne := getLatestL1BlockNumber == nil; latestBlockGetterNotOverridenUseDefaultOne { + getLatestL1BlockNumber = defaultRollupPrecompilesConfig.GetLatestL1BlockNumber + } + pc[rollupL1SloadAddress] = &L1SLoad{ L1RpcClient: l1RpcClient, GetLatestL1BlockNumber: getLatestL1BlockNumber, diff --git a/core/vm/contracts_rollup_overrides.go b/core/vm/contracts_rollup_overrides.go index 81f4464c0d2a..2ae57ada18d3 100644 --- a/core/vm/contracts_rollup_overrides.go +++ b/core/vm/contracts_rollup_overrides.go @@ -7,9 +7,19 @@ import ( "math/big" ) +var defaultRollupPrecompilesConfig RollupPrecompileActivationConfig = RollupPrecompileActivationConfig{ + L1SLoad: L1SLoad{ + GetLatestL1BlockNumber: LetRPCDecideLatestL1Number, + }, +} + +func SetVmL1RpcClient(c L1RpcClient) { + defaultRollupPrecompilesConfig.L1RpcClient = c +} + // generateRollupPrecompiledContractsOverrides generates rollup precompile config including L2 specific overrides -func generateRollupPrecompiledContractsOverrides(evm *EVM) *RollupPrecompileActivationConfig { - return &RollupPrecompileActivationConfig{ +func generateRollupPrecompiledContractsOverrides(evm *EVM) RollupPrecompileActivationConfig { + return RollupPrecompileActivationConfig{ L1SLoad{ L1RpcClient: evm.Config.L1RpcClient, GetLatestL1BlockNumber: LetRPCDecideLatestL1Number, diff --git a/eth/api_backend_rollup.go b/eth/api_backend_rollup.go deleted file mode 100644 index 42548f2ab164..000000000000 --- a/eth/api_backend_rollup.go +++ /dev/null @@ -1,7 +0,0 @@ -package eth - -import "github.com/ethereum/go-ethereum/core/vm" - -func (b *EthAPIBackend) GetL1RpcClient() vm.L1RpcClient { - return b.eth.BlockChain().GetVMConfig().L1RpcClient -} diff --git a/eth/backend.go b/eth/backend.go index 6ca118777cc0..7483f4646e5b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -217,7 +217,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } // [rollup-geth] - vmConfig.L1RpcClient = stack.EthClient() + vm.SetVmL1RpcClient(stack.EthClient()) eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory) if err != nil { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 91babc6ede8b..ec7a48d39add 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -88,9 +88,6 @@ type Backend interface { ChainDb() ethdb.Database StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) - - // [rollup-geth] - GetL1RpcClient() vm.L1RpcClient } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -965,13 +962,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc precompiles := vm.ActivePrecompiledContracts(rules) //[rollup-geth] - rollupsConfig := vm.RollupPrecompileActivationConfig{ - L1SLoad: vm.L1SLoad{ - L1RpcClient: api.backend.GetL1RpcClient(), - GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number, - }, - } - precompiles.ActivateRollupPrecompiledContracts(rules, &rollupsConfig) + precompiles.ActivateRollupPrecompiledContracts(rules, vm.RollupPrecompileActivationConfig{}) if err := config.StateOverrides.Apply(statedb, precompiles); err != nil { return nil, err diff --git a/eth/tracers/api_rollup_test.go b/eth/tracers/api_rollup_test.go deleted file mode 100644 index 21581a015aef..000000000000 --- a/eth/tracers/api_rollup_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package tracers - -import "github.com/ethereum/go-ethereum/core/vm" - -func (b *testBackend) GetL1RpcClient() vm.L1RpcClient { - return nil -} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b652bdf29a9a..37044b6f37a9 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1166,14 +1166,10 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S } rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules)) + //[rollup-geth] - rollupConfig := vm.RollupPrecompileActivationConfig{ - L1SLoad: vm.L1SLoad{ - L1RpcClient: b.GetL1RpcClient(), - GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number, - }, - } - precompiles.ActivateRollupPrecompiledContracts(rules, &rollupConfig) + rollupConfigOverrides := vm.RollupPrecompileActivationConfig{} + precompiles.ActivateRollupPrecompiledContracts(rules, rollupConfigOverrides) if err := overrides.Apply(state, precompiles); err != nil { return nil, err diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 671e5017ac05..0e991592b4b3 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -96,9 +96,6 @@ type Backend interface { SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) - - //[rollup-geth] - GetL1RpcClient() vm.L1RpcClient } func GetAPIs(apiBackend Backend) []rpc.API { diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 0b53dda8f3da..d8e5ba12453b 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -287,15 +287,9 @@ func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContra rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) ) - //[rollup-geth] - rollupsConfig := vm.RollupPrecompileActivationConfig{ - L1SLoad: vm.L1SLoad{ - L1RpcClient: sim.b.GetL1RpcClient(), - GetLatestL1BlockNumber: vm.LetRPCDecideLatestL1Number, - }, - } precompiles := vm.ActivePrecompiledContracts(rules) - precompiles.ActivateRollupPrecompiledContracts(rules, &rollupsConfig) + //[rollup-geth] + precompiles.ActivateRollupPrecompiledContracts(rules, vm.RollupPrecompileActivationConfig{}) return maps.Clone(precompiles) } diff --git a/internal/ethapi/transaction_args_rollup_test.go b/internal/ethapi/transaction_args_rollup_test.go deleted file mode 100644 index 5004799d10a9..000000000000 --- a/internal/ethapi/transaction_args_rollup_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package ethapi - -import "github.com/ethereum/go-ethereum/core/vm" - -func (b *backendMock) GetL1RpcClient() vm.L1RpcClient { - return nil -} From 237b78f4f11f142669cf58b30b5a1c7150b2bc11 Mon Sep 17 00:00:00 2001 From: mralj Date: Fri, 11 Oct 2024 12:46:51 +0200 Subject: [PATCH 26/26] removed unnecessary call to vm.SetVmL1RpcClient --- eth/backend.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 7483f4646e5b..409c0a14bbad 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -216,9 +216,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { overrides.OverrideVerkle = config.OverrideVerkle } - // [rollup-geth] - vm.SetVmL1RpcClient(stack.EthClient()) - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory) if err != nil { return nil, err