diff --git a/vm/test/fake_app_state.go b/vm/test/fake_app_state.go index 876a77cba..3d6f5ca22 100644 --- a/vm/test/fake_app_state.go +++ b/vm/test/fake_app_state.go @@ -1,8 +1,6 @@ package vm import ( - "fmt" - . "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/vm" "github.com/tendermint/tendermint/vm/sha3" @@ -85,33 +83,6 @@ func (fas *FakeAppState) AddLog(log *Log) { fas.logs = append(fas.logs, log) } -func main() { - appState := &FakeAppState{ - accounts: make(map[string]*Account), - storage: make(map[string]Word256), - logs: nil, - } - params := Params{ - BlockHeight: 0, - BlockHash: Zero256, - BlockTime: 0, - GasLimit: 0, - } - ourVm := NewVM(appState, params, Zero256) - - // Create accounts - account1 := &Account{ - Address: Uint64ToWord256(100), - } - account2 := &Account{ - Address: Uint64ToWord256(101), - } - - var gas uint64 = 1000 - output, err := ourVm.Call(account1, account2, []byte{0x5B, 0x60, 0x00, 0x56}, []byte{}, 0, &gas) - fmt.Printf("Output: %v Error: %v\n", output, err) -} - // Creates a 20 byte address and bumps the nonce. func createAddress(creator *Account) Word256 { nonce := creator.Nonce diff --git a/vm/test/vm_test.go b/vm/test/vm_test.go new file mode 100644 index 000000000..ee3fe7e57 --- /dev/null +++ b/vm/test/vm_test.go @@ -0,0 +1,99 @@ +package vm + +import ( + "crypto/rand" + "encoding/hex" + "fmt" + "strings" + "testing" + "time" + + . "github.com/tendermint/tendermint/common" + . "github.com/tendermint/tendermint/vm" +) + +func newAppState() *FakeAppState { + return &FakeAppState{ + accounts: make(map[string]*Account), + storage: make(map[string]Word256), + logs: nil, + } +} + +func newParams() Params { + return Params{ + BlockHeight: 0, + BlockHash: Zero256, + BlockTime: 0, + GasLimit: 0, + } +} + +func makeBytes(n int) []byte { + b := make([]byte, n) + rand.Read(b) + return b +} + +func TestVM(t *testing.T) { + ourVm := NewVM(newAppState(), newParams(), Zero256) + + // Create accounts + account1 := &Account{ + Address: Uint64ToWord256(100), + } + account2 := &Account{ + Address: Uint64ToWord256(101), + } + + var gas uint64 = 1000 + N := []byte{0xff, 0xff} + // Loop N times + code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)} + for i := 0; i < len(N); i++ { + code = append(code, N[i]) + } + code = append(code, []byte{0x60, 0x20, 0x51, 0x12, 0x15, 0x60, byte(0x1b + len(N)), 0x57, 0x60, 0x01, 0x60, 0x20, 0x51, 0x01, 0x60, 0x20, 0x52, 0x60, 0x05, 0x56, 0x5B}...) + start := time.Now() + output, err := ourVm.Call(account1, account2, code, []byte{}, 0, &gas) + fmt.Printf("Output: %v Error: %v\n", output, err) + fmt.Println("Call took:", time.Since(start)) +} + +func TestSubcurrency(t *testing.T) { + st := newAppState() + // Create accounts + account1 := &Account{ + Address: RightPadWord256(makeBytes(20)), + } + account2 := &Account{ + Address: RightPadWord256(makeBytes(20)), + } + st.accounts[account1.Address.String()] = account1 + st.accounts[account2.Address.String()] = account2 + + ourVm := NewVM(st, newParams(), Zero256) + + var gas uint64 = 1000 + code_parts := []string{"620f42403355", + "7c0100000000000000000000000000000000000000000000000000000000", + "600035046315cf268481141561004657", + "6004356040526040515460605260206060f35b63693200ce81141561008757", + "60043560805260243560a052335460c0523360e05260a05160c05112151561008657", + "60a05160c0510360e0515560a0516080515401608051555b5b505b6000f3"} + code, _ := hex.DecodeString(strings.Join(code_parts, "")) + fmt.Printf("Code: %x\n", code) + data, _ := hex.DecodeString("693200CE0000000000000000000000004B4363CDE27C2EB05E66357DB05BC5C88F850C1A0000000000000000000000000000000000000000000000000000000000000005") + output, err := ourVm.Call(account1, account2, code, data, 0, &gas) + fmt.Printf("Output: %v Error: %v\n", output, err) + +} + +/* + // infinite loop + code := []byte{0x5B, 0x60, 0x00, 0x56} + // mstore + code := []byte{0x60, 0x00, 0x60, 0x20} + // mstore, mload + code := []byte{0x60, 0x01, 0x60, 0x20, 0x52, 0x60, 0x20, 0x51} +*/ diff --git a/vm/vm.go b/vm/vm.go index 8d5c15096..52f3d0234 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -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 +}