diff --git a/wallet/priv_account.go b/account/priv_account.go similarity index 77% rename from wallet/priv_account.go rename to account/priv_account.go index db95e725b..b84fc7b16 100644 --- a/wallet/priv_account.go +++ b/account/priv_account.go @@ -1,9 +1,8 @@ -package wallet +package account import ( "github.com/tendermint/go-ed25519" - . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/common" ) @@ -26,3 +25,7 @@ func GenPrivAccount() *PrivAccount { }, } } + +func (privAccount *PrivAccount) Sign(o Signable) Signature { + return privAccount.PrivKey.Sign(SignBytes(o)) +} diff --git a/account/signature_test.go b/account/signature_test.go index cb379741c..ec6234845 100644 --- a/account/signature_test.go +++ b/account/signature_test.go @@ -8,21 +8,22 @@ import ( func TestSignAndValidate(t *testing.T) { privAccount := GenPrivAccount() - account := &privAccount.Account + pubKey := privAccount.PubKey + privKey := privAccount.PrivKey msg := CRandBytes(128) - sig := privAccount.SignBytes(msg) + sig := privKey.Sign(msg) t.Logf("msg: %X, sig: %X", msg, sig) // Test the signature - if !account.VerifyBytes(msg, sig) { + if !pubKey.VerifyBytes(msg, sig) { t.Errorf("Account message signature verification failed") } // Mutate the signature, just one bit. - sig.Bytes[0] ^= byte(0x01) + sig.(SignatureEd25519).Bytes[0] ^= byte(0x01) - if account.VerifyBytes(msg, sig) { + if pubKey.VerifyBytes(msg, sig) { t.Errorf("Account message signature verification should have failed but passed instead") } } diff --git a/binary/binary.go b/binary/binary.go index 7f5dd69b8..8e19bc973 100644 --- a/binary/binary.go +++ b/binary/binary.go @@ -13,7 +13,7 @@ func ReadBinary(o interface{}, r io.Reader, n *int64, err *error) interface{} { } else { ptrRv := reflect.New(rt) readReflect(ptrRv.Elem(), rt, r, n, err) - return ptrRv.Elem() + return ptrRv.Elem().Interface() } } diff --git a/binary/codec.go b/binary/codec.go index 2f94305da..11029ab14 100644 --- a/binary/codec.go +++ b/binary/codec.go @@ -2,7 +2,9 @@ package binary import ( "bytes" + "fmt" "io" + "reflect" "time" ) @@ -80,7 +82,7 @@ func BasicCodecEncoder(o interface{}, w io.Writer, n *int64, err *error) { WriteByte(typeTime, w, n, err) WriteTime(o.(time.Time), w, n, err) default: - panic("Unsupported type") + panic(fmt.Sprintf("Unsupported type: %v", reflect.TypeOf(o))) } } @@ -116,7 +118,11 @@ func BasicCodecDecoder(r io.Reader, n *int64, err *error) (o interface{}) { case typeTime: o = ReadTime(r, n, err) default: - panic("Unsupported type") + if *err != nil { + panic(err) + } else { + panic(fmt.Sprintf("Unsupported type byte: %X", type_)) + } } return o } @@ -151,7 +157,7 @@ func BasicCodecComparator(o1 interface{}, o2 interface{}) int { case time.Time: return int(o1.(time.Time).UnixNano() - o2.(time.Time).UnixNano()) default: - panic("Unsupported type") + panic(fmt.Sprintf("Unsupported type: %v", reflect.TypeOf(o1))) } } diff --git a/binary/reflect.go b/binary/reflect.go index 56981df3f..72f25b6af 100644 --- a/binary/reflect.go +++ b/binary/reflect.go @@ -1,6 +1,7 @@ package binary import ( + "errors" "fmt" "io" "reflect" @@ -10,6 +11,9 @@ type TypeInfo struct { Type reflect.Type // The type Encoder Encoder // Optional custom encoder function Decoder Decoder // Optional custom decoder function + + HasTypeByte bool + TypeByte byte } // If a type implements TypeByte, the byte is included @@ -25,18 +29,33 @@ type HasTypeByte interface { var typeInfos = map[reflect.Type]*TypeInfo{} -func RegisterType(info *TypeInfo) bool { +func RegisterType(info *TypeInfo) *TypeInfo { // Register the type info typeInfos[info.Type] = info // Also register the underlying struct's info, if info.Type is a pointer. + // Or, if info.Type is not a pointer, register the pointer. if info.Type.Kind() == reflect.Ptr { rt := info.Type.Elem() typeInfos[rt] = info + } else { + ptrRt := reflect.PtrTo(info.Type) + typeInfos[ptrRt] = info + } + + // See if the type implements HasTypeByte + if info.Type.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) { + zero := reflect.Zero(info.Type) + typeByte := zero.Interface().(HasTypeByte).TypeByte() + if info.HasTypeByte && info.TypeByte != typeByte { + panic(fmt.Sprintf("Type %v expected TypeByte of %X", info.Type, typeByte)) + } + info.HasTypeByte = true + info.TypeByte = typeByte } - return true + return info } func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *error) { @@ -54,15 +73,29 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err * rv, rt = rv.Elem(), rt.Elem() } - // Custom decoder + // Get typeInfo typeInfo := typeInfos[rt] - if typeInfo != nil && typeInfo.Decoder != nil { + if typeInfo == nil { + typeInfo = RegisterType(&TypeInfo{Type: rt}) + } + + // Custom decoder + if typeInfo.Decoder != nil { decoded := typeInfo.Decoder(r, n, err) decodedRv := reflect.Indirect(reflect.ValueOf(decoded)) rv.Set(decodedRv) return } + // Read TypeByte prefix + if typeInfo.HasTypeByte { + typeByte := ReadByte(r, n, err) + if typeByte != typeInfo.TypeByte { + *err = errors.New(fmt.Sprintf("Expected TypeByte of %X but got %X", typeInfo.TypeByte, typeByte)) + return + } + } + switch rt.Kind() { case reflect.Slice: elemRt := rt.Elem() @@ -86,7 +119,7 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err * numFields := rt.NumField() for i := 0; i < numFields; i++ { field := rt.Field(i) - if field.Anonymous { + if field.PkgPath != "" { continue } fieldRv := rv.Field(i) @@ -97,6 +130,26 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err * str := ReadString(r, n, err) rv.SetString(str) + case reflect.Int64: + num := ReadUInt64(r, n, err) + rv.SetInt(int64(num)) + + case reflect.Int32: + num := ReadUInt32(r, n, err) + rv.SetInt(int64(num)) + + case reflect.Int16: + num := ReadUInt16(r, n, err) + rv.SetInt(int64(num)) + + case reflect.Int8: + num := ReadUInt8(r, n, err) + rv.SetInt(int64(num)) + + case reflect.Int: + num := ReadUVarInt(r, n, err) + rv.SetInt(int64(num)) + case reflect.Uint64: num := ReadUInt64(r, n, err) rv.SetUint(uint64(num)) @@ -124,9 +177,14 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err * func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) { - // Custom encoder + // Get typeInfo typeInfo := typeInfos[rt] - if typeInfo != nil && typeInfo.Encoder != nil { + if typeInfo == nil { + typeInfo = RegisterType(&TypeInfo{Type: rt}) + } + + // Custom encoder, say for an interface type rt. + if typeInfo.Encoder != nil { typeInfo.Encoder(rv.Interface(), w, n, err) return } @@ -135,14 +193,21 @@ func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err if rt.Kind() == reflect.Ptr { rt = rt.Elem() rv = rv.Elem() + // RegisterType registers the ptr type, + // so typeInfo is already for the ptr. } else if rt.Kind() == reflect.Interface { rv = rv.Elem() rt = rv.Type() + typeInfo = typeInfos[rt] + // If interface type, get typeInfo of underlying type. + if typeInfo == nil { + typeInfo = RegisterType(&TypeInfo{Type: rt}) + } } // Write TypeByte prefix - if rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) { - WriteByte(rv.Interface().(HasTypeByte).TypeByte(), w, n, err) + if typeInfo.HasTypeByte { + WriteByte(typeInfo.TypeByte, w, n, err) } switch rt.Kind() { @@ -167,7 +232,7 @@ func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err numFields := rt.NumField() for i := 0; i < numFields; i++ { field := rt.Field(i) - if field.Anonymous { + if field.PkgPath != "" { continue } fieldRv := rv.Field(i) @@ -177,6 +242,21 @@ func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err case reflect.String: WriteString(rv.String(), w, n, err) + case reflect.Int64: + WriteInt64(rv.Int(), w, n, err) + + case reflect.Int32: + WriteInt32(int32(rv.Int()), w, n, err) + + case reflect.Int16: + WriteInt16(int16(rv.Int()), w, n, err) + + case reflect.Int8: + WriteInt8(int8(rv.Int()), w, n, err) + + case reflect.Int: + WriteVarInt(int(rv.Int()), w, n, err) + case reflect.Uint64: WriteUInt64(rv.Uint(), w, n, err) diff --git a/blocks/block.go b/block/block.go similarity index 98% rename from blocks/block.go rename to block/block.go index 9b8147730..469b5182e 100644 --- a/blocks/block.go +++ b/block/block.go @@ -1,4 +1,4 @@ -package blocks +package block import ( "bytes" @@ -42,8 +42,10 @@ func (b *Block) ValidateBasic(lastBlockHeight uint, lastBlockHash []byte, if !b.Time.After(lastBlockTime) { return errors.New("Invalid block time") } - if err := b.Validation.ValidateBasic(); err != nil { - return err + if b.Header.Height != 1 { + if err := b.Validation.ValidateBasic(); err != nil { + return err + } } // XXX more validation return nil diff --git a/blocks/part_set.go b/block/part_set.go similarity index 99% rename from blocks/part_set.go rename to block/part_set.go index a43ec0c30..71d090f2c 100644 --- a/blocks/part_set.go +++ b/block/part_set.go @@ -1,4 +1,4 @@ -package blocks +package block import ( "bytes" diff --git a/blocks/part_set_test.go b/block/part_set_test.go similarity index 99% rename from blocks/part_set_test.go rename to block/part_set_test.go index 22c7e2197..ebfda4524 100644 --- a/blocks/part_set_test.go +++ b/block/part_set_test.go @@ -1,4 +1,4 @@ -package blocks +package block import ( "bytes" diff --git a/blocks/store.go b/block/store.go similarity index 99% rename from blocks/store.go rename to block/store.go index 53aadcf01..b7c5aac72 100644 --- a/blocks/store.go +++ b/block/store.go @@ -1,4 +1,4 @@ -package blocks +package block import ( "bytes" diff --git a/blocks/tx.go b/block/tx.go similarity index 99% rename from blocks/tx.go rename to block/tx.go index c26de4e6b..4d0836924 100644 --- a/blocks/tx.go +++ b/block/tx.go @@ -1,4 +1,4 @@ -package blocks +package block import ( "errors" diff --git a/blocks/vote.go b/block/vote.go similarity index 99% rename from blocks/vote.go rename to block/vote.go index c4f892aaa..1d1d5e26d 100644 --- a/blocks/vote.go +++ b/block/vote.go @@ -1,4 +1,4 @@ -package blocks +package block import ( "errors" diff --git a/blocks/log.go b/blocks/log.go deleted file mode 100644 index 81cf6b4b6..000000000 --- a/blocks/log.go +++ /dev/null @@ -1,15 +0,0 @@ -package blocks - -import ( - "github.com/op/go-logging" -) - -var log = logging.MustGetLogger("block") - -func init() { - logging.SetFormatter(logging.MustStringFormatter("[%{level:.1s}] %{message}")) -} - -func SetBlocksLogger(l *logging.Logger) { - log = l -} diff --git a/cmd/daemon.go b/cmd/daemon.go index b2748ef3c..c7f0ef156 100644 --- a/cmd/daemon.go +++ b/cmd/daemon.go @@ -4,7 +4,7 @@ import ( "os" "os/signal" - "github.com/tendermint/tendermint/blocks" + "github.com/tendermint/tendermint/block" "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/consensus" db_ "github.com/tendermint/tendermint/db" @@ -21,13 +21,13 @@ type Node struct { pexReactor *p2p.PEXReactor mempoolReactor *mempool_.MempoolReactor consensusReactor *consensus.ConsensusReactor - privValidator *consensus.PrivValidator + privValidator *state_.PrivValidator } func NewNode() *Node { // Get BlockStore blockStoreDB := db_.NewMemDB() // TODO configurable db. - blockStore := blocks.NewBlockStore(blockStoreDB) + blockStore := block.NewBlockStore(blockStoreDB) // Get State stateDB := db_.NewMemDB() // TODO configurable db. @@ -38,9 +38,9 @@ func NewNode() *Node { } // Get PrivValidator - var privValidator *consensus.PrivValidator + var privValidator *state_.PrivValidator if _, err := os.Stat(config.PrivValidatorFile()); err == nil { - privValidator = consensus.LoadPrivValidator() + privValidator = state_.LoadPrivValidator() } // Get PEXReactor diff --git a/cmd/gen_account.go b/cmd/gen_account.go index 371e7cf54..2e507f320 100644 --- a/cmd/gen_account.go +++ b/cmd/gen_account.go @@ -4,15 +4,15 @@ import ( "encoding/base64" "fmt" + . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - "github.com/tendermint/tendermint/wallet" ) func gen_account() { // TODO: uh, write better logic. // Generate private account - privAccount := wallet.GenPrivAccount() + privAccount := GenPrivAccount() fmt.Printf(`Generated account: Account Public Key: %X diff --git a/cmd/gen_validator.go b/cmd/gen_validator.go index 14d822fd1..1ae785c55 100644 --- a/cmd/gen_validator.go +++ b/cmd/gen_validator.go @@ -5,7 +5,7 @@ import ( "os" "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/consensus" + "github.com/tendermint/tendermint/state" ) func gen_validator() { @@ -17,7 +17,7 @@ func gen_validator() { } // Generate private validator - privValidator := consensus.GenPrivValidator() + privValidator := state.GenPrivValidator() privValidator.Save() fmt.Printf("Generated a new validator at %v\n", filename) } diff --git a/common/bit_array.go b/common/bit_array.go index 86ef2e4d5..07b72ea98 100644 --- a/common/bit_array.go +++ b/common/bit_array.go @@ -8,8 +8,8 @@ import ( // Not goroutine safe type BitArray struct { - bits uint - elems []uint64 + Bits uint // NOTE: persisted via reflect, must be exported + Elems []uint64 // NOTE: persisted via reflect, must be exported } func NewBitArray(bits uint) BitArray { @@ -17,81 +17,81 @@ func NewBitArray(bits uint) BitArray { } func (bA BitArray) Size() uint { - return bA.bits + return bA.Bits } func (bA BitArray) IsZero() bool { - return bA.bits == 0 + return bA.Bits == 0 } -// NOTE: behavior is undefined if i >= bA.bits +// NOTE: behavior is undefined if i >= bA.Bits func (bA BitArray) GetIndex(i uint) bool { - if i >= bA.bits { + if i >= bA.Bits { return false } - return bA.elems[i/64]&uint64(1<<(i%64)) > 0 + return bA.Elems[i/64]&uint64(1<<(i%64)) > 0 } -// NOTE: behavior is undefined if i >= bA.bits +// NOTE: behavior is undefined if i >= bA.Bits func (bA BitArray) SetIndex(i uint, v bool) bool { - if i >= bA.bits { + if i >= bA.Bits { return false } if v { - bA.elems[i/64] |= uint64(1 << (i % 64)) + bA.Elems[i/64] |= uint64(1 << (i % 64)) } else { - bA.elems[i/64] &= ^uint64(1 << (i % 64)) + bA.Elems[i/64] &= ^uint64(1 << (i % 64)) } return true } func (bA BitArray) Copy() BitArray { - c := make([]uint64, len(bA.elems)) - copy(c, bA.elems) - return BitArray{bA.bits, c} + c := make([]uint64, len(bA.Elems)) + copy(c, bA.Elems) + return BitArray{bA.Bits, c} } func (bA BitArray) copyBits(bits uint) BitArray { c := make([]uint64, (bits+63)/64) - copy(c, bA.elems) + copy(c, bA.Elems) return BitArray{bits, c} } // Returns a BitArray of larger bits size. func (bA BitArray) Or(o BitArray) BitArray { - c := bA.copyBits(MaxUint(bA.bits, o.bits)) - for i := 0; i < len(c.elems); i++ { - c.elems[i] |= o.elems[i] + c := bA.copyBits(MaxUint(bA.Bits, o.Bits)) + for i := 0; i < len(c.Elems); i++ { + c.Elems[i] |= o.Elems[i] } return c } // Returns a BitArray of smaller bit size. func (bA BitArray) And(o BitArray) BitArray { - c := bA.copyBits(MinUint(bA.bits, o.bits)) - for i := 0; i < len(c.elems); i++ { - c.elems[i] &= o.elems[i] + c := bA.copyBits(MinUint(bA.Bits, o.Bits)) + for i := 0; i < len(c.Elems); i++ { + c.Elems[i] &= o.Elems[i] } return c } func (bA BitArray) Not() BitArray { c := bA.Copy() - for i := 0; i < len(c.elems); i++ { - c.elems[i] = ^c.elems[i] + for i := 0; i < len(c.Elems); i++ { + c.Elems[i] = ^c.Elems[i] } return c } func (bA BitArray) Sub(o BitArray) BitArray { - if bA.bits > o.bits { + if bA.Bits > o.Bits { c := bA.Copy() - for i := 0; i < len(o.elems)-1; i++ { - c.elems[i] &= ^c.elems[i] + for i := 0; i < len(o.Elems)-1; i++ { + c.Elems[i] &= ^c.Elems[i] } - i := uint(len(o.elems) - 1) + i := uint(len(o.Elems) - 1) if i >= 0 { - for idx := i * 64; idx < o.bits; idx++ { + for idx := i * 64; idx < o.Bits; idx++ { c.SetIndex(idx, c.GetIndex(idx) && !o.GetIndex(idx)) } } @@ -102,7 +102,7 @@ func (bA BitArray) Sub(o BitArray) BitArray { } func (bA BitArray) PickRandom() (uint, bool) { - length := len(bA.elems) + length := len(bA.Elems) if length == 0 { return 0, false } @@ -110,11 +110,11 @@ func (bA BitArray) PickRandom() (uint, bool) { for i := 0; i < length; i++ { elemIdx := ((i + randElemStart) % length) if elemIdx < length-1 { - if bA.elems[elemIdx] > 0 { + if bA.Elems[elemIdx] > 0 { randBitStart := rand.Intn(64) for j := 0; j < 64; j++ { bitIdx := ((j + randBitStart) % 64) - if (bA.elems[elemIdx] & (1 << uint(bitIdx))) > 0 { + if (bA.Elems[elemIdx] & (1 << uint(bitIdx))) > 0 { return 64*uint(elemIdx) + uint(bitIdx), true } } @@ -122,14 +122,14 @@ func (bA BitArray) PickRandom() (uint, bool) { } } else { // Special case for last elem, to ignore straggler bits - elemBits := int(bA.bits) % 64 + elemBits := int(bA.Bits) % 64 if elemBits == 0 { elemBits = 64 } randBitStart := rand.Intn(elemBits) for j := 0; j < elemBits; j++ { bitIdx := ((j + randBitStart) % elemBits) - if (bA.elems[elemIdx] & (1 << uint(bitIdx))) > 0 { + if (bA.Elems[elemIdx] & (1 << uint(bitIdx))) > 0 { return 64*uint(elemIdx) + uint(bitIdx), true } } @@ -145,7 +145,7 @@ func (bA BitArray) String() string { func (bA BitArray) StringWithIndent(indent string) string { lines := []string{} bits := "" - for i := uint(0); i < bA.bits; i++ { + for i := uint(0); i < bA.Bits; i++ { if bA.GetIndex(i) { bits += "X" } else { @@ -165,5 +165,5 @@ func (bA BitArray) StringWithIndent(indent string) string { if len(bits) > 0 { lines = append(lines, bits) } - return fmt.Sprintf("BA{%v:%v}", bA.bits, strings.Join(lines, indent)) + return fmt.Sprintf("BA{%v:%v}", bA.Bits, strings.Join(lines, indent)) } diff --git a/common/bit_array_test.go b/common/bit_array_test.go index 542522d06..909d784b1 100644 --- a/common/bit_array_test.go +++ b/common/bit_array_test.go @@ -2,7 +2,10 @@ package common import ( "bytes" + "fmt" "testing" + + . "github.com/tendermint/tendermint/binary" ) func randBitArray(bits uint) (BitArray, []byte) { @@ -22,19 +25,18 @@ func randBitArray(bits uint) (BitArray, []byte) { func TestReadWriteEmptyBitarray(t *testing.T) { bA1 := BitArray{} - buf := new(bytes.Buffer) - _, err := bA1.WriteTo(buf) - if err != nil { + buf, n, err := new(bytes.Buffer), new(int64), new(error) + WriteBinary(bA1, buf, n, err) + if *err != nil { t.Error("Failed to write empty bitarray") } - var n int64 - bA2 := ReadBitArray(buf, &n, &err) - if err != nil { + bA2 := ReadBinary(BitArray{}, buf, n, err).(BitArray) + if *err != nil { t.Error("Failed to read empty bitarray") } - if bA2.bits != 0 { - t.Error("Expected to get bA2.bits 0") + if bA2.Bits != 0 { + t.Error("Expected to get bA2.Bits 0") } } @@ -44,16 +46,17 @@ func TestReadWriteBitarray(t *testing.T) { bA1, testData := randBitArray(64*10 + 8) // not divisible by 64 // Write it - buf := new(bytes.Buffer) - _, err := bA1.WriteTo(buf) - if err != nil { + buf, n, err := new(bytes.Buffer), new(int64), new(error) + WriteBinary(bA1, buf, n, err) + if *err != nil { t.Error("Failed to write bitarray") } + fmt.Printf("Bytes: %X", buf.Bytes()) + // Read it - var n int64 - bA2 := ReadBitArray(buf, &n, &err) - if err != nil { + bA2 := ReadBinary(BitArray{}, buf, n, err).(BitArray) + if *err != nil { t.Error("Failed to read bitarray") } testData2 := make([]byte, len(testData)) @@ -77,13 +80,13 @@ func TestAnd(t *testing.T) { bA2, _ := randBitArray(31) bA3 := bA1.And(bA2) - if bA3.bits != 31 { - t.Error("Expected min bits", bA3.bits) + if bA3.Bits != 31 { + t.Error("Expected min bits", bA3.Bits) } - if len(bA3.elems) != len(bA2.elems) { + if len(bA3.Elems) != len(bA2.Elems) { t.Error("Expected min elems length") } - for i := uint(0); i < bA3.bits; i++ { + for i := uint(0); i < bA3.Bits; i++ { expected := bA1.GetIndex(i) && bA2.GetIndex(i) if bA3.GetIndex(i) != expected { t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i)) @@ -97,13 +100,13 @@ func TestOr(t *testing.T) { bA2, _ := randBitArray(31) bA3 := bA1.Or(bA2) - if bA3.bits != 51 { + if bA3.Bits != 51 { t.Error("Expected max bits") } - if len(bA3.elems) != len(bA1.elems) { + if len(bA3.Elems) != len(bA1.Elems) { t.Error("Expected max elems length") } - for i := uint(0); i < bA3.bits; i++ { + for i := uint(0); i < bA3.Bits; i++ { expected := bA1.GetIndex(i) || bA2.GetIndex(i) if bA3.GetIndex(i) != expected { t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i)) @@ -117,13 +120,13 @@ func TestSub1(t *testing.T) { bA2, _ := randBitArray(51) bA3 := bA1.Sub(bA2) - if bA3.bits != bA1.bits { + if bA3.Bits != bA1.Bits { t.Error("Expected bA1 bits") } - if len(bA3.elems) != len(bA1.elems) { + if len(bA3.Elems) != len(bA1.Elems) { t.Error("Expected bA1 elems length") } - for i := uint(0); i < bA3.bits; i++ { + for i := uint(0); i < bA3.Bits; i++ { expected := bA1.GetIndex(i) if bA2.GetIndex(i) { expected = false @@ -140,15 +143,15 @@ func TestSub2(t *testing.T) { bA2, _ := randBitArray(31) bA3 := bA1.Sub(bA2) - if bA3.bits != bA1.bits { + if bA3.Bits != bA1.Bits { t.Error("Expected bA1 bits") } - if len(bA3.elems) != len(bA1.elems) { + if len(bA3.Elems) != len(bA1.Elems) { t.Error("Expected bA1 elems length") } - for i := uint(0); i < bA3.bits; i++ { + for i := uint(0); i < bA3.Bits; i++ { expected := bA1.GetIndex(i) - if i < bA2.bits && bA2.GetIndex(i) { + if i < bA2.Bits && bA2.GetIndex(i) { expected = false } if bA3.GetIndex(i) != expected { diff --git a/consensus/pol.go b/consensus/pol.go index 96e2d010e..d83baef76 100644 --- a/consensus/pol.go +++ b/consensus/pol.go @@ -4,7 +4,7 @@ import ( "fmt" . "github.com/tendermint/tendermint/account" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" "github.com/tendermint/tendermint/state" ) @@ -28,7 +28,7 @@ type POL struct { Votes []POLVoteSignature // Prevote and commit signatures in ValidatorSet order. } -// Returns whether +2/3 have voted/committed for BlockHash. +// Returns whether +2/3 have prevoted/committed for BlockHash. func (pol *POL) Verify(valSet *state.ValidatorSet) error { if uint(len(pol.Votes)) != valSet.Size() { @@ -44,27 +44,32 @@ func (pol *POL) Verify(valSet *state.ValidatorSet) error { }) seenValidators := map[string]struct{}{} - for idx, sig := range pol.Votes { + for idx, vote := range pol.Votes { + // vote may be zero, in which case skip. + if vote.Signature.IsZero() { + continue + } voteDoc := prevoteDoc _, val := valSet.GetByIndex(uint(idx)) - // Commit signature? - if sig.Round < pol.Round { + // Commit vote? + if vote.Round < pol.Round { voteDoc = SignBytes(&Vote{ - Height: pol.Height, Round: sig.Round, Type: VoteTypeCommit, + Height: pol.Height, Round: vote.Round, Type: VoteTypeCommit, BlockHash: pol.BlockHash, BlockParts: pol.BlockParts, }) - } else if sig.Round > pol.Round { - return Errorf("Invalid commit round %v for POL %v", sig.Round, pol) + } else if vote.Round > pol.Round { + return Errorf("Invalid commit round %v for POL %v", vote.Round, pol) } // Validate if _, seen := seenValidators[string(val.Address)]; seen { - return Errorf("Duplicate validator for vote %v for POL %v", sig, pol) + return Errorf("Duplicate validator for vote %v for POL %v", vote, pol) } - if !val.PubKey.VerifyBytes(voteDoc, sig.Signature.Bytes) { - return Errorf("Invalid signature for vote %v for POL %v", sig, pol) + + if !val.PubKey.VerifyBytes(voteDoc, vote.Signature) { + return Errorf("Invalid signature for vote %v for POL %v", vote, pol) } // Tally diff --git a/consensus/pol_test.go b/consensus/pol_test.go index 7e8c23444..5f125a467 100644 --- a/consensus/pol_test.go +++ b/consensus/pol_test.go @@ -1,8 +1,10 @@ package consensus import ( - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/binary" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" + state "github.com/tendermint/tendermint/state" "bytes" "testing" @@ -10,22 +12,30 @@ import ( // NOTE: see consensus/test.go for common test methods. +// Convenience method. +// Signs the vote and sets the POL's vote at the desired index +// Returns the POLVoteSignature pointer, so you can modify it afterwards. +func signAddPOLVoteSignature(val *state.PrivValidator, valSet *state.ValidatorSet, vote *Vote, pol *POL) *POLVoteSignature { + idx, _ := valSet.GetByAddress(val.Address) // now we have the index + pol.Votes[idx] = POLVoteSignature{vote.Round, val.SignVote(vote)} + return &pol.Votes[idx] +} + func TestVerifyVotes(t *testing.T) { - height, round := uint32(1), uint16(0) - _, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(0) + _, valSet, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // Make a POL with -2/3 votes. blockHash := RandBytes(32) pol := &POL{ Height: height, Round: round, BlockHash: blockHash, + Votes: make([]POLVoteSignature, valSet.Size()), } voteProto := &Vote{ Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, } for i := 0; i < 6; i++ { - vote := voteProto.Copy() - privAccounts[i].Sign(vote) - pol.Votes = append(pol.Votes, vote.Signature) + signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol) } // Check that validation fails. @@ -33,35 +43,31 @@ func TestVerifyVotes(t *testing.T) { t.Errorf("Expected POL.Verify() to fail, not enough votes.") } - // Make a POL with +2/3 votes. - vote := voteProto.Copy() - privAccounts[7].Sign(vote) - pol.Votes = append(pol.Votes, vote.Signature) + // Insert another vote to make +2/3 + signAddPOLVoteSignature(privValidators[7], valSet, voteProto, pol) // Check that validation succeeds. if err := pol.Verify(valSet); err != nil { - t.Errorf("Expected POL.Verify() to succeed") + t.Errorf("POL.Verify() failed: %v", err) } } func TestVerifyInvalidVote(t *testing.T) { - height, round := uint32(1), uint16(0) - _, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(0) + _, valSet, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // Make a POL with +2/3 votes with the wrong signature. blockHash := RandBytes(32) pol := &POL{ Height: height, Round: round, BlockHash: blockHash, + Votes: make([]POLVoteSignature, valSet.Size()), } voteProto := &Vote{ Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, } for i := 0; i < 7; i++ { - vote := voteProto.Copy() - privAccounts[i].Sign(vote) - // Mutate the signature. - vote.Signature.Bytes[0] += byte(0x01) - pol.Votes = append(pol.Votes, vote.Signature) + polVoteSig := signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol) + polVoteSig.Signature.Bytes[0] += byte(0x01) // mutated! } // Check that validation fails. @@ -71,47 +77,44 @@ func TestVerifyInvalidVote(t *testing.T) { } func TestVerifyCommits(t *testing.T) { - height, round := uint32(1), uint16(2) - _, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(2) + _, valSet, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // Make a POL with +2/3 votes. blockHash := RandBytes(32) pol := &POL{ Height: height, Round: round, BlockHash: blockHash, + Votes: make([]POLVoteSignature, valSet.Size()), } voteProto := &Vote{ Height: height, Round: round - 1, Type: VoteTypeCommit, BlockHash: blockHash, } for i := 0; i < 7; i++ { - vote := voteProto.Copy() - privAccounts[i].Sign(vote) - pol.Commits = append(pol.Commits, RoundSignature{round - 1, vote.Signature}) + signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol) } // Check that validation succeeds. if err := pol.Verify(valSet); err != nil { - t.Errorf("Expected POL.Verify() to succeed") + t.Errorf("POL.Verify() failed: %v", err) } } func TestVerifyInvalidCommits(t *testing.T) { - height, round := uint32(1), uint16(2) - _, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(2) + _, valSet, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // Make a POL with +2/3 votes with the wrong signature. blockHash := RandBytes(32) pol := &POL{ Height: height, Round: round, BlockHash: blockHash, + Votes: make([]POLVoteSignature, valSet.Size()), } voteProto := &Vote{ Height: height, Round: round - 1, Type: VoteTypeCommit, BlockHash: blockHash, } for i := 0; i < 7; i++ { - vote := voteProto.Copy() - privAccounts[i].Sign(vote) - // Mutate the signature. - vote.Signature.Bytes[0] += byte(0x01) - pol.Commits = append(pol.Commits, RoundSignature{round - 1, vote.Signature}) + polVoteSig := signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol) + polVoteSig.Signature.Bytes[0] += byte(0x01) } // Check that validation fails. @@ -121,21 +124,20 @@ func TestVerifyInvalidCommits(t *testing.T) { } func TestVerifyInvalidCommitRounds(t *testing.T) { - height, round := uint32(1), uint16(2) - _, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(2) + _, valSet, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // Make a POL with +2/3 commits for the current round. blockHash := RandBytes(32) pol := &POL{ Height: height, Round: round, BlockHash: blockHash, + Votes: make([]POLVoteSignature, valSet.Size()), } voteProto := &Vote{ Height: height, Round: round, Type: VoteTypeCommit, BlockHash: blockHash, } for i := 0; i < 7; i++ { - vote := voteProto.Copy() - privAccounts[i].Sign(vote) - pol.Commits = append(pol.Commits, RoundSignature{round, vote.Signature}) + signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol) } // Check that validation fails. @@ -145,21 +147,21 @@ func TestVerifyInvalidCommitRounds(t *testing.T) { } func TestVerifyInvalidCommitRounds2(t *testing.T) { - height, round := uint32(1), uint16(2) - _, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(2) + _, valSet, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // Make a POL with +2/3 commits for future round. blockHash := RandBytes(32) pol := &POL{ Height: height, Round: round, BlockHash: blockHash, + Votes: make([]POLVoteSignature, valSet.Size()), } voteProto := &Vote{ Height: height, Round: round + 1, Type: VoteTypeCommit, BlockHash: blockHash, } for i := 0; i < 7; i++ { - vote := voteProto.Copy() - privAccounts[i].Sign(vote) - pol.Commits = append(pol.Commits, RoundSignature{round + 1, vote.Signature}) + polVoteSig := signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol) + polVoteSig.Round += 1 // mutate round } // Check that validation fails. @@ -169,39 +171,37 @@ func TestVerifyInvalidCommitRounds2(t *testing.T) { } func TestReadWrite(t *testing.T) { - height, round := uint32(1), uint16(2) - _, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(2) + _, valSet, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // Make a POL with +2/3 votes. blockHash := RandBytes(32) pol := &POL{ Height: height, Round: round, BlockHash: blockHash, + Votes: make([]POLVoteSignature, valSet.Size()), } voteProto := &Vote{ Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, } for i := 0; i < 7; i++ { - vote := voteProto.Copy() - privAccounts[i].Sign(vote) - pol.Votes = append(pol.Votes, vote.Signature) + signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol) } // Write it to a buffer. - buf := new(bytes.Buffer) - _, err := pol.WriteTo(buf) - if err != nil { - t.Fatalf("Failed to write POL") + buf, n, err := new(bytes.Buffer), new(int64), new(error) + WriteBinary(pol, buf, n, err) + if *err != nil { + t.Fatalf("Failed to write POL: %v", *err) } // Read from buffer. - var n int64 - pol2 := ReadPOL(buf, &n, &err) - if err != nil { + pol2 := ReadBinary(&POL{}, buf, n, err).(*POL) + if *err != nil { t.Fatalf("Failed to read POL") } // Check that validation succeeds. if err := pol2.Verify(valSet); err != nil { - t.Errorf("Expected POL.Verify() to succeed") + t.Errorf("POL.Verify() failed: %v", err) } } diff --git a/consensus/reactor.go b/consensus/reactor.go index c0b687c33..1b20676eb 100644 --- a/consensus/reactor.go +++ b/consensus/reactor.go @@ -9,8 +9,9 @@ import ( "time" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" + . "github.com/tendermint/tendermint/consensus/types" "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/state" @@ -198,7 +199,7 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte } // Sets our private validator account for signing votes. -func (conR *ConsensusReactor) SetPrivValidator(priv *PrivValidator) { +func (conR *ConsensusReactor) SetPrivValidator(priv *state.PrivValidator) { conR.conS.SetPrivValidator(priv) } diff --git a/consensus/state.go b/consensus/state.go index 35f0a3d6d..ca9edb3ec 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -62,9 +62,10 @@ import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/config" + . "github.com/tendermint/tendermint/consensus/types" "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/state" ) @@ -126,7 +127,7 @@ type RoundState struct { Precommits *VoteSet Commits *VoteSet LastCommits *VoteSet - PrivValidator *PrivValidator + PrivValidator *state.PrivValidator } func (rs *RoundState) String() string { @@ -469,7 +470,7 @@ func (cs *ConsensusState) setupNewRound(round uint) { cs.Precommits.AddFromCommits(cs.Commits) } -func (cs *ConsensusState) SetPrivValidator(priv *PrivValidator) { +func (cs *ConsensusState) SetPrivValidator(priv *state.PrivValidator) { cs.mtx.Lock() defer cs.mtx.Unlock() cs.PrivValidator = priv diff --git a/consensus/state_test.go b/consensus/state_test.go index be19f01a6..8ad631646 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -1,77 +1,33 @@ package consensus import ( + "bytes" "testing" - "time" - . "github.com/tendermint/tendermint/blocks" - . "github.com/tendermint/tendermint/common" - db_ "github.com/tendermint/tendermint/db" - "github.com/tendermint/tendermint/mempool" - "github.com/tendermint/tendermint/state" + . "github.com/tendermint/tendermint/block" ) -func randAccountDetail(id uint64, status byte) (*state.AccountDetail, *state.PrivAccount) { - privAccount := state.GenPrivAccount() - privAccount.Id = id - account := privAccount.Account - return &state.AccountDetail{ - Account: account, - Sequence: RandUInt(), - Balance: 1000, - Status: status, - }, privAccount -} - -// The first numValidators accounts are validators. -func randGenesisState(numAccounts int, numValidators int) (*state.State, []*state.PrivAccount) { - db := db_.NewMemDB() - accountDetails := make([]*state.AccountDetail, numAccounts) - privAccounts := make([]*state.PrivAccount, numAccounts) - for i := 0; i < numAccounts; i++ { - if i < numValidators { - accountDetails[i], privAccounts[i] = - randAccountDetail(uint64(i), state.AccountStatusBonded) - } else { - accountDetails[i], privAccounts[i] = - randAccountDetail(uint64(i), state.AccountStatusNominal) - } - } - s0 := state.GenesisState(db, time.Now(), accountDetails) - s0.Save() - return s0, privAccounts -} - -func makeConsensusState() (*ConsensusState, []*state.PrivAccount) { - state, privAccounts := randGenesisState(20, 10) - blockStore := NewBlockStore(db_.NewMemDB()) - mempool := mempool.NewMempool(state) - cs := NewConsensusState(state, blockStore, mempool) - return cs, privAccounts -} - -//----------------------------------------------------------------------------- - func TestSetupRound(t *testing.T) { - cs, privAccounts := makeConsensusState() + cs, privValidators := makeConsensusState() + val0 := privValidators[0] // Add a vote, precommit, and commit by val0. voteTypes := []byte{VoteTypePrevote, VoteTypePrecommit, VoteTypeCommit} for _, voteType := range voteTypes { vote := &Vote{Height: 1, Round: 0, Type: voteType} // nil vote - privAccounts[0].Sign(vote) - cs.AddVote(vote) + vote.Signature = val0.SignVote(vote) + cs.AddVote(val0.Address, vote) } // Ensure that vote appears in RoundState. rs0 := cs.GetRoundState() - if vote := rs0.Prevotes.GetById(0); vote == nil || vote.Type != VoteTypePrevote { + if vote := rs0.Prevotes.GetByAddress(val0.Address); vote == nil || vote.Type != VoteTypePrevote { t.Errorf("Expected to find prevote but got %v", vote) } - if vote := rs0.Precommits.GetById(0); vote == nil || vote.Type != VoteTypePrecommit { + if vote := rs0.Precommits.GetByAddress(val0.Address); vote == nil || vote.Type != VoteTypePrecommit { t.Errorf("Expected to find precommit but got %v", vote) } - if vote := rs0.Commits.GetById(0); vote == nil || vote.Type != VoteTypeCommit { + if vote := rs0.Commits.GetByAddress(val0.Address); vote == nil || vote.Type != VoteTypeCommit { t.Errorf("Expected to find commit but got %v", vote) } @@ -81,13 +37,13 @@ func TestSetupRound(t *testing.T) { // Now the commit should be copied over to prevotes and precommits. rs1 := cs.GetRoundState() - if vote := rs1.Prevotes.GetById(0); vote == nil || vote.Type != VoteTypeCommit { + if vote := rs1.Prevotes.GetByAddress(val0.Address); vote == nil || vote.Type != VoteTypeCommit { t.Errorf("Expected to find commit but got %v", vote) } - if vote := rs1.Precommits.GetById(0); vote == nil || vote.Type != VoteTypeCommit { + if vote := rs1.Precommits.GetByAddress(val0.Address); vote == nil || vote.Type != VoteTypeCommit { t.Errorf("Expected to find commit but got %v", vote) } - if vote := rs1.Commits.GetById(0); vote == nil || vote.Type != VoteTypeCommit { + if vote := rs1.Commits.GetByAddress(val0.Address); vote == nil || vote.Type != VoteTypeCommit { t.Errorf("Expected to find commit but got %v", vote) } @@ -103,9 +59,9 @@ func TestRunActionProposeNoPrivValidator(t *testing.T) { } func TestRunActionPropose(t *testing.T) { - cs, privAccounts := makeConsensusState() - priv := NewPrivValidator(db_.NewMemDB(), privAccounts[0]) - cs.SetPrivValidator(priv) + cs, privValidators := makeConsensusState() + val0 := privValidators[0] + cs.SetPrivValidator(val0) cs.RunActionPropose(1, 0) rs := cs.GetRoundState() @@ -123,7 +79,7 @@ func TestRunActionPropose(t *testing.T) { } func checkRoundState(t *testing.T, rs *RoundState, - height uint32, round uint16, step RoundStep) { + height uint, round uint, step RoundStep) { if rs.Height != height { t.Errorf("rs.Height should be %v, got %v", height, rs.Height) } @@ -136,13 +92,13 @@ func checkRoundState(t *testing.T, rs *RoundState, } func TestRunActionPrecommitCommitFinalize(t *testing.T) { - cs, privAccounts := makeConsensusState() - priv := NewPrivValidator(db_.NewMemDB(), privAccounts[0]) - cs.SetPrivValidator(priv) + cs, privValidators := makeConsensusState() + val0 := privValidators[0] + cs.SetPrivValidator(val0) cs.RunActionPrecommit(1, 0) <-cs.NewStepCh() // TODO: test this value too. - if cs.Precommits.GetById(0) != nil { + if cs.Precommits.GetByAddress(val0.Address) != nil { t.Errorf("RunActionPrecommit should return nil without a proposal") } @@ -151,7 +107,7 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) { cs.RunActionPrecommit(1, 0) <-cs.NewStepCh() // TODO: test this value too. - if cs.Precommits.GetById(0) != nil { + if cs.Precommits.GetByAddress(val0.Address) != nil { t.Errorf("RunActionPrecommit should return nil, not enough prevotes") } @@ -164,20 +120,26 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) { BlockHash: cs.ProposalBlock.Hash(), BlockParts: cs.ProposalBlockParts.Header(), } - privAccounts[i].Sign(vote) - cs.AddVote(vote) + vote.Signature = privValidators[i].SignVote(vote) + cs.AddVote(privValidators[i].Address, vote) } // Test RunActionPrecommit success: cs.RunActionPrecommit(1, 0) <-cs.NewStepCh() // TODO: test this value too. - if cs.Precommits.GetById(0) == nil { + if cs.Precommits.GetByAddress(val0.Address) == nil { t.Errorf("RunActionPrecommit should have succeeded") } checkRoundState(t, cs.GetRoundState(), 1, 0, RoundStepPrecommit) // Add at least +2/3 precommits. for i := 0; i < 7; i++ { + if bytes.Equal(privValidators[i].Address, val0.Address) { + if cs.Precommits.GetByAddress(val0.Address) == nil { + t.Errorf("Proposer should already have signed a precommit vote") + } + continue + } vote := &Vote{ Height: 1, Round: 0, @@ -185,14 +147,17 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) { BlockHash: cs.ProposalBlock.Hash(), BlockParts: cs.ProposalBlockParts.Header(), } - privAccounts[i].Sign(vote) - cs.AddVote(vote) + vote.Signature = privValidators[i].SignVote(vote) + added, _, err := cs.AddVote(privValidators[i].Address, vote) + if !added || err != nil { + t.Errorf("Error adding precommit: %v", err) + } } // Test RunActionCommit success: cs.RunActionCommit(1) <-cs.NewStepCh() // TODO: test this value too. - if cs.Commits.GetById(0) == nil { + if cs.Commits.GetByAddress(val0.Address) == nil { t.Errorf("RunActionCommit should have succeeded") } checkRoundState(t, cs.GetRoundState(), 1, 0, RoundStepCommit) @@ -204,15 +169,24 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) { // Add at least +2/3 commits. for i := 0; i < 7; i++ { + if bytes.Equal(privValidators[i].Address, val0.Address) { + if cs.Commits.GetByAddress(val0.Address) == nil { + t.Errorf("Proposer should already have signed a commit vote") + } + continue + } vote := &Vote{ Height: 1, - Round: uint16(i), // Doesn't matter what round + Round: uint(i), // Doesn't matter what round Type: VoteTypeCommit, BlockHash: cs.ProposalBlock.Hash(), BlockParts: cs.ProposalBlockParts.Header(), } - privAccounts[i].Sign(vote) - cs.AddVote(vote) + vote.Signature = privValidators[i].SignVote(vote) + added, _, err := cs.AddVote(privValidators[i].Address, vote) + if !added || err != nil { + t.Errorf("Error adding commit: %v", err) + } } // Test TryFinalizeCommit: diff --git a/consensus/test.go b/consensus/test.go index 56348ba8e..77f1da8ed 100644 --- a/consensus/test.go +++ b/consensus/test.go @@ -1,13 +1,18 @@ package consensus import ( + "sort" + + . "github.com/tendermint/tendermint/block" + db_ "github.com/tendermint/tendermint/db" + mempool_ "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/state" ) // Common test methods -func makeValidator(votingPower uint64) (*state.Validator, *PrivValidator) { - privValidator := GenPrivValidator() +func makeValidator(votingPower uint64) (*state.Validator, *state.PrivValidator) { + privValidator := state.GenPrivValidator() return &state.Validator{ Address: privValidator.Address, PubKey: privValidator.PubKey, @@ -19,14 +24,24 @@ func makeValidator(votingPower uint64) (*state.Validator, *PrivValidator) { }, privValidator } -func makeVoteSet(height uint, round uint, type_ byte, numValidators int, votingPower uint64) (*VoteSet, *state.ValidatorSet, []*PrivValidator) { +func makeVoteSet(height uint, round uint, type_ byte, numValidators int, votingPower uint64) (*VoteSet, *state.ValidatorSet, []*state.PrivValidator) { vals := make([]*state.Validator, numValidators) - privValidators := make([]*PrivValidator, numValidators) + privValidators := make([]*state.PrivValidator, numValidators) for i := 0; i < numValidators; i++ { val, privValidator := makeValidator(votingPower) vals[i] = val privValidators[i] = privValidator } valSet := state.NewValidatorSet(vals) + sort.Sort(state.PrivValidatorsByAddress(privValidators)) return NewVoteSet(height, round, type_, valSet), valSet, privValidators } + +func makeConsensusState() (*ConsensusState, []*state.PrivValidator) { + state, _, privValidators := state.RandGenesisState(20, false, 1000, 10, false, 1000) + blockStore := NewBlockStore(db_.NewMemDB()) + mempool := mempool_.NewMempool(state) + mempoolReactor := mempool_.NewMempoolReactor(mempool) + cs := NewConsensusState(state, blockStore, mempoolReactor) + return cs, privValidators +} diff --git a/consensus/proposal.go b/consensus/types/proposal.go similarity index 95% rename from consensus/proposal.go rename to consensus/types/proposal.go index cc64c3102..8b0b8d9a1 100644 --- a/consensus/proposal.go +++ b/consensus/types/proposal.go @@ -7,7 +7,7 @@ import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" ) var ( diff --git a/consensus/vote_set.go b/consensus/vote_set.go index 0c4ae6b43..666c97698 100644 --- a/consensus/vote_set.go +++ b/consensus/vote_set.go @@ -8,7 +8,7 @@ import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" "github.com/tendermint/tendermint/state" ) @@ -128,6 +128,9 @@ func (voteSet *VoteSet) addVote(valIndex uint, vote *Vote) (bool, uint, error) { // Assumes that commits VoteSet is valid. func (voteSet *VoteSet) AddFromCommits(commits *VoteSet) { for valIndex, commit := range commits.votes { + if commit == nil { + continue + } if commit.Round < voteSet.round { voteSet.addVote(uint(valIndex), commit) } @@ -197,6 +200,9 @@ func (voteSet *VoteSet) MakePOL() *POL { Votes: make([]POLVoteSignature, voteSet.valSet.Size()), } for valIndex, vote := range voteSet.votes { + if vote == nil { + continue + } if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) { continue } @@ -245,14 +251,13 @@ func (voteSet *VoteSet) String() string { } func (voteSet *VoteSet) StringWithIndent(indent string) string { - voteSet.mtx.Lock() - defer voteSet.mtx.Unlock() - voteStrings := make([]string, len(voteSet.votes)) - counter := 0 - for _, vote := range voteSet.votes { - voteStrings[counter] = vote.String() - counter++ + for i, vote := range voteSet.votes { + if vote == nil { + voteStrings[i] = "nil" + } else { + voteStrings[i] = vote.String() + } } return fmt.Sprintf(`VoteSet{ %s H:%v R:%v T:%v diff --git a/consensus/vote_set_test.go b/consensus/vote_set_test.go index f33dd1d6c..c34ada917 100644 --- a/consensus/vote_set_test.go +++ b/consensus/vote_set_test.go @@ -3,7 +3,7 @@ package consensus import ( "bytes" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common/test" @@ -13,13 +13,14 @@ import ( // NOTE: see consensus/test.go for common test methods. func TestAddVote(t *testing.T) { - height, round := uint32(1), uint16(0) - voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(0) + voteSet, _, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + val0 := privValidators[0] // t.Logf(">> %v", voteSet) - if voteSet.GetById(0) != nil { - t.Errorf("Expected GetById(0) to be nil") + if voteSet.GetByAddress(val0.Address) != nil { + t.Errorf("Expected GetByAddress(val0.Address) to be nil") } if voteSet.BitArray().GetIndex(0) { t.Errorf("Expected BitArray.GetIndex(0) to be false") @@ -30,11 +31,11 @@ func TestAddVote(t *testing.T) { } vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil} - privAccounts[0].Sign(vote) - voteSet.Add(vote) + vote.Signature = val0.SignVoteUnsafe(vote) + voteSet.Add(val0.Address, vote) - if voteSet.GetById(0) == nil { - t.Errorf("Expected GetById(0) to be present") + if voteSet.GetByAddress(val0.Address) == nil { + t.Errorf("Expected GetByAddress(val0.Address) to be present") } if !voteSet.BitArray().GetIndex(0) { t.Errorf("Expected BitArray.GetIndex(0) to be true") @@ -46,15 +47,15 @@ func TestAddVote(t *testing.T) { } func Test2_3Majority(t *testing.T) { - height, round := uint32(1), uint16(0) - voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(0) + voteSet, _, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // 6 out of 10 voted for nil. voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil} for i := 0; i < 6; i++ { vote := voteProto.Copy() - privAccounts[i].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[i].SignVoteUnsafe(vote) + voteSet.Add(privValidators[i].Address, vote) } hash, header, ok := voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { @@ -65,8 +66,8 @@ func Test2_3Majority(t *testing.T) { { vote := voteProto.Copy() vote.BlockHash = CRandBytes(32) - privAccounts[6].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[6].SignVoteUnsafe(vote) + voteSet.Add(privValidators[6].Address, vote) hash, header, ok = voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { t.Errorf("There should be no 2/3 majority") @@ -77,8 +78,8 @@ func Test2_3Majority(t *testing.T) { { vote := voteProto.Copy() vote.BlockHash = nil - privAccounts[7].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[7].SignVoteUnsafe(vote) + voteSet.Add(privValidators[7].Address, vote) hash, header, ok = voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || !ok { t.Errorf("There should be 2/3 majority for nil") @@ -87,19 +88,19 @@ func Test2_3Majority(t *testing.T) { } func Test2_3MajorityRedux(t *testing.T) { - height, round := uint32(1), uint16(0) - voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 100, 1) + height, round := uint(1), uint(0) + voteSet, _, privValidators := makeVoteSet(height, round, VoteTypePrevote, 100, 1) blockHash := CRandBytes(32) - blockPartsTotal := uint16(123) + blockPartsTotal := uint(123) blockParts := PartSetHeader{blockPartsTotal, CRandBytes(32)} // 66 out of 100 voted for nil. voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: blockParts} for i := 0; i < 66; i++ { vote := voteProto.Copy() - privAccounts[i].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[i].SignVoteUnsafe(vote) + voteSet.Add(privValidators[i].Address, vote) } hash, header, ok := voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { @@ -109,8 +110,8 @@ func Test2_3MajorityRedux(t *testing.T) { // 67th validator voted for nil { vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil, BlockParts: PartSetHeader{}} - privAccounts[66].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[66].SignVoteUnsafe(vote) + voteSet.Add(privValidators[66].Address, vote) hash, header, ok = voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { t.Errorf("There should be no 2/3 majority: last vote added was nil") @@ -120,8 +121,8 @@ func Test2_3MajorityRedux(t *testing.T) { // 68th validator voted for a different BlockParts PartSetHeader { vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: PartSetHeader{blockPartsTotal, CRandBytes(32)}} - privAccounts[67].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[67].SignVoteUnsafe(vote) + voteSet.Add(privValidators[67].Address, vote) hash, header, ok = voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { t.Errorf("There should be no 2/3 majority: last vote added had different PartSetHeader Hash") @@ -131,8 +132,8 @@ func Test2_3MajorityRedux(t *testing.T) { // 69th validator voted for different BlockParts Total { vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: PartSetHeader{blockPartsTotal + 1, blockParts.Hash}} - privAccounts[68].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[68].SignVoteUnsafe(vote) + voteSet.Add(privValidators[68].Address, vote) hash, header, ok = voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { t.Errorf("There should be no 2/3 majority: last vote added had different PartSetHeader Total") @@ -142,8 +143,8 @@ func Test2_3MajorityRedux(t *testing.T) { // 70th validator voted for different BlockHash { vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: CRandBytes(32), BlockParts: blockParts} - privAccounts[69].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[69].SignVoteUnsafe(vote) + voteSet.Add(privValidators[69].Address, vote) hash, header, ok = voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { t.Errorf("There should be no 2/3 majority: last vote added had different BlockHash") @@ -153,8 +154,8 @@ func Test2_3MajorityRedux(t *testing.T) { // 71st validator voted for the right BlockHash & BlockParts { vote := voteProto.Copy() - privAccounts[70].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[70].SignVoteUnsafe(vote) + voteSet.Add(privValidators[70].Address, vote) hash, header, ok = voteSet.TwoThirdsMajority() if !bytes.Equal(hash, blockHash) || !header.Equals(blockParts) || !ok { t.Errorf("There should be 2/3 majority") @@ -163,60 +164,60 @@ func Test2_3MajorityRedux(t *testing.T) { } func TestBadVotes(t *testing.T) { - height, round := uint32(1), uint16(0) - voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(1), uint(0) + voteSet, _, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // val0 votes for nil. vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil} - privAccounts[0].Sign(vote) - added, _, err := voteSet.Add(vote) + vote.Signature = privValidators[0].SignVoteUnsafe(vote) + added, _, err := voteSet.Add(privValidators[0].Address, vote) if !added || err != nil { - t.Errorf("Expected Add(vote) to succeed") + t.Errorf("Expected Add() to succeed") } // val0 votes again for some block. vote = &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: CRandBytes(32)} - privAccounts[0].Sign(vote) - added, _, err = voteSet.Add(vote) + vote.Signature = privValidators[0].SignVoteUnsafe(vote) + added, _, err = voteSet.Add(privValidators[0].Address, vote) if added || err == nil { - t.Errorf("Expected Add(vote) to fail, dupeout.") + t.Errorf("Expected Add() to fail, dupeout.") } // val1 votes on another height vote = &Vote{Height: height + 1, Round: round, Type: VoteTypePrevote, BlockHash: nil} - privAccounts[1].Sign(vote) - added, _, err = voteSet.Add(vote) + vote.Signature = privValidators[1].SignVoteUnsafe(vote) + added, _, err = voteSet.Add(privValidators[1].Address, vote) if added { - t.Errorf("Expected Add(vote) to fail, wrong height") + t.Errorf("Expected Add() to fail, wrong height") } // val2 votes on another round vote = &Vote{Height: height, Round: round + 1, Type: VoteTypePrevote, BlockHash: nil} - privAccounts[2].Sign(vote) - added, _, err = voteSet.Add(vote) + vote.Signature = privValidators[2].SignVoteUnsafe(vote) + added, _, err = voteSet.Add(privValidators[2].Address, vote) if added { - t.Errorf("Expected Add(vote) to fail, wrong round") + t.Errorf("Expected Add() to fail, wrong round") } // val3 votes of another type. vote = &Vote{Height: height, Round: round, Type: VoteTypePrecommit, BlockHash: nil} - privAccounts[3].Sign(vote) - added, _, err = voteSet.Add(vote) + vote.Signature = privValidators[3].SignVoteUnsafe(vote) + added, _, err = voteSet.Add(privValidators[3].Address, vote) if added { - t.Errorf("Expected Add(vote) to fail, wrong type") + t.Errorf("Expected Add() to fail, wrong type") } } func TestAddCommitsToPrevoteVotes(t *testing.T) { - height, round := uint32(2), uint16(5) - voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1) + height, round := uint(2), uint(5) + voteSet, _, privValidators := makeVoteSet(height, round, VoteTypePrevote, 10, 1) // val0, val1, val2, val3, val4, val5 vote for nil. voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil} for i := 0; i < 6; i++ { vote := voteProto.Copy() - privAccounts[i].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[i].SignVoteUnsafe(vote) + voteSet.Add(privValidators[i].Address, vote) } hash, header, ok := voteSet.TwoThirdsMajority() if hash != nil || !header.IsZero() || ok { @@ -225,42 +226,42 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) { // Attempt to add a commit from val6 at a previous height vote := &Vote{Height: height - 1, Round: round, Type: VoteTypeCommit, BlockHash: nil} - privAccounts[6].Sign(vote) - added, _, _ := voteSet.Add(vote) + vote.Signature = privValidators[6].SignVoteUnsafe(vote) + added, _, _ := voteSet.Add(privValidators[6].Address, vote) if added { - t.Errorf("Expected Add(vote) to fail, wrong height.") + t.Errorf("Expected Add() to fail, wrong height.") } // Attempt to add a commit from val6 at a later round vote = &Vote{Height: height, Round: round + 1, Type: VoteTypeCommit, BlockHash: nil} - privAccounts[6].Sign(vote) - added, _, _ = voteSet.Add(vote) + vote.Signature = privValidators[6].SignVoteUnsafe(vote) + added, _, _ = voteSet.Add(privValidators[6].Address, vote) if added { - t.Errorf("Expected Add(vote) to fail, cannot add future round vote.") + t.Errorf("Expected Add() to fail, cannot add future round vote.") } // Attempt to add a commit from val6 for currrent height/round. vote = &Vote{Height: height, Round: round, Type: VoteTypeCommit, BlockHash: nil} - privAccounts[6].Sign(vote) - added, _, err := voteSet.Add(vote) + vote.Signature = privValidators[6].SignVoteUnsafe(vote) + added, _, err := voteSet.Add(privValidators[6].Address, vote) if added || err == nil { - t.Errorf("Expected Add(vote) to fail, only prior round commits can be added.") + t.Errorf("Expected Add() to fail, only prior round commits can be added.") } // Add commit from val6 at a previous round vote = &Vote{Height: height, Round: round - 1, Type: VoteTypeCommit, BlockHash: nil} - privAccounts[6].Sign(vote) - added, _, err = voteSet.Add(vote) + vote.Signature = privValidators[6].SignVoteUnsafe(vote) + added, _, err = voteSet.Add(privValidators[6].Address, vote) if !added || err != nil { - t.Errorf("Expected Add(vote) to succeed, commit for prior rounds are relevant.") + t.Errorf("Expected Add() to succeed, commit for prior rounds are relevant.") } // Also add commit from val7 for previous round. vote = &Vote{Height: height, Round: round - 2, Type: VoteTypeCommit, BlockHash: nil} - privAccounts[7].Sign(vote) - added, _, err = voteSet.Add(vote) + vote.Signature = privValidators[7].SignVoteUnsafe(vote) + added, _, err = voteSet.Add(privValidators[7].Address, vote) if !added || err != nil { - t.Errorf("Expected Add(vote) to succeed. err: %v", err) + t.Errorf("Expected Add() to succeed. err: %v", err) } // We should have 2/3 majority @@ -272,8 +273,8 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) { } func TestMakeValidation(t *testing.T) { - height, round := uint32(1), uint16(0) - voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypeCommit, 10, 1) + height, round := uint(1), uint(0) + voteSet, _, privValidators := makeVoteSet(height, round, VoteTypeCommit, 10, 1) blockHash, blockParts := CRandBytes(32), PartSetHeader{123, CRandBytes(32)} // 6 out of 10 voted for some block. @@ -281,8 +282,8 @@ func TestMakeValidation(t *testing.T) { BlockHash: blockHash, BlockParts: blockParts} for i := 0; i < 6; i++ { vote := voteProto.Copy() - privAccounts[i].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[i].SignVoteUnsafe(vote) + voteSet.Add(privValidators[i].Address, vote) } // MakeValidation should fail. @@ -293,15 +294,15 @@ func TestMakeValidation(t *testing.T) { vote := &Vote{Height: height, Round: round, Type: VoteTypeCommit, BlockHash: CRandBytes(32), BlockParts: PartSetHeader{123, CRandBytes(32)}} - privAccounts[6].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[6].SignVoteUnsafe(vote) + voteSet.Add(privValidators[6].Address, vote) } // The 8th voted like everyone else. { vote := voteProto.Copy() - privAccounts[7].Sign(vote) - voteSet.Add(vote) + vote.Signature = privValidators[7].SignVoteUnsafe(vote) + voteSet.Add(privValidators[7].Address, vote) } validation := voteSet.MakeValidation() @@ -312,24 +313,8 @@ func TestMakeValidation(t *testing.T) { } // Ensure that Validation commits are ordered. - for i, rsig := range validation.Commits { - if i < 6 || i == 7 { - if rsig.Round != round { - t.Errorf("Expected round %v but got %v", round, rsig.Round) - } - if rsig.SignerId != uint64(i) { - t.Errorf("Validation commit signer out of order. Expected %v, got %v", i, rsig.Signature) - } - vote := &Vote{Height: height, Round: rsig.Round, Type: VoteTypeCommit, - BlockHash: blockHash, BlockParts: blockParts, - Signature: rsig.Signature} - if !privAccounts[i].Verify(vote) { - t.Errorf("Validation commit did not verify") - } - } else { - if !rsig.IsZero() { - t.Errorf("Expected zero RoundSignature for the rest") - } - } + if err := validation.ValidateBasic(); err != nil { + t.Errorf("Error in Validation.ValidateBasic(): %v", err) } + } diff --git a/mempool/mempool.go b/mempool/mempool.go index 631890f68..ea095df74 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -12,7 +12,7 @@ import ( "sync" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" "github.com/tendermint/tendermint/state" ) diff --git a/mempool/reactor.go b/mempool/reactor.go index d5d8a5f74..7fb75146f 100644 --- a/mempool/reactor.go +++ b/mempool/reactor.go @@ -6,7 +6,7 @@ import ( "sync/atomic" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" "github.com/tendermint/tendermint/p2p" ) diff --git a/merkle/iavl_tree.go b/merkle/iavl_tree.go index 9b505a432..f9c19ae44 100644 --- a/merkle/iavl_tree.go +++ b/merkle/iavl_tree.go @@ -120,6 +120,9 @@ func (t *IAVLTree) Save() []byte { } func (t *IAVLTree) Load(hash []byte) { + if len(hash) == 0 { + panic("IAVLTree.Load() hash was nil") + } t.root = t.ndb.GetNode(t, hash) } diff --git a/p2p/connection.go b/p2p/connection.go index 925babd53..ce709bd11 100644 --- a/p2p/connection.go +++ b/p2p/connection.go @@ -267,7 +267,7 @@ FOR_LOOP: break FOR_LOOP } if err != nil { - log.Info("%v failed @ sendRoutine:\n%v", c, err) + log.Warning("%v failed @ sendRoutine:\n%v", c, err) c.Stop() break FOR_LOOP } @@ -349,7 +349,7 @@ FOR_LOOP: c.recvMonitor.Update(int(n)) if err != nil { if atomic.LoadUint32(&c.stopped) != 1 { - log.Info("%v failed @ recvRoutine with err: %v", c, err) + log.Warning("%v failed @ recvRoutine with err: %v", c, err) c.Stop() } break FOR_LOOP @@ -377,7 +377,7 @@ FOR_LOOP: c.recvMonitor.Update(int(*n)) if *err != nil { if atomic.LoadUint32(&c.stopped) != 1 { - log.Info("%v failed @ recvRoutine", c) + log.Warning("%v failed @ recvRoutine", c) c.Stop() } break FOR_LOOP @@ -506,6 +506,7 @@ func (ch *Channel) nextMsgPacket() msgPacket { // Not goroutine-safe func (ch *Channel) writeMsgPacketTo(w io.Writer) (n int64, err error) { packet := ch.nextMsgPacket() + WriteByte(packetTypeMsg, w, &n, &err) WriteBinary(packet, w, &n, &err) if err != nil { ch.recentlySent += n @@ -549,8 +550,6 @@ type msgPacket struct { Bytes []byte } -func (p msgPacket) TypeByte() byte { return packetTypeMsg } - func (p msgPacket) String() string { return fmt.Sprintf("MsgPacket{%X:%X}", p.ChannelId, p.Bytes) } diff --git a/p2p/listener.go b/p2p/listener.go index 0b79944c7..ea62cd030 100644 --- a/p2p/listener.go +++ b/p2p/listener.go @@ -62,8 +62,10 @@ func NewDefaultListener(protocol string, lAddr string) Listener { // Determine external address... var extAddr *NetAddress // If the lAddrIP is INADDR_ANY, try UPnP - if lAddrIP == "" || lAddrIP == "0.0.0.0" { - extAddr = getUPNPExternalAddress(lAddrPort, listenerPort) + if false { + if lAddrIP == "" || lAddrIP == "0.0.0.0" { + extAddr = getUPNPExternalAddress(lAddrPort, listenerPort) + } } // Otherwise just use the local address... if extAddr == nil { diff --git a/rpc/blocks.go b/rpc/blocks.go index 5359e8259..653347585 100644 --- a/rpc/blocks.go +++ b/rpc/blocks.go @@ -3,7 +3,7 @@ package rpc import ( "net/http" - //. "github.com/tendermint/tendermint/blocks" + //. "github.com/tendermint/tendermint/block" ) func BlockHandler(w http.ResponseWriter, r *http.Request) { diff --git a/state/genesis.go b/state/genesis.go index efacf91c4..16ecd6a00 100644 --- a/state/genesis.go +++ b/state/genesis.go @@ -7,7 +7,7 @@ import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" db_ "github.com/tendermint/tendermint/db" "github.com/tendermint/tendermint/merkle" @@ -16,7 +16,7 @@ import ( type GenesisDoc struct { GenesisTime time.Time Accounts []*Account - Validators []*Validator + Validators []*ValidatorInfo } func GenesisDocFromJSON(jsonBlob []byte) (genState *GenesisDoc) { @@ -51,14 +51,31 @@ func GenesisState(db db_.DB, genDoc *GenesisDoc) *State { accounts.Set(acc.Address, acc) } + // Make validatorInfos state tree + validatorInfos := merkle.NewIAVLTree(BasicCodec, ValidatorInfoCodec, 0, db) + for _, valInfo := range genDoc.Validators { + validatorInfos.Set(valInfo.Address, valInfo) + } + + // Make validators + validators := make([]*Validator, len(genDoc.Validators)) + for i, valInfo := range genDoc.Validators { + validators[i] = &Validator{ + Address: valInfo.Address, + PubKey: valInfo.PubKey, + VotingPower: valInfo.FirstBondAmount, + } + } + return &State{ DB: db, LastBlockHeight: 0, LastBlockHash: nil, LastBlockParts: PartSetHeader{}, LastBlockTime: genDoc.GenesisTime, - BondedValidators: NewValidatorSet(genDoc.Validators), + BondedValidators: NewValidatorSet(validators), UnbondingValidators: NewValidatorSet(nil), accounts: accounts, + validatorInfos: validatorInfos, } } diff --git a/consensus/priv_validator.go b/state/priv_validator.go similarity index 74% rename from consensus/priv_validator.go rename to state/priv_validator.go index 694abbfed..5c9b6908b 100644 --- a/consensus/priv_validator.go +++ b/state/priv_validator.go @@ -1,4 +1,4 @@ -package consensus +package state // TODO: This logic is crude. Should be more transactional. @@ -12,9 +12,10 @@ import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/config" + . "github.com/tendermint/tendermint/consensus/types" "github.com/tendermint/go-ed25519" ) @@ -47,6 +48,10 @@ type PrivValidator struct { LastHeight uint LastRound uint LastStep uint8 + + // For persistence. + // Overloaded for testing. + filename string } // Generates a new validator with private key. @@ -62,6 +67,7 @@ func GenPrivValidator() *PrivValidator { LastHeight: 0, LastRound: 0, LastStep: stepNone, + filename: PrivValidatorFile(), } } @@ -124,28 +130,47 @@ func (privVal *PrivValidator) Save() { if err != nil { panic(err) } - err = ioutil.WriteFile(PrivValidatorFile(), privValJSONBytes, 0700) + err = ioutil.WriteFile(privVal.filename, privValJSONBytes, 0700) if err != nil { panic(err) } } +// TODO: test func (privVal *PrivValidator) SignVote(vote *Vote) SignatureEd25519 { - if privVal.LastHeight < vote.Height || - privVal.LastHeight == vote.Height && privVal.LastRound < vote.Round || - privVal.LastHeight == vote.Height && privVal.LastRound == vote.Round && privVal.LastStep < voteToStep(vote) { - - // Persist height/round/step - privVal.LastHeight = vote.Height - privVal.LastRound = vote.Round - privVal.LastStep = voteToStep(vote) - privVal.Save() - // Sign - return privVal.PrivKey.Sign(SignBytes(vote)).(SignatureEd25519) - } else { - panic(fmt.Sprintf("Attempt of duplicate signing of vote: Height %v, Round %v, Type %v", vote.Height, vote.Round, vote.Type)) + // If height regression, panic + if privVal.LastHeight > vote.Height { + panic("Height regression in SignVote") + } + // More cases for when the height matches + if privVal.LastHeight == vote.Height { + // If attempting any sign after commit, panic + if privVal.LastStep == stepCommit { + panic("SignVote on matching height after a commit") + } + // If round regression, panic + if privVal.LastRound > vote.Round { + panic("Round regression in SignVote") + } + // If step regression, panic + if privVal.LastRound == vote.Round && privVal.LastStep > voteToStep(vote) { + panic("Step regression in SignVote") + } } + + // Persist height/round/step + privVal.LastHeight = vote.Height + privVal.LastRound = vote.Round + privVal.LastStep = voteToStep(vote) + privVal.Save() + + // Sign + return privVal.SignVoteUnsafe(vote) +} + +func (privVal *PrivValidator) SignVoteUnsafe(vote *Vote) SignatureEd25519 { + return privVal.PrivKey.Sign(SignBytes(vote)).(SignatureEd25519) } func (privVal *PrivValidator) SignProposal(proposal *Proposal) SignatureEd25519 { @@ -181,3 +206,7 @@ func (privVal *PrivValidator) SignRebondTx(rebondTx *RebondTx) SignatureEd25519 panic(fmt.Sprintf("Attempt of duplicate signing of rebondTx: Height %v", rebondTx.Height)) } } + +func (privVal *PrivValidator) String() string { + return fmt.Sprintf("PrivValidator{%X LH:%v, LR:%v, LS:%v}", privVal.Address, privVal.LastHeight, privVal.LastRound, privVal.LastStep) +} diff --git a/state/state.go b/state/state.go index 52d7ceb69..1a20326f8 100644 --- a/state/state.go +++ b/state/state.go @@ -8,7 +8,7 @@ import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/common" db_ "github.com/tendermint/tendermint/db" "github.com/tendermint/tendermint/merkle" @@ -78,6 +78,7 @@ func LoadState(db db_.DB) *State { // Save this state into the db. func (s *State) Save() { s.accounts.Save() + s.validatorInfos.Save() buf, n, err := new(bytes.Buffer), new(int64), new(error) WriteUVarInt(s.LastBlockHeight, buf, n, err) WriteByteSlice(s.LastBlockHash, buf, n, err) @@ -185,6 +186,7 @@ func (s *State) AdjustByInputs(accounts map[string]*Account, ins []*TxInput) { panic("AdjustByInputs() expects sufficient funds") } account.Balance -= in.Amount + account.Sequence += 1 } } @@ -192,7 +194,7 @@ func (s *State) AdjustByOutputs(accounts map[string]*Account, outs []*TxOutput) for _, out := range outs { account := accounts[string(out.Address)] if account == nil { - panic("AdjustByInputs() expects account in accounts") + panic("AdjustByOutputs() expects account in accounts") } account.Balance += out.Amount } @@ -242,7 +244,7 @@ func (s *State) ExecTx(tx_ Tx) error { // add funds, merge UnbondTo outputs, and unbond validator. return errors.New("Adding coins to existing validators not yet supported") } - accounts, err := s.GetOrMakeAccounts(tx.Inputs, tx.UnbondTo) + accounts, err := s.GetOrMakeAccounts(tx.Inputs, nil) if err != nil { return err } @@ -273,13 +275,14 @@ func (s *State) ExecTx(tx_ Tx) error { PubKey: tx.PubKey, UnbondTo: tx.UnbondTo, FirstBondHeight: s.LastBlockHeight + 1, + FirstBondAmount: outTotal, }) // Add Validator added := s.BondedValidators.Add(&Validator{ Address: tx.PubKey.Address(), PubKey: tx.PubKey, BondHeight: s.LastBlockHeight + 1, - VotingPower: inTotal, + VotingPower: outTotal, Accum: 0, }) if !added { @@ -588,6 +591,12 @@ func (s *State) GetAccount(address []byte) *Account { return account.(*Account).Copy() } +// The account is copied before setting, so mutating it +// afterwards has no side effects. +func (s *State) SetAccount(account *Account) { + s.accounts.Set(account.Address, account.Copy()) +} + // The accounts are copied before setting, so mutating it // afterwards has no side effects. func (s *State) SetAccounts(accounts map[string]*Account) { diff --git a/state/state_test.go b/state/state_test.go index a35d1c871..a7b8e0f71 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -3,60 +3,17 @@ package state import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" - . "github.com/tendermint/tendermint/common" + . "github.com/tendermint/tendermint/block" . "github.com/tendermint/tendermint/config" - db_ "github.com/tendermint/tendermint/db" - "github.com/tendermint/tendermint/wallet" "bytes" "testing" "time" ) -func randAccount() (*Account, *PrivAccount) { - privAccount := wallet.GenPrivAccount() - account := NewAccount(privAccount.PubKey) - account.Sequence = RandUInt() - account.Balance = RandUInt32() + 1000 // At least 1000. - return account, privAccount -} - -func genValidator(account *Account) *Validator, *ValidatorInfo { - valInfo := &ValidatorInfo{ - Address: account.Address, - PubKey: account.PubKey, - UnbondTo: []*TxOutput{&TxOutput{ - Address: - Address []byte - PubKey PubKeyEd25519 - UnbondTo []*TxOutput - FirstBondHeight uint - - } -} - -// The first numValidators accounts are validators. -func randGenesisState(numAccounts int, numValidators int) (*State, []*PrivAccount) { - db := db_.NewMemDB() - accounts := make([]*Account, numAccounts) - privAccounts := make([]*PrivAccount, numAccounts) - validators := make([]*Validator, numValidators) - for i := 0; i < numAccounts; i++ { - account, privAccount := randAccount() - accounts[i], privAccounts[i] = account, privAccount - if i < numValidators { - validators[i] = & - } - } - s0 := GenesisState(db, time.Now(), accounts) - s0.Save() - return s0, privAccounts -} - func TestCopyState(t *testing.T) { // Generate a state - s0, _ := randGenesisState(10, 5) + s0, privAccounts, _ := RandGenesisState(10, true, 1000, 5, true, 1000) s0Hash := s0.Hash() if len(s0Hash) == 0 { t.Error("Expected state hash") @@ -69,15 +26,16 @@ func TestCopyState(t *testing.T) { } // Mutate the original; hash should change. - accDet := s0.GetAccountDetail(0) - accDet.Balance += 1 + acc0Address := privAccounts[0].PubKey.Address() + acc := s0.GetAccount(acc0Address) + acc.Balance += 1 // The account balance shouldn't have changed yet. - if s0.GetAccountDetail(0).Balance == accDet.Balance { + if s0.GetAccount(acc0Address).Balance == acc.Balance { t.Error("Account balance changed unexpectedly") } // Setting, however, should change the balance. - s0.SetAccountDetail(accDet) - if s0.GetAccountDetail(0).Balance != accDet.Balance { + s0.SetAccount(acc) + if s0.GetAccount(acc0Address).Balance != acc.Balance { t.Error("Account balance wasn't set") } // How that the state changed, the hash should change too. @@ -93,7 +51,7 @@ func TestCopyState(t *testing.T) { func TestGenesisSaveLoad(t *testing.T) { // Generate a state, save & load it. - s0, _ := randGenesisState(10, 5) + s0, _, _ := RandGenesisState(10, true, 1000, 5, true, 1000) // Mutate the state to append one empty block. block := &Block{ Header: &Header{ @@ -168,150 +126,160 @@ func TestGenesisSaveLoad(t *testing.T) { if !bytes.Equal(s0.UnbondingValidators.Hash(), s1.UnbondingValidators.Hash()) { t.Error("UnbondingValidators hash mismatch") } - if !bytes.Equal(s0.accountDetails.Hash(), s1.accountDetails.Hash()) { - t.Error("AccountDetail mismatch") + if !bytes.Equal(s0.accounts.Hash(), s1.accounts.Hash()) { + t.Error("Accounts mismatch") } } func TestTxSequence(t *testing.T) { - state, privAccounts := randGenesisState(3, 1) - acc1 := state.GetAccountDetail(1) // Non-validator + state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000) + acc0 := state.GetAccount(privAccounts[0].PubKey.Address()) + acc1 := state.GetAccount(privAccounts[1].PubKey.Address()) // Try executing a SendTx with various sequence numbers. - stxProto := SendTx{ - BaseTx: BaseTx{ - Sequence: acc1.Sequence + 1, - Fee: 0}, - To: 2, - Amount: 1, + makeSendTx := func(sequence uint) *SendTx { + return &SendTx{ + Inputs: []*TxInput{ + &TxInput{ + Address: acc0.Address, + Amount: 1, + Sequence: sequence, + }, + }, + Outputs: []*TxOutput{ + &TxOutput{ + Address: acc1.Address, + Amount: 1, + }, + }, + } } // Test a variety of sequence numbers for the tx. // The tx should only pass when i == 1. for i := -1; i < 3; i++ { - stxCopy := stxProto - stx := &stxCopy - stx.Sequence = uint(int(acc1.Sequence) + i) - privAccounts[1].Sign(stx) + sequence := acc0.Sequence + uint(i) + tx := makeSendTx(sequence) + tx.Inputs[0].Signature = privAccounts[0].Sign(tx) stateCopy := state.Copy() - err := stateCopy.ExecTx(stx) - if i >= 1 { + err := stateCopy.ExecTx(tx) + if i == 1 { // Sequence is good. if err != nil { - t.Errorf("Expected good sequence to pass") + t.Errorf("Expected good sequence to pass: %v", err) } - // Check accDet.Sequence. - newAcc1 := stateCopy.GetAccountDetail(1) - if newAcc1.Sequence != stx.Sequence { - t.Errorf("Expected account sequence to change") + // Check acc.Sequence. + newAcc0 := stateCopy.GetAccount(acc0.Address) + if newAcc0.Sequence != sequence { + t.Errorf("Expected account sequence to change to %v, got %v", + sequence, newAcc0.Sequence) } } else { // Sequence is bad. if err == nil { t.Errorf("Expected bad sequence to fail") } - // Check accDet.Sequence. (shouldn't have changed) - newAcc1 := stateCopy.GetAccountDetail(1) - if newAcc1.Sequence != acc1.Sequence { - t.Errorf("Expected account sequence to not change") + // Check acc.Sequence. (shouldn't have changed) + newAcc0 := stateCopy.GetAccount(acc0.Address) + if newAcc0.Sequence != acc0.Sequence { + t.Errorf("Expected account sequence to not change from %v, got %v", + acc0.Sequence, newAcc0.Sequence) } } } } +// TODO: test overflows. +// TODO: test for unbonding validators. func TestTxs(t *testing.T) { - state, privAccounts := randGenesisState(3, 1) + state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000) - acc0 := state.GetAccountDetail(0) // Validator - acc1 := state.GetAccountDetail(1) // Non-validator - acc2 := state.GetAccountDetail(2) // Non-validator + //val0 := state.GetValidatorInfo(privValidators[0].Address) + acc0 := state.GetAccount(privAccounts[0].PubKey.Address()) + acc1 := state.GetAccount(privAccounts[1].PubKey.Address()) // SendTx. { state := state.Copy() - stx := &SendTx{ - BaseTx: BaseTx{ - Sequence: acc1.Sequence + 1, - Fee: 0}, - To: 2, - Amount: 1, + tx := &SendTx{ + Inputs: []*TxInput{ + &TxInput{ + Address: acc0.Address, + Amount: 1, + Sequence: acc0.Sequence + 1, + }, + }, + Outputs: []*TxOutput{ + &TxOutput{ + Address: acc1.Address, + Amount: 1, + }, + }, } - privAccounts[1].Sign(stx) - err := state.ExecTx(stx) + + tx.Inputs[0].Signature = privAccounts[0].Sign(tx) + err := state.ExecTx(tx) if err != nil { t.Errorf("Got error in executing send transaction, %v", err) } - newAcc1 := state.GetAccountDetail(1) - if acc1.Balance-1 != newAcc1.Balance { - t.Errorf("Unexpected newAcc1 balance. Expected %v, got %v", - acc1.Balance-1, newAcc1.Balance) - } - newAcc2 := state.GetAccountDetail(2) - if acc2.Balance+1 != newAcc2.Balance { - t.Errorf("Unexpected newAcc2 balance. Expected %v, got %v", - acc2.Balance+1, newAcc2.Balance) - } - } - - // TODO: test overflows. - - // SendTx should fail for bonded validators. - { - state := state.Copy() - stx := &SendTx{ - BaseTx: BaseTx{ - Sequence: acc0.Sequence + 1, - Fee: 0}, - To: 2, - Amount: 1, + newAcc0 := state.GetAccount(acc0.Address) + if acc0.Balance-1 != newAcc0.Balance { + t.Errorf("Unexpected newAcc0 balance. Expected %v, got %v", + acc0.Balance-1, newAcc0.Balance) } - privAccounts[0].Sign(stx) - err := state.ExecTx(stx) - if err == nil { - t.Errorf("Expected error, SendTx should fail for bonded validators") + newAcc1 := state.GetAccount(acc1.Address) + if acc1.Balance+1 != newAcc1.Balance { + t.Errorf("Unexpected newAcc1 balance. Expected %v, got %v", + acc1.Balance+1, newAcc1.Balance) } } - // TODO: test for unbonding validators. - // BondTx. { state := state.Copy() - btx := &BondTx{ - BaseTx: BaseTx{ - Sequence: acc1.Sequence + 1, - Fee: 0}, + tx := &BondTx{ + PubKey: acc0.PubKey.(PubKeyEd25519), + Inputs: []*TxInput{ + &TxInput{ + Address: acc0.Address, + Amount: 1, + Sequence: acc0.Sequence + 1, + }, + }, + UnbondTo: []*TxOutput{ + &TxOutput{ + Address: acc0.Address, + Amount: 1, + }, + }, } - privAccounts[1].Sign(btx) - err := state.ExecTx(btx) + tx.Inputs[0].Signature = privAccounts[0].Sign(tx) + err := state.ExecTx(tx) if err != nil { t.Errorf("Got error in executing bond transaction, %v", err) } - newAcc1 := state.GetAccountDetail(1) - if acc1.Balance != newAcc1.Balance { - t.Errorf("Unexpected newAcc1 balance. Expected %v, got %v", - acc1.Balance, newAcc1.Balance) - } - if newAcc1.Status != AccountStatusBonded { - t.Errorf("Unexpected newAcc1 status.") + newAcc0 := state.GetAccount(acc0.Address) + if newAcc0.Balance != acc0.Balance-1 { + t.Errorf("Unexpected newAcc0 balance. Expected %v, got %v", + acc0.Balance-1, newAcc0.Balance) } - _, acc1Val := state.BondedValidators.GetById(acc1.Id) - if acc1Val == nil { - t.Errorf("acc1Val not present") + _, acc0Val := state.BondedValidators.GetByAddress(acc0.Address) + if acc0Val == nil { + t.Errorf("acc0Val not present") } - if acc1Val.BondHeight != state.LastBlockHeight { + if acc0Val.BondHeight != state.LastBlockHeight+1 { t.Errorf("Unexpected bond height. Expected %v, got %v", - state.LastBlockHeight, acc1Val.BondHeight) + state.LastBlockHeight, acc0Val.BondHeight) } - if acc1Val.VotingPower != acc1.Balance { + if acc0Val.VotingPower != 1 { t.Errorf("Unexpected voting power. Expected %v, got %v", - acc1Val.VotingPower, acc1.Balance) + acc0Val.VotingPower, acc0.Balance) } - if acc1Val.Accum != 0 { + if acc0Val.Accum != 0 { t.Errorf("Unexpected accum. Expected 0, got %v", - acc1Val.Accum) + acc0Val.Accum) } } diff --git a/state/test.go b/state/test.go new file mode 100644 index 000000000..9d2bcf26d --- /dev/null +++ b/state/test.go @@ -0,0 +1,98 @@ +package state + +import ( + "bytes" + "sort" + + . "github.com/tendermint/tendermint/account" + . "github.com/tendermint/tendermint/block" + . "github.com/tendermint/tendermint/common" + db_ "github.com/tendermint/tendermint/db" + + "io/ioutil" + "os" + "time" +) + +func Tempfile(prefix string) (*os.File, string) { + file, err := ioutil.TempFile("", prefix) + if err != nil { + panic(err) + } + return file, file.Name() +} + +func RandAccount(randBalance bool, minBalance uint64) (*Account, *PrivAccount) { + privAccount := GenPrivAccount() + account := NewAccount(privAccount.PubKey) + account.Sequence = RandUInt() + account.Balance = minBalance + if randBalance { + account.Balance += uint64(RandUInt32()) + } + return account, privAccount +} + +func RandValidator(randBonded bool, minBonded uint64) (*ValidatorInfo, *PrivValidator) { + privVal := GenPrivValidator() + _, privVal.filename = Tempfile("priv_validator_") + bonded := minBonded + if randBonded { + bonded += uint64(RandUInt32()) + } + valInfo := &ValidatorInfo{ + Address: privVal.Address, + PubKey: privVal.PubKey, + UnbondTo: []*TxOutput{&TxOutput{ + Amount: bonded, + Address: privVal.Address, + }}, + FirstBondHeight: 0, + FirstBondAmount: bonded, + } + return valInfo, privVal +} + +// The first numValidators accounts are validators. +func RandGenesisState(numAccounts int, randBalance bool, minBalance uint64, numValidators int, randBonded bool, minBonded uint64) (*State, []*PrivAccount, []*PrivValidator) { + db := db_.NewMemDB() + accounts := make([]*Account, numAccounts) + privAccounts := make([]*PrivAccount, numAccounts) + for i := 0; i < numAccounts; i++ { + account, privAccount := RandAccount(randBalance, minBalance) + accounts[i], privAccounts[i] = account, privAccount + } + validators := make([]*ValidatorInfo, numValidators) + privValidators := make([]*PrivValidator, numValidators) + for i := 0; i < numValidators; i++ { + valInfo, privVal := RandValidator(randBonded, minBonded) + validators[i] = valInfo + privValidators[i] = privVal + } + sort.Sort(PrivValidatorsByAddress(privValidators)) + s0 := GenesisState(db, &GenesisDoc{ + GenesisTime: time.Now(), + Accounts: accounts, + Validators: validators, + }) + s0.Save() + return s0, privAccounts, privValidators +} + +//------------------------------------- + +type PrivValidatorsByAddress []*PrivValidator + +func (pvs PrivValidatorsByAddress) Len() int { + return len(pvs) +} + +func (pvs PrivValidatorsByAddress) Less(i, j int) bool { + return bytes.Compare(pvs[i].Address, pvs[j].Address) == -1 +} + +func (pvs PrivValidatorsByAddress) Swap(i, j int) { + it := pvs[i] + pvs[i] = pvs[j] + pvs[j] = it +} diff --git a/state/validator.go b/state/validator.go index 0ba00f82d..ef0e61631 100644 --- a/state/validator.go +++ b/state/validator.go @@ -7,7 +7,7 @@ import ( . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/blocks" + . "github.com/tendermint/tendermint/block" ) // Persistent static data for each Validator @@ -16,6 +16,7 @@ type ValidatorInfo struct { PubKey PubKeyEd25519 UnbondTo []*TxOutput FirstBondHeight uint + FirstBondAmount uint64 // If destroyed: DestroyedHeight uint diff --git a/state/validator_set.go b/state/validator_set.go index f05ffe4ed..c5087b395 100644 --- a/state/validator_set.go +++ b/state/validator_set.go @@ -22,9 +22,9 @@ import ( // TODO: consider validator Accum overflow // TODO: replace validators []*Validator with github.com/jaekwon/go-ibbs? type ValidatorSet struct { - validators []*Validator + Validators []*Validator // NOTE: persisted via reflect, must be exported. - // cache + // cached (unexported) proposer *Validator totalVotingPower uint64 } @@ -36,7 +36,7 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet { } sort.Sort(ValidatorsByAddress(validators)) return &ValidatorSet{ - validators: validators, + Validators: validators, } } @@ -45,7 +45,7 @@ func (valSet *ValidatorSet) IncrementAccum(times uint) { // Add VotingPower * times to each validator and order into heap. validatorsHeap := NewHeap() - for _, val := range valSet.validators { + for _, val := range valSet.Validators { val.Accum += int64(val.VotingPower) * int64(times) // TODO: mind overflow validatorsHeap.Push(val, accumComparable(val.Accum)) } @@ -62,48 +62,48 @@ func (valSet *ValidatorSet) IncrementAccum(times uint) { } func (valSet *ValidatorSet) Copy() *ValidatorSet { - validators := make([]*Validator, len(valSet.validators)) - for i, val := range valSet.validators { + validators := make([]*Validator, len(valSet.Validators)) + for i, val := range valSet.Validators { // NOTE: must copy, since IncrementAccum updates in place. validators[i] = val.Copy() } return &ValidatorSet{ - validators: validators, + Validators: validators, proposer: valSet.proposer, totalVotingPower: valSet.totalVotingPower, } } func (valSet *ValidatorSet) HasAddress(address []byte) bool { - idx := sort.Search(len(valSet.validators), func(i int) bool { - return bytes.Compare(address, valSet.validators[i].Address) <= 0 + idx := sort.Search(len(valSet.Validators), func(i int) bool { + return bytes.Compare(address, valSet.Validators[i].Address) <= 0 }) - return idx != len(valSet.validators) && bytes.Compare(valSet.validators[idx].Address, address) == 0 + return idx != len(valSet.Validators) && bytes.Compare(valSet.Validators[idx].Address, address) == 0 } func (valSet *ValidatorSet) GetByAddress(address []byte) (index uint, val *Validator) { - idx := sort.Search(len(valSet.validators), func(i int) bool { - return bytes.Compare(address, valSet.validators[i].Address) <= 0 + idx := sort.Search(len(valSet.Validators), func(i int) bool { + return bytes.Compare(address, valSet.Validators[i].Address) <= 0 }) - if idx != len(valSet.validators) && bytes.Compare(valSet.validators[idx].Address, address) == 0 { - return uint(idx), valSet.validators[idx].Copy() + if idx != len(valSet.Validators) && bytes.Compare(valSet.Validators[idx].Address, address) == 0 { + return uint(idx), valSet.Validators[idx].Copy() } else { return 0, nil } } func (valSet *ValidatorSet) GetByIndex(index uint) (address []byte, val *Validator) { - val = valSet.validators[index] + val = valSet.Validators[index] return val.Address, val.Copy() } func (valSet *ValidatorSet) Size() uint { - return uint(len(valSet.validators)) + return uint(len(valSet.Validators)) } func (valSet *ValidatorSet) TotalVotingPower() uint64 { if valSet.totalVotingPower == 0 { - for _, val := range valSet.validators { + for _, val := range valSet.Validators { valSet.totalVotingPower += val.VotingPower } } @@ -112,7 +112,7 @@ func (valSet *ValidatorSet) TotalVotingPower() uint64 { func (valSet *ValidatorSet) Proposer() (proposer *Validator) { if valSet.proposer == nil { - for _, val := range valSet.validators { + for _, val := range valSet.Validators { valSet.proposer = valSet.proposer.CompareAccum(val) } } @@ -120,11 +120,11 @@ func (valSet *ValidatorSet) Proposer() (proposer *Validator) { } func (valSet *ValidatorSet) Hash() []byte { - if len(valSet.validators) == 0 { + if len(valSet.Validators) == 0 { return nil } - hashables := make([]merkle.Hashable, len(valSet.validators)) - for i, val := range valSet.validators { + hashables := make([]merkle.Hashable, len(valSet.Validators)) + for i, val := range valSet.Validators { hashables[i] = val } return merkle.HashFromHashables(hashables) @@ -132,21 +132,21 @@ func (valSet *ValidatorSet) Hash() []byte { func (valSet *ValidatorSet) Add(val *Validator) (added bool) { val = val.Copy() - idx := sort.Search(len(valSet.validators), func(i int) bool { - return bytes.Compare(val.Address, valSet.validators[i].Address) <= 0 + idx := sort.Search(len(valSet.Validators), func(i int) bool { + return bytes.Compare(val.Address, valSet.Validators[i].Address) <= 0 }) - if idx == len(valSet.validators) { - valSet.validators = append(valSet.validators, val) + if idx == len(valSet.Validators) { + valSet.Validators = append(valSet.Validators, val) // Invalidate cache valSet.proposer = nil valSet.totalVotingPower = 0 return true - } else if bytes.Compare(valSet.validators[idx].Address, val.Address) == 0 { + } else if bytes.Compare(valSet.Validators[idx].Address, val.Address) == 0 { return false } else { - newValidators := append(valSet.validators[:idx], val) - newValidators = append(newValidators, valSet.validators[idx:]...) - valSet.validators = newValidators + newValidators := append(valSet.Validators[:idx], val) + newValidators = append(newValidators, valSet.Validators[idx:]...) + valSet.Validators = newValidators // Invalidate cache valSet.proposer = nil valSet.totalVotingPower = 0 @@ -159,7 +159,7 @@ func (valSet *ValidatorSet) Update(val *Validator) (updated bool) { if sameVal == nil { return false } else { - valSet.validators[index] = val.Copy() + valSet.Validators[index] = val.Copy() // Invalidate cache valSet.proposer = nil valSet.totalVotingPower = 0 @@ -168,18 +168,18 @@ func (valSet *ValidatorSet) Update(val *Validator) (updated bool) { } func (valSet *ValidatorSet) Remove(address []byte) (val *Validator, removed bool) { - idx := sort.Search(len(valSet.validators), func(i int) bool { - return bytes.Compare(address, valSet.validators[i].Address) <= 0 + idx := sort.Search(len(valSet.Validators), func(i int) bool { + return bytes.Compare(address, valSet.Validators[i].Address) <= 0 }) - if idx == len(valSet.validators) || bytes.Compare(valSet.validators[idx].Address, address) != 0 { + if idx == len(valSet.Validators) || bytes.Compare(valSet.Validators[idx].Address, address) != 0 { return nil, false } else { - removedVal := valSet.validators[idx] - newValidators := valSet.validators[:idx] - if idx+1 < len(valSet.validators) { - newValidators = append(newValidators, valSet.validators[idx+1:]...) + removedVal := valSet.Validators[idx] + newValidators := valSet.Validators[:idx] + if idx+1 < len(valSet.Validators) { + newValidators = append(newValidators, valSet.Validators[idx+1:]...) } - valSet.validators = newValidators + valSet.Validators = newValidators // Invalidate cache valSet.proposer = nil valSet.totalVotingPower = 0 @@ -188,7 +188,7 @@ func (valSet *ValidatorSet) Remove(address []byte) (val *Validator, removed bool } func (valSet *ValidatorSet) Iterate(fn func(index uint, val *Validator) bool) { - for i, val := range valSet.validators { + for i, val := range valSet.Validators { stop := fn(uint(i), val.Copy()) if stop { break @@ -244,5 +244,5 @@ type accumComparable uint64 // We want to find the validator with the greatest accum. func (ac accumComparable) Less(o interface{}) bool { - return uint64(ac) > o.(uint64) + return uint64(ac) > uint64(o.(accumComparable)) } diff --git a/state/validator_set_test.go b/state/validator_set_test.go index 51e936ca2..b93f2b27d 100644 --- a/state/validator_set_test.go +++ b/state/validator_set_test.go @@ -1,30 +1,27 @@ package state import ( + . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/common" "bytes" "testing" ) -func randValidator() *Validator { +func randValidator_() *Validator { return &Validator{ - Account: Account{ - Id: RandUInt64(), - PubKey: CRandBytes(32), - }, - BondHeight: RandUInt32(), - UnbondHeight: RandUInt32(), - LastCommitHeight: RandUInt32(), - VotingPower: RandUInt64(), - Accum: int64(RandUInt64()), + Address: RandBytes(20), + PubKey: PubKeyEd25519{RandBytes(64)}, + BondHeight: uint(RandUInt32()), + VotingPower: RandUInt64(), + Accum: int64(RandUInt64()), } } func randValidatorSet(numValidators int) *ValidatorSet { validators := make([]*Validator, numValidators) for i := 0; i < numValidators; i++ { - validators[i] = randValidator() + validators[i] = randValidator_() } return NewValidatorSet(validators) }