github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/core/vm/runtime/runtime.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package runtime 18 19 import ( 20 "math" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core/rawdb" 25 "github.com/ethereum/go-ethereum/core/state" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/core/vm" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/params" 30 "github.com/holiman/uint256" 31 ) 32 33 // Config is a basic type specifying certain configuration flags for running 34 // the EVM. 35 type Config struct { 36 ChainConfig *params.ChainConfig 37 Difficulty *big.Int 38 Origin common.Address 39 Coinbase common.Address 40 BlockNumber *big.Int 41 Time uint64 42 GasLimit uint64 43 GasPrice *big.Int 44 Value *big.Int 45 Debug bool 46 EVMConfig vm.Config 47 BaseFee *big.Int 48 BlobBaseFee *big.Int 49 BlobHashes []common.Hash 50 BlobFeeCap *big.Int 51 Random *common.Hash 52 53 State *state.StateDB 54 GetHashFn func(n uint64) common.Hash 55 } 56 57 // sets defaults on the config 58 func setDefaults(cfg *Config) { 59 if cfg.ChainConfig == nil { 60 cfg.ChainConfig = ¶ms.ChainConfig{ 61 ChainID: big.NewInt(1), 62 HomesteadBlock: new(big.Int), 63 DAOForkBlock: new(big.Int), 64 DAOForkSupport: false, 65 EIP150Block: new(big.Int), 66 EIP155Block: new(big.Int), 67 EIP158Block: new(big.Int), 68 ByzantiumBlock: new(big.Int), 69 ConstantinopleBlock: new(big.Int), 70 PetersburgBlock: new(big.Int), 71 IstanbulBlock: new(big.Int), 72 MuirGlacierBlock: new(big.Int), 73 BerlinBlock: new(big.Int), 74 LondonBlock: new(big.Int), 75 } 76 } 77 78 if cfg.Difficulty == nil { 79 cfg.Difficulty = new(big.Int) 80 } 81 if cfg.GasLimit == 0 { 82 cfg.GasLimit = math.MaxUint64 83 } 84 if cfg.GasPrice == nil { 85 cfg.GasPrice = new(big.Int) 86 } 87 if cfg.Value == nil { 88 cfg.Value = new(big.Int) 89 } 90 if cfg.BlockNumber == nil { 91 cfg.BlockNumber = new(big.Int) 92 } 93 if cfg.GetHashFn == nil { 94 cfg.GetHashFn = func(n uint64) common.Hash { 95 return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String()))) 96 } 97 } 98 if cfg.BaseFee == nil { 99 cfg.BaseFee = big.NewInt(params.InitialBaseFee) 100 } 101 if cfg.BlobBaseFee == nil { 102 cfg.BlobBaseFee = big.NewInt(params.BlobTxMinBlobGasprice) 103 } 104 } 105 106 // Execute executes the code using the input as call data during the execution. 107 // It returns the EVM's return value, the new state and an error if it failed. 108 // 109 // Execute sets up an in-memory, temporary, environment for the execution of 110 // the given code. It makes sure that it's restored to its original state afterwards. 111 func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { 112 if cfg == nil { 113 cfg = new(Config) 114 } 115 setDefaults(cfg) 116 117 if cfg.State == nil { 118 cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 119 } 120 var ( 121 address = common.BytesToAddress([]byte("contract")) 122 vmenv = NewEnv(cfg) 123 sender = vm.AccountRef(cfg.Origin) 124 rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) 125 ) 126 if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { 127 cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) 128 } 129 // Execute the preparatory steps for state transition which includes: 130 // - prepare accessList(post-berlin) 131 // - reset transient storage(eip 1153) 132 cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) 133 cfg.State.CreateAccount(address) 134 // set the receiver's (the executing contract) code for execution. 135 cfg.State.SetCode(address, code) 136 // Call the code with the given configuration. 137 ret, _, err := vmenv.Call( 138 sender, 139 common.BytesToAddress([]byte("contract")), 140 input, 141 cfg.GasLimit, 142 uint256.MustFromBig(cfg.Value), 143 ) 144 return ret, cfg.State, err 145 } 146 147 // Create executes the code using the EVM create method 148 func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { 149 if cfg == nil { 150 cfg = new(Config) 151 } 152 setDefaults(cfg) 153 154 if cfg.State == nil { 155 cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 156 } 157 var ( 158 vmenv = NewEnv(cfg) 159 sender = vm.AccountRef(cfg.Origin) 160 rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) 161 ) 162 if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { 163 cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) 164 } 165 // Execute the preparatory steps for state transition which includes: 166 // - prepare accessList(post-berlin) 167 // - reset transient storage(eip 1153) 168 cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) 169 // Call the code with the given configuration. 170 code, address, leftOverGas, err := vmenv.Create( 171 sender, 172 input, 173 cfg.GasLimit, 174 uint256.MustFromBig(cfg.Value), 175 ) 176 return code, address, leftOverGas, err 177 } 178 179 // Call executes the code given by the contract's address. It will return the 180 // EVM's return value or an error if it failed. 181 // 182 // Call, unlike Execute, requires a config and also requires the State field to 183 // be set. 184 func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { 185 setDefaults(cfg) 186 187 var ( 188 vmenv = NewEnv(cfg) 189 sender = vm.AccountRef(cfg.Origin) 190 statedb = cfg.State 191 rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) 192 ) 193 if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { 194 cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) 195 } 196 // Execute the preparatory steps for state transition which includes: 197 // - prepare accessList(post-berlin) 198 // - reset transient storage(eip 1153) 199 statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) 200 201 // Call the code with the given configuration. 202 ret, leftOverGas, err := vmenv.Call( 203 sender, 204 address, 205 input, 206 cfg.GasLimit, 207 uint256.MustFromBig(cfg.Value), 208 ) 209 return ret, leftOverGas, err 210 }