github.com/klaytn/klaytn@v1.12.1/blockchain/vm/runtime/runtime.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/vm/runtime/runtime.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package runtime
    22  
    23  import (
    24  	"math"
    25  	"math/big"
    26  	"time"
    27  
    28  	"github.com/klaytn/klaytn/blockchain/state"
    29  	"github.com/klaytn/klaytn/blockchain/types"
    30  	"github.com/klaytn/klaytn/blockchain/vm"
    31  	"github.com/klaytn/klaytn/common"
    32  	"github.com/klaytn/klaytn/crypto"
    33  	"github.com/klaytn/klaytn/params"
    34  	"github.com/klaytn/klaytn/storage/database"
    35  )
    36  
    37  // Config is a basic type specifying certain configuration flags for running
    38  // the EVM.
    39  type Config struct {
    40  	ChainConfig *params.ChainConfig
    41  	BlockScore  *big.Int
    42  	Origin      common.Address
    43  	Coinbase    common.Address
    44  	Rewardbase  common.Address
    45  	BlockNumber *big.Int
    46  	Time        *big.Int
    47  	GasLimit    uint64
    48  	GasPrice    *big.Int
    49  	Value       *big.Int
    50  	Debug       bool
    51  	EVMConfig   vm.Config
    52  	BaseFee     *big.Int
    53  
    54  	State     *state.StateDB
    55  	GetHashFn func(n uint64) common.Hash
    56  }
    57  
    58  // sets defaults on the config
    59  func setDefaults(cfg *Config) {
    60  	if cfg.ChainConfig == nil {
    61  		cfg.ChainConfig = &params.ChainConfig{
    62  			ChainID:                  big.NewInt(1),
    63  			IstanbulCompatibleBlock:  new(big.Int),
    64  			LondonCompatibleBlock:    new(big.Int),
    65  			EthTxTypeCompatibleBlock: new(big.Int),
    66  			KoreCompatibleBlock:      new(big.Int),
    67  			ShanghaiCompatibleBlock:  new(big.Int),
    68  		}
    69  	}
    70  
    71  	if cfg.BlockScore == nil {
    72  		cfg.BlockScore = new(big.Int)
    73  	}
    74  	if cfg.Time == nil {
    75  		cfg.Time = big.NewInt(time.Now().Unix())
    76  	}
    77  	if cfg.GasLimit == 0 {
    78  		cfg.GasLimit = math.MaxUint64
    79  	}
    80  	if cfg.GasPrice == nil {
    81  		cfg.GasPrice = new(big.Int)
    82  	}
    83  	if cfg.Value == nil {
    84  		cfg.Value = new(big.Int)
    85  	}
    86  	if cfg.BlockNumber == nil {
    87  		cfg.BlockNumber = new(big.Int)
    88  	}
    89  	if cfg.GetHashFn == nil {
    90  		cfg.GetHashFn = func(n uint64) common.Hash {
    91  			return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
    92  		}
    93  	}
    94  	if cfg.BaseFee == nil {
    95  		cfg.BaseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
    96  	}
    97  }
    98  
    99  // Execute executes the code using the input as call data during the execution.
   100  // It returns the EVM's return value, the new state and an error if it failed.
   101  //
   102  // Executes sets up a in memory, temporarily, environment for the execution of
   103  // the given code. It makes sure that it's restored to it's original state afterwards.
   104  func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
   105  	if cfg == nil {
   106  		cfg = new(Config)
   107  	}
   108  	setDefaults(cfg)
   109  
   110  	if cfg.State == nil {
   111  		memDBManager := database.NewMemoryDBManager()
   112  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(memDBManager), nil, nil)
   113  	}
   114  	var (
   115  		address = common.BytesToAddress([]byte("contract"))
   116  		vmenv   = NewEnv(cfg)
   117  		sender  = vm.AccountRef(cfg.Origin)
   118  		rules   = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
   119  	)
   120  
   121  	cfg.State.Prepare(rules, cfg.Origin, common.Address{}, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
   122  	cfg.State.CreateSmartContractAccount(address, params.CodeFormatEVM, cfg.ChainConfig.Rules(cfg.BlockNumber))
   123  	// set the receiver's (the executing contract) code for execution.
   124  	cfg.State.SetCode(address, code)
   125  	// Call the code with the given configuration.
   126  	ret, _, err := vmenv.Call(
   127  		sender,
   128  		common.BytesToAddress([]byte("contract")),
   129  		input,
   130  		cfg.GasLimit,
   131  		cfg.Value,
   132  	)
   133  
   134  	return ret, cfg.State, err
   135  }
   136  
   137  // Create executes the code using the EVM create method
   138  func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
   139  	if cfg == nil {
   140  		cfg = new(Config)
   141  	}
   142  	setDefaults(cfg)
   143  
   144  	if cfg.State == nil {
   145  		memDBManager := database.NewMemoryDBManager()
   146  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(memDBManager), nil, nil)
   147  	}
   148  	var (
   149  		vmenv  = NewEnv(cfg)
   150  		sender = vm.AccountRef(cfg.Origin)
   151  		rules  = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
   152  	)
   153  
   154  	cfg.State.Prepare(rules, cfg.Origin, common.Address{}, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil)
   155  	// Call the code with the given configuration.
   156  	code, address, leftOverGas, err := vmenv.Create(
   157  		sender,
   158  		input,
   159  		cfg.GasLimit,
   160  		cfg.Value,
   161  		params.CodeFormatEVM,
   162  	)
   163  	return code, address, leftOverGas, err
   164  }
   165  
   166  // Call executes the code given by the contract's address. It will return the
   167  // EVM's return value or an error if it failed.
   168  //
   169  // Call, unlike Execute, requires a config and also requires the State field to
   170  // be set.
   171  func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
   172  	setDefaults(cfg)
   173  
   174  	var (
   175  		vmenv         = NewEnv(cfg)
   176  		senderAccount = cfg.State.GetOrNewStateObject(cfg.Origin)
   177  		sender        = types.NewAccountRefWithFeePayer(senderAccount.Address(), senderAccount.Address())
   178  		rules         = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
   179  	)
   180  
   181  	cfg.State.Prepare(rules, cfg.Origin, common.Address{}, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
   182  	// Call the code with the given configuration.
   183  	ret, leftOverGas, err := vmenv.Call(
   184  		sender,
   185  		address,
   186  		input,
   187  		cfg.GasLimit,
   188  		cfg.Value,
   189  	)
   190  
   191  	return ret, leftOverGas, err
   192  }