op-geth/vm/vm.go

904 lines
21 KiB
Go
Raw Normal View History

2014-10-18 11:31:20 +00:00
package vm
2015-01-19 10:18:34 +00:00
import (
"fmt"
"math/big"
2015-01-19 10:18:34 +00:00
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
)
2014-10-15 15:12:26 +00:00
type Vm struct {
2015-01-19 10:18:34 +00:00
env Environment
logTy byte
logStr string
err error
// For logging
debug bool
2015-01-19 10:18:34 +00:00
BreakPoints []int64
Stepping bool
Fn string
Recoverable bool
}
2015-01-20 14:49:12 +00:00
func New(env Environment) *Vm {
2015-01-19 10:18:34 +00:00
lt := LogTyPretty
return &Vm{debug: Debug, env: env, logTy: lt, Recoverable: true}
2015-01-19 10:18:34 +00:00
}
func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
//func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
2015-01-19 10:18:34 +00:00
self.env.SetDepth(self.env.Depth() + 1)
//context := NewContext(caller, me, code, gas, price)
var (
caller = context.caller
code = context.Code
value = context.value
price = context.Price
)
2015-01-19 10:18:34 +00:00
2015-03-11 15:36:10 +00:00
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData).Endl()
2015-01-19 10:18:34 +00:00
if self.Recoverable {
// Recover from any require exception
defer func() {
if r := recover(); r != nil {
self.Printf(" %v", r).Endl()
context.UseGas(context.Gas)
ret = context.Return(nil)
err = fmt.Errorf("%v", r)
}
}()
}
if p := Precompiled[string(context.CodeAddr)]; p != nil {
2015-01-19 10:18:34 +00:00
return self.RunPrecompiled(p, callData, context)
}
var (
op OpCode
destinations = analyseJumpDests(context.Code)
mem = NewMemory()
2015-03-09 23:25:27 +00:00
stack = newStack()
2015-01-19 10:18:34 +00:00
pc uint64 = 0
step = 0
statedb = self.env.State()
jump = func(from uint64, to *big.Int) {
p := to.Uint64()
nop := context.GetOp(p)
if !destinations.Has(p) {
panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p))
}
self.Printf(" ~> %v", to)
pc = to.Uint64()
self.Endl()
}
)
// Don't bother with the execution if there's no code.
if len(code) == 0 {
return context.Return(nil), nil
}
for {
// The base for all big integer arithmetic
base := new(big.Int)
step++
// Get the memory location of pc
op = context.GetOp(pc)
2015-03-09 23:25:27 +00:00
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
2015-01-19 10:18:34 +00:00
newMemSize, gas := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
self.Printf("(g) %-3v (%v)", gas, context.Gas)
if !context.UseGas(gas) {
self.Endl()
tmp := new(big.Int).Set(context.Gas)
context.UseGas(context.Gas)
return context.Return(nil), OOG(gas, tmp)
}
mem.Resize(newMemSize.Uint64())
switch op {
// 0x20 range
case ADD:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
self.Printf(" %v + %v", y, x)
2015-03-09 23:25:27 +00:00
base.Add(x, y)
2015-01-19 10:18:34 +00:00
U256(base)
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case SUB:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
self.Printf(" %v - %v", y, x)
2015-03-09 23:25:27 +00:00
base.Sub(x, y)
2015-01-19 10:18:34 +00:00
U256(base)
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case MUL:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
self.Printf(" %v * %v", y, x)
2015-03-09 23:25:27 +00:00
base.Mul(x, y)
2015-01-19 10:18:34 +00:00
U256(base)
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case DIV:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
self.Printf(" %v / %v", x, y)
if y.Cmp(ethutil.Big0) != 0 {
base.Div(x, y)
}
U256(base)
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case SDIV:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
2015-01-19 10:18:34 +00:00
self.Printf(" %v / %v", x, y)
if y.Cmp(ethutil.Big0) == 0 {
base.Set(ethutil.Big0)
} else {
n := new(big.Int)
if new(big.Int).Mul(x, y).Cmp(ethutil.Big0) < 0 {
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Div(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case MOD:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
self.Printf(" %v %% %v", x, y)
if y.Cmp(ethutil.Big0) == 0 {
base.Set(ethutil.Big0)
} else {
base.Mod(x, y)
}
U256(base)
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case SMOD:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
2015-01-19 10:18:34 +00:00
self.Printf(" %v %% %v", x, y)
if y.Cmp(ethutil.Big0) == 0 {
base.Set(ethutil.Big0)
} else {
n := new(big.Int)
if x.Cmp(ethutil.Big0) < 0 {
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case EXP:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
self.Printf(" %v ** %v", x, y)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
base.Exp(x, y, Pow256)
2015-01-19 10:18:34 +00:00
U256(base)
self.Printf(" = %v", base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case SIGNEXTEND:
2015-03-12 18:41:56 +00:00
back := stack.pop()
if back.Cmp(big.NewInt(31)) < 0 {
bit := uint(back.Uint64()*8 + 7)
2015-03-09 23:25:27 +00:00
num := stack.pop()
2015-01-19 10:18:34 +00:00
mask := new(big.Int).Lsh(ethutil.Big1, bit)
mask.Sub(mask, ethutil.Big1)
if ethutil.BitTest(num, int(bit)) {
num.Or(num, mask.Not(mask))
} else {
num.And(num, mask)
}
num = U256(num)
self.Printf(" = %v", num)
2015-03-09 23:25:27 +00:00
stack.push(num)
2015-01-19 10:18:34 +00:00
}
case NOT:
2015-03-12 17:22:35 +00:00
stack.push(U256(new(big.Int).Not(stack.pop())))
//base.Sub(Pow256, stack.pop()).Sub(base, ethutil.Big1)
//base = U256(base)
//stack.push(base)
2015-01-19 10:18:34 +00:00
case LT:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
self.Printf(" %v < %v", x, y)
2015-01-19 10:18:34 +00:00
// x < y
2015-03-09 23:25:27 +00:00
if x.Cmp(y) < 0 {
stack.push(ethutil.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
}
case GT:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
self.Printf(" %v > %v", x, y)
2015-01-19 10:18:34 +00:00
// x > y
2015-03-09 23:25:27 +00:00
if x.Cmp(y) > 0 {
stack.push(ethutil.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
}
case SLT:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
self.Printf(" %v < %v", x, y)
2015-01-19 10:18:34 +00:00
// x < y
2015-03-09 23:25:27 +00:00
if x.Cmp(S256(y)) < 0 {
stack.push(ethutil.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
}
case SGT:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
self.Printf(" %v > %v", x, y)
2015-01-19 10:18:34 +00:00
// x > y
2015-03-09 23:25:27 +00:00
if x.Cmp(y) > 0 {
stack.push(ethutil.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
}
case EQ:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
self.Printf(" %v == %v", y, x)
// x == y
if x.Cmp(y) == 0 {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
}
case ISZERO:
2015-03-09 23:25:27 +00:00
x := stack.pop()
2015-01-19 10:18:34 +00:00
if x.Cmp(ethutil.BigFalse) > 0 {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigTrue)
2015-01-19 10:18:34 +00:00
}
// 0x10 range
case AND:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
self.Printf(" %v & %v", y, x)
2015-03-09 23:25:27 +00:00
stack.push(base.And(x, y))
2015-01-19 10:18:34 +00:00
case OR:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
self.Printf(" %v | %v", x, y)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
stack.push(base.Or(x, y))
2015-01-19 10:18:34 +00:00
case XOR:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
self.Printf(" %v ^ %v", x, y)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
stack.push(base.Xor(x, y))
2015-01-19 10:18:34 +00:00
case BYTE:
2015-03-09 23:25:27 +00:00
th, val := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
if th.Cmp(big.NewInt(32)) < 0 {
byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
base.Set(byt)
} else {
base.Set(ethutil.BigFalse)
}
self.Printf(" => 0x%x", base.Bytes())
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case ADDMOD:
2015-03-09 23:25:27 +00:00
x := stack.pop()
y := stack.pop()
z := stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-12 17:22:35 +00:00
if z.Cmp(Zero) > 0 {
add := new(big.Int).Add(x, y)
2015-01-19 10:18:34 +00:00
base.Mod(add, z)
2015-03-12 17:22:35 +00:00
base = U256(base)
2015-01-19 10:18:34 +00:00
}
self.Printf(" %v + %v %% %v = %v", x, y, z, base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case MULMOD:
2015-03-09 23:25:27 +00:00
x := stack.pop()
y := stack.pop()
z := stack.pop()
2015-01-19 10:18:34 +00:00
if z.Cmp(Zero) > 0 {
mul := new(big.Int).Mul(x, y)
2015-01-19 10:18:34 +00:00
base.Mod(mul, z)
U256(base)
}
self.Printf(" %v + %v %% %v = %v", x, y, z, base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
// 0x20 range
case SHA3:
2015-03-12 22:26:58 +00:00
offset, size := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(data))
2015-01-19 10:18:34 +00:00
2015-03-03 10:56:43 +00:00
self.Printf(" => (%v) %x", size, data)
2015-01-19 10:18:34 +00:00
// 0x30 range
case ADDRESS:
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(context.Address()))
2015-01-19 10:18:34 +00:00
self.Printf(" => %x", context.Address())
case BALANCE:
2015-03-09 23:25:27 +00:00
addr := stack.pop().Bytes()
2015-03-12 21:29:10 +00:00
balance := statedb.GetBalance(addr)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
stack.push(balance)
2015-01-19 10:18:34 +00:00
self.Printf(" => %v (%x)", balance, addr)
case ORIGIN:
origin := self.env.Origin()
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(origin))
2015-01-19 10:18:34 +00:00
self.Printf(" => %x", origin)
case CALLER:
caller := context.caller.Address()
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(caller))
2015-01-19 10:18:34 +00:00
self.Printf(" => %x", caller)
case CALLVALUE:
2015-03-09 23:25:27 +00:00
stack.push(value)
2015-01-19 10:18:34 +00:00
self.Printf(" => %v", value)
case CALLDATALOAD:
var (
2015-03-09 23:25:27 +00:00
offset = stack.pop()
2015-01-19 10:18:34 +00:00
data = make([]byte, 32)
lenData = big.NewInt(int64(len(callData)))
)
if lenData.Cmp(offset) >= 0 {
length := new(big.Int).Add(offset, ethutil.Big32)
length = ethutil.BigMin(length, lenData)
copy(data, callData[offset.Int64():length.Int64()])
}
self.Printf(" => 0x%x", data)
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(data))
2015-01-19 10:18:34 +00:00
case CALLDATASIZE:
l := int64(len(callData))
2015-03-09 23:25:27 +00:00
stack.push(big.NewInt(l))
2015-01-19 10:18:34 +00:00
self.Printf(" => %d", l)
case CALLDATACOPY:
var (
size = uint64(len(callData))
2015-03-09 23:25:27 +00:00
mOff = stack.pop().Uint64()
cOff = stack.pop().Uint64()
l = stack.pop().Uint64()
2015-01-19 10:18:34 +00:00
)
if cOff > size {
cOff = 0
l = 0
} else if cOff+l > size {
l = 0
}
code := callData[cOff : cOff+l]
mem.Set(mOff, l, code)
self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, callData[cOff:cOff+l])
case CODESIZE, EXTCODESIZE:
var code []byte
if op == EXTCODESIZE {
2015-03-09 23:25:27 +00:00
addr := stack.pop().Bytes()
2015-01-19 10:18:34 +00:00
code = statedb.GetCode(addr)
} else {
code = context.Code
}
l := big.NewInt(int64(len(code)))
2015-03-09 23:25:27 +00:00
stack.push(l)
2015-01-19 10:18:34 +00:00
self.Printf(" => %d", l)
case CODECOPY, EXTCODECOPY:
var code []byte
if op == EXTCODECOPY {
2015-03-09 23:25:27 +00:00
code = statedb.GetCode(stack.pop().Bytes())
2015-01-19 10:18:34 +00:00
} else {
code = context.Code
}
var (
2015-03-09 23:25:27 +00:00
mOff = stack.pop().Uint64()
cOff = stack.pop().Uint64()
l = stack.pop().Uint64()
2015-01-19 10:18:34 +00:00
)
codeCopy := getCode(code, cOff, l)
2015-01-19 10:18:34 +00:00
mem.Set(mOff, l, codeCopy)
self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy)
case GASPRICE:
2015-03-09 23:25:27 +00:00
stack.push(context.Price)
2015-01-19 10:18:34 +00:00
2015-02-04 15:39:02 +00:00
self.Printf(" => %x", context.Price)
2015-01-19 10:18:34 +00:00
// 0x40 range
case BLOCKHASH:
2015-03-09 23:25:27 +00:00
num := stack.pop()
2015-01-19 10:18:34 +00:00
n := new(big.Int).Sub(self.env.BlockNumber(), ethutil.Big257)
2015-01-19 10:18:34 +00:00
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(self.env.GetHash(num.Uint64())))
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.Big0)
2015-01-19 10:18:34 +00:00
}
2015-03-09 23:25:27 +00:00
self.Printf(" => 0x%x", stack.peek().Bytes())
2015-01-19 10:18:34 +00:00
case COINBASE:
coinbase := self.env.Coinbase()
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(coinbase))
2015-01-19 10:18:34 +00:00
self.Printf(" => 0x%x", coinbase)
case TIMESTAMP:
time := self.env.Time()
2015-03-09 23:25:27 +00:00
stack.push(big.NewInt(time))
2015-01-19 10:18:34 +00:00
self.Printf(" => 0x%x", time)
case NUMBER:
number := self.env.BlockNumber()
2015-03-09 23:25:27 +00:00
stack.push(U256(number))
2015-01-19 10:18:34 +00:00
self.Printf(" => 0x%x", number.Bytes())
case DIFFICULTY:
difficulty := self.env.Difficulty()
2015-03-09 23:25:27 +00:00
stack.push(difficulty)
2015-01-19 10:18:34 +00:00
self.Printf(" => 0x%x", difficulty.Bytes())
case GASLIMIT:
self.Printf(" => %v", self.env.GasLimit())
2015-03-09 23:25:27 +00:00
stack.push(self.env.GasLimit())
2015-01-19 10:18:34 +00:00
// 0x50 range
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:
a := uint64(op - PUSH1 + 1)
byts := context.GetRangeValue(pc+1, a)
2015-03-09 23:25:27 +00:00
// push value to stack
stack.push(ethutil.BigD(byts))
2015-01-19 10:18:34 +00:00
pc += a
step += int(op) - int(PUSH1) + 1
self.Printf(" => 0x%x", byts)
case POP:
2015-03-09 23:25:27 +00:00
stack.pop()
2015-01-19 10:18:34 +00:00
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
2015-03-09 23:25:27 +00:00
stack.dup(n)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
self.Printf(" => [%d] 0x%x", n, stack.peek().Bytes())
2015-01-19 10:18:34 +00:00
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
2015-03-09 23:25:27 +00:00
stack.swap(n)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
self.Printf(" => [%d]", n)
2015-01-19 10:18:34 +00:00
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
topics := make([][]byte, n)
2015-03-09 23:25:27 +00:00
mStart, mSize := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
for i := 0; i < n; i++ {
2015-03-09 23:25:27 +00:00
topics[i] = ethutil.LeftPadBytes(stack.pop().Bytes(), 32)
2015-01-19 10:18:34 +00:00
}
data := mem.Get(mStart.Int64(), mSize.Int64())
2015-02-22 12:24:26 +00:00
log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()}
2015-01-19 10:18:34 +00:00
self.env.AddLog(log)
self.Printf(" => %v", log)
case MLOAD:
2015-03-09 23:25:27 +00:00
offset := stack.pop()
2015-01-19 10:18:34 +00:00
val := ethutil.BigD(mem.Get(offset.Int64(), 32))
2015-03-09 23:25:27 +00:00
stack.push(val)
2015-01-19 10:18:34 +00:00
self.Printf(" => 0x%x", val.Bytes())
case MSTORE: // Store the value at stack top-1 in to memory at location stack top
2015-03-09 23:25:27 +00:00
// pop value of the stack
mStart, val := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
mem.Set(mStart.Uint64(), 32, ethutil.BigToBytes(val, 256))
self.Printf(" => 0x%x", val)
case MSTORE8:
2015-03-09 23:25:27 +00:00
off, val := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
mem.store[off.Int64()] = byte(val.Int64() & 0xff)
self.Printf(" => [%v] 0x%x", off, val)
case SLOAD:
2015-03-09 23:25:27 +00:00
loc := stack.pop()
2015-01-19 10:18:34 +00:00
val := ethutil.BigD(statedb.GetState(context.Address(), loc.Bytes()))
2015-03-09 23:25:27 +00:00
stack.push(val)
2015-01-19 10:18:34 +00:00
self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
case SSTORE:
2015-03-09 23:25:27 +00:00
loc, val := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
statedb.SetState(context.Address(), loc.Bytes(), val)
self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
case JUMP:
2015-03-09 23:25:27 +00:00
jump(pc, stack.pop())
2015-01-19 10:18:34 +00:00
continue
case JUMPI:
2015-03-09 23:25:27 +00:00
pos, cond := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
if cond.Cmp(ethutil.BigTrue) >= 0 {
jump(pc, pos)
continue
}
self.Printf(" ~> false")
2015-01-19 10:18:34 +00:00
case JUMPDEST:
case PC:
2015-03-09 23:25:27 +00:00
stack.push(big.NewInt(int64(pc)))
2015-01-19 10:18:34 +00:00
case MSIZE:
2015-03-09 23:25:27 +00:00
stack.push(big.NewInt(int64(mem.Len())))
2015-01-19 10:18:34 +00:00
case GAS:
2015-03-09 23:25:27 +00:00
stack.push(context.Gas)
2015-02-04 15:39:02 +00:00
self.Printf(" => %x", context.Gas)
2015-01-19 10:18:34 +00:00
// 0x60 range
case CREATE:
var (
2015-03-09 23:25:27 +00:00
value = stack.pop()
offset, size = stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
input = mem.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(context.Gas)
addr []byte
)
2015-02-04 15:39:02 +00:00
self.Endl()
2015-01-19 10:18:34 +00:00
context.UseGas(context.Gas)
ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value)
if suberr != nil {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
self.Printf(" (*) 0x0 %v", suberr)
} else {
// gas < len(ret) * CreateDataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, GasCreateByte)
if context.UseGas(dataGas) {
ref.SetCode(ret)
}
addr = ref.Address()
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigD(addr))
2015-01-19 10:18:34 +00:00
}
case CALL, CALLCODE:
2015-03-09 23:25:27 +00:00
gas := stack.pop()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
2015-02-19 10:09:46 +00:00
value = U256(value)
2015-03-09 23:25:27 +00:00
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
address := ethutil.Address(addr.Bytes())
self.Printf(" => %x", address).Endl()
2015-01-19 10:18:34 +00:00
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
2015-03-03 10:56:43 +00:00
if len(value.Bytes()) > 0 {
gas.Add(gas, GasStipend)
}
2015-01-19 10:18:34 +00:00
var (
ret []byte
err error
)
if op == CALLCODE {
ret, err = self.env.CallCode(context, address, args, gas, price, value)
2015-01-19 10:18:34 +00:00
} else {
ret, err = self.env.Call(context, address, args, gas, price, value)
2015-01-19 10:18:34 +00:00
}
if err != nil {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigFalse)
2015-01-19 10:18:34 +00:00
2015-03-11 15:36:10 +00:00
self.Printf("%v").Endl()
2015-01-19 10:18:34 +00:00
} else {
2015-03-09 23:25:27 +00:00
stack.push(ethutil.BigTrue)
2015-01-19 10:18:34 +00:00
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
self.Printf("resume %x (%v)", context.Address(), context.Gas)
case RETURN:
2015-03-09 23:25:27 +00:00
offset, size := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
ret := mem.Get(offset.Int64(), size.Int64())
self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl()
return context.Return(ret), nil
case SUICIDE:
2015-03-09 23:25:27 +00:00
receiver := statedb.GetOrNewStateObject(stack.pop().Bytes())
2015-01-19 10:18:34 +00:00
balance := statedb.GetBalance(context.Address())
self.Printf(" => (%x) %v", receiver.Address()[:4], balance)
receiver.AddBalance(balance)
2015-03-09 10:28:35 +00:00
2015-01-19 10:18:34 +00:00
statedb.Delete(context.Address())
fallthrough
case STOP: // Stop the context
self.Endl()
return context.Return(nil), nil
default:
2015-03-11 15:36:10 +00:00
self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
2015-01-19 10:18:34 +00:00
panic(fmt.Errorf("Invalid opcode %x", op))
}
pc++
self.Endl()
}
}
2015-03-09 23:25:27 +00:00
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int) {
2015-03-02 15:32:02 +00:00
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)
)
baseCheck(op, stack, gas)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
// stack Check, memory resize & gas phase
2015-01-19 10:18:34 +00:00
switch op {
2015-03-02 16:55:45 +00:00
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:
gas.Set(GasFastestStep)
2015-01-19 10:18:34 +00:00
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
stack.require(n)
2015-03-03 10:11:11 +00:00
gas.Set(GasFastestStep)
2015-01-19 10:18:34 +00:00
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
stack.require(n)
2015-03-03 10:11:11 +00:00
gas.Set(GasFastestStep)
2015-01-19 10:18:34 +00:00
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
stack.require(n + 2)
2015-03-09 23:25:27 +00:00
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
2015-03-02 15:32:02 +00:00
gas.Add(gas, GasLogBase)
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic))
2015-03-03 10:11:11 +00:00
gas.Add(gas, new(big.Int).Mul(mSize, GasLogByte))
2015-01-19 10:18:34 +00:00
newMemSize = calcMemSize(mStart, mSize)
case EXP:
2015-03-09 23:25:27 +00:00
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
2015-01-19 10:18:34 +00:00
case SSTORE:
stack.require(2)
2015-03-02 15:32:02 +00:00
var g *big.Int
2015-03-09 23:25:27 +00:00
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
2015-01-19 10:18:34 +00:00
val := statedb.GetState(context.Address(), x.Bytes())
if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0
2015-03-02 15:32:02 +00:00
g = GasStorageAdd
2015-01-19 10:18:34 +00:00
} else if len(val) > 0 && len(y.Bytes()) == 0 {
2015-03-02 15:32:02 +00:00
statedb.Refund(self.env.Origin(), RefundStorage)
2015-01-19 10:18:34 +00:00
2015-03-02 15:32:02 +00:00
g = GasStorageMod
2015-01-19 10:18:34 +00:00
} else {
// non 0 => non 0 (or 0 => 0)
2015-03-02 15:32:02 +00:00
g = GasStorageMod
2015-01-19 10:18:34 +00:00
}
2015-03-02 15:32:02 +00:00
gas.Set(g)
2015-03-09 10:28:35 +00:00
case SUICIDE:
if !statedb.IsDeleted(context.Address()) {
statedb.Refund(self.env.Origin(), RefundSuicide)
}
2015-01-19 10:18:34 +00:00
case MLOAD:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), u256(32))
2015-01-19 10:18:34 +00:00
case MSTORE8:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), u256(1))
2015-03-02 16:55:45 +00:00
case MSTORE:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), u256(32))
2015-01-19 10:18:34 +00:00
case RETURN:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
2015-01-19 10:18:34 +00:00
case SHA3:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-2])
2015-03-02 15:32:02 +00:00
gas.Add(gas, words.Mul(words, GasSha3Word))
case CALLDATACOPY:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-3])
2015-03-02 15:32:02 +00:00
gas.Add(gas, words.Mul(words, GasCopyWord))
case CODECOPY:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-3])
2015-03-02 15:32:02 +00:00
gas.Add(gas, words.Mul(words, GasCopyWord))
case EXTCODECOPY:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
2015-03-02 15:32:02 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-4])
2015-03-02 15:32:02 +00:00
gas.Add(gas, words.Mul(words, GasCopyWord))
2015-03-03 12:29:52 +00:00
2015-03-02 15:32:02 +00:00
case CREATE:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
2015-01-19 10:18:34 +00:00
case CALL, CALLCODE:
2015-03-09 23:25:27 +00:00
gas.Add(gas, stack.data[stack.len()-1])
2015-03-02 15:32:02 +00:00
if op == CALL {
2015-03-09 23:25:27 +00:00
if self.env.State().GetStateObject(stack.data[stack.len()-2].Bytes()) == nil {
2015-03-02 15:32:02 +00:00
gas.Add(gas, GasCallNewAccount)
}
2015-03-03 12:29:52 +00:00
}
2015-03-02 15:32:02 +00:00
2015-03-09 23:25:27 +00:00
if len(stack.data[stack.len()-3].Bytes()) > 0 {
2015-03-03 12:29:52 +00:00
gas.Add(gas, GasCallValueTransfer)
2015-03-02 15:32:02 +00:00
}
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
2015-01-19 10:18:34 +00:00
newMemSize = ethutil.BigMax(x, y)
}
if newMemSize.Cmp(ethutil.Big0) > 0 {
2015-03-03 10:56:43 +00:00
newMemSizeWords := toWordSize(newMemSize)
newMemSize.Mul(newMemSizeWords, u256(32))
2015-01-19 10:18:34 +00:00
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
2015-03-03 10:11:11 +00:00
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
2015-03-03 10:56:43 +00:00
pow := new(big.Int).Exp(oldSize, ethutil.Big2, Zero)
2015-03-03 10:11:11 +00:00
linCoef := new(big.Int).Mul(oldSize, GasMemWord)
quadCoef := new(big.Int).Div(pow, GasQuadCoeffDenom)
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
2015-03-03 10:56:43 +00:00
pow.Exp(newMemSizeWords, ethutil.Big2, Zero)
linCoef = new(big.Int).Mul(newMemSizeWords, GasMemWord)
2015-03-03 10:11:11 +00:00
quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom)
newTotalFee := new(big.Int).Add(linCoef, quadCoef)
gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee))
2015-01-19 10:18:34 +00:00
}
}
2015-01-19 10:18:34 +00:00
return newMemSize, gas
2014-09-14 23:11:01 +00:00
}
2015-01-19 10:18:34 +00:00
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
gas := p.Gas(len(callData))
if context.UseGas(gas) {
ret = p.Call(callData)
self.Printf("NATIVE_FUNC => %x", ret)
self.Endl()
return context.Return(ret), nil
} else {
self.Printf("NATIVE_FUNC => failed").Endl()
tmp := new(big.Int).Set(context.Gas)
panic(OOG(gas, tmp).Error())
}
}
2015-01-19 10:18:34 +00:00
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
self.logStr += fmt.Sprintf(format, v...)
}
2015-01-19 10:18:34 +00:00
}
return self
}
2015-01-19 10:18:34 +00:00
func (self *Vm) Endl() VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
2015-03-11 15:36:10 +00:00
vmlogger.Infoln(self.logStr)
self.logStr = ""
}
2015-01-19 10:18:34 +00:00
}
return self
2014-09-19 11:19:19 +00:00
}
2014-10-14 11:37:26 +00:00
2015-01-19 10:18:34 +00:00
func (self *Vm) Env() Environment {
return self.env
}