github.com/dim4egster/coreth@v0.10.2/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/dim4egster/coreth/core/rawdb"
    35  	"github.com/dim4egster/coreth/core/state"
    36  	"github.com/dim4egster/coreth/core/vm"
    37  	"github.com/dim4egster/coreth/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  			DAOForkBlock:                new(big.Int),
    69  			DAOForkSupport:              false,
    70  			EIP150Block:                 new(big.Int),
    71  			EIP150Hash:                  common.Hash{},
    72  			EIP155Block:                 new(big.Int),
    73  			EIP158Block:                 new(big.Int),
    74  			ByzantiumBlock:              new(big.Int),
    75  			ConstantinopleBlock:         new(big.Int),
    76  			PetersburgBlock:             new(big.Int),
    77  			IstanbulBlock:               new(big.Int),
    78  			MuirGlacierBlock:            new(big.Int),
    79  			ApricotPhase1BlockTimestamp: new(big.Int),
    80  			ApricotPhase2BlockTimestamp: new(big.Int),
    81  			ApricotPhase3BlockTimestamp: new(big.Int),
    82  			ApricotPhase4BlockTimestamp: new(big.Int),
    83  		}
    84  	}
    85  
    86  	if cfg.Difficulty == nil {
    87  		cfg.Difficulty = new(big.Int)
    88  	}
    89  	if cfg.Time == nil {
    90  		cfg.Time = big.NewInt(time.Now().Unix())
    91  	}
    92  	if cfg.GasLimit == 0 {
    93  		cfg.GasLimit = math.MaxUint64
    94  	}
    95  	if cfg.GasPrice == nil {
    96  		cfg.GasPrice = new(big.Int)
    97  	}
    98  	if cfg.Value == nil {
    99  		cfg.Value = new(big.Int)
   100  	}
   101  	if cfg.BlockNumber == nil {
   102  		cfg.BlockNumber = new(big.Int)
   103  	}
   104  	if cfg.GetHashFn == nil {
   105  		cfg.GetHashFn = func(n uint64) common.Hash {
   106  			return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
   107  		}
   108  	}
   109  	if cfg.BaseFee == nil {
   110  		cfg.BaseFee = big.NewInt(params.ApricotPhase3InitialBaseFee)
   111  	}
   112  }
   113  
   114  // Execute executes the code using the input as call data during the execution.
   115  // It returns the EVM's return value, the new state and an error if it failed.
   116  //
   117  // Execute sets up an in-memory, temporary, environment for the execution of
   118  // the given code. It makes sure that it's restored to its original state afterwards.
   119  func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
   120  	if cfg == nil {
   121  		cfg = new(Config)
   122  	}
   123  	setDefaults(cfg)
   124  
   125  	if cfg.State == nil {
   126  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
   127  	}
   128  	var (
   129  		address = common.BytesToAddress([]byte("contract"))
   130  		vmenv   = NewEnv(cfg)
   131  		sender  = vm.AccountRef(cfg.Origin)
   132  	)
   133  	if rules := cfg.ChainConfig.AvalancheRules(vmenv.Context.BlockNumber, vmenv.Context.Time); rules.IsApricotPhase2 {
   134  		cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
   135  	}
   136  	cfg.State.CreateAccount(address)
   137  	// set the receiver's (the executing contract) code for execution.
   138  	cfg.State.SetCode(address, code)
   139  	// Call the code with the given configuration.
   140  	ret, _, err := vmenv.Call(
   141  		sender,
   142  		common.BytesToAddress([]byte("contract")),
   143  		input,
   144  		cfg.GasLimit,
   145  		cfg.Value,
   146  	)
   147  
   148  	return ret, cfg.State, err
   149  }
   150  
   151  // Create executes the code using the EVM create method
   152  func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
   153  	if cfg == nil {
   154  		cfg = new(Config)
   155  	}
   156  	setDefaults(cfg)
   157  
   158  	if cfg.State == nil {
   159  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
   160  	}
   161  	var (
   162  		vmenv  = NewEnv(cfg)
   163  		sender = vm.AccountRef(cfg.Origin)
   164  	)
   165  	if rules := cfg.ChainConfig.AvalancheRules(vmenv.Context.BlockNumber, vmenv.Context.Time); rules.IsApricotPhase2 {
   166  		cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
   167  	}
   168  	// Call the code with the given configuration.
   169  	code, address, leftOverGas, err := vmenv.Create(
   170  		sender,
   171  		input,
   172  		cfg.GasLimit,
   173  		cfg.Value,
   174  	)
   175  	return code, address, leftOverGas, err
   176  }
   177  
   178  // Call executes the code given by the contract's address. It will return the
   179  // EVM's return value or an error if it failed.
   180  //
   181  // Call, unlike Execute, requires a config and also requires the State field to
   182  // be set.
   183  func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
   184  	setDefaults(cfg)
   185  
   186  	vmenv := NewEnv(cfg)
   187  
   188  	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
   189  	statedb := cfg.State
   190  
   191  	if rules := cfg.ChainConfig.AvalancheRules(vmenv.Context.BlockNumber, vmenv.Context.Time); rules.IsApricotPhase2 {
   192  		statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
   193  	}
   194  	// Call the code with the given configuration.
   195  	ret, leftOverGas, err := vmenv.Call(
   196  		sender,
   197  		address,
   198  		input,
   199  		cfg.GasLimit,
   200  		cfg.Value,
   201  	)
   202  	return ret, leftOverGas, err
   203  }