github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/vm/instructions.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 vm
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereumproject/go-ethereum/common"
    23  	"github.com/ethereumproject/go-ethereum/crypto"
    24  )
    25  
    26  var callStipend = big.NewInt(2300) // Free gas given at beginning of call.
    27  
    28  type instrFn func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack)
    29  
    30  type instruction struct {
    31  	op   OpCode
    32  	pc   uint64
    33  	fn   instrFn
    34  	data *big.Int
    35  
    36  	gas   *big.Int
    37  	spop  int
    38  	spush int
    39  
    40  	returns bool
    41  }
    42  
    43  func (instr instruction) halts() bool {
    44  	return instr.returns
    45  }
    46  
    47  func (instr instruction) Op() OpCode {
    48  	return instr.op
    49  }
    50  
    51  func opAdd(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
    52  	x, y := stack.pop(), stack.pop()
    53  	stack.push(U256(x.Add(x, y)))
    54  }
    55  
    56  func opSub(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
    57  	x, y := stack.pop(), stack.pop()
    58  	stack.push(U256(x.Sub(x, y)))
    59  }
    60  
    61  func opMul(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
    62  	x, y := stack.pop(), stack.pop()
    63  	stack.push(U256(x.Mul(x, y)))
    64  }
    65  
    66  func opDiv(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
    67  	x, y := stack.pop(), stack.pop()
    68  	if y.Sign() != 0 {
    69  		stack.push(U256(x.Div(x, y)))
    70  	} else {
    71  		stack.push(new(big.Int))
    72  	}
    73  }
    74  
    75  func opSdiv(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
    76  	x, y := S256(stack.pop()), S256(stack.pop())
    77  	if y.Sign() == 0 {
    78  		stack.push(new(big.Int))
    79  		return
    80  	} else {
    81  		n := new(big.Int)
    82  		if new(big.Int).Mul(x, y).Sign() < 0 {
    83  			n.SetInt64(-1)
    84  		} else {
    85  			n.SetInt64(1)
    86  		}
    87  
    88  		res := x.Div(x.Abs(x), y.Abs(y))
    89  		res.Mul(res, n)
    90  
    91  		stack.push(U256(res))
    92  	}
    93  }
    94  
    95  func opMod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
    96  	x, y := stack.pop(), stack.pop()
    97  	if y.Sign() == 0 {
    98  		stack.push(new(big.Int))
    99  	} else {
   100  		stack.push(U256(x.Mod(x, y)))
   101  	}
   102  }
   103  
   104  func opSmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   105  	x, y := S256(stack.pop()), S256(stack.pop())
   106  
   107  	if y.Sign() == 0 {
   108  		stack.push(new(big.Int))
   109  	} else {
   110  		n := new(big.Int)
   111  		if x.Sign() < 0 {
   112  			n.SetInt64(-1)
   113  		} else {
   114  			n.SetInt64(1)
   115  		}
   116  
   117  		res := x.Mod(x.Abs(x), y.Abs(y))
   118  		res.Mul(res, n)
   119  
   120  		stack.push(U256(res))
   121  	}
   122  }
   123  
   124  func opExp(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   125  	x, y := stack.pop(), stack.pop()
   126  	stack.push(U256(x.Exp(x, y, Pow256)))
   127  }
   128  
   129  func opSignExtend(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   130  	back := stack.pop()
   131  	if back.Cmp(big.NewInt(31)) < 0 {
   132  		bit := uint(back.Uint64()*8 + 7)
   133  		num := stack.pop()
   134  		mask := back.Lsh(common.Big1, bit)
   135  		mask.Sub(mask, common.Big1)
   136  		if common.BitTest(num, int(bit)) {
   137  			num.Or(num, mask.Not(mask))
   138  		} else {
   139  			num.And(num, mask)
   140  		}
   141  
   142  		stack.push(U256(num))
   143  	}
   144  }
   145  
   146  func opNot(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   147  	x := stack.pop()
   148  	stack.push(U256(x.Not(x)))
   149  }
   150  
   151  func opLt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   152  	x, y := stack.pop(), stack.pop()
   153  	if x.Cmp(y) < 0 {
   154  		stack.push(big.NewInt(1))
   155  	} else {
   156  		stack.push(new(big.Int))
   157  	}
   158  }
   159  
   160  func opGt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   161  	x, y := stack.pop(), stack.pop()
   162  	if x.Cmp(y) > 0 {
   163  		stack.push(big.NewInt(1))
   164  	} else {
   165  		stack.push(new(big.Int))
   166  	}
   167  }
   168  
   169  func opSlt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   170  	x, y := S256(stack.pop()), S256(stack.pop())
   171  	if x.Cmp(S256(y)) < 0 {
   172  		stack.push(big.NewInt(1))
   173  	} else {
   174  		stack.push(new(big.Int))
   175  	}
   176  }
   177  
   178  func opSgt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   179  	x, y := S256(stack.pop()), S256(stack.pop())
   180  	if x.Cmp(y) > 0 {
   181  		stack.push(big.NewInt(1))
   182  	} else {
   183  		stack.push(new(big.Int))
   184  	}
   185  }
   186  
   187  func opEq(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   188  	x, y := stack.pop(), stack.pop()
   189  	if x.Cmp(y) == 0 {
   190  		stack.push(big.NewInt(1))
   191  	} else {
   192  		stack.push(new(big.Int))
   193  	}
   194  }
   195  
   196  func opIszero(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   197  	x := stack.pop()
   198  	if x.Sign() != 0 {
   199  		stack.push(new(big.Int))
   200  	} else {
   201  		stack.push(big.NewInt(1))
   202  	}
   203  }
   204  
   205  func opAnd(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   206  	x, y := stack.pop(), stack.pop()
   207  	stack.push(x.And(x, y))
   208  }
   209  func opOr(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   210  	x, y := stack.pop(), stack.pop()
   211  	stack.push(x.Or(x, y))
   212  }
   213  func opXor(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   214  	x, y := stack.pop(), stack.pop()
   215  	stack.push(x.Xor(x, y))
   216  }
   217  func opByte(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   218  	th, val := stack.pop(), stack.pop()
   219  	if th.Cmp(big.NewInt(32)) < 0 {
   220  		byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
   221  		stack.push(byte)
   222  	} else {
   223  		stack.push(new(big.Int))
   224  	}
   225  }
   226  func opAddmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   227  	x, y, z := stack.pop(), stack.pop(), stack.pop()
   228  	if z.Sign() > 0 {
   229  		add := x.Add(x, y)
   230  		add.Mod(add, z)
   231  		stack.push(U256(add))
   232  	} else {
   233  		stack.push(new(big.Int))
   234  	}
   235  }
   236  func opMulmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   237  	x, y, z := stack.pop(), stack.pop(), stack.pop()
   238  	if z.Sign() > 0 {
   239  		mul := x.Mul(x, y)
   240  		mul.Mod(mul, z)
   241  		stack.push(U256(mul))
   242  	} else {
   243  		stack.push(new(big.Int))
   244  	}
   245  }
   246  
   247  func opSha3(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   248  	offset, size := stack.pop(), stack.pop()
   249  	hash := crypto.Keccak256(memory.Get(offset.Int64(), size.Int64()))
   250  
   251  	stack.push(new(big.Int).SetBytes(hash))
   252  }
   253  
   254  func opAddress(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   255  	stack.push(new(big.Int).SetBytes(contract.Address().Bytes()))
   256  }
   257  
   258  func opBalance(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   259  	addr := common.BigToAddress(stack.pop())
   260  	balance := env.Db().GetBalance(addr)
   261  
   262  	stack.push(new(big.Int).Set(balance))
   263  }
   264  
   265  func opOrigin(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   266  	stack.push(env.Origin().Big())
   267  }
   268  
   269  func opCaller(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   270  	stack.push(contract.Caller().Big())
   271  }
   272  
   273  func opCallValue(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   274  	stack.push(new(big.Int).Set(contract.value))
   275  }
   276  
   277  func opCalldataLoad(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   278  	stack.push(new(big.Int).SetBytes(getData(contract.Input, stack.pop(), common.Big32)))
   279  }
   280  
   281  func opCalldataSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   282  	stack.push(big.NewInt(int64(len(contract.Input))))
   283  }
   284  
   285  func opCalldataCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   286  	var (
   287  		mOff = stack.pop()
   288  		cOff = stack.pop()
   289  		l    = stack.pop()
   290  	)
   291  	memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l))
   292  }
   293  
   294  func opExtCodeSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   295  	addr := common.BigToAddress(stack.pop())
   296  	l := big.NewInt(int64(env.Db().GetCodeSize(addr)))
   297  	stack.push(l)
   298  }
   299  
   300  func opCodeSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   301  	l := big.NewInt(int64(len(contract.Code)))
   302  	stack.push(l)
   303  }
   304  
   305  func opCodeCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   306  	var (
   307  		mOff = stack.pop()
   308  		cOff = stack.pop()
   309  		l    = stack.pop()
   310  	)
   311  	codeCopy := getData(contract.Code, cOff, l)
   312  
   313  	memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
   314  }
   315  
   316  func opExtCodeCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   317  	var (
   318  		addr = common.BigToAddress(stack.pop())
   319  		mOff = stack.pop()
   320  		cOff = stack.pop()
   321  		l    = stack.pop()
   322  	)
   323  	codeCopy := getData(env.Db().GetCode(addr), cOff, l)
   324  
   325  	memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
   326  }
   327  
   328  func opGasprice(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   329  	stack.push(new(big.Int).Set(contract.Price))
   330  }
   331  
   332  func opBlockhash(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   333  	num := stack.pop()
   334  
   335  	n := new(big.Int).Sub(env.BlockNumber(), common.Big257)
   336  	if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber()) < 0 {
   337  		stack.push(env.GetHash(num.Uint64()).Big())
   338  	} else {
   339  		stack.push(new(big.Int))
   340  	}
   341  }
   342  
   343  func opCoinbase(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   344  	stack.push(env.Coinbase().Big())
   345  }
   346  
   347  func opTimestamp(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   348  	stack.push(U256(new(big.Int).Set(env.Time())))
   349  }
   350  
   351  func opNumber(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   352  	stack.push(U256(new(big.Int).Set(env.BlockNumber())))
   353  }
   354  
   355  func opDifficulty(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   356  	stack.push(U256(new(big.Int).Set(env.Difficulty())))
   357  }
   358  
   359  func opGasLimit(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   360  	stack.push(U256(new(big.Int).Set(env.GasLimit())))
   361  }
   362  
   363  func opPop(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   364  	stack.pop()
   365  }
   366  
   367  func opMload(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   368  	offset := stack.pop()
   369  	val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32))
   370  	stack.push(val)
   371  }
   372  
   373  func opMstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   374  	// pop value of the stack
   375  	mStart, val := stack.pop(), stack.pop()
   376  	memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
   377  }
   378  
   379  func opMstore8(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   380  	off, val := stack.pop().Int64(), stack.pop().Int64()
   381  	memory.store[off] = byte(val & 0xff)
   382  }
   383  
   384  func opSload(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   385  	loc := common.BigToHash(stack.pop())
   386  	val := env.Db().GetState(contract.Address(), loc).Big()
   387  	stack.push(val)
   388  }
   389  
   390  func opSstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   391  	loc := common.BigToHash(stack.pop())
   392  	val := stack.pop()
   393  	env.Db().SetState(contract.Address(), loc, common.BigToHash(val))
   394  }
   395  
   396  func opJumpdest(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   397  }
   398  
   399  func opPc(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   400  	stack.push(new(big.Int).Set(instr.data))
   401  }
   402  
   403  func opMsize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   404  	stack.push(big.NewInt(int64(memory.Len())))
   405  }
   406  
   407  func opGas(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   408  	stack.push(new(big.Int).Set(contract.Gas))
   409  }
   410  
   411  func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   412  	var (
   413  		value        = stack.pop()
   414  		offset, size = stack.pop(), stack.pop()
   415  		input        = memory.Get(offset.Int64(), size.Int64())
   416  		gas          = new(big.Int).Set(contract.Gas)
   417  	)
   418  	if env.RuleSet().GasTable(env.BlockNumber()).CreateBySuicide != nil {
   419  		gas.Div(gas, n64)
   420  		gas = gas.Sub(contract.Gas, gas)
   421  	}
   422  
   423  	contract.UseGas(gas)
   424  	_, addr, suberr := env.Create(contract, input, gas, contract.Price, value)
   425  	// Push item on the stack based on the returned error. If the ruleset is
   426  	// homestead we must check for CodeStoreOutOfGasError (homestead only
   427  	// rule) and treat as an error, if the ruleset is frontier we must
   428  	// ignore this error and pretend the operation was successful.
   429  	if env.RuleSet().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError {
   430  		stack.push(new(big.Int))
   431  	} else if suberr != nil && suberr != CodeStoreOutOfGasError {
   432  		stack.push(new(big.Int))
   433  	} else {
   434  		stack.push(addr.Big())
   435  	}
   436  }
   437  
   438  func opCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   439  	gas := stack.pop()
   440  	// pop gas and value of the stack.
   441  	addr, value := stack.pop(), stack.pop()
   442  	value = U256(value)
   443  	// pop input size and offset
   444  	inOffset, inSize := stack.pop(), stack.pop()
   445  	// pop return size and offset
   446  	retOffset, retSize := stack.pop(), stack.pop()
   447  
   448  	address := common.BigToAddress(addr)
   449  
   450  	// Get the arguments from the memory
   451  	args := memory.Get(inOffset.Int64(), inSize.Int64())
   452  
   453  	if len(value.Bytes()) > 0 {
   454  		gas.Add(gas, callStipend)
   455  	}
   456  
   457  	ret, err := env.Call(contract, address, args, gas, contract.Price, value)
   458  
   459  	if err != nil {
   460  		stack.push(new(big.Int))
   461  
   462  	} else {
   463  		stack.push(big.NewInt(1))
   464  
   465  		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
   466  	}
   467  }
   468  
   469  func opCallCode(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   470  	gas := stack.pop()
   471  	// pop gas and value of the stack.
   472  	addr, value := stack.pop(), stack.pop()
   473  	value = U256(value)
   474  	// pop input size and offset
   475  	inOffset, inSize := stack.pop(), stack.pop()
   476  	// pop return size and offset
   477  	retOffset, retSize := stack.pop(), stack.pop()
   478  
   479  	address := common.BigToAddress(addr)
   480  
   481  	// Get the arguments from the memory
   482  	args := memory.Get(inOffset.Int64(), inSize.Int64())
   483  
   484  	if len(value.Bytes()) > 0 {
   485  		gas.Add(gas, callStipend)
   486  	}
   487  
   488  	ret, err := env.CallCode(contract, address, args, gas, contract.Price, value)
   489  
   490  	if err != nil {
   491  		stack.push(new(big.Int))
   492  
   493  	} else {
   494  		stack.push(big.NewInt(1))
   495  
   496  		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
   497  	}
   498  }
   499  
   500  func opDelegateCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   501  	gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
   502  
   503  	toAddr := common.BigToAddress(to)
   504  	args := memory.Get(inOffset.Int64(), inSize.Int64())
   505  	ret, err := env.DelegateCall(contract, toAddr, args, gas, contract.Price)
   506  	if err != nil {
   507  		stack.push(new(big.Int))
   508  	} else {
   509  		stack.push(big.NewInt(1))
   510  		memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
   511  	}
   512  }
   513  
   514  func opSuicide(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   515  	balance := env.Db().GetBalance(contract.Address())
   516  	env.Db().AddBalance(common.BigToAddress(stack.pop()), balance)
   517  
   518  	env.Db().Suicide(contract.Address())
   519  }
   520  
   521  // following functions are used by the instruction jump  table
   522  
   523  // make log instruction function
   524  func makeLog(size int) instrFn {
   525  	return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   526  		topics := make([]common.Hash, size)
   527  		mStart, mSize := stack.pop(), stack.pop()
   528  		for i := 0; i < size; i++ {
   529  			topics[i] = common.BigToHash(stack.pop())
   530  		}
   531  
   532  		d := memory.Get(mStart.Int64(), mSize.Int64())
   533  		log := NewLog(contract.Address(), topics, d, env.BlockNumber().Uint64())
   534  		env.AddLog(log)
   535  	}
   536  }
   537  
   538  // make push instruction function
   539  func makePush(size uint64, bsize *big.Int) instrFn {
   540  	return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   541  		bytes := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize)
   542  		stack.push(new(big.Int).SetBytes(bytes))
   543  		*pc += size
   544  	}
   545  }
   546  
   547  // make push instruction function
   548  func makeDup(size int64) instrFn {
   549  	return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   550  		stack.dup(int(size))
   551  	}
   552  }
   553  
   554  // make swap instruction function
   555  func makeSwap(size int64) instrFn {
   556  	// switch n + 1 otherwise n would be swapped with n
   557  	size += 1
   558  	return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
   559  		stack.swap(int(size))
   560  	}
   561  }