Official Go implementation of the Ethereum protocol
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-ethereum/core/vm/vm.go

865 lines
22 KiB

// Copyright 2014 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 <http://www.gnu.org/licenses/>.
// Package vm implements the Ethereum Virtual Machine.
10 years ago
package vm
10 years ago
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
10 years ago
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
10 years ago
)
// Vm implements VirtualMachine
type Vm struct {
10 years ago
env Environment
}
// New returns a new Virtual Machine
10 years ago
func New(env Environment) *Vm {
return &Vm{env: env}
10 years ago
}
// Run loops and evaluates the contract's code with the given input data
func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
10 years ago
self.env.SetDepth(self.env.Depth() + 1)
10 years ago
defer self.env.SetDepth(self.env.Depth() - 1)
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
defer func() {
if err != nil {
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
context.UseGas(context.Gas)
ret = context.Return(nil)
}
}()
if context.CodeAddr != nil {
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
return self.RunPrecompiled(p, input, context)
}
}
var (
codehash = crypto.Sha3Hash(context.Code) // codehash is used when doing jump dest caching
program *Program
)
if EnableJit {
// Fetch program status.
// * If ready run using JIT
// * If unknown, compile in a seperate goroutine
// * If forced wait for compilation and run once done
if status := GetProgramStatus(codehash); status == progReady {
return RunProgram(GetProgram(codehash), self.env, context, input)
} else if status == progUnknown {
if ForceJit {
// Create and compile program
program = NewProgram(context.Code)
perr := CompileProgram(program)
if perr == nil {
return RunProgram(program, self.env, context, input)
}
glog.V(logger.Info).Infoln("error compiling program", err)
} else {
// create and compile the program. Compilation
// is done in a seperate goroutine
program = NewProgram(context.Code)
go func() {
err := CompileProgram(program)
if err != nil {
glog.V(logger.Info).Infoln("error compiling program", err)
return
}
}()
}
}
}
var (
caller = context.caller
code = context.Code
value = context.value
price = context.Price
op OpCode // current opcode
mem = NewMemory() // bound memory
stack = newstack() // local stack
statedb = self.env.State() // current state
// For optimisation reason we're using uint64 as the program counter.
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Pratically much less so feasible.
pc = uint64(0) // program counter
// jump evaluates and checks whether the given jump destination is a valid one
// if valid move the `pc` otherwise return an error.
jump = func(from uint64, to *big.Int) error {
if !context.jumpdests.has(codehash, code, to) {
nop := context.GetOp(to.Uint64())
return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
}
pc = to.Uint64()
return nil
}
newMemSize *big.Int
cost *big.Int
)
10 years ago
10 years ago
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
defer func() {
if err != nil {
self.log(pc, op, context.Gas, cost, mem, stack, context, err)
}
}()
10 years ago
// Don't bother with the execution if there's no code.
if len(code) == 0 {
return context.Return(nil), nil
}
10 years ago
for {
// Overhead of the atomic read might not be worth it
/* TODO this still causes a few issues in the tests
if program != nil && progStatus(atomic.LoadInt32(&program.status)) == progReady {
// move execution
glog.V(logger.Info).Infoln("Moved execution to JIT")
return runProgram(program, pc, mem, stack, self.env, context, input)
}
*/
10 years ago
// The base for all big integer arithmetic
base := new(big.Int)
// Get the memory location of pc
op = context.GetOp(pc)
// calculate the new memory size and gas price for the current executing opcode
newMemSize, cost, err = calculateGasAndSize(self.env, context, caller, op, statedb, mem, stack)
if err != nil {
return nil, err
}
10 years ago
// Use the calculated gas. When insufficient gas is present, use all gas and return an
// Out Of Gas error
if !context.UseGas(cost) {
return nil, OutOfGasError
10 years ago
}
// Resize the memory calculated previously
10 years ago
mem.Resize(newMemSize.Uint64())
// Add a log message
self.log(pc, op, context.Gas, cost, mem, stack, context, nil)
10 years ago
switch op {
case ADD:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
base.Add(x, y)
10 years ago
U256(base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case SUB:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
base.Sub(x, y)
10 years ago
U256(base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case MUL:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
base.Mul(x, y)
10 years ago
U256(base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case DIV:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
if y.Cmp(common.Big0) != 0 {
10 years ago
base.Div(x, y)
}
U256(base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case SDIV:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
10 years ago
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
10 years ago
} else {
n := new(big.Int)
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
10 years ago
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Div(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
10 years ago
stack.push(base)
10 years ago
case MOD:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
10 years ago
} else {
base.Mod(x, y)
}
U256(base)
10 years ago
stack.push(base)
10 years ago
case SMOD:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
10 years ago
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
10 years ago
} else {
n := new(big.Int)
if x.Cmp(common.Big0) < 0 {
10 years ago
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
10 years ago
stack.push(base)
10 years ago
case EXP:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
base.Exp(x, y, Pow256)
10 years ago
U256(base)
10 years ago
stack.push(base)
10 years ago
case SIGNEXTEND:
10 years ago
back := stack.pop()
if back.Cmp(big.NewInt(31)) < 0 {
bit := uint(back.Uint64()*8 + 7)
10 years ago
num := stack.pop()
mask := new(big.Int).Lsh(common.Big1, bit)
mask.Sub(mask, common.Big1)
if common.BitTest(num, int(bit)) {
10 years ago
num.Or(num, mask.Not(mask))
} else {
num.And(num, mask)
}
num = U256(num)
10 years ago
stack.push(num)
10 years ago
}
case NOT:
stack.push(U256(new(big.Int).Not(stack.pop())))
10 years ago
case LT:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
// x < y
10 years ago
if x.Cmp(y) < 0 {
stack.push(common.BigTrue)
10 years ago
} else {
stack.push(common.BigFalse)
10 years ago
}
case GT:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
// x > y
10 years ago
if x.Cmp(y) > 0 {
stack.push(common.BigTrue)
10 years ago
} else {
stack.push(common.BigFalse)
10 years ago
}
case SLT:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
10 years ago
// x < y
10 years ago
if x.Cmp(S256(y)) < 0 {
stack.push(common.BigTrue)
10 years ago
} else {
stack.push(common.BigFalse)
10 years ago
}
case SGT:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
10 years ago
// x > y
10 years ago
if x.Cmp(y) > 0 {
stack.push(common.BigTrue)
10 years ago
} else {
stack.push(common.BigFalse)
10 years ago
}
case EQ:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
// x == y
if x.Cmp(y) == 0 {
stack.push(common.BigTrue)
10 years ago
} else {
stack.push(common.BigFalse)
10 years ago
}
case ISZERO:
10 years ago
x := stack.pop()
if x.Cmp(common.BigFalse) > 0 {
stack.push(common.BigFalse)
10 years ago
} else {
stack.push(common.BigTrue)
10 years ago
}
case AND:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
stack.push(base.And(x, y))
10 years ago
case OR:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
stack.push(base.Or(x, y))
10 years ago
case XOR:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
stack.push(base.Xor(x, y))
10 years ago
case BYTE:
10 years ago
th, val := stack.pop(), stack.pop()
10 years ago
if th.Cmp(big.NewInt(32)) < 0 {
byt := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
10 years ago
base.Set(byt)
} else {
base.Set(common.BigFalse)
10 years ago
}
10 years ago
stack.push(base)
10 years ago
case ADDMOD:
10 years ago
x := stack.pop()
y := stack.pop()
z := stack.pop()
10 years ago
if z.Cmp(Zero) > 0 {
add := new(big.Int).Add(x, y)
10 years ago
base.Mod(add, z)
base = U256(base)
10 years ago
}
10 years ago
stack.push(base)
10 years ago
case MULMOD:
10 years ago
x := stack.pop()
y := stack.pop()
z := stack.pop()
10 years ago
if z.Cmp(Zero) > 0 {
mul := new(big.Int).Mul(x, y)
10 years ago
base.Mod(mul, z)
U256(base)
}
10 years ago
stack.push(base)
10 years ago
case SHA3:
offset, size := stack.pop(), stack.pop()
10 years ago
data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
stack.push(common.BigD(data))
10 years ago
case ADDRESS:
10 years ago
stack.push(common.Bytes2Big(context.Address().Bytes()))
10 years ago
case BALANCE:
10 years ago
addr := common.BigToAddress(stack.pop())
balance := statedb.GetBalance(addr)
10 years ago
stack.push(new(big.Int).Set(balance))
10 years ago
case ORIGIN:
origin := self.env.Origin()
10 years ago
stack.push(origin.Big())
10 years ago
case CALLER:
caller := context.caller.Address()
10 years ago
stack.push(common.Bytes2Big(caller.Bytes()))
10 years ago
case CALLVALUE:
stack.push(new(big.Int).Set(value))
10 years ago
case CALLDATALOAD:
data := getData(input, stack.pop(), common.Big32)
10 years ago
stack.push(common.Bytes2Big(data))
10 years ago
case CALLDATASIZE:
l := int64(len(input))
10 years ago
stack.push(big.NewInt(l))
10 years ago
case CALLDATACOPY:
var (
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
10 years ago
)
data := getData(input, cOff, l)
10 years ago
mem.Set(mOff.Uint64(), l.Uint64(), data)
10 years ago
case CODESIZE, EXTCODESIZE:
var code []byte
if op == EXTCODESIZE {
10 years ago
addr := common.BigToAddress(stack.pop())
10 years ago
code = statedb.GetCode(addr)
} else {
code = context.Code
}
l := big.NewInt(int64(len(code)))
10 years ago
stack.push(l)
10 years ago
case CODECOPY, EXTCODECOPY:
var code []byte
if op == EXTCODECOPY {
10 years ago
addr := common.BigToAddress(stack.pop())
code = statedb.GetCode(addr)
10 years ago
} else {
code = context.Code
}
10 years ago
var (
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
10 years ago
)
codeCopy := getData(code, cOff, l)
mem.Set(mOff.Uint64(), l.Uint64(), codeCopy)
10 years ago
case GASPRICE:
stack.push(new(big.Int).Set(context.Price))
10 years ago
case BLOCKHASH:
10 years ago
num := stack.pop()
10 years ago
n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257)
10 years ago
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
10 years ago
stack.push(self.env.GetHash(num.Uint64()).Big())
10 years ago
} else {
stack.push(common.Big0)
10 years ago
}
case COINBASE:
coinbase := self.env.Coinbase()
10 years ago
stack.push(coinbase.Big())
10 years ago
case TIMESTAMP:
time := self.env.Time()
stack.push(new(big.Int).SetUint64(time))
10 years ago
case NUMBER:
number := self.env.BlockNumber()
10 years ago
stack.push(U256(number))
10 years ago
case DIFFICULTY:
difficulty := self.env.Difficulty()
stack.push(new(big.Int).Set(difficulty))
10 years ago
case GASLIMIT:
stack.push(new(big.Int).Set(self.env.GasLimit()))
10 years ago
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
size := uint64(op - PUSH1 + 1)
byts := getData(code, new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
10 years ago
// push value to stack
stack.push(common.Bytes2Big(byts))
pc += size
10 years ago
case POP:
10 years ago
stack.pop()
10 years ago
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
10 years ago
stack.dup(n)
10 years ago
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
10 years ago
stack.swap(n)
10 years ago
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
10 years ago
topics := make([]common.Hash, n)
10 years ago
mStart, mSize := stack.pop(), stack.pop()
10 years ago
for i := 0; i < n; i++ {
topics[i] = common.BigToHash(stack.pop())
10 years ago
}
data := mem.Get(mStart.Int64(), mSize.Int64())
log := state.NewLog(context.Address(), topics, data, self.env.BlockNumber().Uint64())
10 years ago
self.env.AddLog(log)
case MLOAD:
10 years ago
offset := stack.pop()
val := common.BigD(mem.Get(offset.Int64(), 32))
10 years ago
stack.push(val)
10 years ago
case MSTORE:
10 years ago
// pop value of the stack
mStart, val := stack.pop(), stack.pop()
mem.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
10 years ago
case MSTORE8:
off, val := stack.pop().Int64(), stack.pop().Int64()
10 years ago
mem.store[off] = byte(val & 0xff)
10 years ago
case SLOAD:
10 years ago
loc := common.BigToHash(stack.pop())
val := statedb.GetState(context.Address(), loc).Big()
10 years ago
stack.push(val)
10 years ago
case SSTORE:
10 years ago
loc := common.BigToHash(stack.pop())
val := stack.pop()
statedb.SetState(context.Address(), loc, common.BigToHash(val))
10 years ago
case JUMP:
if err := jump(pc, stack.pop()); err != nil {
return nil, err
}
10 years ago
continue
case JUMPI:
10 years ago
pos, cond := stack.pop(), stack.pop()
10 years ago
if cond.Cmp(common.BigTrue) >= 0 {
if err := jump(pc, pos); err != nil {
return nil, err
}
10 years ago
continue
}
case JUMPDEST:
case PC:
stack.push(new(big.Int).SetUint64(pc))
10 years ago
case MSIZE:
10 years ago
stack.push(big.NewInt(int64(mem.Len())))
10 years ago
case GAS:
stack.push(new(big.Int).Set(context.Gas))
10 years ago
case CREATE:
var (
10 years ago
value = stack.pop()
offset, size = stack.pop(), stack.pop()
10 years ago
input = mem.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(context.Gas)
10 years ago
addr common.Address
10 years ago
)
context.UseGas(context.Gas)
ret, suberr, ref := self.env.Create(context, input, gas, price, value)
10 years ago
if suberr != nil {
stack.push(common.BigFalse)
10 years ago
} else {
// gas < len(ret) * CreateDataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, params.CreateDataGas)
10 years ago
if context.UseGas(dataGas) {
ref.SetCode(ret)
}
addr = ref.Address()
10 years ago
stack.push(addr.Big())
10 years ago
}
case CALL, CALLCODE:
10 years ago
gas := stack.pop()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
10 years ago
value = U256(value)
10 years ago
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
10 years ago
10 years ago
address := common.BigToAddress(addr)
10 years ago
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
if len(value.Bytes()) > 0 {
gas.Add(gas, params.CallStipend)
}
10 years ago
var (
ret []byte
err error
)
if op == CALLCODE {
ret, err = self.env.CallCode(context, address, args, gas, price, value)
10 years ago
} else {
ret, err = self.env.Call(context, address, args, gas, price, value)
10 years ago
}
if err != nil {
stack.push(common.BigFalse)
10 years ago
} else {
stack.push(common.BigTrue)
10 years ago
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
10 years ago
case RETURN:
10 years ago
offset, size := stack.pop(), stack.pop()
ret := mem.GetPtr(offset.Int64(), size.Int64())
10 years ago
return context.Return(ret), nil
case SUICIDE:
10 years ago
receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop()))
10 years ago
balance := statedb.GetBalance(context.Address())
receiver.AddBalance(balance)
10 years ago
statedb.Delete(context.Address())
fallthrough
case STOP: // Stop the context
return context.Return(nil), nil
default:
return nil, fmt.Errorf("Invalid opcode %x", op)
10 years ago
}
pc++
10 years ago
}
}
// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
// the operation. This does not reduce gas or resizes the memory.
func calculateGasAndSize(env Environment, context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)
)
err := baseCheck(op, stack, gas)
if err != nil {
return nil, nil, err
}
10 years ago
10 years ago
// stack Check, memory resize & gas phase
10 years ago
switch op {
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
err := stack.require(n)
if err != nil {
return nil, nil, err
}
10 years ago
gas.Set(GasFastestStep)
10 years ago
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
err := stack.require(n)
if err != nil {
return nil, nil, err
}
10 years ago
gas.Set(GasFastestStep)
10 years ago
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
err := stack.require(n + 2)
if err != nil {
return nil, nil, err
}
10 years ago
10 years ago
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
gas.Add(gas, params.LogGas)
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
10 years ago
newMemSize = calcMemSize(mStart, mSize)
case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
10 years ago
case SSTORE:
err := stack.require(2)
if err != nil {
return nil, nil, err
}
10 years ago
var g *big.Int
10 years ago
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
10 years ago
val := statedb.GetState(context.Address(), common.BigToHash(x))
// This checks for 3 scenario's and calculates gas accordingly
// 1. From a zero-value address to a non-zero value (NEW VALUE)
// 2. From a non-zero value address to a zero-value address (DELETE)
// 3. From a nen-zero to a non-zero (CHANGE)
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
10 years ago
// 0 => non 0
g = params.SstoreSetGas
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
statedb.Refund(params.SstoreRefundGas)
10 years ago
g = params.SstoreClearGas
10 years ago
} else {
// non 0 => non 0 (or 0 => 0)
g = params.SstoreClearGas
10 years ago
}
gas.Set(g)
case SUICIDE:
if !statedb.IsDeleted(context.Address()) {
statedb.Refund(params.SuicideRefundGas)
}
10 years ago
case MLOAD:
10 years ago
newMemSize = calcMemSize(stack.peek(), u256(32))
10 years ago
case MSTORE8:
10 years ago
newMemSize = calcMemSize(stack.peek(), u256(1))
10 years ago
case MSTORE:
10 years ago
newMemSize = calcMemSize(stack.peek(), u256(32))
10 years ago
case RETURN:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
10 years ago
case SHA3:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
10 years ago
10 years ago
words := toWordSize(stack.data[stack.len()-2])
gas.Add(gas, words.Mul(words, params.Sha3WordGas))
case CALLDATACOPY:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
10 years ago
10 years ago
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas))
case CODECOPY:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
10 years ago
10 years ago
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas))
case EXTCODECOPY:
10 years ago
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
10 years ago
words := toWordSize(stack.data[stack.len()-4])
gas.Add(gas, words.Mul(words, params.CopyGas))
case CREATE:
10 years ago
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
10 years ago
case CALL, CALLCODE:
10 years ago
gas.Add(gas, stack.data[stack.len()-1])
if op == CALL {
if env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
gas.Add(gas, params.CallNewAccountGas)
}
}
10 years ago
if len(stack.data[stack.len()-3].Bytes()) > 0 {
gas.Add(gas, params.CallValueTransferGas)
}
10 years ago
10 years ago
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
10 years ago
newMemSize = common.BigMax(x, y)
10 years ago
}
if newMemSize.Cmp(common.Big0) > 0 {
newMemSizeWords := toWordSize(newMemSize)
newMemSize.Mul(newMemSizeWords, u256(32))
10 years ago
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
10 years ago
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
linCoef := new(big.Int).Mul(oldSize, params.MemoryGas)
quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
10 years ago
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
pow.Exp(newMemSizeWords, common.Big2, Zero)
linCoef = new(big.Int).Mul(newMemSizeWords, params.MemoryGas)
quadCoef = new(big.Int).Div(pow, params.QuadCoeffDiv)
10 years ago
newTotalFee := new(big.Int).Add(linCoef, quadCoef)
fee := new(big.Int).Sub(newTotalFee, oldTotalFee)
gas.Add(gas, fee)
10 years ago
}
}
10 years ago
return newMemSize, gas, nil
10 years ago
}
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, input []byte, context *Context) (ret []byte, err error) {
gas := p.Gas(len(input))
10 years ago
if context.UseGas(gas) {
ret = p.Call(input)
10 years ago
return context.Return(ret), nil
} else {
return nil, OutOfGasError
10 years ago
}
}
// log emits a log event to the environment for each opcode encountered. This is not to be confused with the
// LOG* opcode.
func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, context *Context, err error) {
if Debug {
mem := make([]byte, len(memory.Data()))
copy(mem, memory.Data())
stck := make([]*big.Int, len(stack.Data()))
copy(stck, stack.Data())
object := context.self.(*state.StateObject)
storage := make(map[common.Hash][]byte)
object.EachStorage(func(k, v []byte) {
storage[common.BytesToHash(k)] = v
})
self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, err})
10 years ago
}
10 years ago
}
// Environment returns the current workable state of the VM
10 years ago
func (self *Vm) Env() Environment {
return self.env
}