github.com/MetalBlockchain/subnet-evm@v0.4.9/core/vm/runtime/runtime.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2015 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package runtime
    28  
    29  import (
    30  	"math"
    31  	"math/big"
    32  	"time"
    33  
    34  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    35  	"github.com/MetalBlockchain/subnet-evm/core/state"
    36  	"github.com/MetalBlockchain/subnet-evm/core/vm"
    37  	"github.com/MetalBlockchain/subnet-evm/params"
    38  	"github.com/ethereum/go-ethereum/common"
    39  	"github.com/ethereum/go-ethereum/crypto"
    40  )
    41  
    42  // Config is a basic type specifying certain configuration flags for running
    43  // the EVM.
    44  type Config struct {
    45  	ChainConfig *params.ChainConfig
    46  	Difficulty  *big.Int
    47  	Origin      common.Address
    48  	Coinbase    common.Address
    49  	BlockNumber *big.Int
    50  	Time        *big.Int
    51  	GasLimit    uint64
    52  	GasPrice    *big.Int
    53  	Value       *big.Int
    54  	Debug       bool
    55  	EVMConfig   vm.Config
    56  	BaseFee     *big.Int
    57  
    58  	State     *state.StateDB
    59  	GetHashFn func(n uint64) common.Hash
    60  }
    61  
    62  // sets defaults on the config
    63  func setDefaults(cfg *Config) {
    64  	if cfg.ChainConfig == nil {
    65  		cfg.ChainConfig = &params.ChainConfig{
    66  			ChainID:             big.NewInt(1),
    67  			HomesteadBlock:      new(big.Int),
    68  			EIP150Block:         new(big.Int),
    69  			EIP150Hash:          common.Hash{},
    70  			EIP155Block:         new(big.Int),
    71  			EIP158Block:         new(big.Int),
    72  			ByzantiumBlock:      new(big.Int),
    73  			ConstantinopleBlock: new(big.Int),
    74  			PetersburgBlock:     new(big.Int),
    75  			IstanbulBlock:       new(big.Int),
    76  			MuirGlacierBlock:    new(big.Int),
    77  			NetworkUpgrades: params.NetworkUpgrades{
    78  				SubnetEVMTimestamp: new(big.Int),
    79  			},
    80  		}
    81  	}
    82  
    83  	if cfg.Difficulty == nil {
    84  		cfg.Difficulty = new(big.Int)
    85  	}
    86  	if cfg.Time == nil {
    87  		cfg.Time = big.NewInt(time.Now().Unix())
    88  	}
    89  	if cfg.GasLimit == 0 {
    90  		cfg.GasLimit = math.MaxUint64
    91  	}
    92  	if cfg.GasPrice == nil {
    93  		cfg.GasPrice = new(big.Int)
    94  	}
    95  	if cfg.Value == nil {
    96  		cfg.Value = new(big.Int)
    97  	}
    98  	if cfg.BlockNumber == nil {
    99  		cfg.BlockNumber = new(big.Int)
   100  	}
   101  	if cfg.GetHashFn == nil {
   102  		cfg.GetHashFn = func(n uint64) common.Hash {
   103  			return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
   104  		}
   105  	}
   106  	if cfg.BaseFee == nil {
   107  		cfg.BaseFee = new(big.Int).Set(params.DefaultFeeConfig.MinBaseFee)
   108  	}
   109  }
   110  
   111  // Execute executes the code using the input as call data during the execution.
   112  // It returns the EVM's return value, the new state and an error if it failed.
   113  //
   114  // Execute sets up an in-memory, temporary, environment for the execution of
   115  // the given code. It makes sure that it's restored to its original state afterwards.
   116  func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
   117  	if cfg == nil {
   118  		cfg = new(Config)
   119  	}
   120  	setDefaults(cfg)
   121  
   122  	if cfg.State == nil {
   123  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
   124  	}
   125  	var (
   126  		address = common.BytesToAddress([]byte("contract"))
   127  		vmenv   = NewEnv(cfg)
   128  		sender  = vm.AccountRef(cfg.Origin)
   129  	)
   130  	if rules := cfg.ChainConfig.AvalancheRules(vmenv.Context.BlockNumber, vmenv.Context.Time); rules.IsSubnetEVM {
   131  		cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
   132  	}
   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  		cfg.Value,
   143  	)
   144  
   145  	return ret, cfg.State, err
   146  }
   147  
   148  // Create executes the code using the EVM create method
   149  func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
   150  	if cfg == nil {
   151  		cfg = new(Config)
   152  	}
   153  	setDefaults(cfg)
   154  
   155  	if cfg.State == nil {
   156  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
   157  	}
   158  	var (
   159  		vmenv  = NewEnv(cfg)
   160  		sender = vm.AccountRef(cfg.Origin)
   161  	)
   162  	if rules := cfg.ChainConfig.AvalancheRules(vmenv.Context.BlockNumber, vmenv.Context.Time); rules.IsSubnetEVM {
   163  		cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
   164  	}
   165  	// Call the code with the given configuration.
   166  	code, address, leftOverGas, err := vmenv.Create(
   167  		sender,
   168  		input,
   169  		cfg.GasLimit,
   170  		cfg.Value,
   171  	)
   172  	return code, address, leftOverGas, err
   173  }
   174  
   175  // Call executes the code given by the contract's address. It will return the
   176  // EVM's return value or an error if it failed.
   177  //
   178  // Call, unlike Execute, requires a config and also requires the State field to
   179  // be set.
   180  func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
   181  	setDefaults(cfg)
   182  
   183  	vmenv := NewEnv(cfg)
   184  
   185  	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
   186  	statedb := cfg.State
   187  
   188  	if rules := cfg.ChainConfig.AvalancheRules(vmenv.Context.BlockNumber, vmenv.Context.Time); rules.IsSubnetEVM {
   189  		statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
   190  	}
   191  	// Call the code with the given configuration.
   192  	ret, leftOverGas, err := vmenv.Call(
   193  		sender,
   194  		address,
   195  		input,
   196  		cfg.GasLimit,
   197  		cfg.Value,
   198  	)
   199  	return ret, leftOverGas, err
   200  }