github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/vm/runtime/runtime.go (about)

     1  package runtime
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"time"
     7  
     8  	"github.com/quickchainproject/quickchain/common"
     9  	"github.com/quickchainproject/quickchain/core/state"
    10  	"github.com/quickchainproject/quickchain/core/vm"
    11  	"github.com/quickchainproject/quickchain/crypto"
    12  	"github.com/quickchainproject/quickchain/qctdb"
    13  	"github.com/quickchainproject/quickchain/params"
    14  )
    15  
    16  // Config is a basic type specifying certain configuration flags for running
    17  // the EVM.
    18  type Config struct {
    19  	ChainConfig *params.ChainConfig
    20  	Difficulty  *big.Int
    21  	Origin      common.Address
    22  	Coinbase    common.Address
    23  	BlockNumber *big.Int
    24  	Time        *big.Int
    25  	GasLimit    uint64
    26  	GasPrice    *big.Int
    27  	Value       *big.Int
    28  	Debug       bool
    29  	EVMConfig   vm.Config
    30  
    31  	State     *state.StateDB
    32  	GetHashFn func(n uint64) common.Hash
    33  }
    34  
    35  // sets defaults on the config
    36  func setDefaults(cfg *Config) {
    37  	if cfg.ChainConfig == nil {
    38  		cfg.ChainConfig = &params.ChainConfig{
    39  			ChainId:        big.NewInt(1),
    40  			HomesteadBlock: new(big.Int),
    41  			DAOForkBlock:   new(big.Int),
    42  			DAOForkSupport: false,
    43  			EIP150Block:    new(big.Int),
    44  			EIP155Block:    new(big.Int),
    45  			EIP158Block:    new(big.Int),
    46  		}
    47  	}
    48  
    49  	if cfg.Difficulty == nil {
    50  		cfg.Difficulty = new(big.Int)
    51  	}
    52  	if cfg.Time == nil {
    53  		cfg.Time = big.NewInt(time.Now().Unix())
    54  	}
    55  	if cfg.GasLimit == 0 {
    56  		cfg.GasLimit = math.MaxUint64
    57  	}
    58  	if cfg.GasPrice == nil {
    59  		cfg.GasPrice = new(big.Int)
    60  	}
    61  	if cfg.Value == nil {
    62  		cfg.Value = new(big.Int)
    63  	}
    64  	if cfg.BlockNumber == nil {
    65  		cfg.BlockNumber = new(big.Int)
    66  	}
    67  	if cfg.GetHashFn == nil {
    68  		cfg.GetHashFn = func(n uint64) common.Hash {
    69  			return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
    70  		}
    71  	}
    72  }
    73  
    74  // Execute executes the code using the input as call data during the execution.
    75  // It returns the EVM's return value, the new state and an error if it failed.
    76  //
    77  // Executes sets up a in memory, temporarily, environment for the execution of
    78  // the given code. It makes sure that it's restored to it's original state afterwards.
    79  func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
    80  	if cfg == nil {
    81  		cfg = new(Config)
    82  	}
    83  	setDefaults(cfg)
    84  
    85  	if cfg.State == nil {
    86  		db, _ := qctdb.NewMemDatabase()
    87  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db))
    88  	}
    89  	var (
    90  		address = common.BytesToAddress([]byte("contract"))
    91  		vmenv   = NewEnv(cfg)
    92  		sender  = vm.AccountRef(cfg.Origin)
    93  	)
    94  	cfg.State.CreateAccount(address)
    95  	// set the receiver's (the executing contract) code for execution.
    96  	cfg.State.SetCode(address, code)
    97  	// Call the code with the given configuration.
    98  	ret, _, err := vmenv.Call(
    99  		sender,
   100  		common.BytesToAddress([]byte("contract")),
   101  		input,
   102  		cfg.GasLimit,
   103  		cfg.Value,
   104  	)
   105  
   106  	return ret, cfg.State, err
   107  }
   108  
   109  // Create executes the code using the EVM create method
   110  func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
   111  	if cfg == nil {
   112  		cfg = new(Config)
   113  	}
   114  	setDefaults(cfg)
   115  
   116  	if cfg.State == nil {
   117  		db, _ := qctdb.NewMemDatabase()
   118  		cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db))
   119  	}
   120  	var (
   121  		vmenv  = NewEnv(cfg)
   122  		sender = vm.AccountRef(cfg.Origin)
   123  	)
   124  
   125  	// Call the code with the given configuration.
   126  	code, address, leftOverGas, err := vmenv.Create(
   127  		sender,
   128  		input,
   129  		cfg.GasLimit,
   130  		cfg.Value,
   131  	)
   132  	return code, address, leftOverGas, err
   133  }
   134  
   135  // Call executes the code given by the contract's address. It will return the
   136  // EVM's return value or an error if it failed.
   137  //
   138  // Call, unlike Execute, requires a config and also requires the State field to
   139  // be set.
   140  func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
   141  	setDefaults(cfg)
   142  
   143  	vmenv := NewEnv(cfg)
   144  
   145  	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
   146  	// Call the code with the given configuration.
   147  	ret, leftOverGas, err := vmenv.Call(
   148  		sender,
   149  		address,
   150  		input,
   151  		cfg.GasLimit,
   152  		cfg.Value,
   153  	)
   154  
   155  	return ret, leftOverGas, err
   156  }