mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-13 21:31:23 +00:00
Fixed tests
This commit is contained in:
@ -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))
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
return true
|
||||
// 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 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)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package blocks
|
||||
package block
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -42,9 +42,11 @@ func (b *Block) ValidateBasic(lastBlockHeight uint, lastBlockHash []byte,
|
||||
if !b.Time.After(lastBlockTime) {
|
||||
return errors.New("Invalid block time")
|
||||
}
|
||||
if b.Header.Height != 1 {
|
||||
if err := b.Validation.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// XXX more validation
|
||||
return nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package blocks
|
||||
package block
|
||||
|
||||
import (
|
||||
"bytes"
|
@ -1,4 +1,4 @@
|
||||
package blocks
|
||||
package block
|
||||
|
||||
import (
|
||||
"bytes"
|
@ -1,4 +1,4 @@
|
||||
package blocks
|
||||
package block
|
||||
|
||||
import (
|
||||
"bytes"
|
@ -1,4 +1,4 @@
|
||||
package blocks
|
||||
package block
|
||||
|
||||
import (
|
||||
"errors"
|
@ -1,4 +1,4 @@
|
||||
package blocks
|
||||
package block
|
||||
|
||||
import (
|
||||
"errors"
|
@ -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
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 (
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -62,9 +62,11 @@ func NewDefaultListener(protocol string, lAddr string) Listener {
|
||||
// Determine external address...
|
||||
var extAddr *NetAddress
|
||||
// If the lAddrIP is INADDR_ANY, try UPnP
|
||||
if false {
|
||||
if lAddrIP == "" || lAddrIP == "0.0.0.0" {
|
||||
extAddr = getUPNPExternalAddress(lAddrPort, listenerPort)
|
||||
}
|
||||
}
|
||||
// Otherwise just use the local address...
|
||||
if extAddr == nil {
|
||||
extAddr = getNaiveExternalAddress(listenerPort)
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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,16 +130,34 @@ 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) {
|
||||
|
||||
// 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
|
||||
@ -142,10 +166,11 @@ func (privVal *PrivValidator) SignVote(vote *Vote) SignatureEd25519 {
|
||||
privVal.Save()
|
||||
|
||||
// Sign
|
||||
return privVal.SignVoteUnsafe(vote)
|
||||
}
|
||||
|
||||
func (privVal *PrivValidator) SignVoteUnsafe(vote *Vote) SignatureEd25519 {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
@ -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) {
|
||||
|
@ -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,
|
||||
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,
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
newAcc2 := state.GetAccountDetail(2)
|
||||
if acc2.Balance+1 != newAcc2.Balance {
|
||||
t.Errorf("Unexpected newAcc2 balance. Expected %v, got %v",
|
||||
acc2.Balance+1, newAcc2.Balance)
|
||||
acc1.Balance+1, newAcc1.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,
|
||||
}
|
||||
privAccounts[0].Sign(stx)
|
||||
err := state.ExecTx(stx)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, SendTx should fail for bonded validators")
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
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)
|
||||
}
|
||||
if newAcc1.Status != AccountStatusBonded {
|
||||
t.Errorf("Unexpected newAcc1 status.")
|
||||
_, acc0Val := state.BondedValidators.GetByAddress(acc0.Address)
|
||||
if acc0Val == nil {
|
||||
t.Errorf("acc0Val not present")
|
||||
}
|
||||
_, acc1Val := state.BondedValidators.GetById(acc1.Id)
|
||||
if acc1Val == nil {
|
||||
t.Errorf("acc1Val 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
98
state/test.go
Normal file
98
state/test.go
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -1,21 +1,18 @@
|
||||
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(),
|
||||
Address: RandBytes(20),
|
||||
PubKey: PubKeyEd25519{RandBytes(64)},
|
||||
BondHeight: uint(RandUInt32()),
|
||||
VotingPower: RandUInt64(),
|
||||
Accum: int64(RandUInt64()),
|
||||
}
|
||||
@ -24,7 +21,7 @@ func randValidator() *Validator {
|
||||
func randValidatorSet(numValidators int) *ValidatorSet {
|
||||
validators := make([]*Validator, numValidators)
|
||||
for i := 0; i < numValidators; i++ {
|
||||
validators[i] = randValidator()
|
||||
validators[i] = randValidator_()
|
||||
}
|
||||
return NewValidatorSet(validators)
|
||||
}
|
||||
|
Reference in New Issue
Block a user