github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/vm/vm.go (about)

     1  // Copyright 2014 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 vm
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  	"time"
    24  
    25  	"github.com/ethereumproject/go-ethereum/common"
    26  	"github.com/ethereumproject/go-ethereum/crypto"
    27  	"github.com/ethereumproject/go-ethereum/logger"
    28  	"github.com/ethereumproject/go-ethereum/logger/glog"
    29  )
    30  
    31  var (
    32  	OutOfGasError          = errors.New("Out of gas")
    33  	CodeStoreOutOfGasError = errors.New("Contract creation code storage out of gas")
    34  )
    35  
    36  // VirtualMachine is an EVM interface
    37  type VirtualMachine interface {
    38  	Run(*Contract, []byte) ([]byte, error)
    39  }
    40  
    41  // EVM is used to run Ethereum based contracts and will utilise the
    42  // passed environment to query external sources for state information.
    43  // The EVM will run the byte code VM or JIT VM based on the passed
    44  // configuration.
    45  type EVM struct {
    46  	env       Environment
    47  	jumpTable vmJumpTable
    48  	gasTable  GasTable
    49  }
    50  
    51  // New returns a new instance of the EVM.
    52  func New(env Environment) *EVM {
    53  	return &EVM{
    54  		env:       env,
    55  		jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()),
    56  		gasTable:  *env.RuleSet().GasTable(env.BlockNumber()),
    57  	}
    58  }
    59  
    60  // Run loops and evaluates the contract's code with the given input data
    61  func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
    62  	evm.env.SetDepth(evm.env.Depth() + 1)
    63  	defer evm.env.SetDepth(evm.env.Depth() - 1)
    64  
    65  	if contract.CodeAddr != nil {
    66  		if p := Precompiled[contract.CodeAddr.Str()]; p != nil {
    67  			return evm.RunPrecompiled(p, input, contract)
    68  		}
    69  	}
    70  
    71  	// Don't bother with the execution if there's no code.
    72  	if len(contract.Code) == 0 {
    73  		return nil, nil
    74  	}
    75  
    76  	codehash := contract.CodeHash // codehash is used when doing jump dest caching
    77  	if codehash == (common.Hash{}) {
    78  		codehash = crypto.Keccak256Hash(contract.Code)
    79  	}
    80  
    81  	var (
    82  		caller     = contract.caller
    83  		code       = contract.Code
    84  		instrCount = 0
    85  
    86  		op      OpCode         // current opcode
    87  		mem     = NewMemory()  // bound memory
    88  		stack   = newstack()   // local stack
    89  		statedb = evm.env.Db() // current state
    90  		// For optimisation reason we're using uint64 as the program counter.
    91  		// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible.
    92  		pc = uint64(0) // program counter
    93  
    94  		// jump evaluates and checks whether the given jump destination is a valid one
    95  		// if valid move the `pc` otherwise return an error.
    96  		jump = func(from uint64, to *big.Int) error {
    97  			if !contract.jumpdests.has(codehash, code, to) {
    98  				nop := contract.GetOp(to.Uint64())
    99  				return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
   100  			}
   101  
   102  			pc = to.Uint64()
   103  
   104  			return nil
   105  		}
   106  
   107  		newMemSize *big.Int
   108  		cost       *big.Int
   109  	)
   110  	contract.Input = input
   111  
   112  	if glog.V(logger.Debug) {
   113  		glog.Infof("running byte VM %x\n", codehash[:4])
   114  		tstart := time.Now()
   115  		defer func() {
   116  			glog.Infof("byte VM %x done. time: %v instrc: %v\n", codehash[:4], time.Since(tstart), instrCount)
   117  		}()
   118  	}
   119  
   120  	for ; ; instrCount++ {
   121  		// Get the memory location of pc
   122  		op = contract.GetOp(pc)
   123  		// calculate the new memory size and gas price for the current executing opcode
   124  		newMemSize, cost, err = calculateGasAndSize(&evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack)
   125  		if err != nil {
   126  			return nil, err
   127  		}
   128  
   129  		// Use the calculated gas. When insufficient gas is present, use all gas and return an
   130  		// Out Of Gas error
   131  		if !contract.UseGas(cost) {
   132  			return nil, OutOfGasError
   133  		}
   134  
   135  		// Resize the memory calculated previously
   136  		mem.Resize(newMemSize.Uint64())
   137  
   138  		if opPtr := evm.jumpTable[op]; opPtr.valid {
   139  			if opPtr.fn != nil {
   140  				opPtr.fn(instruction{}, &pc, evm.env, contract, mem, stack)
   141  			} else {
   142  				switch op {
   143  				case PC:
   144  					opPc(instruction{data: new(big.Int).SetUint64(pc)}, &pc, evm.env, contract, mem, stack)
   145  				case JUMP:
   146  					if err := jump(pc, stack.pop()); err != nil {
   147  						return nil, err
   148  					}
   149  
   150  					continue
   151  				case JUMPI:
   152  					pos, cond := stack.pop(), stack.pop()
   153  
   154  					if cond.Sign() != 0 {
   155  						if err := jump(pc, pos); err != nil {
   156  							return nil, err
   157  						}
   158  
   159  						continue
   160  					}
   161  				case RETURN:
   162  					offset, size := stack.pop(), stack.pop()
   163  					ret := mem.GetPtr(offset.Int64(), size.Int64())
   164  
   165  					return ret, nil
   166  				case SUICIDE:
   167  					opSuicide(instruction{}, nil, evm.env, contract, mem, stack)
   168  
   169  					fallthrough
   170  				case STOP: // Stop the contract
   171  					return nil, nil
   172  				}
   173  			}
   174  		} else {
   175  			return nil, fmt.Errorf("Invalid opcode %x", op)
   176  		}
   177  
   178  		pc++
   179  
   180  	}
   181  }
   182  
   183  // calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
   184  // the operation. This does not reduce gas or resizes the memory.
   185  func calculateGasAndSize(gasTable *GasTable, env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
   186  	var (
   187  		gas                 = new(big.Int)
   188  		newMemSize *big.Int = new(big.Int)
   189  	)
   190  	err := baseCheck(op, stack, gas)
   191  	if err != nil {
   192  		return nil, nil, err
   193  	}
   194  
   195  	// stack Check, memory resize & gas phase
   196  	switch op {
   197  	case SUICIDE:
   198  		// if suicide is not nil: homestead gas fork
   199  		if gasTable.CreateBySuicide != nil {
   200  			gas.Set(gasTable.Suicide)
   201  			if !env.Db().Exist(common.BigToAddress(stack.data[len(stack.data)-1])) {
   202  				gas.Add(gas, gasTable.CreateBySuicide)
   203  			}
   204  		}
   205  
   206  		if !statedb.HasSuicided(contract.Address()) {
   207  			statedb.AddRefund(big.NewInt(24000))
   208  		}
   209  	case EXTCODESIZE:
   210  		gas.Set(gasTable.ExtcodeSize)
   211  	case BALANCE:
   212  		gas.Set(gasTable.Balance)
   213  	case SLOAD:
   214  		gas.Set(gasTable.SLoad)
   215  	case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
   216  		n := int(op - SWAP1 + 2)
   217  		err := stack.require(n)
   218  		if err != nil {
   219  			return nil, nil, err
   220  		}
   221  		gas.Set(GasFastestStep)
   222  	case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
   223  		n := int(op - DUP1 + 1)
   224  		err := stack.require(n)
   225  		if err != nil {
   226  			return nil, nil, err
   227  		}
   228  		gas.Set(GasFastestStep)
   229  	case LOG0, LOG1, LOG2, LOG3, LOG4:
   230  		n := int(op - LOG0)
   231  		err := stack.require(n + 2)
   232  		if err != nil {
   233  			return nil, nil, err
   234  		}
   235  
   236  		mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
   237  
   238  		// log gas
   239  		gas.Add(gas, big.NewInt(375))
   240  		// log topic gass
   241  		gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), big.NewInt(375)))
   242  		// log data gass
   243  		gas.Add(gas, new(big.Int).Mul(mSize, big.NewInt(8)))
   244  
   245  		newMemSize = calcMemSize(mStart, mSize)
   246  
   247  		quadMemGas(mem, newMemSize, gas)
   248  	case EXP:
   249  		expByteLen := int64(len(stack.data[stack.len()-2].Bytes()))
   250  		gas.Add(gas, new(big.Int).Mul(big.NewInt(expByteLen), gasTable.ExpByte))
   251  	case SSTORE:
   252  		err := stack.require(2)
   253  		if err != nil {
   254  			return nil, nil, err
   255  		}
   256  
   257  		var g *big.Int
   258  		y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
   259  		val := statedb.GetState(contract.Address(), common.BigToHash(x))
   260  
   261  		// This checks for 3 scenario's and calculates gas accordingly
   262  		// 1. From a zero-value address to a non-zero value         (NEW VALUE)
   263  		// 2. From a non-zero value address to a zero-value address (DELETE)
   264  		// 3. From a non-zero to a non-zero                         (CHANGE)
   265  		if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
   266  			// 0 => non 0
   267  			g = big.NewInt(20000) // Once per SLOAD operation.
   268  		} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
   269  			statedb.AddRefund(big.NewInt(15000))
   270  			g = big.NewInt(5000)
   271  		} else {
   272  			// non 0 => non 0 (or 0 => 0)
   273  			g = big.NewInt(5000)
   274  		}
   275  		gas.Set(g)
   276  
   277  	case MLOAD:
   278  		newMemSize = calcMemSize(stack.peek(), u256(32))
   279  		quadMemGas(mem, newMemSize, gas)
   280  	case MSTORE8:
   281  		newMemSize = calcMemSize(stack.peek(), u256(1))
   282  		quadMemGas(mem, newMemSize, gas)
   283  	case MSTORE:
   284  		newMemSize = calcMemSize(stack.peek(), u256(32))
   285  		quadMemGas(mem, newMemSize, gas)
   286  	case RETURN:
   287  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
   288  		quadMemGas(mem, newMemSize, gas)
   289  	case SHA3:
   290  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
   291  
   292  		words := toWordSize(stack.data[stack.len()-2])
   293  		gas.Add(gas, words.Mul(words, big.NewInt(6)))
   294  
   295  		quadMemGas(mem, newMemSize, gas)
   296  	case CALLDATACOPY:
   297  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
   298  
   299  		words := toWordSize(stack.data[stack.len()-3])
   300  		gas.Add(gas, words.Mul(words, big.NewInt(3)))
   301  
   302  		quadMemGas(mem, newMemSize, gas)
   303  	case CODECOPY:
   304  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
   305  
   306  		words := toWordSize(stack.data[stack.len()-3])
   307  		gas.Add(gas, words.Mul(words, big.NewInt(3)))
   308  
   309  		quadMemGas(mem, newMemSize, gas)
   310  	case EXTCODECOPY:
   311  		gas.Set(gasTable.ExtcodeCopy)
   312  
   313  		newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
   314  
   315  		words := toWordSize(stack.data[stack.len()-4])
   316  		gas.Add(gas, words.Mul(words, big.NewInt(3)))
   317  
   318  		quadMemGas(mem, newMemSize, gas)
   319  	case CREATE:
   320  		newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
   321  
   322  		quadMemGas(mem, newMemSize, gas)
   323  	case CALL, CALLCODE:
   324  		gas.Set(gasTable.Calls)
   325  
   326  		if op == CALL {
   327  			if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) {
   328  				gas.Add(gas, big.NewInt(25000))
   329  			}
   330  		}
   331  		if len(stack.data[stack.len()-3].Bytes()) > 0 {
   332  			gas.Add(gas, big.NewInt(9000))
   333  		}
   334  		x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
   335  		y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
   336  
   337  		newMemSize = common.BigMax(x, y)
   338  
   339  		quadMemGas(mem, newMemSize, gas)
   340  
   341  		cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1])
   342  		// Replace the stack item with the new gas calculation. This means that
   343  		// either the original item is left on the stack or the item is replaced by:
   344  		// (availableGas - gas) * 63 / 64
   345  		// We replace the stack item so that it's available when the opCall instruction is
   346  		// called. This information is otherwise lost due to the dependency on *current*
   347  		// available gas.
   348  		stack.data[stack.len()-1] = cg
   349  		gas.Add(gas, cg)
   350  
   351  	case DELEGATECALL:
   352  		gas.Set(gasTable.Calls)
   353  
   354  		x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6])
   355  		y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4])
   356  
   357  		newMemSize = common.BigMax(x, y)
   358  
   359  		quadMemGas(mem, newMemSize, gas)
   360  
   361  		cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1])
   362  		// Replace the stack item with the new gas calculation. This means that
   363  		// either the original item is left on the stack or the item is replaced by:
   364  		// (availableGas - gas) * 63 / 64
   365  		// We replace the stack item so that it's available when the opCall instruction is
   366  		// called.
   367  		stack.data[stack.len()-1] = cg
   368  		gas.Add(gas, cg)
   369  
   370  	}
   371  
   372  	return newMemSize, gas, nil
   373  }
   374  
   375  // RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
   376  func (evm *EVM) RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Contract) (ret []byte, err error) {
   377  	gas := p.Gas(len(input))
   378  	if contract.UseGas(gas) {
   379  		ret = p.Call(input)
   380  
   381  		return ret, nil
   382  	} else {
   383  		return nil, OutOfGasError
   384  	}
   385  }