github.com/amazechain/amc@v0.1.3/internal/vm/evm.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 package vm 17 18 import ( 19 "github.com/amazechain/amc/common/crypto" 20 "github.com/amazechain/amc/common/types" 21 "github.com/amazechain/amc/common/u256" 22 "github.com/amazechain/amc/internal/vm/evmtypes" 23 "github.com/amazechain/amc/params" 24 "github.com/holiman/uint256" 25 "sync/atomic" 26 ) 27 28 // emptyCodeHash is used by create to ensure deployment is disallowed to already 29 // deployed contract addresses (relevant after the account abstraction). 30 var emptyCodeHash = crypto.Keccak256Hash(nil) 31 32 func (evm *EVM) precompile(addr types.Address) (PrecompiledContract, bool) { 33 var precompiles map[types.Address]PrecompiledContract 34 switch { 35 case evm.chainRules.IsMoran: 36 precompiles = PrecompiledContractsIsMoran 37 case evm.chainRules.IsNano: 38 precompiles = PrecompiledContractsNano 39 case evm.chainRules.IsBerlin: 40 precompiles = PrecompiledContractsBerlin 41 case evm.chainRules.IsIstanbul: 42 if evm.chainRules.IsParlia { 43 precompiles = PrecompiledContractsIstanbulForBSC 44 } else { 45 precompiles = PrecompiledContractsIstanbul 46 } 47 case evm.chainRules.IsByzantium: 48 precompiles = PrecompiledContractsByzantium 49 default: 50 precompiles = PrecompiledContractsHomestead 51 } 52 p, ok := precompiles[addr] 53 return p, ok 54 } 55 56 // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. 57 func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { 58 return evm.interpreter.Run(contract, input, readOnly) 59 } 60 61 // EVM is the Ethereum Virtual Machine base object and provides 62 // the necessary tools to run a contract on the given state with 63 // the provided context. It should be noted that any error 64 // generated through any of the calls should be considered a 65 // revert-state-and-consume-all-gas operation, no checks on 66 // specific errors should ever be performed. The interpreter makes 67 // sure that any errors generated are to be considered faulty code. 68 // 69 // The EVM should never be reused and is not thread safe. 70 type EVM struct { 71 // Context provides auxiliary blockchain related information 72 context evmtypes.BlockContext 73 txContext evmtypes.TxContext 74 // IntraBlockState gives access to the underlying state 75 intraBlockState evmtypes.IntraBlockState 76 77 // chainConfig contains information about the current chain 78 chainConfig *params.ChainConfig 79 // chain rules contains the chain rules for the current epoch 80 chainRules *params.Rules 81 // virtual machine configuration options used to initialise the 82 // evm. 83 config Config 84 // global (to this context) ethereum virtual machine 85 // used throughout the execution of the tx. 86 interpreter Interpreter 87 // abort is used to abort the EVM calling operations 88 // NOTE: must be set atomically 89 abort int32 90 // callGasTemp holds the gas available for the current call. This is needed because the 91 // available gas is calculated in gasCall* according to the 63/64 rule and later 92 // applied in opCall*. 93 callGasTemp uint64 94 } 95 96 // NewEVM returns a new EVM. The returned EVM is not thread safe and should 97 // only ever be used *once*. 98 func NewEVM(blockCtx evmtypes.BlockContext, txCtx evmtypes.TxContext, state evmtypes.IntraBlockState, chainConfig *params.ChainConfig, vmConfig Config) *EVM { 99 evm := &EVM{ 100 context: blockCtx, 101 txContext: txCtx, 102 intraBlockState: state, 103 config: vmConfig, 104 chainConfig: chainConfig, 105 chainRules: chainConfig.Rules(blockCtx.BlockNumber), 106 } 107 108 evm.interpreter = NewEVMInterpreter(evm, vmConfig) 109 110 return evm 111 } 112 113 // Reset resets the EVM with a new transaction context.Reset 114 // This is not threadsafe and should only be done very cautiously. 115 func (evm *EVM) Reset(txCtx evmtypes.TxContext, ibs evmtypes.IntraBlockState) { 116 evm.txContext = txCtx 117 evm.intraBlockState = ibs 118 119 // ensure the evm is reset to be used again 120 atomic.StoreInt32(&evm.abort, 0) 121 } 122 123 func (evm *EVM) ResetBetweenBlocks(blockCtx evmtypes.BlockContext, txCtx evmtypes.TxContext, ibs evmtypes.IntraBlockState, vmConfig Config, chainRules *params.Rules) { 124 evm.context = blockCtx 125 evm.txContext = txCtx 126 evm.intraBlockState = ibs 127 evm.config = vmConfig 128 evm.chainRules = chainRules 129 130 evm.interpreter = NewEVMInterpreter(evm, vmConfig) 131 132 // ensure the evm is reset to be used again 133 atomic.StoreInt32(&evm.abort, 0) 134 } 135 136 // Cancel cancels any running EVM operation. This may be called concurrently and 137 // it's safe to be called multiple times. 138 func (evm *EVM) Cancel() { 139 atomic.StoreInt32(&evm.abort, 1) 140 } 141 142 // Cancelled returns true if Cancel has been called 143 func (evm *EVM) Cancelled() bool { 144 return atomic.LoadInt32(&evm.abort) == 1 145 } 146 147 // CallGasTemp returns the callGasTemp for the EVM 148 func (evm *EVM) CallGasTemp() uint64 { 149 return evm.callGasTemp 150 } 151 152 // SetCallGasTemp sets the callGasTemp for the EVM 153 func (evm *EVM) SetCallGasTemp(gas uint64) { 154 evm.callGasTemp = gas 155 } 156 157 // Interpreter returns the current interpreter 158 func (evm *EVM) Interpreter() Interpreter { 159 return evm.interpreter 160 } 161 162 func (evm *EVM) call(typ OpCode, caller ContractRef, addr types.Address, input []byte, gas uint64, value *uint256.Int, bailout bool) (ret []byte, leftOverGas uint64, err error) { 163 depth := evm.interpreter.Depth() 164 165 if evm.config.NoRecursion && depth > 0 { 166 return nil, gas, nil 167 } 168 // Fail if we're trying to execute above the call depth limit 169 if depth > int(params.CallCreateDepth) { 170 return nil, gas, ErrDepth 171 } 172 if typ == CALL || typ == CALLCODE { 173 // Fail if we're trying to transfer more than the available balance 174 if !value.IsZero() && !evm.context.CanTransfer(evm.intraBlockState, caller.Address(), value) { 175 if !bailout { 176 return nil, gas, ErrInsufficientBalance 177 } 178 } 179 } 180 p, isPrecompile := evm.precompile(addr) 181 var code []byte 182 if !isPrecompile { 183 code = evm.intraBlockState.GetCode(addr) 184 } 185 186 snapshot := evm.intraBlockState.Snapshot() 187 188 if typ == CALL { 189 if !evm.intraBlockState.Exist(addr) { 190 if !isPrecompile && evm.chainRules.IsSpuriousDragon && value.IsZero() { 191 if evm.config.Debug { 192 v := value 193 if typ == STATICCALL { 194 v = nil 195 } 196 // Calling a non existing account, don't do anything, but ping the tracer 197 if depth == 0 { 198 evm.config.Tracer.CaptureStart(evm, caller.Address(), addr, false /* create */, input, gas, v) 199 evm.config.Tracer.CaptureEnd(ret, 0, nil) 200 } else { 201 evm.config.Tracer.CaptureEnter(typ, caller.Address(), addr, input /* create */, gas, v) 202 evm.config.Tracer.CaptureExit(ret, 0, nil) 203 } 204 } 205 return nil, gas, nil 206 } 207 evm.intraBlockState.CreateAccount(addr, false) 208 } 209 evm.context.Transfer(evm.intraBlockState, caller.Address(), addr, value, bailout) 210 } else if typ == STATICCALL { 211 // We do an AddBalance of zero here, just in order to trigger a touch. 212 // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, 213 // but is the correct thing to do and matters on other networks, in tests, and potential 214 // future scenarios 215 evm.intraBlockState.AddBalance(addr, u256.Num0) 216 } 217 if evm.config.Debug { 218 v := value 219 if typ == STATICCALL { 220 v = nil 221 } 222 if depth == 0 { 223 evm.config.Tracer.CaptureStart(evm, caller.Address(), addr, false /* create */, input, gas, v) 224 defer func(startGas uint64) { // Lazy evaluation of the parameters 225 evm.config.Tracer.CaptureEnd(ret, startGas-gas, err) 226 }(gas) 227 } else { 228 evm.config.Tracer.CaptureEnter(typ, caller.Address(), addr /* create */, input, gas, v) 229 defer func(startGas uint64) { // Lazy evaluation of the parameters 230 evm.config.Tracer.CaptureExit(ret, startGas-gas, err) 231 }(gas) 232 } 233 } 234 235 // It is allowed to call precompiles, even via delegatecall 236 if isPrecompile { 237 ret, gas, err = RunPrecompiledContract(p, input, gas) 238 } else if len(code) == 0 { 239 // If the account has no code, we can abort here 240 // The depth-check is already done, and precompiles handled above 241 ret, err = nil, nil // gas is unchanged 242 } else { 243 // At this point, we use a copy of address. If we don't, the go compiler will 244 // leak the 'contract' to the outer scope, and make allocation for 'contract' 245 // even if the actual execution ends on RunPrecompiled above. 246 addrCopy := addr 247 // Initialise a new contract and set the code that is to be used by the EVM. 248 // The contract is a scoped environment for this execution context only. 249 codeHash := evm.intraBlockState.GetCodeHash(addrCopy) 250 var contract *Contract 251 if typ == CALLCODE { 252 contract = NewContract(caller, AccountRef(caller.Address()), value, gas, evm.config.SkipAnalysis) 253 } else if typ == DELEGATECALL { 254 contract = NewContract(caller, AccountRef(caller.Address()), value, gas, evm.config.SkipAnalysis).AsDelegate() 255 } else { 256 contract = NewContract(caller, AccountRef(addrCopy), value, gas, evm.config.SkipAnalysis) 257 } 258 contract.SetCallCode(&addrCopy, codeHash, code) 259 readOnly := false 260 if typ == STATICCALL { 261 readOnly = true 262 } 263 ret, err = run(evm, contract, input, readOnly) 264 gas = contract.Gas 265 } 266 // When an error was returned by the EVM or when setting the creation code 267 // above we revert to the snapshot and consume any gas remaining. Additionally 268 // when we're in Homestead this also counts for code storage gas errors. 269 if err != nil || evm.config.RestoreState { 270 evm.intraBlockState.RevertToSnapshot(snapshot) 271 if err != ErrExecutionReverted { 272 gas = 0 273 } 274 // TODO: consider clearing up unused snapshots: 275 //} else { 276 // evm.StateDB.DiscardSnapshot(snapshot) 277 } 278 return ret, gas, err 279 } 280 281 // Call executes the contract associated with the addr with the given input as 282 // parameters. It also handles any necessary value transfer required and takes 283 // the necessary steps to create accounts and reverses the state in case of an 284 // execution error or failed value transfer. 285 func (evm *EVM) Call(caller ContractRef, addr types.Address, input []byte, gas uint64, value *uint256.Int, bailout bool) (ret []byte, leftOverGas uint64, err error) { 286 return evm.call(CALL, caller, addr, input, gas, value, bailout) 287 } 288 289 // CallCode executes the contract associated with the addr with the given input 290 // as parameters. It also handles any necessary value transfer required and takes 291 // the necessary steps to create accounts and reverses the state in case of an 292 // execution error or failed value transfer. 293 // 294 // CallCode differs from Call in the sense that it executes the given address' 295 // code with the caller as context. 296 func (evm *EVM) CallCode(caller ContractRef, addr types.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { 297 return evm.call(CALLCODE, caller, addr, input, gas, value, false) 298 } 299 300 // DelegateCall executes the contract associated with the addr with the given input 301 // as parameters. It reverses the state in case of an execution error. 302 // 303 // DelegateCall differs from CallCode in the sense that it executes the given address' 304 // code with the caller as context and the caller is set to the caller of the caller. 305 func (evm *EVM) DelegateCall(caller ContractRef, addr types.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 306 return evm.call(DELEGATECALL, caller, addr, input, gas, nil, false) 307 } 308 309 // StaticCall executes the contract associated with the addr with the given input 310 // as parameters while disallowing any modifications to the state during the call. 311 // Opcodes that attempt to perform such modifications will result in exceptions 312 // instead of performing the modifications. 313 func (evm *EVM) StaticCall(caller ContractRef, addr types.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 314 return evm.call(STATICCALL, caller, addr, input, gas, new(uint256.Int), false) 315 } 316 317 type codeAndHash struct { 318 code []byte 319 hash types.Hash 320 } 321 322 func (c *codeAndHash) Hash() types.Hash { 323 if c.hash == (types.Hash{}) { 324 c.hash = crypto.Keccak256Hash(c.code) 325 } 326 return c.hash 327 } 328 329 // create creates a new contract using code as deployment code. 330 func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address types.Address, typ OpCode, incrementNonce bool) ([]byte, types.Address, uint64, error) { 331 var ret []byte 332 var err error 333 var gasConsumption uint64 334 depth := evm.interpreter.Depth() 335 336 if evm.config.Debug { 337 if depth == 0 { 338 evm.config.Tracer.CaptureStart(evm, caller.Address(), address, true /* create */, codeAndHash.code, gas, value) 339 defer func() { 340 evm.config.Tracer.CaptureEnd(ret, gasConsumption, err) 341 }() 342 } else { 343 evm.config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) 344 defer func() { 345 evm.config.Tracer.CaptureExit(ret, gasConsumption, err) 346 }() 347 } 348 } 349 350 // Depth check execution. Fail if we're trying to execute above the 351 // limit. 352 if depth > int(params.CallCreateDepth) { 353 err = ErrDepth 354 return nil, types.Address{}, gas, err 355 } 356 if !evm.context.CanTransfer(evm.intraBlockState, caller.Address(), value) { 357 err = ErrInsufficientBalance 358 return nil, types.Address{}, gas, err 359 } 360 if incrementNonce { 361 nonce := evm.intraBlockState.GetNonce(caller.Address()) 362 if nonce+1 < nonce { 363 err = ErrNonceUintOverflow 364 return nil, types.Address{}, gas, err 365 } 366 evm.intraBlockState.SetNonce(caller.Address(), nonce+1) 367 } 368 // We add this to the access list _before_ taking a snapshot. Even if the creation fails, 369 // the access-list change should not be rolled back 370 if evm.chainRules.IsBerlin { 371 evm.intraBlockState.AddAddressToAccessList(address) 372 } 373 // Ensure there's no existing contract already at the designated address 374 contractHash := evm.intraBlockState.GetCodeHash(address) 375 if evm.intraBlockState.GetNonce(address) != 0 || (contractHash != (types.Hash{}) && contractHash != emptyCodeHash) { 376 err = ErrContractAddressCollision 377 return nil, types.Address{}, 0, err 378 } 379 // Create a new account on the state 380 snapshot := evm.intraBlockState.Snapshot() 381 evm.intraBlockState.CreateAccount(address, true) 382 if evm.chainRules.IsSpuriousDragon { 383 evm.intraBlockState.SetNonce(address, 1) 384 } 385 evm.context.Transfer(evm.intraBlockState, caller.Address(), address, value, false /* bailout */) 386 387 // Initialise a new contract and set the code that is to be used by the EVM. 388 // The contract is a scoped environment for this execution context only. 389 contract := NewContract(caller, AccountRef(address), value, gas, evm.config.SkipAnalysis) 390 contract.SetCodeOptionalHash(&address, codeAndHash) 391 392 if evm.config.NoRecursion && depth > 0 { 393 return nil, address, gas, nil 394 } 395 396 ret, err = run(evm, contract, nil, false) 397 398 // EIP-170: Contract code size limit 399 if err == nil && evm.chainRules.IsSpuriousDragon && len(ret) > params.MaxCodeSize { 400 // Gnosis Chain prior to Shanghai didn't have EIP-170 enabled, 401 // but EIP-3860 (part of Shanghai) requires EIP-170. 402 if !evm.chainRules.IsAura || evm.config.HasEip3860(evm.chainRules) { 403 err = ErrMaxCodeSizeExceeded 404 } 405 } 406 407 // Reject code starting with 0xEF if EIP-3541 is enabled. 408 if err == nil && evm.chainRules.IsLondon && len(ret) >= 1 && ret[0] == 0xEF { 409 err = ErrInvalidCode 410 } 411 // if the contract creation ran successfully and no errors were returned 412 // calculate the gas required to store the code. If the code could not 413 // be stored due to not enough gas set an error and let it be handled 414 // by the error checking condition below. 415 if err == nil { 416 createDataGas := uint64(len(ret)) * params.CreateDataGas 417 if contract.UseGas(createDataGas) { 418 evm.intraBlockState.SetCode(address, ret) 419 } else if evm.chainRules.IsHomestead { 420 err = ErrCodeStoreOutOfGas 421 } 422 } 423 424 // When an error was returned by the EVM or when setting the creation code 425 // above we revert to the snapshot and consume any gas remaining. Additionally 426 // when we're in homestead this also counts for code storage gas errors. 427 if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { 428 evm.intraBlockState.RevertToSnapshot(snapshot) 429 if err != ErrExecutionReverted { 430 contract.UseGas(contract.Gas) 431 } 432 } 433 434 // calculate gasConsumption for deferred captures 435 gasConsumption = gas - contract.Gas 436 437 return ret, address, contract.Gas, err 438 } 439 440 // Create creates a new contract using code as deployment code. 441 // DESCRIBED: docs/programmers_guide/guide.md#nonce 442 func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int) (ret []byte, contractAddr types.Address, leftOverGas uint64, err error) { 443 contractAddr = crypto.CreateAddress(caller.Address(), evm.intraBlockState.GetNonce(caller.Address())) 444 return evm.create(caller, &codeAndHash{code: code}, gas, endowment, contractAddr, CREATE, true /* incrementNonce */) 445 } 446 447 // Create2 creates a new contract using code as deployment code. 448 // 449 // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] 450 // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. 451 // DESCRIBED: docs/programmers_guide/guide.md#nonce 452 func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr types.Address, leftOverGas uint64, err error) { 453 codeAndHash := &codeAndHash{code: code} 454 contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) 455 return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2, true /* incrementNonce */) 456 } 457 458 // SysCreate is a special (system) contract creation methods for genesis constructors. 459 // Unlike the normal Create & Create2, it doesn't increment caller's nonce. 460 func (evm *EVM) SysCreate(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, contractAddr types.Address) (ret []byte, leftOverGas uint64, err error) { 461 ret, _, leftOverGas, err = evm.create(caller, &codeAndHash{code: code}, gas, endowment, contractAddr, CREATE, false /* incrementNonce */) 462 return 463 } 464 465 // ChainConfig returns the environment's chain configuration 466 func (evm *EVM) Config() Config { 467 return evm.config 468 } 469 470 // ChainConfig returns the environment's chain configuration 471 func (evm *EVM) ChainConfig() *params.ChainConfig { 472 return evm.chainConfig 473 } 474 475 func (evm *EVM) ChainRules() *params.Rules { 476 return evm.chainRules 477 } 478 479 func (evm *EVM) Context() evmtypes.BlockContext { 480 return evm.context 481 } 482 483 func (evm *EVM) TxContext() evmtypes.TxContext { 484 return evm.txContext 485 } 486 487 func (evm *EVM) IntraBlockState() evmtypes.IntraBlockState { 488 return evm.intraBlockState 489 }