|
|
@ -3,7 +3,7 @@ package vm |
|
|
|
import ( |
|
|
|
"errors" |
|
|
|
"fmt" |
|
|
|
"math" |
|
|
|
"math/big" |
|
|
|
|
|
|
|
. "github.com/tendermint/tendermint/common" |
|
|
|
"github.com/tendermint/tendermint/vm/sha3" |
|
|
@ -24,12 +24,21 @@ var ( |
|
|
|
ErrInvalidContract = errors.New("Invalid contract") |
|
|
|
) |
|
|
|
|
|
|
|
type Debug bool |
|
|
|
|
|
|
|
const ( |
|
|
|
dataStackCapacity = 1024 |
|
|
|
callStackCapacity = 100 // TODO ensure usage.
|
|
|
|
memoryCapacity = 1024 * 1024 // 1 MB
|
|
|
|
dataStackCapacity = 1024 |
|
|
|
callStackCapacity = 100 // TODO ensure usage.
|
|
|
|
memoryCapacity = 1024 * 1024 // 1 MB
|
|
|
|
dbg Debug = true |
|
|
|
) |
|
|
|
|
|
|
|
func (d Debug) Printf(s string, a ...interface{}) { |
|
|
|
if d { |
|
|
|
fmt.Printf(s, a...) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
type VM struct { |
|
|
|
appState AppState |
|
|
|
params Params |
|
|
@ -74,7 +83,7 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
|
|
|
|
// Just like Call() but does not transfer 'value' or modify the callDepth.
|
|
|
|
func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { |
|
|
|
fmt.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input) |
|
|
|
dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input) |
|
|
|
|
|
|
|
var ( |
|
|
|
pc uint64 = 0 |
|
|
@ -90,7 +99,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} |
|
|
|
|
|
|
|
var op = codeGetOp(code, pc) |
|
|
|
fmt.Printf("(pc) %-3d (op) %-14s (st) %-4d ", pc, op.String(), stack.Len()) |
|
|
|
dbg.Printf("(pc) %-3d (op) %-14s (st) %-4d ", pc, op.String(), stack.Len()) |
|
|
|
|
|
|
|
switch op { |
|
|
|
|
|
|
@ -98,90 +107,123 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
return nil, nil |
|
|
|
|
|
|
|
case ADD: // 0x01
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
stack.Push64(x + y) |
|
|
|
fmt.Printf(" %v + %v = %v\n", x, y, x+y) |
|
|
|
//x, y := stack.Pop64(), stack.Pop64()
|
|
|
|
//stack.Push64(x + y)
|
|
|
|
x, y := stack.Pop(), stack.Pop() |
|
|
|
xb := new(big.Int).SetBytes(flip(x[:])) |
|
|
|
yb := new(big.Int).SetBytes(flip(y[:])) |
|
|
|
sum := new(big.Int).Add(xb, yb) |
|
|
|
stack.Push(RightPadWord256(flip(sum.Bytes()))) |
|
|
|
dbg.Printf(" %v + %v = %v\n", xb, yb, sum) |
|
|
|
|
|
|
|
case MUL: // 0x02
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
stack.Push64(x * y) |
|
|
|
fmt.Printf(" %v * %v = %v\n", x, y, x*y) |
|
|
|
//x, y := stack.Pop64(), stack.Pop64()
|
|
|
|
//stack.Push64(x * y)
|
|
|
|
x, y := stack.Pop(), stack.Pop() |
|
|
|
xb := new(big.Int).SetBytes(flip(x[:])) |
|
|
|
yb := new(big.Int).SetBytes(flip(y[:])) |
|
|
|
prod := new(big.Int).Mul(xb, yb) |
|
|
|
stack.Push(RightPadWord256(flip(prod.Bytes()))) |
|
|
|
dbg.Printf(" %v * %v = %v\n", xb, yb, prod) |
|
|
|
|
|
|
|
case SUB: // 0x03
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
stack.Push64(x - y) |
|
|
|
fmt.Printf(" %v - %v = %v\n", x, y, x-y) |
|
|
|
//x, y := stack.Pop64(), stack.Pop64()
|
|
|
|
//stack.Push64(x - y)
|
|
|
|
x, y := stack.Pop(), stack.Pop() |
|
|
|
xb := new(big.Int).SetBytes(flip(x[:])) |
|
|
|
yb := new(big.Int).SetBytes(flip(y[:])) |
|
|
|
diff := new(big.Int).Sub(xb, yb) |
|
|
|
stack.Push(RightPadWord256(flip(diff.Bytes()))) |
|
|
|
dbg.Printf(" %v - %v = %v\n", xb, yb, diff) |
|
|
|
|
|
|
|
case DIV: // 0x04
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
if y == 0 { // TODO
|
|
|
|
//x, y := stack.Pop64(), stack.Pop64()
|
|
|
|
//stack.Push64(x / y)
|
|
|
|
x, y := stack.Pop(), stack.Pop() |
|
|
|
if y.IsZero() { // TODO
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" %v / %v = %v (TODO)\n", x, y, 0) |
|
|
|
dbg.Printf(" %x / %x = %v (TODO)\n", x, y, 0) |
|
|
|
} else { |
|
|
|
stack.Push64(x / y) |
|
|
|
fmt.Printf(" %v / %v = %v\n", x, y, x/y) |
|
|
|
xb := new(big.Int).SetBytes(flip(x[:])) |
|
|
|
yb := new(big.Int).SetBytes(flip(y[:])) |
|
|
|
div := new(big.Int).Div(xb, yb) |
|
|
|
stack.Push(RightPadWord256(flip(div.Bytes()))) |
|
|
|
dbg.Printf(" %v / %v = %v\n", xb, yb, div) |
|
|
|
} |
|
|
|
|
|
|
|
case SDIV: // 0x05
|
|
|
|
// TODO ... big?
|
|
|
|
x, y := int64(stack.Pop64()), int64(stack.Pop64()) |
|
|
|
if y == 0 { // TODO
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" %v / %v = %v (TODO)\n", x, y, 0) |
|
|
|
dbg.Printf(" %v / %v = %v (TODO)\n", x, y, 0) |
|
|
|
} else { |
|
|
|
stack.Push64(uint64(x / y)) |
|
|
|
fmt.Printf(" %v / %v = %v\n", x, y, x/y) |
|
|
|
dbg.Printf(" %v / %v = %v\n", x, y, x/y) |
|
|
|
} |
|
|
|
|
|
|
|
case MOD: // 0x06
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
if y == 0 { // TODO
|
|
|
|
//x, y := stack.Pop64(), stack.Pop64()
|
|
|
|
x, y := stack.Pop(), stack.Pop() |
|
|
|
if y.IsZero() { // TODO
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) |
|
|
|
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) |
|
|
|
} else { |
|
|
|
stack.Push64(x % y) |
|
|
|
fmt.Printf(" %v %% %v = %v\n", x, y, x%y) |
|
|
|
xb := new(big.Int).SetBytes(flip(x[:])) |
|
|
|
yb := new(big.Int).SetBytes(flip(y[:])) |
|
|
|
mod := new(big.Int).Mod(xb, yb) |
|
|
|
stack.Push(RightPadWord256(flip(mod.Bytes()))) |
|
|
|
dbg.Printf(" %v %% %v = %v\n", xb, yb, mod) |
|
|
|
} |
|
|
|
|
|
|
|
case SMOD: // 0x07
|
|
|
|
// TODO ... big?
|
|
|
|
x, y := int64(stack.Pop64()), int64(stack.Pop64()) |
|
|
|
if y == 0 { // TODO
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) |
|
|
|
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) |
|
|
|
} else { |
|
|
|
stack.Push64(uint64(x % y)) |
|
|
|
fmt.Printf(" %v %% %v = %v\n", x, y, x%y) |
|
|
|
dbg.Printf(" %v %% %v = %v\n", x, y, x%y) |
|
|
|
} |
|
|
|
|
|
|
|
case ADDMOD: // 0x08
|
|
|
|
// TODO ... big?
|
|
|
|
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() |
|
|
|
if z == 0 { // TODO
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) |
|
|
|
dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) |
|
|
|
} else { |
|
|
|
stack.Push64(x % y) |
|
|
|
fmt.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z) |
|
|
|
stack.Push64((x + y) % z) |
|
|
|
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z) |
|
|
|
} |
|
|
|
|
|
|
|
case MULMOD: // 0x09
|
|
|
|
// TODO ... big?
|
|
|
|
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() |
|
|
|
if z == 0 { // TODO
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) |
|
|
|
dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) |
|
|
|
} else { |
|
|
|
stack.Push64(x % y) |
|
|
|
fmt.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z) |
|
|
|
stack.Push64((x * y) % z) |
|
|
|
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z) |
|
|
|
} |
|
|
|
|
|
|
|
case EXP: // 0x0A
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
stack.Push64(ExpUint64(x, y)) |
|
|
|
fmt.Printf(" %v ** %v = %v\n", x, y, uint64(math.Pow(float64(x), float64(y)))) |
|
|
|
//x, y := stack.Pop64(), stack.Pop64()
|
|
|
|
//stack.Push64(ExpUint64(x, y))
|
|
|
|
x, y := stack.Pop(), stack.Pop() |
|
|
|
xb := new(big.Int).SetBytes(flip(x[:])) |
|
|
|
yb := new(big.Int).SetBytes(flip(y[:])) |
|
|
|
pow := new(big.Int).Exp(xb, yb, big.NewInt(0)) |
|
|
|
stack.Push(RightPadWord256(flip(pow.Bytes()))) |
|
|
|
dbg.Printf(" %v ** %v = %v\n", xb, yb, pow) |
|
|
|
|
|
|
|
case SIGNEXTEND: // 0x0B
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
res := (y << uint(x)) >> x |
|
|
|
stack.Push64(res) |
|
|
|
fmt.Printf(" (%v << %v) >> %v = %v\n", y, x, x, res) |
|
|
|
dbg.Printf(" (%v << %v) >> %v = %v\n", y, x, x, res) |
|
|
|
|
|
|
|
case LT: // 0x10
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
@ -190,7 +232,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} else { |
|
|
|
stack.Push(Zero256) |
|
|
|
} |
|
|
|
fmt.Printf(" %v < %v = %v\n", x, y, x < y) |
|
|
|
dbg.Printf(" %v < %v = %v\n", x, y, x < y) |
|
|
|
|
|
|
|
case GT: // 0x11
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
@ -199,7 +241,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} else { |
|
|
|
stack.Push(Zero256) |
|
|
|
} |
|
|
|
fmt.Printf(" %v > %v = %v\n", x, y, x > y) |
|
|
|
dbg.Printf(" %v > %v = %v\n", x, y, x > y) |
|
|
|
|
|
|
|
case SLT: // 0x12
|
|
|
|
x, y := int64(stack.Pop64()), int64(stack.Pop64()) |
|
|
@ -208,7 +250,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} else { |
|
|
|
stack.Push(Zero256) |
|
|
|
} |
|
|
|
fmt.Printf(" %v < %v = %v\n", x, y, x < y) |
|
|
|
dbg.Printf(" %v < %v = %v\n", x, y, x < y) |
|
|
|
|
|
|
|
case SGT: // 0x13
|
|
|
|
x, y := int64(stack.Pop64()), int64(stack.Pop64()) |
|
|
@ -217,16 +259,16 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} else { |
|
|
|
stack.Push(Zero256) |
|
|
|
} |
|
|
|
fmt.Printf(" %v > %v = %v\n", x, y, x > y) |
|
|
|
dbg.Printf(" %v > %v = %v\n", x, y, x > y) |
|
|
|
|
|
|
|
case EQ: // 0x14
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
if x > y { |
|
|
|
if x == y { |
|
|
|
stack.Push64(1) |
|
|
|
} else { |
|
|
|
stack.Push(Zero256) |
|
|
|
} |
|
|
|
fmt.Printf(" %v == %v = %v\n", x, y, x == y) |
|
|
|
dbg.Printf(" %v == %v = %v\n", x, y, x == y) |
|
|
|
|
|
|
|
case ISZERO: // 0x15
|
|
|
|
x := stack.Pop64() |
|
|
@ -235,27 +277,27 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} else { |
|
|
|
stack.Push(Zero256) |
|
|
|
} |
|
|
|
fmt.Printf(" %v == 0 = %v\n", x, x == 0) |
|
|
|
dbg.Printf(" %v == 0 = %v\n", x, x == 0) |
|
|
|
|
|
|
|
case AND: // 0x16
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
stack.Push64(x & y) |
|
|
|
fmt.Printf(" %v & %v = %v\n", x, y, x&y) |
|
|
|
dbg.Printf(" %v & %v = %v\n", x, y, x&y) |
|
|
|
|
|
|
|
case OR: // 0x17
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
stack.Push64(x | y) |
|
|
|
fmt.Printf(" %v | %v = %v\n", x, y, x|y) |
|
|
|
dbg.Printf(" %v | %v = %v\n", x, y, x|y) |
|
|
|
|
|
|
|
case XOR: // 0x18
|
|
|
|
x, y := stack.Pop64(), stack.Pop64() |
|
|
|
stack.Push64(x ^ y) |
|
|
|
fmt.Printf(" %v ^ %v = %v\n", x, y, x^y) |
|
|
|
dbg.Printf(" %v ^ %v = %v\n", x, y, x^y) |
|
|
|
|
|
|
|
case NOT: // 0x19
|
|
|
|
x := stack.Pop64() |
|
|
|
stack.Push64(^x) |
|
|
|
fmt.Printf(" !%v = %v\n", x, ^x) |
|
|
|
dbg.Printf(" !%v = %v\n", x, ^x) |
|
|
|
|
|
|
|
case BYTE: // 0x1A
|
|
|
|
idx, val := stack.Pop64(), stack.Pop() |
|
|
@ -264,7 +306,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
res = val[idx] |
|
|
|
} |
|
|
|
stack.Push64(uint64(res)) |
|
|
|
fmt.Printf(" => 0x%X\n", res) |
|
|
|
dbg.Printf(" => 0x%X\n", res) |
|
|
|
|
|
|
|
case SHA3: // 0x20
|
|
|
|
if ok = useGas(gas, GasSha3); !ok { |
|
|
@ -277,11 +319,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} |
|
|
|
data = sha3.Sha3(data) |
|
|
|
stack.PushBytes(data) |
|
|
|
fmt.Printf(" => (%v) %X\n", size, data) |
|
|
|
dbg.Printf(" => (%v) %X\n", size, data) |
|
|
|
|
|
|
|
case ADDRESS: // 0x30
|
|
|
|
stack.Push(callee.Address) |
|
|
|
fmt.Printf(" => %X\n", callee.Address) |
|
|
|
dbg.Printf(" => %X\n", callee.Address) |
|
|
|
|
|
|
|
case BALANCE: // 0x31
|
|
|
|
addr := stack.Pop() |
|
|
@ -294,19 +336,19 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
} |
|
|
|
balance := acc.Balance |
|
|
|
stack.Push64(balance) |
|
|
|
fmt.Printf(" => %v (%X)\n", balance, addr) |
|
|
|
dbg.Printf(" => %v (%X)\n", balance, addr) |
|
|
|
|
|
|
|
case ORIGIN: // 0x32
|
|
|
|
stack.Push(vm.origin) |
|
|
|
fmt.Printf(" => %X\n", vm.origin) |
|
|
|
dbg.Printf(" => %X\n", vm.origin) |
|
|
|
|
|
|
|
case CALLER: // 0x33
|
|
|
|
stack.Push(caller.Address) |
|
|
|
fmt.Printf(" => %X\n", caller.Address) |
|
|
|
dbg.Printf(" => %X\n", caller.Address) |
|
|
|
|
|
|
|
case CALLVALUE: // 0x34
|
|
|
|
stack.Push64(value) |
|
|
|
fmt.Printf(" => %v\n", value) |
|
|
|
dbg.Printf(" => %v\n", value) |
|
|
|
|
|
|
|
case CALLDATALOAD: // 0x35
|
|
|
|
offset := stack.Pop64() |
|
|
@ -315,11 +357,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
return nil, firstErr(err, ErrInputOutOfBounds) |
|
|
|
} |
|
|
|
stack.Push(RightPadWord256(data)) |
|
|
|
fmt.Printf(" => 0x%X\n", data) |
|
|
|
dbg.Printf(" => 0x%X\n", data) |
|
|
|
|
|
|
|
case CALLDATASIZE: // 0x36
|
|
|
|
stack.Push64(uint64(len(input))) |
|
|
|
fmt.Printf(" => %d\n", len(input)) |
|
|
|
dbg.Printf(" => %d\n", len(input)) |
|
|
|
|
|
|
|
case CALLDATACOPY: // 0x37
|
|
|
|
memOff := stack.Pop64() |
|
|
@ -334,18 +376,17 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
return nil, firstErr(err, ErrMemoryOutOfBounds) |
|
|
|
} |
|
|
|
copy(dest, data) |
|
|
|
fmt.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data) |
|
|
|
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data) |
|
|
|
|
|
|
|
case CODESIZE: // 0x38
|
|
|
|
l := uint64(len(code)) |
|
|
|
stack.Push64(l) |
|
|
|
fmt.Printf(" => %d\n", l) |
|
|
|
dbg.Printf(" => %d\n", l) |
|
|
|
|
|
|
|
case CODECOPY: // 0x39
|
|
|
|
memOff := stack.Pop64() |
|
|
|
codeOff := stack.Pop64() |
|
|
|
length := stack.Pop64() |
|
|
|
fmt.Println("CODECOPY: codeOff, length, codelength", codeOff, length, len(code)) |
|
|
|
data, ok := subslice(code, codeOff, length, false) |
|
|
|
if !ok { |
|
|
|
return nil, firstErr(err, ErrCodeOutOfBounds) |
|
|
@ -355,11 +396,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
return nil, firstErr(err, ErrMemoryOutOfBounds) |
|
|
|
} |
|
|
|
copy(dest, data) |
|
|
|
fmt.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data) |
|
|
|
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data) |
|
|
|
|
|
|
|
case GASPRICE_DEPRECATED: // 0x3A
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" => %X (GASPRICE IS DEPRECATED)\n") |
|
|
|
dbg.Printf(" => %X (GASPRICE IS DEPRECATED)\n") |
|
|
|
|
|
|
|
case EXTCODESIZE: // 0x3B
|
|
|
|
addr := stack.Pop() |
|
|
@ -373,7 +414,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
code := acc.Code |
|
|
|
l := uint64(len(code)) |
|
|
|
stack.Push64(l) |
|
|
|
fmt.Printf(" => %d\n", l) |
|
|
|
dbg.Printf(" => %d\n", l) |
|
|
|
|
|
|
|
case EXTCODECOPY: // 0x3C
|
|
|
|
addr := stack.Pop() |
|
|
@ -397,33 +438,33 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
return nil, firstErr(err, ErrMemoryOutOfBounds) |
|
|
|
} |
|
|
|
copy(dest, data) |
|
|
|
fmt.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data) |
|
|
|
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data) |
|
|
|
|
|
|
|
case BLOCKHASH: // 0x40
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes()) |
|
|
|
dbg.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes()) |
|
|
|
|
|
|
|
case COINBASE: // 0x41
|
|
|
|
stack.Push(Zero256) |
|
|
|
fmt.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes()) |
|
|
|
dbg.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes()) |
|
|
|
|
|
|
|
case TIMESTAMP: // 0x42
|
|
|
|
time := vm.params.BlockTime |
|
|
|
stack.Push64(uint64(time)) |
|
|
|
fmt.Printf(" => 0x%X\n", time) |
|
|
|
dbg.Printf(" => 0x%X\n", time) |
|
|
|
|
|
|
|
case BLOCKHEIGHT: // 0x43
|
|
|
|
number := uint64(vm.params.BlockHeight) |
|
|
|
stack.Push64(number) |
|
|
|
fmt.Printf(" => 0x%X\n", number) |
|
|
|
dbg.Printf(" => 0x%X\n", number) |
|
|
|
|
|
|
|
case GASLIMIT: // 0x45
|
|
|
|
stack.Push64(vm.params.GasLimit) |
|
|
|
fmt.Printf(" => %v\n", vm.params.GasLimit) |
|
|
|
dbg.Printf(" => %v\n", vm.params.GasLimit) |
|
|
|
|
|
|
|
case POP: // 0x50
|
|
|
|
stack.Pop() |
|
|
|
fmt.Printf(" => %v\n", vm.params.GasLimit) |
|
|
|
dbg.Printf(" => %v\n", vm.params.GasLimit) |
|
|
|
|
|
|
|
case MLOAD: // 0x51
|
|
|
|
offset := stack.Pop64() |
|
|
@ -432,16 +473,16 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
return nil, firstErr(err, ErrMemoryOutOfBounds) |
|
|
|
} |
|
|
|
stack.Push(RightPadWord256(data)) |
|
|
|
fmt.Printf(" => 0x%X\n", data) |
|
|
|
dbg.Printf(" => 0x%X\n", data) |
|
|
|
|
|
|
|
case MSTORE: // 0x52
|
|
|
|
offset, data := stack.Pop64(), stack.Pop() |
|
|
|
dest, ok := subslice(memory, offset, 32, true) |
|
|
|
dest, ok := subslice(memory, offset, 32, false) |
|
|
|
if !ok { |
|
|
|
return nil, firstErr(err, ErrMemoryOutOfBounds) |
|
|
|
} |
|
|
|
copy(dest, data[:]) |
|
|
|
fmt.Printf(" => 0x%X\n", data) |
|
|
|
copy(dest, flip(data[:])) |
|
|
|
dbg.Printf(" => 0x%X\n", data) |
|
|
|
|
|
|
|
case MSTORE8: // 0x53
|
|
|
|
offset, val := stack.Pop64(), byte(stack.Pop64()&0xFF) |
|
|
@ -449,19 +490,21 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
return nil, firstErr(err, ErrMemoryOutOfBounds) |
|
|
|
} |
|
|
|
memory[offset] = val |
|
|
|
fmt.Printf(" => [%v] 0x%X\n", offset, val) |
|
|
|
dbg.Printf(" => [%v] 0x%X\n", offset, val) |
|
|
|
|
|
|
|
case SLOAD: // 0x54
|
|
|
|
loc := stack.Pop() |
|
|
|
data := vm.appState.GetStorage(callee.Address, loc) |
|
|
|
stack.Push(data) |
|
|
|
fmt.Printf(" {0x%X : 0x%X}\n", loc, data) |
|
|
|
stack.Push(flipWord(data)) |
|
|
|
dbg.Printf(" {0x%X : 0x%X}\n", loc, data) |
|
|
|
|
|
|
|
case SSTORE: // 0x55
|
|
|
|
loc, data := stack.Pop(), stack.Pop() |
|
|
|
loc = flipWord(loc) |
|
|
|
data = flipWord(data) |
|
|
|
vm.appState.SetStorage(callee.Address, loc, data) |
|
|
|
useGas(gas, GasStorageUpdate) |
|
|
|
fmt.Printf(" {0x%X : 0x%X}\n", loc, data) |
|
|
|
dbg.Printf(" {0x%X : 0x%X}\n", loc, data) |
|
|
|
|
|
|
|
case JUMP: // 0x56
|
|
|
|
err = jump(code, stack.Pop64(), &pc) |
|
|
@ -473,7 +516,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
err = jump(code, pos, &pc) |
|
|
|
continue |
|
|
|
} |
|
|
|
fmt.Printf(" ~> false\n") |
|
|
|
dbg.Printf(" ~> false\n") |
|
|
|
|
|
|
|
case PC: // 0x58
|
|
|
|
stack.Push64(pc) |
|
|
@ -483,10 +526,10 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
|
|
|
|
case GAS: // 0x5A
|
|
|
|
stack.Push64(*gas) |
|
|
|
fmt.Printf(" => %X\n", *gas) |
|
|
|
dbg.Printf(" => %X\n", *gas) |
|
|
|
|
|
|
|
case JUMPDEST: // 0x5B
|
|
|
|
fmt.Printf("\n") |
|
|
|
dbg.Printf("\n") |
|
|
|
// Do nothing
|
|
|
|
|
|
|
|
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: |
|
|
@ -498,17 +541,17 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
res := RightPadWord256(codeSegment) |
|
|
|
stack.Push(res) |
|
|
|
pc += a |
|
|
|
fmt.Printf(" => 0x%X\n", res) |
|
|
|
dbg.Printf(" => 0x%X\n", res) |
|
|
|
|
|
|
|
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: |
|
|
|
n := int(op - DUP1 + 1) |
|
|
|
stack.Dup(n) |
|
|
|
fmt.Printf(" => [%d] 0x%X\n", n, stack.Peek().Bytes()) |
|
|
|
dbg.Printf(" => [%d] 0x%X\n", n, stack.Peek().Bytes()) |
|
|
|
|
|
|
|
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: |
|
|
|
n := int(op - SWAP1 + 2) |
|
|
|
stack.Swap(n) |
|
|
|
fmt.Printf(" => [%d]\n", n) |
|
|
|
dbg.Printf(" => [%d]\n", n) |
|
|
|
|
|
|
|
case LOG0, LOG1, LOG2, LOG3, LOG4: |
|
|
|
n := int(op - LOG0) |
|
|
@ -528,7 +571,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
vm.params.BlockHeight, |
|
|
|
} |
|
|
|
vm.appState.AddLog(log) |
|
|
|
fmt.Printf(" => %v\n", log) |
|
|
|
dbg.Printf(" => %v\n", log) |
|
|
|
|
|
|
|
case CREATE: // 0xF0
|
|
|
|
contractValue := stack.Pop64() |
|
|
@ -560,7 +603,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
addr, value := stack.Pop(), stack.Pop64() |
|
|
|
inOffset, inSize := stack.Pop64(), stack.Pop64() // inputs
|
|
|
|
retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs
|
|
|
|
fmt.Printf(" => %X\n", addr) |
|
|
|
dbg.Printf(" => %X\n", addr) |
|
|
|
|
|
|
|
// Get the arguments from the memory
|
|
|
|
args, ok := subslice(memory, inOffset, inSize, false) |
|
|
@ -613,7 +656,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
// Handle remaining gas.
|
|
|
|
*gas += gasLimit |
|
|
|
|
|
|
|
fmt.Printf("resume %X (%v)\n", callee.Address, gas) |
|
|
|
dbg.Printf("resume %X (%v)\n", callee.Address, gas) |
|
|
|
|
|
|
|
case RETURN: // 0xF3
|
|
|
|
offset, size := stack.Pop64(), stack.Pop64() |
|
|
@ -621,7 +664,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
if !ok { |
|
|
|
return nil, firstErr(err, ErrMemoryOutOfBounds) |
|
|
|
} |
|
|
|
fmt.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(ret), ret) |
|
|
|
dbg.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(ret), ret) |
|
|
|
return ret, nil |
|
|
|
|
|
|
|
case SUICIDE: // 0xFF
|
|
|
@ -629,7 +672,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
if ok = useGas(gas, GasGetAccount); !ok { |
|
|
|
return nil, firstErr(err, ErrInsufficientGas) |
|
|
|
} |
|
|
|
// TODO if the receiver is Zero256, then make it the fee.
|
|
|
|
// TODO if the receiver is , then make it the fee.
|
|
|
|
receiver := vm.appState.GetAccount(addr) |
|
|
|
if receiver == nil { |
|
|
|
return nil, firstErr(err, ErrUnknownAddress) |
|
|
@ -638,11 +681,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga |
|
|
|
receiver.Balance += balance |
|
|
|
vm.appState.UpdateAccount(receiver) |
|
|
|
vm.appState.RemoveAccount(callee) |
|
|
|
fmt.Printf(" => (%X) %v\n", addr[:4], balance) |
|
|
|
dbg.Printf(" => (%X) %v\n", addr[:4], balance) |
|
|
|
fallthrough |
|
|
|
|
|
|
|
default: |
|
|
|
fmt.Printf("(pc) %-3v Invalid opcode %X\n", pc, op) |
|
|
|
dbg.Printf("(pc) %-3v Invalid opcode %X\n", pc, op) |
|
|
|
panic(fmt.Errorf("Invalid opcode %X", op)) |
|
|
|
} |
|
|
|
|
|
|
@ -677,10 +720,10 @@ func codeGetOp(code []byte, n uint64) OpCode { |
|
|
|
func jump(code []byte, to uint64, pc *uint64) (err error) { |
|
|
|
dest := codeGetOp(code, to) |
|
|
|
if dest != JUMPDEST { |
|
|
|
fmt.Printf(" ~> %v invalid jump dest %v\n", to, dest) |
|
|
|
dbg.Printf(" ~> %v invalid jump dest %v\n", to, dest) |
|
|
|
return ErrInvalidJumpDest |
|
|
|
} |
|
|
|
fmt.Printf(" ~> %v\n", to) |
|
|
|
dbg.Printf(" ~> %v\n", to) |
|
|
|
*pc = to |
|
|
|
return nil |
|
|
|
} |
|
|
@ -713,10 +756,25 @@ func transfer(from, to *Account, amount uint64) error { |
|
|
|
} |
|
|
|
|
|
|
|
func flip(in []byte) []byte { |
|
|
|
l2 := len(in) / 2 |
|
|
|
flipped := make([]byte, len(in)) |
|
|
|
for i := 0; i < len(flipped)/2; i++ { |
|
|
|
// copy the middle bit (if its even it will get overwritten)
|
|
|
|
if len(in) != 0 { |
|
|
|
flipped[l2] = in[l2] |
|
|
|
} |
|
|
|
for i := 0; i < l2; i++ { |
|
|
|
flipped[i] = in[len(in)-1-i] |
|
|
|
flipped[len(in)-1-i] = in[i] |
|
|
|
} |
|
|
|
return flipped |
|
|
|
} |
|
|
|
|
|
|
|
func flipWord(in Word256) Word256 { |
|
|
|
word := Word256{} |
|
|
|
// copy the middle bit (if its even it will get overwritten)
|
|
|
|
for i := 0; i < 16; i++ { |
|
|
|
word[i] = in[len(in)-1-i] |
|
|
|
word[len(in)-1-i] = in[i] |
|
|
|
} |
|
|
|
return word |
|
|
|
} |