github.com/dominant-strategies/go-quai@v0.28.2/core/vm/runtime/runtime.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package runtime
    18  
    19  import (
    20  	"math"
    21  	"math/big"
    22  	"time"
    23  
    24  	"github.com/dominant-strategies/go-quai/common"
    25  	"github.com/dominant-strategies/go-quai/core/rawdb"
    26  	"github.com/dominant-strategies/go-quai/core/state"
    27  	"github.com/dominant-strategies/go-quai/core/vm"
    28  	"github.com/dominant-strategies/go-quai/crypto"
    29  	"github.com/dominant-strategies/go-quai/params"
    30  )
    31  
    32  // Config is a basic type specifying certain configuration flags for running
    33  // the EVM.
    34  type Config struct {
    35  	ChainConfig *params.ChainConfig
    36  	Difficulty  *big.Int
    37  	Origin      common.Address
    38  	Coinbase    common.Address
    39  	BlockNumber *big.Int
    40  	Time        *big.Int
    41  	GasLimit    uint64
    42  	GasPrice    *big.Int
    43  	Value       *big.Int
    44  	Debug       bool
    45  	EVMConfig   vm.Config
    46  	BaseFee     *big.Int
    47  
    48  	State     *state.StateDB
    49  	GetHashFn func(n uint64) common.Hash
    50  }
    51  
    52  // sets defaults on the config
    53  func setDefaults(cfg *Config) {
    54  	if cfg.ChainConfig == nil {
    55  		cfg.ChainConfig = &params.ChainConfig{
    56  			ChainID: big.NewInt(1),
    57  		}
    58  	}
    59  
    60  	if cfg.Difficulty == nil {
    61  		cfg.Difficulty = new(big.Int)
    62  	}
    63  	if cfg.Time == nil {
    64  		cfg.Time = big.NewInt(time.Now().Unix())
    65  	}
    66  	if cfg.GasLimit == 0 {
    67  		cfg.GasLimit = math.MaxUint64
    68  	}
    69  	if cfg.GasPrice == nil {
    70  		cfg.GasPrice = new(big.Int)
    71  	}
    72  	if cfg.Value == nil {
    73  		cfg.Value = new(big.Int)
    74  	}
    75  	if cfg.BlockNumber == nil {
    76  		cfg.BlockNumber = new(big.Int)
    77  	}
    78  	if cfg.GetHashFn == nil {
    79  		cfg.GetHashFn = func(n uint64) common.Hash {
    80  			return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
    81  		}
    82  	}
    83  	if cfg.BaseFee == nil {
    84  		cfg.BaseFee = big.NewInt(params.InitialBaseFee)
    85  	}
    86  }
    87  
    88  // Execute executes the code using the input as call data during the execution.
    89  // It returns the EVM's return value, the new state and an error if it failed.
    90  //
    91  // Execute sets up an in-memory, temporary, environment for the execution of
    92  // the given code. It makes sure that it's restored to its original state afterwards.
    93  func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
    94  	if cfg == nil {
    95  		cfg = new(Config)
    96  	}
    97  	setDefaults(cfg)
    98  
    99  	if cfg.State == nil {
   100  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
   101  	}
   102  	var (
   103  		address = common.BytesToAddress([]byte("contract"))
   104  		vmenv   = NewEnv(cfg)
   105  		sender  = vm.AccountRef(cfg.Origin)
   106  	)
   107  	internal, err := address.InternalAddress()
   108  	if err != nil {
   109  		return []byte{}, nil, err
   110  	}
   111  	rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
   112  	cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
   113  
   114  	cfg.State.CreateAccount(internal)
   115  	// set the receiver's (the executing contract) code for execution.
   116  	cfg.State.SetCode(internal, code)
   117  	// Call the code with the given configuration.
   118  	ret, _, err := vmenv.Call(
   119  		sender,
   120  		common.BytesToAddress([]byte("contract")),
   121  		input,
   122  		cfg.GasLimit,
   123  		cfg.Value,
   124  	)
   125  
   126  	return ret, cfg.State, err
   127  }
   128  
   129  // Create executes the code using the EVM create method
   130  func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
   131  	if cfg == nil {
   132  		cfg = new(Config)
   133  	}
   134  	setDefaults(cfg)
   135  
   136  	if cfg.State == nil {
   137  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
   138  	}
   139  	var (
   140  		vmenv  = NewEnv(cfg)
   141  		sender = vm.AccountRef(cfg.Origin)
   142  	)
   143  	rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
   144  	cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
   145  
   146  	// Call the code with the given configuration.
   147  	code, address, leftOverGas, err := vmenv.Create(
   148  		sender,
   149  		input,
   150  		cfg.GasLimit,
   151  		cfg.Value,
   152  	)
   153  	return code, address, leftOverGas, err
   154  }
   155  
   156  // Call executes the code given by the contract's address. It will return the
   157  // EVM's return value or an error if it failed.
   158  //
   159  // Call, unlike Execute, requires a config and also requires the State field to
   160  // be set.
   161  func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
   162  	setDefaults(cfg)
   163  
   164  	vmenv := NewEnv(cfg)
   165  	_, err := cfg.Origin.InternalAddress()
   166  	if err != nil {
   167  		return []byte{}, 0, err
   168  	}
   169  
   170  	statedb := cfg.State
   171  
   172  	rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
   173  	statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
   174  
   175  	// Call the code with the given configuration.
   176  	ret, leftOverGas, err := vmenv.Call(
   177  		vm.AccountRef(cfg.Origin),
   178  		address,
   179  		input,
   180  		cfg.GasLimit,
   181  		cfg.Value,
   182  	)
   183  	return ret, leftOverGas, err
   184  }