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  }