From 2668b5963124594afcf7ef8f0115adaef34cb7f1 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Fri, 17 Apr 2015 16:05:36 -0700 Subject: [PATCH 1/5] =?UTF-8?q?=E2=94=AC=E2=94=80=E2=94=AC=20=EF=B8=B5=20/?= =?UTF-8?q?(.=E2=96=A1.=20\=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vm/common.go | 26 ++++ vm/vm.go | 339 ++++++++++++++++++++++++++++----------------------- 2 files changed, 211 insertions(+), 154 deletions(-) create mode 100644 vm/common.go diff --git a/vm/common.go b/vm/common.go new file mode 100644 index 00000000..00ab93c7 --- /dev/null +++ b/vm/common.go @@ -0,0 +1,26 @@ +package vm + +import ( + "math/big" +) + +// To256 +// +// "cast" the big int to a 256 big int (i.e., limit to) +var tt256 = new(big.Int).Lsh(big.NewInt(1), 256) +var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) +var tt255 = new(big.Int).Lsh(big.NewInt(1), 255) + +func U256(x *big.Int) *big.Int { + x.And(x, tt256m1) + return x +} + +func S256(x *big.Int) *big.Int { + if x.Cmp(tt255) < 0 { + return x + } else { + // We don't want to modify x, ever + return new(big.Int).Sub(x, tt256) + } +} diff --git a/vm/vm.go b/vm/vm.go index ba16d846..0363a5fa 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -1,6 +1,7 @@ package vm import ( + "bytes" "errors" "fmt" "math/big" @@ -131,196 +132,252 @@ 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) x, y := stack.Pop(), stack.Pop() - xb := new(big.Int).SetBytes(flip(x[:])) - yb := new(big.Int).SetBytes(flip(y[:])) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) sum := new(big.Int).Add(xb, yb) - stack.Push(RightPadWord256(flip(sum.Bytes()))) - dbg.Printf(" %v + %v = %v\n", xb, yb, sum) + res := LeftPadWord256(U256(sum).Bytes()) + stack.Push(res) + dbg.Printf(" %v + %v = %v (%X)\n", xb, yb, sum, res) case MUL: // 0x02 - //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[:])) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) prod := new(big.Int).Mul(xb, yb) - stack.Push(RightPadWord256(flip(prod.Bytes()))) - dbg.Printf(" %v * %v = %v\n", xb, yb, prod) + res := LeftPadWord256(U256(prod).Bytes()) + stack.Push(res) + dbg.Printf(" %v * %v = %v (%X)\n", xb, yb, prod, res) case SUB: // 0x03 - //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[:])) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) diff := new(big.Int).Sub(xb, yb) - stack.Push(RightPadWord256(flip(diff.Bytes()))) - dbg.Printf(" %v - %v = %v\n", xb, yb, diff) + res := LeftPadWord256(U256(diff).Bytes()) + stack.Push(res) + dbg.Printf(" %v - %v = %v (%X)\n", xb, yb, diff, res) case DIV: // 0x04 - //x, y := stack.Pop64(), stack.Pop64() - //stack.Push64(x / y) x, y := stack.Pop(), stack.Pop() - if y.IsZero() { // TODO + if y.IsZero() { stack.Push(Zero256) - dbg.Printf(" %x / %x = %v (TODO)\n", x, y, 0) + dbg.Printf(" %x / %x = %v\n", x, y, 0) } else { - xb := new(big.Int).SetBytes(flip(x[:])) - yb := new(big.Int).SetBytes(flip(y[:])) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) div := new(big.Int).Div(xb, yb) - stack.Push(RightPadWord256(flip(div.Bytes()))) - dbg.Printf(" %v / %v = %v\n", xb, yb, div) + res := LeftPadWord256(U256(div).Bytes()) + stack.Push(res) + dbg.Printf(" %v / %v = %v (%X)\n", xb, yb, div, res) } case SDIV: // 0x05 - // TODO ... big? - x, y := int64(stack.Pop64()), int64(stack.Pop64()) - if y == 0 { // TODO + x, y := stack.Pop(), stack.Pop() + if y.IsZero() { stack.Push(Zero256) - dbg.Printf(" %v / %v = %v (TODO)\n", x, y, 0) + dbg.Printf(" %x / %x = %v\n", x, y, 0) } else { - stack.Push64(uint64(x / y)) - dbg.Printf(" %v / %v = %v\n", x, y, x/y) + xb := S256(new(big.Int).SetBytes(x[:])) + yb := S256(new(big.Int).SetBytes(y[:])) + div := new(big.Int).Div(xb, yb) + res := LeftPadWord256(U256(div).Bytes()) + stack.Push(res) + dbg.Printf(" %v / %v = %v (%X)\n", xb, yb, div, res) } case MOD: // 0x06 - //x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop(), stack.Pop() - if y.IsZero() { // TODO + if y.IsZero() { stack.Push(Zero256) - dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) + dbg.Printf(" %v %% %v = %v\n", x, y, 0) } else { - xb := new(big.Int).SetBytes(flip(x[:])) - yb := new(big.Int).SetBytes(flip(y[:])) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) mod := new(big.Int).Mod(xb, yb) - stack.Push(RightPadWord256(flip(mod.Bytes()))) - dbg.Printf(" %v %% %v = %v\n", xb, yb, mod) + res := LeftPadWord256(U256(mod).Bytes()) + stack.Push(res) + dbg.Printf(" %v %% %v = %v (%X)\n", xb, yb, mod, res) } case SMOD: // 0x07 - // TODO ... big? - x, y := int64(stack.Pop64()), int64(stack.Pop64()) - if y == 0 { // TODO + x, y := stack.Pop(), stack.Pop() + if y.IsZero() { stack.Push(Zero256) - dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) + dbg.Printf(" %v %% %v = %v\n", x, y, 0) } else { - stack.Push64(uint64(x % y)) - dbg.Printf(" %v %% %v = %v\n", x, y, x%y) + xb := S256(new(big.Int).SetBytes(x[:])) + yb := S256(new(big.Int).SetBytes(y[:])) + mod := new(big.Int).Mod(xb, yb) + res := LeftPadWord256(U256(mod).Bytes()) + stack.Push(res) + dbg.Printf(" %v %% %v = %v (%X)\n", xb, yb, mod, res) } case ADDMOD: // 0x08 - // TODO ... big? - x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() - if z == 0 { // TODO + x, y, z := stack.Pop(), stack.Pop(), stack.Pop() + if z.IsZero() { stack.Push(Zero256) - dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) + dbg.Printf(" %v %% %v = %v\n", x, y, 0) } else { - stack.Push64((x + y) % z) - dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) + zb := new(big.Int).SetBytes(z[:]) + add := new(big.Int).Add(xb, yb) + mod := new(big.Int).Mod(add, zb) + res := LeftPadWord256(U256(mod).Bytes()) + stack.Push(res) + dbg.Printf(" %v + %v %% %v = %v (%X)\n", + xb, yb, zb, mod, res) } case MULMOD: // 0x09 - // TODO ... big? - x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() - if z == 0 { // TODO + x, y, z := stack.Pop(), stack.Pop(), stack.Pop() + if z.IsZero() { stack.Push(Zero256) - dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) + dbg.Printf(" %v %% %v = %v\n", x, y, 0) } else { - stack.Push64((x * y) % z) - dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) + zb := new(big.Int).SetBytes(z[:]) + mul := new(big.Int).Mul(xb, yb) + mod := new(big.Int).Mod(mul, zb) + res := LeftPadWord256(U256(mod).Bytes()) + stack.Push(res) + dbg.Printf(" %v * %v %% %v = %v (%X)\n", + xb, yb, zb, mod, res) } case EXP: // 0x0A - //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[:])) + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(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) + res := LeftPadWord256(U256(pow).Bytes()) + dbg.Printf(" %v ** %v = %v (%X)\n", xb, yb, pow, res) case SIGNEXTEND: // 0x0B - x, y := stack.Pop64(), stack.Pop64() - res := (y << uint(x)) >> x - stack.Push64(res) - dbg.Printf(" (%v << %v) >> %v = %v\n", y, x, x, res) + back := stack.Pop() + backb := new(big.Int).SetBytes(back[:]) + if backb.Cmp(big.NewInt(31)) < 0 { + bit := uint(backb.Uint64()*8 + 7) + num := stack.Pop() + numb := new(big.Int).SetBytes(num[:]) + mask := new(big.Int).Lsh(big.NewInt(1), bit) + mask.Sub(mask, big.NewInt(1)) + if numb.Bit(int(bit)) == 1 { + numb.Or(numb, mask.Not(mask)) + } else { + numb.Add(numb, mask) + } + res := LeftPadWord256(U256(numb).Bytes()) + dbg.Printf(" = %v (%X)", numb, res) + stack.Push(res) + } case LT: // 0x10 - x, y := stack.Pop64(), stack.Pop64() - if x < y { + x, y := stack.Pop(), stack.Pop() + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) + if xb.Cmp(yb) < 0 { stack.Push64(1) + dbg.Printf(" %v < %v = %v\n", xb, yb, 1) } else { stack.Push(Zero256) + dbg.Printf(" %v < %v = %v\n", xb, yb, 0) } - dbg.Printf(" %v < %v = %v\n", x, y, x < y) case GT: // 0x11 - x, y := stack.Pop64(), stack.Pop64() - if x > y { + x, y := stack.Pop(), stack.Pop() + xb := new(big.Int).SetBytes(x[:]) + yb := new(big.Int).SetBytes(y[:]) + if xb.Cmp(yb) > 0 { stack.Push64(1) + dbg.Printf(" %v > %v = %v\n", xb, yb, 1) } else { stack.Push(Zero256) + dbg.Printf(" %v > %v = %v\n", xb, yb, 0) } - dbg.Printf(" %v > %v = %v\n", x, y, x > y) case SLT: // 0x12 - x, y := int64(stack.Pop64()), int64(stack.Pop64()) - if x < y { + x, y := stack.Pop(), stack.Pop() + xb := S256(new(big.Int).SetBytes(x[:])) + yb := S256(new(big.Int).SetBytes(y[:])) + if xb.Cmp(yb) < 0 { stack.Push64(1) + dbg.Printf(" %v < %v = %v\n", xb, yb, 1) } else { stack.Push(Zero256) + dbg.Printf(" %v < %v = %v\n", xb, yb, 0) } - dbg.Printf(" %v < %v = %v\n", x, y, x < y) case SGT: // 0x13 - x, y := int64(stack.Pop64()), int64(stack.Pop64()) - if x > y { + x, y := stack.Pop(), stack.Pop() + xb := S256(new(big.Int).SetBytes(x[:])) + yb := S256(new(big.Int).SetBytes(y[:])) + if xb.Cmp(yb) > 0 { stack.Push64(1) + dbg.Printf(" %v > %v = %v\n", xb, yb, 1) } else { stack.Push(Zero256) + dbg.Printf(" %v > %v = %v\n", xb, yb, 0) } - dbg.Printf(" %v > %v = %v\n", x, y, x > y) case EQ: // 0x14 - x, y := stack.Pop64(), stack.Pop64() - if x == y { + x, y := stack.Pop(), stack.Pop() + if bytes.Equal(x[:], y[:]) { stack.Push64(1) + dbg.Printf(" %X == %X = %v\n", x, y, 1) } else { stack.Push(Zero256) + dbg.Printf(" %X == %X = %v\n", x, y, 0) } - dbg.Printf(" %v == %v = %v\n", x, y, x == y) case ISZERO: // 0x15 - x := stack.Pop64() - if x == 0 { + x := stack.Pop() + if x.IsZero() { stack.Push64(1) + dbg.Printf(" %v == 0 = %v\n", x, 1) } else { stack.Push(Zero256) + dbg.Printf(" %v == 0 = %v\n", x, 0) } - dbg.Printf(" %v == 0 = %v\n", x, x == 0) case AND: // 0x16 - x, y := stack.Pop64(), stack.Pop64() - stack.Push64(x & y) - dbg.Printf(" %v & %v = %v\n", x, y, x&y) + x, y := stack.Pop(), stack.Pop() + z := [32]byte{} + for i := 0; i < 32; i++ { + z[i] = x[i] & y[i] + } + stack.Push(z) + dbg.Printf(" %X & %X = %X\n", x, y, z) + case OR: // 0x17 - x, y := stack.Pop64(), stack.Pop64() - stack.Push64(x | y) - dbg.Printf(" %v | %v = %v\n", x, y, x|y) + x, y := stack.Pop(), stack.Pop() + z := [32]byte{} + for i := 0; i < 32; i++ { + z[i] = x[i] | y[i] + } + stack.Push(z) + dbg.Printf(" %X | %X = %X\n", x, y, z) case XOR: // 0x18 - x, y := stack.Pop64(), stack.Pop64() - stack.Push64(x ^ y) - dbg.Printf(" %v ^ %v = %v\n", x, y, x^y) + x, y := stack.Pop(), stack.Pop() + z := [32]byte{} + for i := 0; i < 32; i++ { + z[i] = x[i] ^ y[i] + } + stack.Push(z) + dbg.Printf(" %X ^ %X = %X\n", x, y, z) case NOT: // 0x19 - x := stack.Pop64() - stack.Push64(^x) - dbg.Printf(" !%v = %v\n", x, ^x) + x := stack.Pop() + z := [32]byte{} + for i := 0; i < 32; i++ { + z[i] = ^x[i] + } + stack.Push(z) + dbg.Printf(" !%X = %X\n", x, z) case BYTE: // 0x1A idx, val := stack.Pop64(), stack.Pop() @@ -336,12 +393,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga return nil, firstErr(err, ErrInsufficientGas) } offset, size := stack.Pop64(), stack.Pop64() - data, ok := subslice(memory, offset, size, false) + data, ok := subslice(memory, offset, size) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } data = sha3.Sha3(data) - stack.PushBytes(flip(data)) + stack.PushBytes(data) dbg.Printf(" => (%v) %X\n", size, data) case ADDRESS: // 0x30 @@ -353,7 +410,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) } - acc := vm.appState.GetAccount(flipWord(addr)) // TODO ensure that 20byte lengths are supported. + acc := vm.appState.GetAccount(addr) if acc == nil { return nil, firstErr(err, ErrUnknownAddress) } @@ -375,12 +432,13 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga case CALLDATALOAD: // 0x35 offset := stack.Pop64() - data, ok := subslice(input, offset, 32, true) + data, ok := subslice(input, offset, 32) if !ok { return nil, firstErr(err, ErrInputOutOfBounds) } - stack.Push(RightPadWord256(data)) - dbg.Printf(" => 0x%X\n", RightPadWord256(data)) + res := LeftPadWord256(data) + stack.Push(res) + dbg.Printf(" => 0x%X\n", res) case CALLDATASIZE: // 0x36 stack.Push64(uint64(len(input))) @@ -390,11 +448,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga memOff := stack.Pop64() inputOff := stack.Pop64() length := stack.Pop64() - data, ok := subslice(input, inputOff, length, false) + data, ok := subslice(input, inputOff, length) if !ok { return nil, firstErr(err, ErrInputOutOfBounds) } - dest, ok := subslice(memory, memOff, length, false) + dest, ok := subslice(memory, memOff, length) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -410,11 +468,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga memOff := stack.Pop64() codeOff := stack.Pop64() length := stack.Pop64() - data, ok := subslice(code, codeOff, length, false) + data, ok := subslice(code, codeOff, length) if !ok { return nil, firstErr(err, ErrCodeOutOfBounds) } - dest, ok := subslice(memory, memOff, length, false) + dest, ok := subslice(memory, memOff, length) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -430,7 +488,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) } - acc := vm.appState.GetAccount(flipWord(addr)) + acc := vm.appState.GetAccount(addr) if acc == nil { return nil, firstErr(err, ErrUnknownAddress) } @@ -444,7 +502,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) } - acc := vm.appState.GetAccount(flipWord(addr)) + acc := vm.appState.GetAccount(addr) if acc == nil { return nil, firstErr(err, ErrUnknownAddress) } @@ -452,11 +510,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga memOff := stack.Pop64() codeOff := stack.Pop64() length := stack.Pop64() - data, ok := subslice(code, codeOff, length, false) + data, ok := subslice(code, codeOff, length) if !ok { return nil, firstErr(err, ErrCodeOutOfBounds) } - dest, ok := subslice(memory, memOff, length, false) + dest, ok := subslice(memory, memOff, length) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -491,20 +549,20 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga case MLOAD: // 0x51 offset := stack.Pop64() - data, ok := subslice(memory, offset, 32, true) + data, ok := subslice(memory, offset, 32) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } - stack.Push(RightPadWord256(data)) + stack.Push(LeftPadWord256(data)) dbg.Printf(" => 0x%X\n", data) case MSTORE: // 0x52 offset, data := stack.Pop64(), stack.Pop() - dest, ok := subslice(memory, offset, 32, false) + dest, ok := subslice(memory, offset, 32) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } - copy(dest, flip(data[:])) + copy(dest, data[:]) dbg.Printf(" => 0x%X\n", data) case MSTORE8: // 0x53 @@ -532,8 +590,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga continue case JUMPI: // 0x57 - pos, cond := stack.Pop64(), stack.Pop64() - if cond >= 1 { + pos, cond := stack.Pop64(), stack.Pop() + if !cond.IsZero() { err = jump(code, pos, &pc) continue } @@ -555,11 +613,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga 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) - codeSegment, ok := subslice(code, pc+1, a, true) + codeSegment, ok := subslice(code, pc+1, a) if !ok { return nil, firstErr(err, ErrCodeOutOfBounds) } - res := RightPadWord256(codeSegment) + res := LeftPadWord256(codeSegment) stack.Push(res) pc += a dbg.Printf(" => 0x%X\n", res) @@ -581,7 +639,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga for i := 0; i < n; i++ { topics[i] = stack.Pop() } - data, ok := subslice(memory, offset, size, false) + data, ok := subslice(memory, offset, size) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -597,7 +655,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga case CREATE: // 0xF0 contractValue := stack.Pop64() offset, size := stack.Pop64(), stack.Pop64() - input, ok := subslice(memory, offset, size, false) + input, ok := subslice(memory, offset, size) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -627,7 +685,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga dbg.Printf(" => %X\n", addr) // Get the arguments from the memory - args, ok := subslice(memory, inOffset, inSize, false) + args, ok := subslice(memory, inOffset, inSize) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -651,7 +709,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) } - acc := vm.appState.GetAccount(flipWord(addr)) + acc := vm.appState.GetAccount(addr) if acc == nil { return nil, firstErr(err, ErrUnknownAddress) } @@ -667,7 +725,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga stack.Push(Zero256) } else { stack.Push(One256) - dest, ok := subslice(memory, retOffset, retSize, false) + dest, ok := subslice(memory, retOffset, retSize) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -681,7 +739,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga case RETURN: // 0xF3 offset, size := stack.Pop64(), stack.Pop64() - ret, ok := subslice(memory, offset, size, false) + ret, ok := subslice(memory, offset, size) if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } @@ -694,7 +752,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga return nil, firstErr(err, ErrInsufficientGas) } // TODO if the receiver is , then make it the fee. - receiver := vm.appState.GetAccount(flipWord(addr)) + receiver := vm.appState.GetAccount(addr) if receiver == nil { return nil, firstErr(err, ErrUnknownAddress) } @@ -715,7 +773,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga } } -func subslice(data []byte, offset, length uint64, flip_ bool) (ret []byte, ok bool) { +func subslice(data []byte, offset, length uint64) (ret []byte, ok bool) { size := uint64(len(data)) if size < offset { return nil, false @@ -726,9 +784,6 @@ func subslice(data []byte, offset, length uint64, flip_ bool) (ret []byte, ok bo ret, ok = data[offset:offset+length], true } - if flip_ { - ret = flip(ret) - } return } @@ -777,27 +832,3 @@ func transfer(from, to *Account, amount uint64) error { return nil } } - -func flip(in []byte) []byte { - l2 := len(in) / 2 - flipped := make([]byte, len(in)) - // 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 -} From b11ca1bbfc3f157bda20c12fcfd6316e76a92701 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Fri, 17 Apr 2015 17:39:50 -0700 Subject: [PATCH 2/5] =?UTF-8?q?(=E2=95=AF=C2=B0=E2=96=A1=C2=B0=EF=BC=89?= =?UTF-8?q?=E2=95=AF=EF=B8=B5=20=E2=94=BB=E2=94=81=E2=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/word.go | 10 ++++++++-- rpc/core/accounts.go | 2 +- rpc/core/txs.go | 9 ++++----- rpc/test/helpers_test.go | 2 +- rpc/test/tests_test.go | 4 ++-- state/block_cache.go | 2 +- state/execution.go | 2 +- state/tx_cache.go | 2 +- vm/native.go | 4 ++-- vm/stack.go | 5 +++-- vm/test/fake_app_state.go | 2 +- vm/test/vm_test.go | 4 ++-- 12 files changed, 27 insertions(+), 21 deletions(-) diff --git a/common/word.go b/common/word.go index 7c5c8a81..1b62f064 100644 --- a/common/word.go +++ b/common/word.go @@ -31,7 +31,10 @@ func (w Word256) Compare(other Word256) int { func Uint64ToWord256(i uint64) Word256 { word := Word256{} - PutUint64(word[:], i) + buf := [8]byte{} + PutUint64(buf[:], i) + word[24], word[25], word[26], word[27] = buf[7], buf[6], buf[5], buf[4] + word[28], word[29], word[30], word[31] = buf[3], buf[2], buf[1], buf[0] return word } @@ -46,7 +49,10 @@ func LeftPadWord256(bz []byte) (word Word256) { } func Uint64FromWord256(word Word256) uint64 { - return binary.LittleEndian.Uint64(word[:]) + buf := [8]byte{} + buf[0], buf[1], buf[2], buf[3] = word[31], word[30], word[29], word[28] + buf[4], buf[5], buf[6], buf[7] = word[27], word[26], word[25], word[24] + return binary.LittleEndian.Uint64(buf[:]) } //------------------------------------- diff --git a/rpc/core/accounts.go b/rpc/core/accounts.go index b6206fd9..ba43673a 100644 --- a/rpc/core/accounts.go +++ b/rpc/core/accounts.go @@ -36,7 +36,7 @@ func GetStorage(address, key []byte) (*ctypes.ResponseGetStorage, error) { storageRoot := account.StorageRoot storageTree := state.LoadStorage(storageRoot) - _, value := storageTree.Get(RightPadWord256(key).Bytes()) + _, value := storageTree.Get(LeftPadWord256(key).Bytes()) if value == nil { return &ctypes.ResponseGetStorage{key, nil}, nil } diff --git a/rpc/core/txs.go b/rpc/core/txs.go index 628bc658..82ff13ef 100644 --- a/rpc/core/txs.go +++ b/rpc/core/txs.go @@ -12,11 +12,11 @@ import ( func toVMAccount(acc *account.Account) *vm.Account { return &vm.Account{ - Address: RightPadWord256(acc.Address), + Address: LeftPadWord256(acc.Address), Balance: acc.Balance, Code: acc.Code, // This is crazy. Nonce: uint64(acc.Sequence), - StorageRoot: RightPadWord256(acc.StorageRoot), + StorageRoot: LeftPadWord256(acc.StorageRoot), Other: acc.PubKey, } } @@ -26,7 +26,6 @@ func toVMAccount(acc *account.Account) *vm.Account { // Run a contract's code on an isolated and unpersisted state // Cannot be used to create new contracts func Call(address, data []byte) (*ctypes.ResponseCall, error) { - st := consensusState.GetState() // performs a copy cache := mempoolReactor.Mempool.GetCache() outAcc := cache.GetAccount(address) @@ -38,7 +37,7 @@ func Call(address, data []byte) (*ctypes.ResponseCall, error) { txCache := state.NewTxCache(cache) params := vm.Params{ BlockHeight: uint64(st.LastBlockHeight), - BlockHash: RightPadWord256(st.LastBlockHash), + BlockHash: LeftPadWord256(st.LastBlockHash), BlockTime: st.LastBlockTime.Unix(), GasLimit: 10000000, } @@ -63,7 +62,7 @@ func CallCode(code, data []byte) (*ctypes.ResponseCall, error) { txCache := state.NewTxCache(cache) params := vm.Params{ BlockHeight: uint64(st.LastBlockHeight), - BlockHash: RightPadWord256(st.LastBlockHash), + BlockHash: LeftPadWord256(st.LastBlockHash), BlockTime: st.LastBlockTime.Unix(), GasLimit: 10000000, } diff --git a/rpc/test/helpers_test.go b/rpc/test/helpers_test.go index 7755277c..07f05a6f 100644 --- a/rpc/test/helpers_test.go +++ b/rpc/test/helpers_test.go @@ -288,7 +288,7 @@ func simpleContract() ([]byte, []byte, []byte) { // the is the code we need to return the contractCode when the contract is initialized lenCode := len(contractCode) // push code to the stack - //code := append([]byte{byte(0x60 + lenCode - 1)}, LeftPadWord256(contractCode).Bytes()...) + //code := append([]byte{byte(0x60 + lenCode - 1)}, RightPadWord256(contractCode).Bytes()...) code := append([]byte{0x7f}, RightPadWord256(contractCode).Bytes()...) // store it in memory code = append(code, []byte{0x60, 0x0, 0x52}...) diff --git a/rpc/test/tests_test.go b/rpc/test/tests_test.go index f95a42d4..311505d0 100644 --- a/rpc/test/tests_test.go +++ b/rpc/test/tests_test.go @@ -119,8 +119,8 @@ func testGetStorage(t *testing.T, typ string) { mempoolCount = 0 v := getStorage(t, typ, contractAddr, []byte{0x1}) - got := RightPadWord256(v) - expected := RightPadWord256([]byte{0x5}) + got := LeftPadWord256(v) + expected := LeftPadWord256([]byte{0x5}) if got.Compare(expected) != 0 { t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(), expected.Bytes()) } diff --git a/state/block_cache.go b/state/block_cache.go index 27775454..2eda83fa 100644 --- a/state/block_cache.go +++ b/state/block_cache.go @@ -106,7 +106,7 @@ func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) { _, val_ := storage.Get(key.Bytes()) value = Zero256 if val_ != nil { - value = RightPadWord256(val_.([]byte)) + value = LeftPadWord256(val_.([]byte)) } cache.storages[Tuple256{addr, key}] = storageInfo{value, false} return value diff --git a/state/execution.go b/state/execution.go index 5152b16f..cf2843db 100644 --- a/state/execution.go +++ b/state/execution.go @@ -395,7 +395,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea txCache = NewTxCache(blockCache) params = vm.Params{ BlockHeight: uint64(_s.LastBlockHeight), - BlockHash: RightPadWord256(_s.LastBlockHash), + BlockHash: LeftPadWord256(_s.LastBlockHash), BlockTime: _s.LastBlockTime.Unix(), GasLimit: 10000000, } diff --git a/state/tx_cache.go b/state/tx_cache.go index d5a23d6c..d181e047 100644 --- a/state/tx_cache.go +++ b/state/tx_cache.go @@ -158,7 +158,7 @@ func toVMAccount(acc *ac.Account) *vm.Account { Balance: acc.Balance, Code: acc.Code, // This is crazy. Nonce: uint64(acc.Sequence), - StorageRoot: RightPadWord256(acc.StorageRoot), + StorageRoot: LeftPadWord256(acc.StorageRoot), Other: acc.PubKey, } } diff --git a/vm/native.go b/vm/native.go index ad9f3f3a..07621b92 100644 --- a/vm/native.go +++ b/vm/native.go @@ -39,7 +39,7 @@ func ecrecoverFunc(input []byte, gas *uint64) (output []byte, err error) { return nil, err } hashed := sha3.Sha3(recovered[1:]) - return RightPadBytes(hashed, 32), nil + return LeftPadBytes(hashed, 32), nil } func sha256Func(input []byte, gas *uint64) (output []byte, err error) { @@ -73,7 +73,7 @@ func ripemd160Func(input []byte, gas *uint64) (output []byte, err error) { if err != nil { panic(err) } - return RightPadBytes(hasher.Sum(nil), 32), nil + return LeftPadBytes(hasher.Sum(nil), 32), nil } func identityFunc(input []byte, gas *uint64) (output []byte, err error) { diff --git a/vm/stack.go b/vm/stack.go index 41d50c70..17938d2c 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -51,7 +51,7 @@ func (st *Stack) PushBytes(bz []byte) { if len(bz) != 32 { panic("Invalid bytes size: expected 32") } - st.Push(RightPadWord256(bz)) + st.Push(LeftPadWord256(bz)) } func (st *Stack) Push64(i uint64) { @@ -73,7 +73,8 @@ func (st *Stack) PopBytes() []byte { } func (st *Stack) Pop64() uint64 { - return GetUint64(st.Pop().Bytes()) + d := st.Pop() + return Uint64FromWord256(d) } func (st *Stack) Len() int { diff --git a/vm/test/fake_app_state.go b/vm/test/fake_app_state.go index 3d6f5ca2..456e3b3c 100644 --- a/vm/test/fake_app_state.go +++ b/vm/test/fake_app_state.go @@ -90,5 +90,5 @@ func createAddress(creator *Account) Word256 { temp := make([]byte, 32+8) copy(temp, creator.Address[:]) PutUint64(temp[32:], nonce) - return RightPadWord256(sha3.Sha3(temp)[:20]) + return LeftPadWord256(sha3.Sha3(temp)[:20]) } diff --git a/vm/test/vm_test.go b/vm/test/vm_test.go index 740d0063..ef9d8834 100644 --- a/vm/test/vm_test.go +++ b/vm/test/vm_test.go @@ -64,10 +64,10 @@ func TestSubcurrency(t *testing.T) { st := newAppState() // Create accounts account1 := &Account{ - Address: RightPadWord256(makeBytes(20)), + Address: LeftPadWord256(makeBytes(20)), } account2 := &Account{ - Address: RightPadWord256(makeBytes(20)), + Address: LeftPadWord256(makeBytes(20)), } st.accounts[account1.Address.String()] = account1 st.accounts[account2.Address.String()] = account2 From 3579a3fdb9cb72fa4da1515e9f516a3d1e6e9007 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 17 Apr 2015 17:43:45 -0700 Subject: [PATCH 3/5] tiny fixes --- merkle/iavl_tree.go | 4 ++-- rpc/core/txs.go | 5 ++--- vm/vm.go | 45 +++++++++++++++++++++++++++++++-------------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/merkle/iavl_tree.go b/merkle/iavl_tree.go index da474318..725d9a6f 100644 --- a/merkle/iavl_tree.go +++ b/merkle/iavl_tree.go @@ -235,9 +235,9 @@ func (ndb *nodeDB) SaveNode(t *IAVLTree, node *IAVLNode) { if node.persisted { panic("Shouldn't be calling save on an already persisted node.") } - if _, ok := ndb.cache[string(node.hash)]; ok { + /*if _, ok := ndb.cache[string(node.hash)]; ok { panic("Shouldn't be calling save on an already cached node.") - } + }*/ // Save node bytes to db buf := bytes.NewBuffer(nil) _, _, err := node.writeToCountHashes(t, buf) diff --git a/rpc/core/txs.go b/rpc/core/txs.go index 628bc658..84606ccf 100644 --- a/rpc/core/txs.go +++ b/rpc/core/txs.go @@ -12,7 +12,7 @@ import ( func toVMAccount(acc *account.Account) *vm.Account { return &vm.Account{ - Address: RightPadWord256(acc.Address), + Address: LeftPadWord256(acc.Address), Balance: acc.Balance, Code: acc.Code, // This is crazy. Nonce: uint64(acc.Sequence), @@ -26,9 +26,8 @@ func toVMAccount(acc *account.Account) *vm.Account { // Run a contract's code on an isolated and unpersisted state // Cannot be used to create new contracts func Call(address, data []byte) (*ctypes.ResponseCall, error) { - st := consensusState.GetState() // performs a copy - cache := mempoolReactor.Mempool.GetCache() + cache := state.NewBlockCache(st) outAcc := cache.GetAccount(address) if outAcc == nil { return nil, fmt.Errorf("Account %x does not exist", address) diff --git a/vm/vm.go b/vm/vm.go index ba16d846..19344591 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -147,7 +147,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga 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()))) + stack.Push(RightPadWord256(flip(rightMostBytes(prod.Bytes(), 32)))) dbg.Printf(" %v * %v = %v\n", xb, yb, prod) case SUB: // 0x03 @@ -304,13 +304,24 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga dbg.Printf(" %v == 0 = %v\n", x, x == 0) case AND: // 0x16 - x, y := stack.Pop64(), stack.Pop64() - stack.Push64(x & y) - dbg.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[:])) + res := new(big.Int).And(xb, yb) + stack.Push(RightPadWord256(flip(res.Bytes()))) + dbg.Printf(" %v & %v = %v\n", xb, yb, res) case OR: // 0x17 - x, y := stack.Pop64(), stack.Pop64() - stack.Push64(x | y) - dbg.Printf(" %v | %v = %v\n", x, y, x|y) + //x, y := stack.Pop64(), stack.Pop64() + //stack.Push64(x | y) + //dbg.Printf(" %v | %v = %v\n", x, y, x|y) + x, y := stack.Pop(), stack.Pop() + xb := new(big.Int).SetBytes(flip(x[:])) + yb := new(big.Int).SetBytes(flip(y[:])) + res := new(big.Int).Or(xb, yb) + stack.Push(RightPadWord256(flip(res.Bytes()))) + dbg.Printf(" %v & %v = %v\n", xb, yb, res) case XOR: // 0x18 x, y := stack.Pop64(), stack.Pop64() @@ -345,8 +356,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga dbg.Printf(" => (%v) %X\n", size, data) case ADDRESS: // 0x30 - stack.Push(callee.Address) - dbg.Printf(" => %X\n", callee.Address) + stack.Push(flipWord(callee.Address)) + dbg.Printf(" => %X\n", flipWord(callee.Address)) case BALANCE: // 0x31 addr := stack.Pop() @@ -362,12 +373,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga dbg.Printf(" => %v (%X)\n", balance, addr) case ORIGIN: // 0x32 - stack.Push(vm.origin) - dbg.Printf(" => %X\n", vm.origin) + stack.Push(flipWord(vm.origin)) + dbg.Printf(" => %X\n", flipWord(vm.origin)) case CALLER: // 0x33 - stack.Push(caller.Address) - dbg.Printf(" => %X\n", caller.Address) + stack.Push(flipWord(caller.Address)) + dbg.Printf(" => %X\n", flipWord(caller.Address)) case CALLVALUE: // 0x34 stack.Push64(value) @@ -616,7 +627,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga stack.Push(Zero256) } else { newAccount.Code = ret // Set the code - stack.Push(newAccount.Address) + stack.Push(flipWord(newAccount.Address)) } case CALL, CALLCODE: // 0xF1, 0xF2 @@ -732,6 +743,12 @@ func subslice(data []byte, offset, length uint64, flip_ bool) (ret []byte, ok bo return } +func rightMostBytes(data []byte, n int) []byte { + size := MinInt(len(data), n) + offset := len(data) - size + return data[offset:] +} + func codeGetOp(code []byte, n uint64) OpCode { if uint64(len(code)) <= n { return OpCode(0) // stop From e702303e16d02dd3f7eaa161480672682c2e2d2d Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 17 Apr 2015 20:51:01 -0700 Subject: [PATCH 4/5] little fixes to vm and endianess --- common/int.go | 12 ++++++++++-- common/word.go | 14 ++++---------- state/tx_cache.go | 2 +- vm/stack.go | 8 +++++--- vm/test/fake_app_state.go | 2 +- vm/vm.go | 19 +++++++++++-------- 6 files changed, 32 insertions(+), 25 deletions(-) diff --git a/common/int.go b/common/int.go index f1c376d7..c6e85dc6 100644 --- a/common/int.go +++ b/common/int.go @@ -22,10 +22,18 @@ func (p Uint64Slice) Search(x uint64) int { return SearchUint64s(p, x) } //----------------------------------------------------------------------------- -func PutUint64(dest []byte, i uint64) { +func PutUint64LE(dest []byte, i uint64) { binary.LittleEndian.PutUint64(dest, i) } -func GetUint64(src []byte) uint64 { +func GetUint64LE(src []byte) uint64 { return binary.LittleEndian.Uint64(src) } + +func PutUint64BE(dest []byte, i uint64) { + binary.BigEndian.PutUint64(dest, i) +} + +func GetUint64BE(src []byte) uint64 { + return binary.BigEndian.Uint64(src) +} diff --git a/common/word.go b/common/word.go index 1b62f064..264a7dcc 100644 --- a/common/word.go +++ b/common/word.go @@ -2,7 +2,6 @@ package common import ( "bytes" - "encoding/binary" "sort" ) @@ -30,12 +29,9 @@ func (w Word256) Compare(other Word256) int { } func Uint64ToWord256(i uint64) Word256 { - word := Word256{} buf := [8]byte{} - PutUint64(buf[:], i) - word[24], word[25], word[26], word[27] = buf[7], buf[6], buf[5], buf[4] - word[28], word[29], word[30], word[31] = buf[3], buf[2], buf[1], buf[0] - return word + PutUint64BE(buf[:], i) + return LeftPadWord256(buf[:]) } func RightPadWord256(bz []byte) (word Word256) { @@ -49,10 +45,8 @@ func LeftPadWord256(bz []byte) (word Word256) { } func Uint64FromWord256(word Word256) uint64 { - buf := [8]byte{} - buf[0], buf[1], buf[2], buf[3] = word[31], word[30], word[29], word[28] - buf[4], buf[5], buf[6], buf[7] = word[27], word[26], word[25], word[24] - return binary.LittleEndian.Uint64(buf[:]) + buf := word.Postfix(8) + return GetUint64BE(buf) } //------------------------------------- diff --git a/state/tx_cache.go b/state/tx_cache.go index d181e047..568639d0 100644 --- a/state/tx_cache.go +++ b/state/tx_cache.go @@ -147,7 +147,7 @@ func (cache *TxCache) AddLog(log *vm.Log) { func NewContractAddress(caller []byte, nonce uint64) []byte { temp := make([]byte, 32+8) copy(temp, caller) - PutUint64(temp[32:], nonce) + PutUint64LE(temp[32:], nonce) return sha3.Sha3(temp)[:20] } diff --git a/vm/stack.go b/vm/stack.go index 17938d2c..500ff4d1 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -106,11 +106,13 @@ func (st *Stack) Peek() Word256 { return st.data[st.ptr-1] } -func (st *Stack) Print() { +func (st *Stack) Print(n int) { fmt.Println("### stack ###") if st.ptr > 0 { - for i, val := range st.data { - fmt.Printf("%-3d %v\n", i, val) + nn := MinInt(n, st.ptr) + for j, i := 0, st.ptr-1; i > st.ptr-1-nn; i-- { + fmt.Printf("%-3d %X\n", j, st.data[i]) + j += 1 } } else { fmt.Println("-- empty --") diff --git a/vm/test/fake_app_state.go b/vm/test/fake_app_state.go index 456e3b3c..a6e29e92 100644 --- a/vm/test/fake_app_state.go +++ b/vm/test/fake_app_state.go @@ -89,6 +89,6 @@ func createAddress(creator *Account) Word256 { creator.Nonce += 1 temp := make([]byte, 32+8) copy(temp, creator.Address[:]) - PutUint64(temp[32:], nonce) + PutUint64LE(temp[32:], nonce) return LeftPadWord256(sha3.Sha3(temp)[:20]) } diff --git a/vm/vm.go b/vm/vm.go index e24da3a0..f9ad0b1c 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -254,6 +254,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga yb := new(big.Int).SetBytes(y[:]) pow := new(big.Int).Exp(xb, yb, big.NewInt(0)) res := LeftPadWord256(U256(pow).Bytes()) + stack.Push(res) dbg.Printf(" %v ** %v = %v (%X)\n", xb, yb, pow, res) case SIGNEXTEND: // 0x0B @@ -402,8 +403,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga dbg.Printf(" => (%v) %X\n", size, data) case ADDRESS: // 0x30 - stack.Push(flipWord(callee.Address)) - dbg.Printf(" => %X\n", flipWord(callee.Address)) + stack.Push(callee.Address) + dbg.Printf(" => %X\n", callee.Address) case BALANCE: // 0x31 addr := stack.Pop() @@ -419,12 +420,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga dbg.Printf(" => %v (%X)\n", balance, addr) case ORIGIN: // 0x32 - stack.Push(flipWord(vm.origin)) - dbg.Printf(" => %X\n", flipWord(vm.origin)) + stack.Push(vm.origin) + dbg.Printf(" => %X\n", vm.origin) case CALLER: // 0x33 - stack.Push(flipWord(caller.Address)) - dbg.Printf(" => %X\n", flipWord(caller.Address)) + stack.Push(caller.Address) + dbg.Printf(" => %X\n", caller.Address) case CALLVALUE: // 0x34 stack.Push64(value) @@ -621,6 +622,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga stack.Push(res) pc += a dbg.Printf(" => 0x%X\n", res) + stack.Print(10) case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) @@ -630,7 +632,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga 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) - dbg.Printf(" => [%d]\n", n) + dbg.Printf(" => [%d] %X\n", n, stack.Peek()) + stack.Print(10) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) @@ -674,7 +677,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga stack.Push(Zero256) } else { newAccount.Code = ret // Set the code - stack.Push(flipWord(newAccount.Address)) + stack.Push(newAccount.Address) } case CALL, CALLCODE: // 0xF1, 0xF2 From 8057fb7125e809222d3570071e44fafc96e9c20f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 17 Apr 2015 20:51:15 -0700 Subject: [PATCH 5/5] fix websocket handler --- rpc/handlers.go | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/rpc/handlers.go b/rpc/handlers.go index 2d0bb1ea..5d2064b8 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -225,6 +225,7 @@ type WSConnection struct { id string wsConn *websocket.Conn writeChan chan WSResponse + quitChan chan struct{} failedSends uint started uint32 stopped uint32 @@ -238,6 +239,7 @@ func NewWSConnection(wsConn *websocket.Conn) *WSConnection { id: wsConn.RemoteAddr().String(), wsConn: wsConn, writeChan: make(chan WSResponse, WriteChanBufferSize), // buffered. we keep track when its full + quitChan: make(chan struct{}), } } @@ -256,8 +258,10 @@ func (con *WSConnection) Start(evsw *events.EventSwitch) { // close the connection func (con *WSConnection) Stop() { if atomic.CompareAndSwapUint32(&con.stopped, 0, 1) { - con.wsConn.Close() - close(con.writeChan) + close(con.quitChan) + // the write loop closes the websocket connection + // when it exits its loop, and the read loop + // closes the writeChan } } @@ -277,6 +281,7 @@ func (con *WSConnection) safeWrite(resp WSResponse) { // read from the socket and subscribe to or unsubscribe from events func (con *WSConnection) read() { + defer close(con.writeChan) reaper := time.Tick(time.Second * WSConnectionReaperSeconds) for { select { @@ -322,32 +327,30 @@ func (con *WSConnection) read() { default: con.safeWrite(WSResponse{Error: "Unknown request type: " + req.Type}) } - } } } // receives on a write channel and writes out on the socket func (con *WSConnection) write() { + defer con.wsConn.Close() n, err := new(int64), new(error) for { - msg, more := <-con.writeChan - if !more { - // the channel was closed, so ensure - // connection is stopped and return - con.Stop() - return - } - buf := new(bytes.Buffer) - binary.WriteJSON(msg, buf, n, err) - if *err != nil { - log.Error("Failed to write JSON WSResponse", "error", err) - } else { - if err := con.wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil { - log.Error("Failed to write response on websocket", "error", err) - con.Stop() - return + select { + case msg := <-con.writeChan: + buf := new(bytes.Buffer) + binary.WriteJSON(msg, buf, n, err) + if *err != nil { + log.Error("Failed to marshal WSResponse to JSON", "error", err) + } else { + if err := con.wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil { + log.Error("Failed to write response on websocket", "error", err) + con.Stop() + return + } } + case <-con.quitChan: + return } } }