From 2668b5963124594afcf7ef8f0115adaef34cb7f1 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Fri, 17 Apr 2015 16:05:36 -0700 Subject: [PATCH 01/16] =?UTF-8?q?=E2=94=AC=E2=94=80=E2=94=AC=20=EF=B8=B5?= =?UTF-8?q?=20/(.=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 000000000..00ab93c77 --- /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 ba16d846a..0363a5faf 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 02/16] =?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 7c5c8a81a..1b62f0640 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 b6206fd9e..ba43673a0 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 628bc6584..82ff13ef4 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 7755277cc..07f05a6f2 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 f95a42d4b..311505d0e 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 277754541..2eda83fa9 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 5152b16f8..cf2843dbf 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 d5a23d6c2..d181e0472 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 ad9f3f3ae..07621b92d 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 41d50c702..17938d2c5 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 3d6f5ca22..456e3b3c9 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 740d0063a..ef9d88343 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 e0d6fd6bfa9e6988036470f45192b2c7aadfced7 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Fri, 17 Apr 2015 18:22:44 -0700 Subject: [PATCH 03/16] RPC shows Peer{Address,IsOutbound} --- rpc/core/net.go | 7 +++++-- rpc/core/types/responses.go | 7 ++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/rpc/core/net.go b/rpc/core/net.go index 64a3c572d..a6036989e 100644 --- a/rpc/core/net.go +++ b/rpc/core/net.go @@ -38,9 +38,12 @@ func NetInfo() (*ctypes.ResponseNetInfo, error) { for _, listener := range p2pSwitch.Listeners() { listeners = append(listeners, listener.String()) } - peers := []string{} + peers := []ctypes.Peer{} for _, peer := range p2pSwitch.Peers().List() { - peers = append(peers, peer.String()) + peers = append(peers, ctypes.Peer{ + Address: peer.Connection().RemoteAddress.String(), + IsOutbound: peer.IsOutbound(), + }) } return &ctypes.ResponseNetInfo{ Network: network, diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index 50a3ea549..35fed0e87 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -73,7 +73,12 @@ type ResponseNetInfo struct { Network string Listening bool Listeners []string - Peers []string + Peers []Peer +} + +type Peer struct { + Address string + IsOutbound bool } type ResponseSignTx struct { From e702303e16d02dd3f7eaa161480672682c2e2d2d Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 17 Apr 2015 20:51:01 -0700 Subject: [PATCH 04/16] 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 f1c376d75..c6e85dc62 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 1b62f0640..264a7dcc1 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 d181e0472..568639d0b 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 17938d2c5..500ff4d15 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 456e3b3c9..a6e29e926 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 e24da3a06..f9ad0b1c7 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 05/16] 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 2d0bb1eaf..5d2064b89 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 } } } From da9f4118a74c7b6c3031a7bcc1ff7929ea07eb48 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sat, 18 Apr 2015 12:48:14 -0700 Subject: [PATCH 06/16] Atomic write to addrbook and privvalidator --- common/os.go | 24 ++++++++++++++++++++++++ config/config.go | 1 + p2p/addrbook.go | 8 +++----- state/priv_validator.go | 3 ++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/common/os.go b/common/os.go index bab5fbce6..2d65683b8 100644 --- a/common/os.go +++ b/common/os.go @@ -2,6 +2,7 @@ package common import ( "fmt" + "io/ioutil" "os" "os/signal" ) @@ -26,3 +27,26 @@ func Exit(s string) { fmt.Printf(s + "\n") os.Exit(1) } + +// Writes to newBytes to filePath. +// Guaranteed not to lose *both* oldBytes and newBytes, +// (assuming that the OS is perfect) +func AtomicWriteFile(filePath string, newBytes []byte) error { + // If a file already exists there, copy to filePath+".bak" (overwrite anything) + if _, err := os.Stat(filePath); !os.IsNotExist(err) { + fileBytes, err := ioutil.ReadFile(filePath) + if err != nil { + return fmt.Errorf("Failed to read file %v. %v", filePath, err) + } + err = ioutil.WriteFile(filePath+".bak", fileBytes, 0600) + if err != nil { + return fmt.Errorf("Failed to write file %v. %v", filePath+".bak", err) + } + } + // Write newBytes to filePath. + err := ioutil.WriteFile(filePath, newBytes, 0600) + if err != nil { + return fmt.Errorf("Failed to write file %v. %v", filePath, err) + } + return nil +} diff --git a/config/config.go b/config/config.go index 23ed290b5..739b4d154 100644 --- a/config/config.go +++ b/config/config.go @@ -37,6 +37,7 @@ var defaultConfig = `# This is a TOML config file. Network = "tendermint_testnet0" ListenAddr = "0.0.0.0:8080" +NodeName = "anon_dev" # First node to connect to. Command-line overridable. SeedNode = "188.166.55.222:8080" diff --git a/p2p/addrbook.go b/p2p/addrbook.go index 893cf1c9e..f8abe28ee 100644 --- a/p2p/addrbook.go +++ b/p2p/addrbook.go @@ -319,14 +319,12 @@ func (a *AddrBook) saveToFile(filePath string) { Addrs: addrs, } - w, err := os.Create(filePath) + jsonBytes, err := json.MarshalIndent(aJSON, "", "\t") if err != nil { - log.Error("Error opening file", "file", filePath, "error", err) + log.Error("Failed to save AddrBook to file", "err", err) return } - defer w.Close() - jsonBytes, err := json.MarshalIndent(aJSON, "", "\t") - _, err = w.Write(jsonBytes) + err = AtomicWriteFile(filePath, jsonBytes) if err != nil { log.Error("Failed to save AddrBook to file", "file", filePath, "error", err) } diff --git a/state/priv_validator.go b/state/priv_validator.go index 17839a500..ed5dff713 100644 --- a/state/priv_validator.go +++ b/state/priv_validator.go @@ -99,8 +99,9 @@ func (privVal *PrivValidator) Save() { func (privVal *PrivValidator) save() { jsonBytes := binary.JSONBytes(privVal) - err := ioutil.WriteFile(privVal.filename, jsonBytes, 0700) + err := AtomicWriteFile(privVal.filename, jsonBytes) if err != nil { + // `@; BOOM!!! panic(err) } } From 6890593a7e5d2cbea1d68bc1d59d1c63322c11a1 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sat, 18 Apr 2015 13:28:38 -0700 Subject: [PATCH 07/16] ... --- config/config.go | 1 - 1 file changed, 1 deletion(-) diff --git a/config/config.go b/config/config.go index 739b4d154..23ed290b5 100644 --- a/config/config.go +++ b/config/config.go @@ -37,7 +37,6 @@ var defaultConfig = `# This is a TOML config file. Network = "tendermint_testnet0" ListenAddr = "0.0.0.0:8080" -NodeName = "anon_dev" # First node to connect to. Command-line overridable. SeedNode = "188.166.55.222:8080" From 5e45a849abb2ce8efb7dcb026d38c1866b0542ad Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sat, 18 Apr 2015 14:46:44 -0700 Subject: [PATCH 08/16] Generate PrivValidator file when it doesn't exist already --- cmd/debora/main.go | 40 +++++++++++++++++++++++----------------- config/config.go | 10 ++++++++-- node/id.go | 34 ++++++++++++++++++++++++++++++++++ node/node.go | 13 +++++++++---- 4 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 node/id.go diff --git a/cmd/debora/main.go b/cmd/debora/main.go index 9c634ffcd..47d0fe4b1 100644 --- a/cmd/debora/main.go +++ b/cmd/debora/main.go @@ -17,25 +17,31 @@ var Config = struct { PrivKey acm.PrivKey }{} -var ( - configFlag = cli.StringFlag{ - Name: "config-file", - Value: ".debora/config.json", - Usage: "config file", - } - waitFlag = cli.BoolFlag{ - Name: "wait", - Usage: "whether to wait for termination", - } - inputFlag = cli.StringFlag{ - Name: "input", - Value: "", - Usage: "input to the program (e.g. stdin)", - } -) - func main() { fmt.Printf("New Debora Process (PID: %d)\n", os.Getpid()) + + rootDir := os.Getenv("DEBROOT") + if rootDir == "" { + rootDir = os.Getenv("HOME") + "/.debora" + } + + var ( + configFlag = cli.StringFlag{ + Name: "config-file", + Value: rootDir + "/config.json", + Usage: "config file", + } + waitFlag = cli.BoolFlag{ + Name: "wait", + Usage: "whether to wait for termination", + } + inputFlag = cli.StringFlag{ + Name: "input", + Value: "", + Usage: "input to the program (e.g. stdin)", + } + ) + app := cli.NewApp() app.Name = "debora" app.Usage = "summons commands to barak" diff --git a/config/config.go b/config/config.go index 23ed290b5..50a7292f5 100644 --- a/config/config.go +++ b/config/config.go @@ -20,7 +20,7 @@ func App() *confer.Config { appMtx.Lock() defer appMtx.Unlock() if app == nil { - Init(".tendermint") + Init("") } return app } @@ -104,7 +104,13 @@ func initDefaults(rootDir string) { func Init(rootDir string) { - // Get RootDir + // Get rootdir + if rootDir == "" { + rootDir = os.Getenv("TMROOT") + } + if rootDir == "" { + rootDir = os.Getenv("HOME") + "/.tendermint" + } configFile := path.Join(rootDir, "config.toml") genesisFile := path.Join(rootDir, "genesis.json") diff --git a/node/id.go b/node/id.go new file mode 100644 index 000000000..b65ea4ac1 --- /dev/null +++ b/node/id.go @@ -0,0 +1,34 @@ +package node + +import ( + acm "github.com/tendermint/tendermint/account" + "time" +) + +type NodeID struct { + Name string + PubKey acm.PubKey +} + +type PrivNodeID struct { + NodeID + PrivKey acm.PrivKey +} + +type NodeGreeting struct { + NodeID + Version string + Network string + Message string + Time time.Time +} + +type SignedNodeGreeting struct { + NodeGreeting + Signature acm.Signature +} + +func (pnid *PrivNodeID) SignGreeting() *SignedNodeGreeting { + //greeting := NodeGreeting{} + return nil +} diff --git a/node/node.go b/node/node.go index a4071752a..df5bd5a26 100644 --- a/node/node.go +++ b/node/node.go @@ -45,11 +45,16 @@ func NewNode() *Node { // Get PrivValidator var privValidator *sm.PrivValidator - if _, err := os.Stat(config.App().GetString("PrivValidatorFile")); err == nil { - privValidator = sm.LoadPrivValidator(config.App().GetString("PrivValidatorFile")) - log.Info("Loaded PrivValidator", "file", config.App().GetString("PrivValidatorFile"), "privValidator", privValidator) + privValidatorFile := config.App().GetString("PrivValidatorFile") + if _, err := os.Stat(privValidatorFile); err == nil { + privValidator = sm.LoadPrivValidator(privValidatorFile) + log.Info("Loaded PrivValidator", + "file", privValidatorFile, "privValidator", privValidator) } else { - log.Info("No PrivValidator found", "file", config.App().GetString("PrivValidatorFile")) + privValidator = sm.GenPrivValidator() + privValidator.SetFile(privValidatorFile) + privValidator.Save() + log.Info("Generated PrivValidator", "file", privValidatorFile) } eventSwitch := new(events.EventSwitch) From fa669ae4362549224d3c779a23b596358b460bcd Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sat, 18 Apr 2015 16:43:48 -0700 Subject: [PATCH 09/16] added Moniker as config, available in RPC. --- config/config.go | 2 ++ rpc/core/net.go | 2 ++ rpc/core/types/responses.go | 1 + 3 files changed, 5 insertions(+) diff --git a/config/config.go b/config/config.go index 50a7292f5..00ae835fd 100644 --- a/config/config.go +++ b/config/config.go @@ -35,6 +35,7 @@ func SetApp(a *confer.Config) { var defaultConfig = `# This is a TOML config file. # For more information, see https://github.com/toml-lang/toml +Moniker = "anonymous" Network = "tendermint_testnet0" ListenAddr = "0.0.0.0:8080" # First node to connect to. Command-line overridable. @@ -86,6 +87,7 @@ var DefaultGenesis = `{ // NOTE: If you change this, maybe also change defaultConfig func initDefaults(rootDir string) { + app.SetDefault("Moniker", "anonymous") app.SetDefault("Network", "tendermint_testnet0") app.SetDefault("ListenAddr", "0.0.0.0:8080") app.SetDefault("DB.Backend", "leveldb") diff --git a/rpc/core/net.go b/rpc/core/net.go index a6036989e..3fcb37e13 100644 --- a/rpc/core/net.go +++ b/rpc/core/net.go @@ -33,6 +33,7 @@ func Status() (*ctypes.ResponseStatus, error) { func NetInfo() (*ctypes.ResponseNetInfo, error) { listening := p2pSwitch.IsListening() + moniker := config.App().GetString("Moniker") network := config.App().GetString("Network") listeners := []string{} for _, listener := range p2pSwitch.Listeners() { @@ -46,6 +47,7 @@ func NetInfo() (*ctypes.ResponseNetInfo, error) { }) } return &ctypes.ResponseNetInfo{ + Moniker: moniker, Network: network, Listening: listening, Listeners: listeners, diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index 35fed0e87..e7c71e259 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -70,6 +70,7 @@ type ResponseStatus struct { } type ResponseNetInfo struct { + Moniker string Network string Listening bool Listeners []string From 5bdd73f4a4a9485b31cd63e21e3e69a768599f36 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sat, 18 Apr 2015 23:08:02 -0700 Subject: [PATCH 10/16] New genesis.json --- config/config.go | 32 +++++++++++++++++++++++++++++++- consensus/state.go | 21 ++++++++++++--------- state/execution.go | 2 ++ state/validator_set_test.go | 12 +++++++++++- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/config/config.go b/config/config.go index 00ae835fd..13da51449 100644 --- a/config/config.go +++ b/config/config.go @@ -68,10 +68,20 @@ var DefaultGenesis = `{ "Accounts": [ { "Address": "29BF3A0A13001A0D23533386BE03E74923AF1179", - "Amount": 2099900000000000 + "Amount": 2099600000000000 } ], "Validators": [ + { + "PubKey": [1, "1ED8C1E665B5035E62DDB3D6B8E7B4D728E13B5F571E687BB9C4B161C23D7686"], + "Amount": 100000000000, + "UnbondTo": [ + { + "Address": "32B472D2E90FD423ABB6942AB27434471F92D736", + "Amount": 100000000000 + } + ] + }, { "PubKey": [1, "3A2C5C341FFC1D5F7AB518519FF8289D3BFAB82DFD6E167B926FAD72C1BF10F8"], "Amount": 100000000000, @@ -81,6 +91,26 @@ var DefaultGenesis = `{ "Amount": 100000000000 } ] + }, + { + "PubKey": [1, "E9664351DC7C15F431E1ADBA5E135F171F67C85DFF64B689FC3359D62E437EEF"], + "Amount": 100000000000, + "UnbondTo": [ + { + "Address": "F1901AF1B2778DBB7939569A91CEB1FE72A7AB12", + "Amount": 100000000000 + } + ] + }, + { + "PubKey": [1, "5D56001CB46D67045FC78A431E844AC94E5780CCEE235B3D8E8666349F1BC1C2"], + "Amount": 100000000000, + "UnbondTo": [ + { + "Address": "E91C4F631EF6DAA25C3E658F72E152AD853EA221", + "Amount": 100000000000 + } + ] } ] }` diff --git a/consensus/state.go b/consensus/state.go index c1579c7e9..6374e7d7e 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -317,11 +317,10 @@ func (cs *ConsensusState) stepTransitionRoutine() { // For clarity, all state transitions that happen after some timeout are here. // Schedule the next action by pushing a RoundAction{} to cs.runActionCh. - scheduleNextAction := func() { + scheduleNextAction := func(rs *RoundState) { go func() { // NOTE: We can push directly to runActionCh because // we're running in a separate goroutine, which avoids deadlocks. - rs := cs.getRoundState() round, roundStartTime, RoundDuration, _, elapsedRatio := calcRoundInfo(rs.StartTime) log.Debug("Scheduling next action", "height", rs.Height, "round", round, "step", rs.Step, "roundStartTime", roundStartTime, "elapsedRatio", elapsedRatio) switch rs.Step { @@ -351,14 +350,14 @@ func (cs *ConsensusState) stepTransitionRoutine() { // There's nothing to scheudle, we're waiting for // ProposalBlockParts.IsComplete() && // Commits.HasTwoThirdsMajority() - panic("The next action from RoundStepCommit is not scheduled by time") + //panic("The next action from RoundStepCommit is not scheduled by time") default: panic("Should not happen") } }() } - scheduleNextAction() + scheduleNextAction(cs.getRoundState()) // NOTE: All ConsensusState.RunAction*() calls come from here. // Since only one routine calls them, it is safe to assume that @@ -397,7 +396,7 @@ ACTION_LOOP: continue ACTION_LOOP } cs.RunActionPropose(rs.Height, rs.Round) - scheduleNextAction() + scheduleNextAction(rs) continue ACTION_LOOP case RoundActionPrevote: @@ -405,7 +404,7 @@ ACTION_LOOP: continue ACTION_LOOP } cs.RunActionPrevote(rs.Height, rs.Round) - scheduleNextAction() + scheduleNextAction(rs) continue ACTION_LOOP case RoundActionPrecommit: @@ -413,7 +412,7 @@ ACTION_LOOP: continue ACTION_LOOP } cs.RunActionPrecommit(rs.Height, rs.Round) - scheduleNextAction() + scheduleNextAction(rs) continue ACTION_LOOP case RoundActionTryCommit: @@ -428,7 +427,7 @@ ACTION_LOOP: // Could not commit, move onto next round. cs.SetupNewRound(rs.Height, rs.Round+1) // cs.Step is now at RoundStepNewRound - scheduleNextAction() + scheduleNextAction(rs) continue ACTION_LOOP } @@ -450,7 +449,7 @@ ACTION_LOOP: cs.evsw.FireEvent(types.EventStringNewBlock(), newBlock) cs.evc.Flush() }() - scheduleNextAction() + scheduleNextAction(rs) continue ACTION_LOOP } else { // do not schedule next action. @@ -533,14 +532,18 @@ func (cs *ConsensusState) updateToState(state *sm.State, contiguous bool) { // After the call cs.Step becomes RoundStepNewRound. func (cs *ConsensusState) setupNewRound(round uint) { + // XXX Looks like this is just not called. // Sanity check if round == 0 { panic("setupNewRound() should never be called for round 0") } // Increment all the way to round. + log.Debug(Fmt("Validators prior to IncrementAccum: %v, %v-%v", cs.Validators.String(), + round, cs.Round)) validators := cs.Validators.Copy() validators.IncrementAccum(round - cs.Round) + log.Debug(Fmt("Validators after IncrementAccum: %v", validators.String())) cs.Round = round cs.Step = RoundStepNewRound diff --git a/state/execution.go b/state/execution.go index cf2843dbf..c34076314 100644 --- a/state/execution.go +++ b/state/execution.go @@ -151,7 +151,9 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade } // Increment validator AccumPowers + log.Debug(Fmt("Bonded Validators prior to IncrementAccum: %v", s.BondedValidators.String())) s.BondedValidators.IncrementAccum(1) + log.Debug(Fmt("Bonded Validators after IncrementAccum: %v", s.BondedValidators.String())) s.LastBlockHeight = block.Height s.LastBlockHash = block.Hash() diff --git a/state/validator_set_test.go b/state/validator_set_test.go index 0153c1440..be108acf9 100644 --- a/state/validator_set_test.go +++ b/state/validator_set_test.go @@ -5,6 +5,7 @@ import ( . "github.com/tendermint/tendermint/common" "bytes" + "fmt" "testing" ) @@ -41,6 +42,15 @@ func TestCopy(t *testing.T) { } } +func TestProposerSelection(t *testing.T) { + vset := randValidatorSet(10) + for i := 0; i < 100; i++ { + val := vset.Proposer() + fmt.Printf("Proposer: %v\n", val) + vset.IncrementAccum(1) + } +} + func BenchmarkValidatorSetCopy(b *testing.B) { b.StopTimer() vset := NewValidatorSet([]*Validator{}) @@ -51,7 +61,7 @@ func BenchmarkValidatorSetCopy(b *testing.B) { PubKey: privAccount.PubKey.(account.PubKeyEd25519), } if !vset.Add(val) { - panic("Failde to add validator") + panic("Failed to add validator") } } b.StartTimer() From 0db6b0b00554b7c544aaeb37060f93033110c0a1 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 19 Apr 2015 09:55:06 -0700 Subject: [PATCH 11/16] Maybe fixed validatorSet.IncrementAccum() --- consensus/state.go | 25 ++++++++++++++----------- state/execution.go | 3 --- state/validator_set.go | 14 +++++++++++--- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/consensus/state.go b/consensus/state.go index 6374e7d7e..6352769bb 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -317,7 +317,8 @@ func (cs *ConsensusState) stepTransitionRoutine() { // For clarity, all state transitions that happen after some timeout are here. // Schedule the next action by pushing a RoundAction{} to cs.runActionCh. - scheduleNextAction := func(rs *RoundState) { + scheduleNextAction := func() { + rs := cs.getRoundState() go func() { // NOTE: We can push directly to runActionCh because // we're running in a separate goroutine, which avoids deadlocks. @@ -350,14 +351,19 @@ func (cs *ConsensusState) stepTransitionRoutine() { // There's nothing to scheudle, we're waiting for // ProposalBlockParts.IsComplete() && // Commits.HasTwoThirdsMajority() - //panic("The next action from RoundStepCommit is not scheduled by time") + panic("The next action from RoundStepCommit is not scheduled by time") default: panic("Should not happen") } }() } - scheduleNextAction(cs.getRoundState()) + if cs.getRoundState().Step < RoundStepCommit { + scheduleNextAction() + } else { + // Race condition with receipt of commits, maybe. + // We shouldn't have to schedule anything. + } // NOTE: All ConsensusState.RunAction*() calls come from here. // Since only one routine calls them, it is safe to assume that @@ -396,7 +402,7 @@ ACTION_LOOP: continue ACTION_LOOP } cs.RunActionPropose(rs.Height, rs.Round) - scheduleNextAction(rs) + scheduleNextAction() continue ACTION_LOOP case RoundActionPrevote: @@ -404,7 +410,7 @@ ACTION_LOOP: continue ACTION_LOOP } cs.RunActionPrevote(rs.Height, rs.Round) - scheduleNextAction(rs) + scheduleNextAction() continue ACTION_LOOP case RoundActionPrecommit: @@ -412,7 +418,7 @@ ACTION_LOOP: continue ACTION_LOOP } cs.RunActionPrecommit(rs.Height, rs.Round) - scheduleNextAction(rs) + scheduleNextAction() continue ACTION_LOOP case RoundActionTryCommit: @@ -427,7 +433,7 @@ ACTION_LOOP: // Could not commit, move onto next round. cs.SetupNewRound(rs.Height, rs.Round+1) // cs.Step is now at RoundStepNewRound - scheduleNextAction(rs) + scheduleNextAction() continue ACTION_LOOP } @@ -449,7 +455,7 @@ ACTION_LOOP: cs.evsw.FireEvent(types.EventStringNewBlock(), newBlock) cs.evc.Flush() }() - scheduleNextAction(rs) + scheduleNextAction() continue ACTION_LOOP } else { // do not schedule next action. @@ -539,11 +545,8 @@ func (cs *ConsensusState) setupNewRound(round uint) { } // Increment all the way to round. - log.Debug(Fmt("Validators prior to IncrementAccum: %v, %v-%v", cs.Validators.String(), - round, cs.Round)) validators := cs.Validators.Copy() validators.IncrementAccum(round - cs.Round) - log.Debug(Fmt("Validators after IncrementAccum: %v", validators.String())) cs.Round = round cs.Step = RoundStepNewRound diff --git a/state/execution.go b/state/execution.go index c34076314..33eb160ab 100644 --- a/state/execution.go +++ b/state/execution.go @@ -151,10 +151,7 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade } // Increment validator AccumPowers - log.Debug(Fmt("Bonded Validators prior to IncrementAccum: %v", s.BondedValidators.String())) s.BondedValidators.IncrementAccum(1) - log.Debug(Fmt("Bonded Validators after IncrementAccum: %v", s.BondedValidators.String())) - s.LastBlockHeight = block.Height s.LastBlockHash = block.Hash() s.LastBlockParts = blockPartsHeader diff --git a/state/validator_set.go b/state/validator_set.go index 817e52293..6220f2667 100644 --- a/state/validator_set.go +++ b/state/validator_set.go @@ -45,6 +45,9 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet { // TODO: mind the overflow when times and votingPower shares too large. func (valSet *ValidatorSet) IncrementAccum(times uint) { + log.Debug("IncrementAccum", "times", times) + + log.Debug(Fmt("IncrementAccum prior to accum: %v\n", valSet)) // Add VotingPower * times to each validator and order into heap. validatorsHeap := NewHeap() @@ -53,15 +56,20 @@ func (valSet *ValidatorSet) IncrementAccum(times uint) { validatorsHeap.Push(val, accumComparable(val.Accum)) } + log.Debug(Fmt("IncrementAccum after accum: %v\n", valSet)) + // Decrement the validator with most accum, times times. for i := uint(0); i < times; i++ { mostest := validatorsHeap.Peek().(*Validator) + if i == times-1 { + valSet.proposer = mostest + } mostest.Accum -= int64(valSet.TotalVotingPower()) validatorsHeap.Update(mostest, accumComparable(mostest.Accum)) } - // The next proposer is the next most accums remaining - valSet.proposer = validatorsHeap.Peek().(*Validator) + log.Debug(Fmt("IncrementAccum after decrements: %v\n", valSet)) + log.Debug(Fmt("IncrementAccum chose proposer: %v\n", valSet.proposer)) } func (valSet *ValidatorSet) Copy() *ValidatorSet { @@ -293,5 +301,5 @@ type accumComparable uint64 // We want to find the validator with the greatest accum. func (ac accumComparable) Less(o interface{}) bool { - return uint64(ac) > uint64(o.(accumComparable)) + return uint64(ac) < uint64(o.(accumComparable)) } From e4f01a55cf9050e4a7895c590b4ed954ed31b7c2 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 19 Apr 2015 10:05:20 -0700 Subject: [PATCH 12/16] update genesis.json --- config/config.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/config/config.go b/config/config.go index 13da51449..2be5438f1 100644 --- a/config/config.go +++ b/config/config.go @@ -67,47 +67,47 @@ ListenAddr = "127.0.0.1:8081" var DefaultGenesis = `{ "Accounts": [ { - "Address": "29BF3A0A13001A0D23533386BE03E74923AF1179", + "Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C", "Amount": 2099600000000000 } ], "Validators": [ { - "PubKey": [1, "1ED8C1E665B5035E62DDB3D6B8E7B4D728E13B5F571E687BB9C4B161C23D7686"], + "PubKey": [1, "323A31EB01877858592AB7D593E9447110AFCD3ACF280D60C4F8E7C04FACC955"], "Amount": 100000000000, "UnbondTo": [ { - "Address": "32B472D2E90FD423ABB6942AB27434471F92D736", + "Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C", "Amount": 100000000000 } ] }, { - "PubKey": [1, "3A2C5C341FFC1D5F7AB518519FF8289D3BFAB82DFD6E167B926FAD72C1BF10F8"], + "PubKey": [1, "DD2206E8F889EED3ABAAECEB2D18962D062A887346241820493FFE3B1DEF255D"], "Amount": 100000000000, "UnbondTo": [ { - "Address": "29BF3A0A13001A0D23533386BE03E74923AF1179", + "Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C", "Amount": 100000000000 } ] }, { - "PubKey": [1, "E9664351DC7C15F431E1ADBA5E135F171F67C85DFF64B689FC3359D62E437EEF"], + "PubKey": [1, "1B3256A3754FC6AB01110C166199A2F619E2D76DB3EE751E376FE404AC9FDCFF"], "Amount": 100000000000, "UnbondTo": [ { - "Address": "F1901AF1B2778DBB7939569A91CEB1FE72A7AB12", + "Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C", "Amount": 100000000000 } ] }, { - "PubKey": [1, "5D56001CB46D67045FC78A431E844AC94E5780CCEE235B3D8E8666349F1BC1C2"], + "PubKey": [1, "62CF1048BAEBB4FFFF360D5E896E3F4EC72D03D55183596931ED14995D512926"], "Amount": 100000000000, "UnbondTo": [ { - "Address": "E91C4F631EF6DAA25C3E658F72E152AD853EA221", + "Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C", "Amount": 100000000000 } ] From 59e69434e1e67d546989f347c655a3a3b2b5c5c3 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 19 Apr 2015 15:45:06 -0700 Subject: [PATCH 13/16] improved barak with logging into ~/.barak/outputs --- cmd/barak/main.go | 14 +++++++++++++- common/os.go | 10 ++++++++++ process/process.go | 17 +++++------------ state/validator_set.go | 9 --------- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/cmd/barak/main.go b/cmd/barak/main.go index 4c056e6be..5c2195780 100644 --- a/cmd/barak/main.go +++ b/cmd/barak/main.go @@ -14,6 +14,7 @@ import ( "os" "reflect" "sync" + "time" "github.com/tendermint/tendermint/binary" . "github.com/tendermint/tendermint/cmd/barak/types" @@ -41,12 +42,14 @@ var barak = struct { nonce uint64 processes map[string]*pcm.Process validators []Validator + rootDir string }{ mtx: sync.Mutex{}, pid: os.Getpid(), nonce: 0, processes: make(map[string]*pcm.Process), validators: nil, + rootDir: "", } func main() { @@ -72,6 +75,10 @@ func main() { } barak.nonce = options.StartNonce barak.validators = options.Validators + barak.rootDir = os.Getenv("BRKROOT") + if barak.rootDir == "" { + barak.rootDir = os.Getenv("HOME") + "/.barak" + } // Debug. fmt.Printf("Options: %v\n", options) @@ -174,7 +181,12 @@ func RunProcess(wait bool, label string, execPath string, args []string, input s } // Otherwise, create one. - proc, err := pcm.Create(pcm.ProcessModeDaemon, label, execPath, args, input) + err := EnsureDir(barak.rootDir + "/outputs") + if err != nil { + return nil, fmt.Errorf("Failed to create outputs dir: %v", err) + } + outPath := Fmt("%v/outputs/%v_%v.out", barak.rootDir, label, time.Now().Format("2006_01_02_15_04_05_MST")) + proc, err := pcm.Create(pcm.ProcessModeDaemon, label, execPath, args, input, outPath) if err == nil { barak.processes[label] = proc } diff --git a/common/os.go b/common/os.go index 2d65683b8..7a5ec0fa2 100644 --- a/common/os.go +++ b/common/os.go @@ -50,3 +50,13 @@ func AtomicWriteFile(filePath string, newBytes []byte) error { } return nil } + +func EnsureDir(dir string) error { + if _, err := os.Stat(dir); os.IsNotExist(err) { + err := os.MkdirAll(dir, 0700) + if err != nil { + return fmt.Errorf("Could not create directory %v. %v", dir, err) + } + } + return nil +} diff --git a/process/process.go b/process/process.go index 1bbe686e6..3f18378e4 100644 --- a/process/process.go +++ b/process/process.go @@ -10,16 +10,6 @@ import ( "time" ) -func makeFile(prefix string) (string, *os.File) { - now := time.Now() - path := fmt.Sprintf("%v_%v.out", prefix, now.Format("2006_01_02_15_04_05_MST")) - file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - panic(err) - } - return path, file -} - type Process struct { Label string ExecPath string @@ -40,8 +30,11 @@ const ( // execPath: command name // args: args to command. (should not include name) -func Create(mode int, label string, execPath string, args []string, input string) (*Process, error) { - outPath, outFile := makeFile("output_" + label) +func Create(mode int, label string, execPath string, args []string, input string, outPath string) (*Process, error) { + outFile, err := os.OpenFile(outPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return nil, err + } cmd := exec.Command(execPath, args...) switch mode { case ProcessModeStd: diff --git a/state/validator_set.go b/state/validator_set.go index 6220f2667..2d247313b 100644 --- a/state/validator_set.go +++ b/state/validator_set.go @@ -45,10 +45,6 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet { // TODO: mind the overflow when times and votingPower shares too large. func (valSet *ValidatorSet) IncrementAccum(times uint) { - log.Debug("IncrementAccum", "times", times) - - log.Debug(Fmt("IncrementAccum prior to accum: %v\n", valSet)) - // Add VotingPower * times to each validator and order into heap. validatorsHeap := NewHeap() for _, val := range valSet.Validators { @@ -56,8 +52,6 @@ func (valSet *ValidatorSet) IncrementAccum(times uint) { validatorsHeap.Push(val, accumComparable(val.Accum)) } - log.Debug(Fmt("IncrementAccum after accum: %v\n", valSet)) - // Decrement the validator with most accum, times times. for i := uint(0); i < times; i++ { mostest := validatorsHeap.Peek().(*Validator) @@ -67,9 +61,6 @@ func (valSet *ValidatorSet) IncrementAccum(times uint) { mostest.Accum -= int64(valSet.TotalVotingPower()) validatorsHeap.Update(mostest, accumComparable(mostest.Accum)) } - - log.Debug(Fmt("IncrementAccum after decrements: %v\n", valSet)) - log.Debug(Fmt("IncrementAccum chose proposer: %v\n", valSet.proposer)) } func (valSet *ValidatorSet) Copy() *ValidatorSet { From 8b36f308e26633cc460d388d31813efebfcd1406 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 19 Apr 2015 15:51:43 -0700 Subject: [PATCH 14/16] Add command logging to barak --- cmd/barak/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/barak/main.go b/cmd/barak/main.go index 5c2195780..efb56789f 100644 --- a/cmd/barak/main.go +++ b/cmd/barak/main.go @@ -118,7 +118,7 @@ func Run(authCommand AuthCommand) (interface{}, error) { if err != nil { return nil, err } - log.Info(Fmt("Run() received command %v", reflect.TypeOf(command))) + log.Info(Fmt("Run() received command %v:\n%v", reflect.TypeOf(command), command)) // Issue command switch c := command.(type) { case CommandRunProcess: From a4c098ac0b5b6d83ca7e0a1eaaa167e78ef53176 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 19 Apr 2015 16:20:00 -0700 Subject: [PATCH 15/16] Format of debora output --- cmd/debora/main.go | 11 ++++-- common/colors.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++ common/string.go | 17 ++++++++++ 3 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 common/colors.go diff --git a/cmd/debora/main.go b/cmd/debora/main.go index 47d0fe4b1..714f80917 100644 --- a/cmd/debora/main.go +++ b/cmd/debora/main.go @@ -177,9 +177,14 @@ func cliListProcesses(c *cli.Context) { } else { fmt.Printf("%v processes:\n", remote) for _, proc := range response.Processes { - fmt.Printf(" \"%v\" => `%v` (%v) start:%v end:%v output:%v\n", - proc.Label, proc.ExecPath, proc.Pid, - proc.StartTime, proc.EndTime, proc.OutputPath) + startTimeStr := Green(proc.StartTime.String()) + endTimeStr := proc.EndTime.String() + if !proc.EndTime.IsZero() { + endTimeStr = Red(endTimeStr) + } + fmt.Printf(" %v start:%v end:%v output:%v\n", + RightPadString(Fmt("\"%v\" => `%v` (%v)", proc.Label, proc.ExecPath, proc.Pid), 40), + startTimeStr, endTimeStr, proc.OutputPath) } } } diff --git a/common/colors.go b/common/colors.go new file mode 100644 index 000000000..776b22e2e --- /dev/null +++ b/common/colors.go @@ -0,0 +1,84 @@ +package common + +import ( + "fmt" + "strings" +) + +const ( + ANSIReset = "\x1b[0m" + ANSIBright = "\x1b[1m" + ANSIDim = "\x1b[2m" + ANSIUnderscore = "\x1b[4m" + ANSIBlink = "\x1b[5m" + ANSIReverse = "\x1b[7m" + ANSIHidden = "\x1b[8m" + + ANSIFgBlack = "\x1b[30m" + ANSIFgRed = "\x1b[31m" + ANSIFgGreen = "\x1b[32m" + ANSIFgYellow = "\x1b[33m" + ANSIFgBlue = "\x1b[34m" + ANSIFgMagenta = "\x1b[35m" + ANSIFgCyan = "\x1b[36m" + ANSIFgWhite = "\x1b[37m" + + ANSIBgBlack = "\x1b[40m" + ANSIBgRed = "\x1b[41m" + ANSIBgGreen = "\x1b[42m" + ANSIBgYellow = "\x1b[43m" + ANSIBgBlue = "\x1b[44m" + ANSIBgMagenta = "\x1b[45m" + ANSIBgCyan = "\x1b[46m" + ANSIBgWhite = "\x1b[47m" +) + +// color the string s with color 'color' +// unless s is already colored +func treat(s string, color string) string { + if len(s) > 2 && s[:2] == "\x1b[" { + return s + } else { + return color + s + ANSIReset + } +} + +func treatAll(color string, args ...interface{}) string { + var parts []string + for _, arg := range args { + parts = append(parts, treat(fmt.Sprintf("%v", arg), color)) + } + return strings.Join(parts, "") +} + +func Black(args ...interface{}) string { + return treatAll(ANSIFgBlack, args...) +} + +func Red(args ...interface{}) string { + return treatAll(ANSIFgRed, args...) +} + +func Green(args ...interface{}) string { + return treatAll(ANSIFgGreen, args...) +} + +func Yellow(args ...interface{}) string { + return treatAll(ANSIFgYellow, args...) +} + +func Blue(args ...interface{}) string { + return treatAll(ANSIFgBlue, args...) +} + +func Magenta(args ...interface{}) string { + return treatAll(ANSIFgMagenta, args...) +} + +func Cyan(args ...interface{}) string { + return treatAll(ANSIFgCyan, args...) +} + +func White(args ...interface{}) string { + return treatAll(ANSIFgWhite, args...) +} diff --git a/common/string.go b/common/string.go index f786a2a4f..a4d221b74 100644 --- a/common/string.go +++ b/common/string.go @@ -2,6 +2,23 @@ package common import ( "fmt" + "strings" ) var Fmt = fmt.Sprintf + +func RightPadString(s string, totalLength int) string { + remaining := totalLength - len(s) + if remaining > 0 { + s = s + strings.Repeat(" ", remaining) + } + return s +} + +func LeftPadString(s string, totalLength int) string { + remaining := totalLength - len(s) + if remaining > 0 { + s = strings.Repeat(" ", remaining) + s + } + return s +} From 8c0fe845c757288fa2e427f4c3a60ecb67a81e67 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 19 Apr 2015 16:45:10 -0700 Subject: [PATCH 16/16] barak writes pidfile --- cmd/barak/main.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/barak/main.go b/cmd/barak/main.go index efb56789f..deafa0b5c 100644 --- a/cmd/barak/main.go +++ b/cmd/barak/main.go @@ -80,6 +80,9 @@ func main() { barak.rootDir = os.Getenv("HOME") + "/.barak" } + // Write pid to file. + AtomicWriteFile(barak.rootDir+"/pidfile", []byte(Fmt("%v", barak.pid))) + // Debug. fmt.Printf("Options: %v\n", options) fmt.Printf("Barak: %v\n", barak)