github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/core/vm/evm.go (about)

     1  package vm
     2  
     3  import (
     4  	"math/big"
     5  	"sync/atomic"
     6  	"time"
     7  
     8  	"github.com/neatio-net/neatio/params"
     9  	"github.com/neatio-net/neatio/utilities/common"
    10  	"github.com/neatio-net/neatio/utilities/crypto"
    11  )
    12  
    13  var emptyCodeHash = crypto.Keccak256Hash(nil)
    14  
    15  type (
    16  	CanTransferFunc func(StateDB, common.Address, *big.Int) bool
    17  
    18  	TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
    19  
    20  	GetHashFunc func(uint64) common.Hash
    21  )
    22  
    23  func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
    24  	if contract.CodeAddr != nil {
    25  		precompiles := PrecompiledContractsHomestead
    26  		if evm.chainRules.IsByzantium {
    27  			precompiles = PrecompiledContractsByzantium
    28  		}
    29  		if evm.chainRules.IsIstanbul {
    30  			precompiles = PrecompiledContractsIstanbul
    31  		}
    32  		if p := precompiles[*contract.CodeAddr]; p != nil {
    33  			return RunPrecompiledContract(p, input, contract)
    34  		}
    35  	}
    36  	for _, interpreter := range evm.interpreters {
    37  		if interpreter.CanRun(contract.Code) {
    38  			if evm.interpreter != interpreter {
    39  
    40  				defer func(i Interpreter) {
    41  					evm.interpreter = i
    42  				}(evm.interpreter)
    43  				evm.interpreter = interpreter
    44  			}
    45  			return interpreter.Run(contract, input, readOnly)
    46  		}
    47  	}
    48  	return nil, ErrNoCompatibleInterpreter
    49  }
    50  
    51  type Context struct {
    52  	CanTransfer CanTransferFunc
    53  
    54  	Transfer TransferFunc
    55  
    56  	GetHash GetHashFunc
    57  
    58  	Origin   common.Address
    59  	GasPrice *big.Int
    60  
    61  	Coinbase    common.Address
    62  	GasLimit    uint64
    63  	BlockNumber *big.Int
    64  	Time        *big.Int
    65  	Difficulty  *big.Int
    66  }
    67  
    68  type EVM struct {
    69  	Context
    70  
    71  	StateDB StateDB
    72  
    73  	depth int
    74  
    75  	chainConfig *params.ChainConfig
    76  
    77  	chainRules params.Rules
    78  
    79  	vmConfig Config
    80  
    81  	interpreters []Interpreter
    82  	interpreter  Interpreter
    83  
    84  	abort int32
    85  
    86  	callGasTemp uint64
    87  }
    88  
    89  func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
    90  	evm := &EVM{
    91  		Context:      ctx,
    92  		StateDB:      statedb,
    93  		vmConfig:     vmConfig,
    94  		chainConfig:  chainConfig,
    95  		chainRules:   chainConfig.Rules(ctx.BlockNumber),
    96  		interpreters: make([]Interpreter, 0, 1),
    97  	}
    98  
    99  	if chainConfig.IsEWASM(ctx.BlockNumber) {
   100  
   101  		panic("No supported ewasm interpreter yet.")
   102  	}
   103  
   104  	evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig))
   105  	evm.interpreter = evm.interpreters[0]
   106  
   107  	return evm
   108  }
   109  
   110  func (evm *EVM) Cancel() {
   111  	atomic.StoreInt32(&evm.abort, 1)
   112  }
   113  
   114  func (evm *EVM) Cancelled() bool {
   115  	return atomic.LoadInt32(&evm.abort) == 1
   116  }
   117  
   118  func (evm *EVM) Interpreter() Interpreter {
   119  	return evm.interpreter
   120  }
   121  
   122  func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
   123  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   124  		return nil, gas, nil
   125  	}
   126  
   127  	if evm.depth > int(params.CallCreateDepth) {
   128  		return nil, gas, ErrDepth
   129  	}
   130  
   131  	if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
   132  		return nil, gas, ErrInsufficientBalance
   133  	}
   134  
   135  	var (
   136  		to       = AccountRef(addr)
   137  		snapshot = evm.StateDB.Snapshot()
   138  	)
   139  	if !evm.StateDB.Exist(addr) {
   140  		precompiles := PrecompiledContractsHomestead
   141  		if evm.chainRules.IsByzantium {
   142  			precompiles = PrecompiledContractsByzantium
   143  		}
   144  		if evm.chainRules.IsIstanbul {
   145  			precompiles = PrecompiledContractsIstanbul
   146  		}
   147  		if precompiles[addr] == nil && evm.chainRules.IsEIP158 && value.Sign() == 0 {
   148  
   149  			if evm.vmConfig.Debug && evm.depth == 0 {
   150  				evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
   151  				evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
   152  			}
   153  			return nil, gas, nil
   154  		}
   155  		evm.StateDB.CreateAccount(addr)
   156  	}
   157  	evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
   158  
   159  	contract := NewContract(caller, to, value, gas)
   160  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   161  
   162  	start := time.Now()
   163  
   164  	if evm.vmConfig.Debug && evm.depth == 0 {
   165  		evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
   166  
   167  		defer func() {
   168  			evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
   169  		}()
   170  	}
   171  	ret, err = run(evm, contract, input, false)
   172  
   173  	if err != nil {
   174  		evm.StateDB.RevertToSnapshot(snapshot)
   175  		if err != ErrExecutionReverted {
   176  			contract.UseGas(contract.Gas)
   177  		}
   178  	}
   179  	return ret, contract.Gas, err
   180  }
   181  
   182  func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
   183  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   184  		return nil, gas, nil
   185  	}
   186  
   187  	if evm.depth > int(params.CallCreateDepth) {
   188  		return nil, gas, ErrDepth
   189  	}
   190  
   191  	if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
   192  		return nil, gas, ErrInsufficientBalance
   193  	}
   194  
   195  	var (
   196  		snapshot = evm.StateDB.Snapshot()
   197  		to       = AccountRef(caller.Address())
   198  	)
   199  
   200  	contract := NewContract(caller, to, value, gas)
   201  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   202  
   203  	ret, err = run(evm, contract, input, false)
   204  	if err != nil {
   205  		evm.StateDB.RevertToSnapshot(snapshot)
   206  		if err != ErrExecutionReverted {
   207  			contract.UseGas(contract.Gas)
   208  		}
   209  	}
   210  	return ret, contract.Gas, err
   211  }
   212  
   213  func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
   214  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   215  		return nil, gas, nil
   216  	}
   217  
   218  	if evm.depth > int(params.CallCreateDepth) {
   219  		return nil, gas, ErrDepth
   220  	}
   221  
   222  	var (
   223  		snapshot = evm.StateDB.Snapshot()
   224  		to       = AccountRef(caller.Address())
   225  	)
   226  
   227  	contract := NewContract(caller, to, nil, gas).AsDelegate()
   228  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   229  
   230  	ret, err = run(evm, contract, input, false)
   231  	if err != nil {
   232  		evm.StateDB.RevertToSnapshot(snapshot)
   233  		if err != ErrExecutionReverted {
   234  			contract.UseGas(contract.Gas)
   235  		}
   236  	}
   237  	return ret, contract.Gas, err
   238  }
   239  
   240  func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
   241  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   242  		return nil, gas, nil
   243  	}
   244  
   245  	if evm.depth > int(params.CallCreateDepth) {
   246  		return nil, gas, ErrDepth
   247  	}
   248  
   249  	var (
   250  		to       = AccountRef(addr)
   251  		snapshot = evm.StateDB.Snapshot()
   252  	)
   253  
   254  	contract := NewContract(caller, to, new(big.Int), gas)
   255  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   256  
   257  	evm.StateDB.AddBalance(addr, bigZero)
   258  
   259  	ret, err = run(evm, contract, input, true)
   260  	if err != nil {
   261  		evm.StateDB.RevertToSnapshot(snapshot)
   262  		if err != ErrExecutionReverted {
   263  			contract.UseGas(contract.Gas)
   264  		}
   265  	}
   266  	return ret, contract.Gas, err
   267  }
   268  
   269  type codeAndHash struct {
   270  	code []byte
   271  	hash common.Hash
   272  }
   273  
   274  func (c *codeAndHash) Hash() common.Hash {
   275  	if c.hash == (common.Hash{}) {
   276  		c.hash = crypto.Keccak256Hash(c.code)
   277  	}
   278  	return c.hash
   279  }
   280  
   281  func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
   282  
   283  	if evm.depth > int(params.CallCreateDepth) {
   284  		return nil, common.Address{}, gas, ErrDepth
   285  	}
   286  	if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
   287  		return nil, common.Address{}, gas, ErrInsufficientBalance
   288  	}
   289  	nonce := evm.StateDB.GetNonce(caller.Address())
   290  	evm.StateDB.SetNonce(caller.Address(), nonce+1)
   291  
   292  	contractHash := evm.StateDB.GetCodeHash(address)
   293  	if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
   294  		return nil, common.Address{}, 0, ErrContractAddressCollision
   295  	}
   296  
   297  	snapshot := evm.StateDB.Snapshot()
   298  	evm.StateDB.CreateAccount(address)
   299  	if evm.chainRules.IsEIP158 {
   300  		evm.StateDB.SetNonce(address, 1)
   301  	}
   302  	evm.Transfer(evm.StateDB, caller.Address(), address, value)
   303  
   304  	contract := NewContract(caller, AccountRef(address), value, gas)
   305  	contract.SetCodeOptionalHash(&address, codeAndHash)
   306  
   307  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   308  		return nil, address, gas, nil
   309  	}
   310  
   311  	if evm.vmConfig.Debug && evm.depth == 0 {
   312  		evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
   313  	}
   314  	start := time.Now()
   315  
   316  	ret, err := run(evm, contract, nil, false)
   317  
   318  	maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize
   319  
   320  	if err == nil && !maxCodeSizeExceeded {
   321  		createDataGas := uint64(len(ret)) * params.CreateDataGas
   322  		if contract.UseGas(createDataGas) {
   323  			evm.StateDB.SetCode(address, ret)
   324  		} else {
   325  			err = ErrCodeStoreOutOfGas
   326  		}
   327  	}
   328  
   329  	if maxCodeSizeExceeded || (err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas)) {
   330  		evm.StateDB.RevertToSnapshot(snapshot)
   331  		if err != ErrExecutionReverted {
   332  			contract.UseGas(contract.Gas)
   333  		}
   334  	}
   335  
   336  	if maxCodeSizeExceeded && err == nil {
   337  		err = ErrMaxCodeSizeExceeded
   338  	}
   339  	if evm.vmConfig.Debug && evm.depth == 0 {
   340  		evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
   341  	}
   342  	return ret, address, contract.Gas, err
   343  
   344  }
   345  
   346  func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
   347  	contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
   348  	return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr)
   349  }
   350  
   351  func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
   352  	codeAndHash := &codeAndHash{code: code}
   353  	contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes())
   354  	return evm.create(caller, codeAndHash, gas, endowment, contractAddr)
   355  }
   356  
   357  func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }