// Copyright 2015 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package vm import ( "errors" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) var ( bigZero = new(big.Int) tt255 = math.BigPow(2, 255) tt256 = math.BigPow(2, 256) errWriteProtection = errors.New("evm: write protection") errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") errExecutionReverted = errors.New("evm: execution reverted") errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(math.U256(x.Add(x, y))) evm.interpreter.intPool.put(y) return nil, nil } func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(math.U256(x.Sub(x, y))) evm.interpreter.intPool.put(y) return nil, nil } func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(math.U256(x.Mul(x, y))) evm.interpreter.intPool.put(y) return nil, nil } func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Sign() != 0 { stack.push(math.U256(x.Div(x, y))) } else { stack.push(new(big.Int)) } evm.interpreter.intPool.put(y) return nil, nil } func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := math.S256(stack.pop()), math.S256(stack.pop()) if y.Sign() == 0 { stack.push(new(big.Int)) return nil, nil } else { n := new(big.Int) if evm.interpreter.intPool.get().Mul(x, y).Sign() < 0 { n.SetInt64(-1) } else { n.SetInt64(1) } res := x.Div(x.Abs(x), y.Abs(y)) res.Mul(res, n) stack.push(math.U256(res)) } evm.interpreter.intPool.put(y) return nil, nil } func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Sign() == 0 { stack.push(new(big.Int)) } else { stack.push(math.U256(x.Mod(x, y))) } evm.interpreter.intPool.put(y) return nil, nil } func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := math.S256(stack.pop()), math.S256(stack.pop()) if y.Sign() == 0 { stack.push(new(big.Int)) } else { n := new(big.Int) if x.Sign() < 0 { n.SetInt64(-1) } else { n.SetInt64(1) } res := x.Mod(x.Abs(x), y.Abs(y)) res.Mul(res, n) stack.push(math.U256(res)) } evm.interpreter.intPool.put(y) return nil, nil } func opExp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { base, exponent := stack.pop(), stack.pop() stack.push(math.Exp(base, exponent)) evm.interpreter.intPool.put(base, exponent) return nil, nil } func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { back := stack.pop() if back.Cmp(big.NewInt(31)) < 0 { bit := uint(back.Uint64()*8 + 7) num := stack.pop() mask := back.Lsh(common.Big1, bit) mask.Sub(mask, common.Big1) if num.Bit(int(bit)) > 0 { num.Or(num, mask.Not(mask)) } else { num.And(num, mask) } stack.push(math.U256(num)) } evm.interpreter.intPool.put(back) return nil, nil } func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x := stack.pop() stack.push(math.U256(x.Not(x))) return nil, nil } func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) < 0 { stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) } evm.interpreter.intPool.put(x, y) return nil, nil } func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) > 0 { stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) } evm.interpreter.intPool.put(x, y) return nil, nil } func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.peek() xSign := x.Cmp(tt255) ySign := y.Cmp(tt255) switch { case xSign >= 0 && ySign < 0: y.SetUint64(1) case xSign < 0 && ySign >= 0: y.SetUint64(0) default: if x.Cmp(y) < 0 { y.SetUint64(1) } else { y.SetUint64(0) } } evm.interpreter.intPool.put(x) return nil, nil } func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.peek() xSign := x.Cmp(tt255) ySign := y.Cmp(tt255) switch { case xSign >= 0 && ySign < 0: y.SetUint64(0) case xSign < 0 && ySign >= 0: y.SetUint64(1) default: if x.Cmp(y) > 0 { y.SetUint64(1) } else { y.SetUint64(0) } } evm.interpreter.intPool.put(x) return nil, nil } func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.peek() if x.Cmp(y) == 0 { y.SetUint64(1) } else { y.SetUint64(0) } evm.interpreter.intPool.put(x) return nil, nil } func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x := stack.peek() if x.Sign() > 0 { x.SetUint64(0) } else { x.SetUint64(1) } return nil, nil } func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.And(x, y)) evm.interpreter.intPool.put(y) return nil, nil } func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Or(x, y)) evm.interpreter.intPool.put(y) return nil, nil } func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Xor(x, y)) evm.interpreter.intPool.put(y) return nil, nil } func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { th, val := stack.pop(), stack.peek() if th.Cmp(common.Big32) < 0 { b := math.Byte(val, 32, int(th.Int64())) val.SetUint64(uint64(b)) } else { val.SetUint64(0) } evm.interpreter.intPool.put(th) return nil, nil } func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { add := x.Add(x, y) add.Mod(add, z) stack.push(math.U256(add)) } else { stack.push(new(big.Int)) } evm.interpreter.intPool.put(y, z) return nil, nil } func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { mul := x.Mul(x, y) mul.Mod(mul, z) stack.push(math.U256(mul)) } else { stack.push(new(big.Int)) } evm.interpreter.intPool.put(y, z) return nil, nil } // opSHL implements Shift Left // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the left by arg1 number of bits. func opSHL(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := math.U256(stack.pop()), math.U256(stack.peek()) defer evm.interpreter.intPool.put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) return nil, nil } n := uint(shift.Uint64()) math.U256(value.Lsh(value, n)) return nil, nil } // opSHR implements Logical Shift Right // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. func opSHR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := math.U256(stack.pop()), math.U256(stack.peek()) defer evm.interpreter.intPool.put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) return nil, nil } n := uint(shift.Uint64()) math.U256(value.Rsh(value, n)) return nil, nil } // opSAR implements Arithmetic Shift Right // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. func opSAR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one shift, value := math.U256(stack.pop()), math.S256(stack.pop()) defer evm.interpreter.intPool.put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { if value.Sign() > 0 { value.SetUint64(0) } else { value.SetInt64(-1) } stack.push(math.U256(value)) return nil, nil } n := uint(shift.Uint64()) value.Rsh(value, n) stack.push(math.U256(value)) return nil, nil } func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() data := memory.Get(offset.Int64(), size.Int64()) hash := crypto.Keccak256(data) if evm.vmConfig.EnablePreimageRecording { evm.StateDB.AddPreimage(common.BytesToHash(hash), data) } stack.push(new(big.Int).SetBytes(hash)) evm.interpreter.intPool.put(offset, size) return nil, nil } func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(contract.Address().Big()) return nil, nil } func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { addr := common.BigToAddress(stack.pop()) balance := evm.StateDB.GetBalance(addr) stack.push(new(big.Int).Set(balance)) return nil, nil } func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.Origin.Big()) return nil, nil } func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(contract.Caller().Big()) return nil, nil } func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().Set(contract.value)) return nil, nil } func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(new(big.Int).SetBytes(getDataBig(contract.Input, stack.pop(), big32))) return nil, nil } func opCallDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) return nil, nil } func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( memOffset = stack.pop() dataOffset = stack.pop() length = stack.pop() ) memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length)) evm.interpreter.intPool.put(memOffset, dataOffset, length) return nil, nil } func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData)))) return nil, nil } func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( memOffset = stack.pop() dataOffset = stack.pop() length = stack.pop() ) defer evm.interpreter.intPool.put(memOffset, dataOffset, length) end := new(big.Int).Add(dataOffset, length) if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() { return nil, errReturnDataOutOfBounds } memory.Set(memOffset.Uint64(), length.Uint64(), evm.interpreter.returnData[dataOffset.Uint64():end.Uint64()]) return nil, nil } func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { a := stack.pop() addr := common.BigToAddress(a) a.SetInt64(int64(evm.StateDB.GetCodeSize(addr))) stack.push(a) return nil, nil } func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code))) stack.push(l) return nil, nil } func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( memOffset = stack.pop() codeOffset = stack.pop() length = stack.pop() ) codeCopy := getDataBig(contract.Code, codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) evm.interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil } func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( addr = common.BigToAddress(stack.pop()) memOffset = stack.pop() codeOffset = stack.pop() length = stack.pop() ) codeCopy := getDataBig(evm.StateDB.GetCode(addr), codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) evm.interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil } func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice)) return nil, nil } func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { num := stack.pop() n := evm.interpreter.intPool.get().Sub(evm.BlockNumber, common.Big257) if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 { stack.push(evm.GetHash(num.Uint64()).Big()) } else { stack.push(new(big.Int)) } evm.interpreter.intPool.put(num, n) return nil, nil } func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.Coinbase.Big()) return nil, nil } func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(math.U256(new(big.Int).Set(evm.Time))) return nil, nil } func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(math.U256(new(big.Int).Set(evm.BlockNumber))) return nil, nil } func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(math.U256(new(big.Int).Set(evm.Difficulty))) return nil, nil } func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(math.U256(new(big.Int).SetUint64(evm.GasLimit))) return nil, nil } func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { evm.interpreter.intPool.put(stack.pop()) return nil, nil } func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset := stack.pop() val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32)) stack.push(val) evm.interpreter.intPool.put(offset) return nil, nil } func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // pop value of the stack mStart, val := stack.pop(), stack.pop() memory.Set(mStart.Uint64(), 32, math.PaddedBigBytes(val, 32)) evm.interpreter.intPool.put(mStart, val) return nil, nil } func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { off, val := stack.pop().Int64(), stack.pop().Int64() memory.store[off] = byte(val & 0xff) return nil, nil } func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) val := evm.StateDB.GetState(contract.Address(), loc).Big() stack.push(val) return nil, nil } func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) val := stack.pop() evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) evm.interpreter.intPool.put(val) return nil, nil } func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos := stack.pop() if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { nop := contract.GetOp(pos.Uint64()) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } *pc = pos.Uint64() evm.interpreter.intPool.put(pos) return nil, nil } func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos, cond := stack.pop(), stack.pop() if cond.Sign() != 0 { if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { nop := contract.GetOp(pos.Uint64()) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } *pc = pos.Uint64() } else { *pc++ } evm.interpreter.intPool.put(pos, cond) return nil, nil } func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().SetUint64(*pc)) return nil, nil } func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len()))) return nil, nil } func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().SetUint64(contract.Gas)) return nil, nil } func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( value = stack.pop() offset, size = stack.pop(), stack.pop() input = memory.Get(offset.Int64(), size.Int64()) gas = contract.Gas ) if evm.ChainConfig().IsEIP150(evm.BlockNumber) { gas -= gas / 64 } contract.UseGas(gas) res, addr, returnGas, suberr := evm.Create(contract, input, gas, value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { stack.push(new(big.Int)) } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stack.push(new(big.Int)) } else { stack.push(addr.Big()) } contract.Gas += returnGas evm.interpreter.intPool.put(value, offset, size) if suberr == errExecutionReverted { return res, nil } return nil, nil } func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // Pop gas. The actual gas in in evm.callGasTemp. evm.interpreter.intPool.put(stack.pop()) gas := evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) value = math.U256(value) // Get the arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) if value.Sign() != 0 { gas += params.CallStipend } ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value) if err != nil { stack.push(new(big.Int)) } else { stack.push(big.NewInt(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // Pop gas. The actual gas is in evm.callGasTemp. evm.interpreter.intPool.put(stack.pop()) gas := evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) value = math.U256(value) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) if value.Sign() != 0 { gas += params.CallStipend } ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value) if err != nil { stack.push(new(big.Int)) } else { stack.push(big.NewInt(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // Pop gas. The actual gas is in evm.callGasTemp. evm.interpreter.intPool.put(stack.pop()) gas := evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas) if err != nil { stack.push(new(big.Int)) } else { stack.push(big.NewInt(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // Pop gas. The actual gas is in evm.callGasTemp. evm.interpreter.intPool.put(stack.pop()) gas := evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas) if err != nil { stack.push(new(big.Int)) } else { stack.push(big.NewInt(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) evm.interpreter.intPool.put(offset, size) return ret, nil } func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) evm.interpreter.intPool.put(offset, size) return ret, nil } func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { balance := evm.StateDB.GetBalance(contract.Address()) evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) evm.StateDB.Suicide(contract.Address()) return nil, nil } // following functions are used by the instruction jump table // make log instruction function func makeLog(size int) executionFunc { return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { topics := make([]common.Hash, size) mStart, mSize := stack.pop(), stack.pop() for i := 0; i < size; i++ { topics[i] = common.BigToHash(stack.pop()) } d := memory.Get(mStart.Int64(), mSize.Int64()) evm.StateDB.AddLog(&types.Log{ Address: contract.Address(), Topics: topics, Data: d, // This is a non-consensus field, but assigned here because // core/state doesn't know the current block number. BlockNumber: evm.BlockNumber.Uint64(), }) evm.interpreter.intPool.put(mStart, mSize) return nil, nil } } // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { codeLen := len(contract.Code) startMin := codeLen if int(*pc+1) < startMin { startMin = int(*pc + 1) } endMin := codeLen if startMin+pushByteSize < endMin { endMin = startMin + pushByteSize } integer := evm.interpreter.intPool.get() stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) *pc += size return nil, nil } } // make push instruction function func makeDup(size int64) executionFunc { return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.dup(evm.interpreter.intPool, int(size)) return nil, nil } } // make swap instruction function func makeSwap(size int64) executionFunc { // switch n + 1 otherwise n would be swapped with n size += 1 return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.swap(int(size)) return nil, nil } }