mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-18 07:31:20 +00:00
fix basic tests.
This commit is contained in:
@ -160,8 +160,9 @@ func ReadUInt64(r io.Reader, n *int64, err *error) uint64 {
|
|||||||
|
|
||||||
func WriteVarInt(w io.Writer, i int64, n *int64, err *error) {
|
func WriteVarInt(w io.Writer, i int64, n *int64, err *error) {
|
||||||
buf := make([]byte, 9)
|
buf := make([]byte, 9)
|
||||||
*n += int64(binary.PutVarint(buf, int64(i)))
|
n_ := int64(binary.PutVarint(buf, int64(i)))
|
||||||
WriteTo(w, buf, n, err)
|
*n += n_
|
||||||
|
WriteTo(w, buf[:n_], n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadVarInt(r io.Reader, n *int64, err *error) int64 {
|
func ReadVarInt(r io.Reader, n *int64, err *error) int64 {
|
||||||
@ -175,8 +176,9 @@ func ReadVarInt(r io.Reader, n *int64, err *error) int64 {
|
|||||||
|
|
||||||
func WriteUVarInt(w io.Writer, i uint64, n *int64, err *error) {
|
func WriteUVarInt(w io.Writer, i uint64, n *int64, err *error) {
|
||||||
buf := make([]byte, 9)
|
buf := make([]byte, 9)
|
||||||
*n += int64(binary.PutUvarint(buf, uint64(i)))
|
n_ := int64(binary.PutUvarint(buf, uint64(i)))
|
||||||
WriteTo(w, buf, n, err)
|
*n += n_
|
||||||
|
WriteTo(w, buf[:n_], n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadUVarInt(r io.Reader, n *int64, err *error) uint64 {
|
func ReadUVarInt(r io.Reader, n *int64, err *error) uint64 {
|
||||||
|
@ -7,7 +7,10 @@ import (
|
|||||||
|
|
||||||
func BinaryBytes(b Binary) []byte {
|
func BinaryBytes(b Binary) []byte {
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
b.WriteTo(buf)
|
_, err := b.WriteTo(buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,46 +3,16 @@ package blocks
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
. "github.com/tendermint/tendermint/binary"
|
. "github.com/tendermint/tendermint/binary"
|
||||||
"math/rand"
|
. "github.com/tendermint/tendermint/common"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Distributed pseudo-exponentially to test for various cases
|
|
||||||
func randUInt64() uint64 {
|
|
||||||
bits := rand.Uint32() % 64
|
|
||||||
if bits == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
n := uint64(1 << (bits - 1))
|
|
||||||
n += uint64(rand.Int63()) & ((1 << (bits - 1)) - 1)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func randUInt32() uint32 {
|
|
||||||
bits := rand.Uint32() % 32
|
|
||||||
if bits == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
n := uint32(1 << (bits - 1))
|
|
||||||
n += uint32(rand.Int31()) & ((1 << (bits - 1)) - 1)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func randTime() time.Time {
|
|
||||||
return time.Unix(int64(randUInt64()), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func randBytes(n int) []byte {
|
|
||||||
bs := make([]byte, n)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
bs[i] = byte(rand.Intn(256))
|
|
||||||
}
|
|
||||||
return bs
|
|
||||||
}
|
|
||||||
|
|
||||||
func randSig() Signature {
|
func randSig() Signature {
|
||||||
return Signature{randUInt64(), randBytes(32)}
|
return Signature{RandUInt64Exp(), RandBytes(32)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func randBaseTx() BaseTx {
|
||||||
|
return BaseTx{0, randSig()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBlock(t *testing.T) {
|
func TestBlock(t *testing.T) {
|
||||||
@ -50,48 +20,52 @@ func TestBlock(t *testing.T) {
|
|||||||
// Account Txs
|
// Account Txs
|
||||||
|
|
||||||
sendTx := &SendTx{
|
sendTx := &SendTx{
|
||||||
Signature: randSig(),
|
BaseTx: randBaseTx(),
|
||||||
Fee: randUInt64(),
|
Fee: RandUInt64Exp(),
|
||||||
To: randUInt64(),
|
To: RandUInt64Exp(),
|
||||||
Amount: randUInt64(),
|
Amount: RandUInt64Exp(),
|
||||||
}
|
}
|
||||||
|
|
||||||
nameTx := &NameTx{
|
nameTx := &NameTx{
|
||||||
Signature: randSig(),
|
BaseTx: randBaseTx(),
|
||||||
Fee: randUInt64(),
|
Fee: RandUInt64Exp(),
|
||||||
Name: string(randBytes(12)),
|
Name: string(RandBytes(12)),
|
||||||
PubKey: randBytes(32),
|
PubKey: RandBytes(32),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation Txs
|
// Validation Txs
|
||||||
|
|
||||||
bond := &Bond{
|
bondTx := &BondTx{
|
||||||
Signature: randSig(),
|
BaseTx: randBaseTx(),
|
||||||
Fee: randUInt64(),
|
Fee: RandUInt64Exp(),
|
||||||
UnbondTo: randUInt64(),
|
UnbondTo: RandUInt64Exp(),
|
||||||
Amount: randUInt64(),
|
Amount: RandUInt64Exp(),
|
||||||
}
|
}
|
||||||
|
|
||||||
unbond := &Unbond{
|
unbondTx := &UnbondTx{
|
||||||
Signature: randSig(),
|
BaseTx: randBaseTx(),
|
||||||
Fee: randUInt64(),
|
Fee: RandUInt64Exp(),
|
||||||
Amount: randUInt64(),
|
Amount: RandUInt64Exp(),
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout := &Timeout{
|
timeoutTx := &TimeoutTx{
|
||||||
AccountId: randUInt64(),
|
AccountId: RandUInt64Exp(),
|
||||||
Penalty: randUInt64(),
|
Penalty: RandUInt64Exp(),
|
||||||
}
|
}
|
||||||
|
|
||||||
dupeout := &Dupeout{
|
dupeoutTx := &DupeoutTx{
|
||||||
VoteA: BlockVote{
|
VoteA: Vote{
|
||||||
Height: randUInt64(),
|
Height: RandUInt32Exp(),
|
||||||
BlockHash: randBytes(32),
|
Round: RandUInt16Exp(),
|
||||||
|
Type: VoteTypeBare,
|
||||||
|
BlockHash: RandBytes(32),
|
||||||
Signature: randSig(),
|
Signature: randSig(),
|
||||||
},
|
},
|
||||||
VoteB: BlockVote{
|
VoteB: Vote{
|
||||||
Height: randUInt64(),
|
Height: RandUInt32Exp(),
|
||||||
BlockHash: randBytes(32),
|
Round: RandUInt16Exp(),
|
||||||
|
Type: VoteTypeBare,
|
||||||
|
BlockHash: RandBytes(32),
|
||||||
Signature: randSig(),
|
Signature: randSig(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -100,30 +74,34 @@ func TestBlock(t *testing.T) {
|
|||||||
|
|
||||||
block := &Block{
|
block := &Block{
|
||||||
Header: Header{
|
Header: Header{
|
||||||
Network: "Tendermint",
|
Network: "Tendermint",
|
||||||
Height: randUInt32(),
|
Height: RandUInt32Exp(),
|
||||||
Fees: randUInt64(),
|
Fees: RandUInt64Exp(),
|
||||||
Time: randTime(),
|
Time: RandTime(),
|
||||||
LastBlockHash: randBytes(32),
|
LastBlockHash: RandBytes(32),
|
||||||
ValidationHash: randBytes(32),
|
ValidationStateHash: RandBytes(32),
|
||||||
DataHash: randBytes(32),
|
AccountStateHash: RandBytes(32),
|
||||||
},
|
},
|
||||||
Validation: Validation{
|
Validation: Validation{
|
||||||
Signatures: []Signature{randSig(), randSig()},
|
Signatures: []Signature{randSig(), randSig()},
|
||||||
Txs: []Txs{bond, unbond, timeout, dupeout},
|
|
||||||
},
|
},
|
||||||
Data: Data{
|
Data: Data{
|
||||||
Txs: []Tx{sendTx, nameTx},
|
Txs: []Tx{sendTx, nameTx, bondTx, unbondTx, timeoutTx, dupeoutTx},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the block, read it in again, write it again.
|
// Write the block, read it in again, write it again.
|
||||||
// Then, compare.
|
// Then, compare.
|
||||||
|
// TODO We should compute the hash instead, so Block -> Bytes -> Block and compare hashes.
|
||||||
|
|
||||||
blockBytes := BinaryBytes(block)
|
blockBytes := BinaryBytes(block)
|
||||||
var n int64
|
var n int64
|
||||||
var err error
|
var err error
|
||||||
block2 := ReadBlock(bytes.NewReader(blockBytes), &n, &err)
|
block2 := ReadBlock(bytes.NewReader(blockBytes), &n, &err)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Reading block failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
blockBytes2 := BinaryBytes(block2)
|
blockBytes2 := BinaryBytes(block2)
|
||||||
|
|
||||||
if !bytes.Equal(blockBytes, blockBytes2) {
|
if !bytes.Equal(blockBytes, blockBytes2) {
|
||||||
|
@ -15,13 +15,13 @@ func BenchmarkTestCustom(b *testing.B) {
|
|||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
|
||||||
h := &Header{
|
h := &Header{
|
||||||
Network: "Header",
|
Network: "Header",
|
||||||
Height: 123,
|
Height: 123,
|
||||||
Fees: 123,
|
Fees: 123,
|
||||||
Time: time.Unix(123, 0),
|
Time: time.Unix(123, 0),
|
||||||
LastBlockHash: []byte("prevhash"),
|
LastBlockHash: []byte("prevhash"),
|
||||||
ValidationHash: []byte("validationhash"),
|
ValidationStateHash: []byte("validationhash"),
|
||||||
DataHash: []byte("datahash"),
|
AccountStateHash: []byte("accounthash"),
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
@ -40,26 +40,26 @@ func BenchmarkTestCustom(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HHeader struct {
|
type HHeader struct {
|
||||||
Network string `json:"N"`
|
Network string `json:"N"`
|
||||||
Height uint64 `json:"H"`
|
Height uint64 `json:"H"`
|
||||||
Fees uint64 `json:"F"`
|
Fees uint64 `json:"F"`
|
||||||
Time uint64 `json:"T"`
|
Time uint64 `json:"T"`
|
||||||
LastBlockHash []byte `json:"PH"`
|
LastBlockHash []byte `json:"PH"`
|
||||||
ValidationHash []byte `json:"VH"`
|
ValidationStateHash []byte `json:"VH"`
|
||||||
DataHash []byte `json:"DH"`
|
AccountStateHash []byte `json:"DH"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkTestJSON(b *testing.B) {
|
func BenchmarkTestJSON(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
|
||||||
h := &HHeader{
|
h := &HHeader{
|
||||||
Network: "Header",
|
Network: "Header",
|
||||||
Height: 123,
|
Height: 123,
|
||||||
Fees: 123,
|
Fees: 123,
|
||||||
Time: 123,
|
Time: 123,
|
||||||
LastBlockHash: []byte("prevhash"),
|
LastBlockHash: []byte("prevhash"),
|
||||||
ValidationHash: []byte("validationhash"),
|
ValidationStateHash: []byte("validationhash"),
|
||||||
DataHash: []byte("datahash"),
|
AccountStateHash: []byte("accounthash"),
|
||||||
}
|
}
|
||||||
h2 := &HHeader{}
|
h2 := &HHeader{}
|
||||||
|
|
||||||
@ -82,13 +82,13 @@ func BenchmarkTestGob(b *testing.B) {
|
|||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
|
||||||
h := &Header{
|
h := &Header{
|
||||||
Network: "Header",
|
Network: "Header",
|
||||||
Height: 123,
|
Height: 123,
|
||||||
Fees: 123,
|
Fees: 123,
|
||||||
Time: time.Unix(123, 0),
|
Time: time.Unix(123, 0),
|
||||||
LastBlockHash: []byte("prevhash"),
|
LastBlockHash: []byte("prevhash"),
|
||||||
ValidationHash: []byte("validationhash"),
|
ValidationStateHash: []byte("validationhash"),
|
||||||
DataHash: []byte("datahash"),
|
AccountStateHash: []byte("datahash"),
|
||||||
}
|
}
|
||||||
h2 := &Header{}
|
h2 := &Header{}
|
||||||
|
|
||||||
@ -111,13 +111,13 @@ func BenchmarkTestMsgPack(b *testing.B) {
|
|||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
|
||||||
h := &Header{
|
h := &Header{
|
||||||
Network: "Header",
|
Network: "Header",
|
||||||
Height: 123,
|
Height: 123,
|
||||||
Fees: 123,
|
Fees: 123,
|
||||||
Time: time.Unix(123, 0),
|
Time: time.Unix(123, 0),
|
||||||
LastBlockHash: []byte("prevhash"),
|
LastBlockHash: []byte("prevhash"),
|
||||||
ValidationHash: []byte("validationhash"),
|
ValidationStateHash: []byte("validationhash"),
|
||||||
DataHash: []byte("datahash"),
|
AccountStateHash: []byte("datahash"),
|
||||||
}
|
}
|
||||||
h2 := &Header{}
|
h2 := &Header{}
|
||||||
|
|
||||||
@ -140,13 +140,13 @@ func BenchmarkTestMsgPack2(b *testing.B) {
|
|||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
|
||||||
h := &Header{
|
h := &Header{
|
||||||
Network: "Header",
|
Network: "Header",
|
||||||
Height: 123,
|
Height: 123,
|
||||||
Fees: 123,
|
Fees: 123,
|
||||||
Time: time.Unix(123, 0),
|
Time: time.Unix(123, 0),
|
||||||
LastBlockHash: []byte("prevhash"),
|
LastBlockHash: []byte("prevhash"),
|
||||||
ValidationHash: []byte("validationhash"),
|
ValidationStateHash: []byte("validationhash"),
|
||||||
DataHash: []byte("datahash"),
|
AccountStateHash: []byte("accounthash"),
|
||||||
}
|
}
|
||||||
h2 := &Header{}
|
h2 := &Header{}
|
||||||
var mh codec.MsgpackHandle
|
var mh codec.MsgpackHandle
|
||||||
|
38
blocks/tx.go
38
blocks/tx.go
@ -28,59 +28,59 @@ type Tx interface {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Account transactions
|
// Account transactions
|
||||||
TX_TYPE_SEND = byte(0x01)
|
txTypeSend = byte(0x01)
|
||||||
TX_TYPE_NAME = byte(0x02)
|
txTypeName = byte(0x02)
|
||||||
|
|
||||||
// Validation transactions
|
// Validation transactions
|
||||||
TX_TYPE_BOND = byte(0x11)
|
txTypeBond = byte(0x11)
|
||||||
TX_TYPE_UNBOND = byte(0x12)
|
txTypeUnbond = byte(0x12)
|
||||||
TX_TYPE_TIMEOUT = byte(0x13)
|
txTypeTimeout = byte(0x13)
|
||||||
TX_TYPE_DUPEOUT = byte(0x14)
|
txTypeDupeout = byte(0x14)
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReadTx(r io.Reader, n *int64, err *error) Tx {
|
func ReadTx(r io.Reader, n *int64, err *error) Tx {
|
||||||
switch t := ReadByte(r, n, err); t {
|
switch t := ReadByte(r, n, err); t {
|
||||||
case TX_TYPE_SEND:
|
case txTypeSend:
|
||||||
return &SendTx{
|
return &SendTx{
|
||||||
BaseTx: ReadBaseTx(r, n, err),
|
BaseTx: ReadBaseTx(r, n, err),
|
||||||
Fee: ReadUInt64(r, n, err),
|
Fee: ReadUInt64(r, n, err),
|
||||||
To: ReadUInt64(r, n, err),
|
To: ReadUInt64(r, n, err),
|
||||||
Amount: ReadUInt64(r, n, err),
|
Amount: ReadUInt64(r, n, err),
|
||||||
}
|
}
|
||||||
case TX_TYPE_NAME:
|
case txTypeName:
|
||||||
return &NameTx{
|
return &NameTx{
|
||||||
BaseTx: ReadBaseTx(r, n, err),
|
BaseTx: ReadBaseTx(r, n, err),
|
||||||
Fee: ReadUInt64(r, n, err),
|
Fee: ReadUInt64(r, n, err),
|
||||||
Name: ReadString(r, n, err),
|
Name: ReadString(r, n, err),
|
||||||
PubKey: ReadByteSlice(r, n, err),
|
PubKey: ReadByteSlice(r, n, err),
|
||||||
}
|
}
|
||||||
case TX_TYPE_BOND:
|
case txTypeBond:
|
||||||
return &BondTx{
|
return &BondTx{
|
||||||
BaseTx: ReadBaseTx(r, n, err),
|
BaseTx: ReadBaseTx(r, n, err),
|
||||||
Fee: ReadUInt64(r, n, err),
|
Fee: ReadUInt64(r, n, err),
|
||||||
UnbondTo: ReadUInt64(r, n, err),
|
UnbondTo: ReadUInt64(r, n, err),
|
||||||
Amount: ReadUInt64(r, n, err),
|
Amount: ReadUInt64(r, n, err),
|
||||||
}
|
}
|
||||||
case TX_TYPE_UNBOND:
|
case txTypeUnbond:
|
||||||
return &UnbondTx{
|
return &UnbondTx{
|
||||||
BaseTx: ReadBaseTx(r, n, err),
|
BaseTx: ReadBaseTx(r, n, err),
|
||||||
Fee: ReadUInt64(r, n, err),
|
Fee: ReadUInt64(r, n, err),
|
||||||
Amount: ReadUInt64(r, n, err),
|
Amount: ReadUInt64(r, n, err),
|
||||||
}
|
}
|
||||||
case TX_TYPE_TIMEOUT:
|
case txTypeTimeout:
|
||||||
return &TimeoutTx{
|
return &TimeoutTx{
|
||||||
BaseTx: ReadBaseTx(r, n, err),
|
BaseTx: ReadBaseTx(r, n, err),
|
||||||
AccountId: ReadUInt64(r, n, err),
|
AccountId: ReadUInt64(r, n, err),
|
||||||
Penalty: ReadUInt64(r, n, err),
|
Penalty: ReadUInt64(r, n, err),
|
||||||
}
|
}
|
||||||
case TX_TYPE_DUPEOUT:
|
case txTypeDupeout:
|
||||||
return &DupeoutTx{
|
return &DupeoutTx{
|
||||||
BaseTx: ReadBaseTx(r, n, err),
|
BaseTx: ReadBaseTx(r, n, err),
|
||||||
VoteA: *ReadVote(r, n, err),
|
VoteA: *ReadVote(r, n, err),
|
||||||
VoteB: *ReadVote(r, n, err),
|
VoteB: *ReadVote(r, n, err),
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
Panicf("Unknown Tx type %x", t)
|
*err = Errorf("Unknown Tx type %X", t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ type SendTx struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tx *SendTx) Type() byte {
|
func (tx *SendTx) Type() byte {
|
||||||
return TX_TYPE_SEND
|
return txTypeSend
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *SendTx) WriteTo(w io.Writer) (n int64, err error) {
|
func (tx *SendTx) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
@ -145,7 +145,7 @@ type NameTx struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tx *NameTx) Type() byte {
|
func (tx *NameTx) Type() byte {
|
||||||
return TX_TYPE_NAME
|
return txTypeName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *NameTx) WriteTo(w io.Writer) (n int64, err error) {
|
func (tx *NameTx) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
@ -167,7 +167,7 @@ type BondTx struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tx *BondTx) Type() byte {
|
func (tx *BondTx) Type() byte {
|
||||||
return TX_TYPE_BOND
|
return txTypeBond
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *BondTx) WriteTo(w io.Writer) (n int64, err error) {
|
func (tx *BondTx) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
@ -188,7 +188,7 @@ type UnbondTx struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tx *UnbondTx) Type() byte {
|
func (tx *UnbondTx) Type() byte {
|
||||||
return TX_TYPE_UNBOND
|
return txTypeUnbond
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *UnbondTx) WriteTo(w io.Writer) (n int64, err error) {
|
func (tx *UnbondTx) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
@ -208,7 +208,7 @@ type TimeoutTx struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tx *TimeoutTx) Type() byte {
|
func (tx *TimeoutTx) Type() byte {
|
||||||
return TX_TYPE_TIMEOUT
|
return txTypeTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *TimeoutTx) WriteTo(w io.Writer) (n int64, err error) {
|
func (tx *TimeoutTx) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
@ -228,7 +228,7 @@ type DupeoutTx struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tx *DupeoutTx) Type() byte {
|
func (tx *DupeoutTx) Type() byte {
|
||||||
return TX_TYPE_DUPEOUT
|
return txTypeDupeout
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *DupeoutTx) WriteTo(w io.Writer) (n int64, err error) {
|
func (tx *DupeoutTx) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -12,7 +13,7 @@ const (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Seed math/rand with "secure" int64
|
// Seed math/rand with "secure" int64
|
||||||
b := RandBytes(8)
|
b := CRandBytes(8)
|
||||||
var seed uint64
|
var seed uint64
|
||||||
for i := 0; i < 8; i++ {
|
for i := 0; i < 8; i++ {
|
||||||
seed |= uint64(b[i])
|
seed |= uint64(b[i])
|
||||||
@ -22,7 +23,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructs an alphanumeric string of given length.
|
// Constructs an alphanumeric string of given length.
|
||||||
// Not crypto safe
|
|
||||||
func RandStr(length int) string {
|
func RandStr(length int) string {
|
||||||
chars := []byte{}
|
chars := []byte{}
|
||||||
MAIN_LOOP:
|
MAIN_LOOP:
|
||||||
@ -46,8 +46,67 @@ MAIN_LOOP:
|
|||||||
return string(chars)
|
return string(chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crypto safe
|
func RandUInt16() uint16 {
|
||||||
func RandBytes(numBytes int) []byte {
|
return uint16(rand.Uint32() & (1<<16 - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandUInt32() uint32 {
|
||||||
|
return rand.Uint32()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandUInt64() uint64 {
|
||||||
|
return uint64(rand.Uint32())<<32 + uint64(rand.Uint32())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distributed pseudo-exponentially to test for various cases
|
||||||
|
func RandUInt16Exp() uint16 {
|
||||||
|
bits := rand.Uint32() % 16
|
||||||
|
if bits == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
n := uint16(1 << (bits - 1))
|
||||||
|
n += uint16(rand.Int31()) & ((1 << (bits - 1)) - 1)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distributed pseudo-exponentially to test for various cases
|
||||||
|
func RandUInt32Exp() uint32 {
|
||||||
|
bits := rand.Uint32() % 32
|
||||||
|
if bits == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
n := uint32(1 << (bits - 1))
|
||||||
|
n += uint32(rand.Int31()) & ((1 << (bits - 1)) - 1)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distributed pseudo-exponentially to test for various cases
|
||||||
|
func RandUInt64Exp() uint64 {
|
||||||
|
bits := rand.Uint32() % 64
|
||||||
|
if bits == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
n := uint64(1 << (bits - 1))
|
||||||
|
n += uint64(rand.Int63()) & ((1 << (bits - 1)) - 1)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandTime() time.Time {
|
||||||
|
return time.Unix(int64(RandUInt64Exp()), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandBytes(n int) []byte {
|
||||||
|
bs := make([]byte, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
bs[i] = byte(rand.Intn(256))
|
||||||
|
}
|
||||||
|
return bs
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// CRand* methods are crypto safe.
|
||||||
|
|
||||||
|
func CRandBytes(numBytes int) []byte {
|
||||||
b := make([]byte, numBytes)
|
b := make([]byte, numBytes)
|
||||||
_, err := crand.Read(b)
|
_, err := crand.Read(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -56,8 +115,7 @@ func RandBytes(numBytes int) []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crypto safe
|
|
||||||
// RandHex(24) gives 96 bits of randomness, strong enough for most purposes.
|
// RandHex(24) gives 96 bits of randomness, strong enough for most purposes.
|
||||||
func RandHex(numDigits int) string {
|
func CRandHex(numDigits int) string {
|
||||||
return hex.EncodeToString(RandBytes(numDigits / 2))
|
return hex.EncodeToString(CRandBytes(numDigits / 2))
|
||||||
}
|
}
|
||||||
|
@ -142,25 +142,16 @@ func (conR *ConsensusReactor) GetChannels() []*p2p.ChannelDescriptor {
|
|||||||
// TODO optimize
|
// TODO optimize
|
||||||
return []*p2p.ChannelDescriptor{
|
return []*p2p.ChannelDescriptor{
|
||||||
&p2p.ChannelDescriptor{
|
&p2p.ChannelDescriptor{
|
||||||
Id: StateCh,
|
Id: StateCh,
|
||||||
SendQueueCapacity: 1,
|
Priority: 5,
|
||||||
RecvQueueCapacity: 10,
|
|
||||||
RecvBufferSize: 10240,
|
|
||||||
DefaultPriority: 5,
|
|
||||||
},
|
},
|
||||||
&p2p.ChannelDescriptor{
|
&p2p.ChannelDescriptor{
|
||||||
Id: DataCh,
|
Id: DataCh,
|
||||||
SendQueueCapacity: 1,
|
Priority: 5,
|
||||||
RecvQueueCapacity: 10,
|
|
||||||
RecvBufferSize: 10240,
|
|
||||||
DefaultPriority: 5,
|
|
||||||
},
|
},
|
||||||
&p2p.ChannelDescriptor{
|
&p2p.ChannelDescriptor{
|
||||||
Id: VoteCh,
|
Id: VoteCh,
|
||||||
SendQueueCapacity: 1,
|
Priority: 5,
|
||||||
RecvQueueCapacity: 1000,
|
|
||||||
RecvBufferSize: 10240,
|
|
||||||
DefaultPriority: 5,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
db/db.go
2
db/db.go
@ -1,6 +1,6 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
type Db interface {
|
type DB interface {
|
||||||
Get([]byte) []byte
|
Get([]byte) []byte
|
||||||
Set([]byte, []byte)
|
Set([]byte, []byte)
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ func NewAddrBook(filePath string) *AddrBook {
|
|||||||
|
|
||||||
// When modifying this, don't forget to update loadFromFile()
|
// When modifying this, don't forget to update loadFromFile()
|
||||||
func (a *AddrBook) init() {
|
func (a *AddrBook) init() {
|
||||||
a.key = RandHex(24) // 24/2 * 8 = 96 bits
|
a.key = CRandHex(24) // 24/2 * 8 = 96 bits
|
||||||
// New addr buckets
|
// New addr buckets
|
||||||
a.addrNew = make([]map[string]*knownAddress, newBucketCount)
|
a.addrNew = make([]map[string]*knownAddress, newBucketCount)
|
||||||
for i := range a.addrNew {
|
for i := range a.addrNew {
|
||||||
|
@ -16,15 +16,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
numBatchPackets = 10
|
numBatchPackets = 10
|
||||||
minReadBufferSize = 1024
|
minReadBufferSize = 1024
|
||||||
minWriteBufferSize = 1024
|
minWriteBufferSize = 1024
|
||||||
flushThrottleMS = 50
|
flushThrottleMS = 50
|
||||||
idleTimeoutMinutes = 5
|
idleTimeoutMinutes = 5
|
||||||
updateStatsSeconds = 2
|
updateStatsSeconds = 2
|
||||||
pingTimeoutMinutes = 2
|
pingTimeoutMinutes = 2
|
||||||
defaultSendRate = 51200 // 5Kb/s
|
defaultSendRate = 51200 // 5Kb/s
|
||||||
defaultRecvRate = 51200 // 5Kb/s
|
defaultRecvRate = 51200 // 5Kb/s
|
||||||
|
defaultSendQueueCapacity = 1
|
||||||
|
defaultRecvBufferCapacity = 4096
|
||||||
)
|
)
|
||||||
|
|
||||||
type receiveCbFunc func(chId byte, msgBytes []byte)
|
type receiveCbFunc func(chId byte, msgBytes []byte)
|
||||||
@ -399,11 +401,8 @@ FOR_LOOP:
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
type ChannelDescriptor struct {
|
type ChannelDescriptor struct {
|
||||||
Id byte
|
Id byte
|
||||||
SendQueueCapacity int // One per MConnection.
|
Priority uint
|
||||||
RecvQueueCapacity int // Global for this channel.
|
|
||||||
RecvBufferSize int
|
|
||||||
DefaultPriority uint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: lowercase.
|
// TODO: lowercase.
|
||||||
@ -421,16 +420,16 @@ type Channel struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newChannel(conn *MConnection, desc *ChannelDescriptor) *Channel {
|
func newChannel(conn *MConnection, desc *ChannelDescriptor) *Channel {
|
||||||
if desc.DefaultPriority <= 0 {
|
if desc.Priority <= 0 {
|
||||||
panic("Channel default priority must be a postive integer")
|
panic("Channel default priority must be a postive integer")
|
||||||
}
|
}
|
||||||
return &Channel{
|
return &Channel{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
desc: desc,
|
desc: desc,
|
||||||
id: desc.Id,
|
id: desc.Id,
|
||||||
sendQueue: make(chan []byte, desc.SendQueueCapacity),
|
sendQueue: make(chan []byte, defaultSendQueueCapacity),
|
||||||
recving: make([]byte, 0, desc.RecvBufferSize),
|
recving: make([]byte, 0, defaultRecvBufferCapacity),
|
||||||
priority: desc.DefaultPriority,
|
priority: desc.Priority,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +461,7 @@ func (ch *Channel) loadSendQueueSize() (size int) {
|
|||||||
// Goroutine-safe
|
// Goroutine-safe
|
||||||
// Use only as a heuristic.
|
// Use only as a heuristic.
|
||||||
func (ch *Channel) canSend() bool {
|
func (ch *Channel) canSend() bool {
|
||||||
return ch.loadSendQueueSize() < ch.desc.SendQueueCapacity
|
return ch.loadSendQueueSize() < defaultSendQueueCapacity
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if any packets are pending to be sent.
|
// Returns true if any packets are pending to be sent.
|
||||||
@ -513,7 +512,7 @@ func (ch *Channel) recvPacket(pkt packet) []byte {
|
|||||||
ch.recving = append(ch.recving, pkt.Bytes...)
|
ch.recving = append(ch.recving, pkt.Bytes...)
|
||||||
if pkt.EOF == byte(0x01) {
|
if pkt.EOF == byte(0x01) {
|
||||||
msgBytes := ch.recving
|
msgBytes := ch.recving
|
||||||
ch.recving = make([]byte, 0, ch.desc.RecvBufferSize)
|
ch.recving = make([]byte, 0, defaultRecvBufferCapacity)
|
||||||
return msgBytes
|
return msgBytes
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -68,14 +68,10 @@ func (pexR *PEXReactor) SendAddrs(peer *Peer, addrs []*NetAddress) {
|
|||||||
|
|
||||||
// Implements Reactor
|
// Implements Reactor
|
||||||
func (pexR *PEXReactor) GetChannels() []*ChannelDescriptor {
|
func (pexR *PEXReactor) GetChannels() []*ChannelDescriptor {
|
||||||
// TODO optimize
|
|
||||||
return []*ChannelDescriptor{
|
return []*ChannelDescriptor{
|
||||||
&ChannelDescriptor{
|
&ChannelDescriptor{
|
||||||
Id: PexCh,
|
Id: PexCh,
|
||||||
SendQueueCapacity: 1,
|
Priority: 1,
|
||||||
RecvQueueCapacity: 2,
|
|
||||||
RecvBufferSize: 1024,
|
|
||||||
DefaultPriority: 1,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,10 @@ func (s *Switch) Stop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Switch) Reactors() []Reactor {
|
||||||
|
return s.reactors
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, error) {
|
func (s *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, error) {
|
||||||
if atomic.LoadUint32(&s.stopped) == 1 {
|
if atomic.LoadUint32(&s.stopped) == 1 {
|
||||||
return nil, ErrSwitchStopped
|
return nil, ErrSwitchStopped
|
||||||
|
@ -2,8 +2,8 @@ package p2p
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
|
||||||
"io"
|
"io"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -17,30 +17,66 @@ func (s String) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type PeerMessage struct {
|
||||||
|
PeerKey string
|
||||||
|
Bytes []byte
|
||||||
|
Counter int
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestReactor struct {
|
||||||
|
mtx sync.Mutex
|
||||||
|
channels []*ChannelDescriptor
|
||||||
|
peersAdded []*Peer
|
||||||
|
peersRemoved []*Peer
|
||||||
|
logMessages bool
|
||||||
|
msgsCounter int
|
||||||
|
msgsReceived map[byte][]PeerMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTestReactor(channels []*ChannelDescriptor, logMessages bool) *TestReactor {
|
||||||
|
return &TestReactor{
|
||||||
|
channels: channels,
|
||||||
|
logMessages: logMessages,
|
||||||
|
msgsReceived: make(map[byte][]PeerMessage),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *TestReactor) GetChannels() []*ChannelDescriptor {
|
||||||
|
return tr.channels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *TestReactor) AddPeer(peer *Peer) {
|
||||||
|
tr.mtx.Lock()
|
||||||
|
defer tr.mtx.Unlock()
|
||||||
|
tr.peersAdded = append(tr.peersAdded, peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *TestReactor) RemovePeer(peer *Peer, reason interface{}) {
|
||||||
|
tr.mtx.Lock()
|
||||||
|
defer tr.mtx.Unlock()
|
||||||
|
tr.peersRemoved = append(tr.peersRemoved, peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *TestReactor) Receive(chId byte, peer *Peer, msgBytes []byte) {
|
||||||
|
if tr.logMessages {
|
||||||
|
tr.mtx.Lock()
|
||||||
|
defer tr.mtx.Unlock()
|
||||||
|
//fmt.Printf("Received: %X, %X\n", chId, msgBytes)
|
||||||
|
tr.msgsReceived[chId] = append(tr.msgsReceived[chId], PeerMessage{peer.Key, msgBytes, tr.msgsCounter})
|
||||||
|
tr.msgsCounter++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// convenience method for creating two switches connected to each other.
|
// convenience method for creating two switches connected to each other.
|
||||||
func makeSwitchPair(t testing.TB, numChannels int, sendQueueCapacity int, recvBufferSize int, recvQueueCapacity int) (*Switch, *Switch, []*ChannelDescriptor) {
|
func makeSwitchPair(t testing.TB, reactorsGenerator func() []Reactor) (*Switch, *Switch) {
|
||||||
|
|
||||||
// Make numChannels channels starting at byte(0x00)
|
|
||||||
chIds := []byte{}
|
|
||||||
for i := 0; i < numChannels; i++ {
|
|
||||||
chIds = append(chIds, byte(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make some channel descriptors.
|
|
||||||
chDescs := []*ChannelDescriptor{}
|
|
||||||
for _, chId := range chIds {
|
|
||||||
chDescs = append(chDescs, &ChannelDescriptor{
|
|
||||||
Id: chId,
|
|
||||||
SendQueueCapacity: sendQueueCapacity,
|
|
||||||
RecvBufferSize: recvBufferSize,
|
|
||||||
RecvQueueCapacity: recvQueueCapacity,
|
|
||||||
DefaultPriority: 1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create two switches that will be interconnected.
|
// Create two switches that will be interconnected.
|
||||||
s1 := NewSwitch(chDescs)
|
s1 := NewSwitch(reactorsGenerator())
|
||||||
s2 := NewSwitch(chDescs)
|
s2 := NewSwitch(reactorsGenerator())
|
||||||
|
|
||||||
// Create a listener for s1
|
// Create a listener for s1
|
||||||
l := NewDefaultListener("tcp", ":8001")
|
l := NewDefaultListener("tcp", ":8001")
|
||||||
@ -67,11 +103,23 @@ func makeSwitchPair(t testing.TB, numChannels int, sendQueueCapacity int, recvBu
|
|||||||
// Close the server, no longer needed.
|
// Close the server, no longer needed.
|
||||||
l.Stop()
|
l.Stop()
|
||||||
|
|
||||||
return s1, s2, chDescs
|
return s1, s2
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSwitches(t *testing.T) {
|
func TestSwitches(t *testing.T) {
|
||||||
s1, s2, _ := makeSwitchPair(t, 10, 10, 1024, 10)
|
s1, s2 := makeSwitchPair(t, func() []Reactor {
|
||||||
|
// Make two reactors of two channels each
|
||||||
|
reactors := make([]Reactor, 2)
|
||||||
|
reactors[0] = NewTestReactor([]*ChannelDescriptor{
|
||||||
|
&ChannelDescriptor{Id: byte(0x00), Priority: 10},
|
||||||
|
&ChannelDescriptor{Id: byte(0x01), Priority: 10},
|
||||||
|
}, true)
|
||||||
|
reactors[1] = NewTestReactor([]*ChannelDescriptor{
|
||||||
|
&ChannelDescriptor{Id: byte(0x02), Priority: 10},
|
||||||
|
&ChannelDescriptor{Id: byte(0x03), Priority: 10},
|
||||||
|
}, true)
|
||||||
|
return reactors
|
||||||
|
})
|
||||||
defer s1.Stop()
|
defer s1.Stop()
|
||||||
defer s2.Stop()
|
defer s2.Stop()
|
||||||
|
|
||||||
@ -83,61 +131,66 @@ func TestSwitches(t *testing.T) {
|
|||||||
t.Errorf("Expected exactly 1 peer in s2, got %v", s2.Peers().Size())
|
t.Errorf("Expected exactly 1 peer in s2, got %v", s2.Peers().Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast a message on ch0
|
ch0Msg := String("channel zero")
|
||||||
s1.Broadcast(byte(0x00), String("channel zero"))
|
ch1Msg := String("channel one")
|
||||||
// Broadcast a message on ch1
|
ch2Msg := String("channel two")
|
||||||
s1.Broadcast(byte(0x01), String("channel one"))
|
|
||||||
// Broadcast a message on ch2
|
s1.Broadcast(byte(0x00), ch0Msg)
|
||||||
s1.Broadcast(byte(0x02), String("channel two"))
|
s1.Broadcast(byte(0x01), ch1Msg)
|
||||||
|
s1.Broadcast(byte(0x02), ch2Msg)
|
||||||
|
|
||||||
// Wait for things to settle...
|
// Wait for things to settle...
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
// Receive message from channel 1 and check
|
// Check message on ch0
|
||||||
inMsg, ok := s2.Receive(byte(0x01))
|
ch0Msgs := s2.Reactors()[0].(*TestReactor).msgsReceived[byte(0x00)]
|
||||||
var n int64
|
if len(ch0Msgs) != 1 {
|
||||||
var err error
|
t.Errorf("Expected to have received 1 message in ch0")
|
||||||
if !ok {
|
|
||||||
t.Errorf("Failed to receive from channel one")
|
|
||||||
}
|
}
|
||||||
if ReadString(bytes.NewBuffer(inMsg.Bytes), &n, &err) != "channel one" {
|
if !bytes.Equal(ch0Msgs[0].Bytes, BinaryBytes(ch0Msg)) {
|
||||||
t.Errorf("Unexpected received message bytes:\n%v", hex.Dump(inMsg.Bytes))
|
t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", BinaryBytes(ch0Msg), ch0Msgs[0].Bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive message from channel 0 and check
|
// Check message on ch1
|
||||||
inMsg, ok = s2.Receive(byte(0x00))
|
ch1Msgs := s2.Reactors()[0].(*TestReactor).msgsReceived[byte(0x01)]
|
||||||
if !ok {
|
if len(ch1Msgs) != 1 {
|
||||||
t.Errorf("Failed to receive from channel zero")
|
t.Errorf("Expected to have received 1 message in ch1")
|
||||||
}
|
}
|
||||||
if ReadString(bytes.NewBuffer(inMsg.Bytes), &n, &err) != "channel zero" {
|
if !bytes.Equal(ch1Msgs[0].Bytes, BinaryBytes(ch1Msg)) {
|
||||||
t.Errorf("Unexpected received message bytes:\n%v", hex.Dump(inMsg.Bytes))
|
t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", BinaryBytes(ch1Msg), ch1Msgs[0].Bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check message on ch2
|
||||||
|
ch2Msgs := s2.Reactors()[1].(*TestReactor).msgsReceived[byte(0x02)]
|
||||||
|
if len(ch2Msgs) != 1 {
|
||||||
|
t.Errorf("Expected to have received 1 message in ch2")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(ch2Msgs[0].Bytes, BinaryBytes(ch2Msg)) {
|
||||||
|
t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", BinaryBytes(ch2Msg), ch2Msgs[0].Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkSwitches(b *testing.B) {
|
func BenchmarkSwitches(b *testing.B) {
|
||||||
|
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
|
||||||
s1, s2, chDescs := makeSwitchPair(b, 10, 10, 1024, 10)
|
s1, s2 := makeSwitchPair(b, func() []Reactor {
|
||||||
|
// Make two reactors of two channels each
|
||||||
|
reactors := make([]Reactor, 2)
|
||||||
|
reactors[0] = NewTestReactor([]*ChannelDescriptor{
|
||||||
|
&ChannelDescriptor{Id: byte(0x00), Priority: 10},
|
||||||
|
&ChannelDescriptor{Id: byte(0x01), Priority: 10},
|
||||||
|
}, false)
|
||||||
|
reactors[1] = NewTestReactor([]*ChannelDescriptor{
|
||||||
|
&ChannelDescriptor{Id: byte(0x02), Priority: 10},
|
||||||
|
&ChannelDescriptor{Id: byte(0x03), Priority: 10},
|
||||||
|
}, false)
|
||||||
|
return reactors
|
||||||
|
})
|
||||||
defer s1.Stop()
|
defer s1.Stop()
|
||||||
defer s2.Stop()
|
defer s2.Stop()
|
||||||
|
|
||||||
// Create a sink on either channel to just pop off messages.
|
|
||||||
recvRoutine := func(c *Switch, chId byte) {
|
|
||||||
for {
|
|
||||||
_, ok := c.Receive(chId)
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create routines to consume from recvQueues.
|
|
||||||
for _, chDesc := range chDescs {
|
|
||||||
go recvRoutine(s1, chDesc.Id)
|
|
||||||
go recvRoutine(s2, chDesc.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow time for goroutines to boot up
|
// Allow time for goroutines to boot up
|
||||||
time.Sleep(1000 * time.Millisecond)
|
time.Sleep(1000 * time.Millisecond)
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
@ -146,7 +199,7 @@ func BenchmarkSwitches(b *testing.B) {
|
|||||||
|
|
||||||
// Send random message from one channel to another
|
// Send random message from one channel to another
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
chId := chDescs[i%len(chDescs)].Id
|
chId := byte(i % 4)
|
||||||
nS, nF := s1.Broadcast(chId, String("test data"))
|
nS, nF := s1.Broadcast(chId, String("test data"))
|
||||||
numSuccess += nS
|
numSuccess += nS
|
||||||
numFailure += nF
|
numFailure += nF
|
||||||
|
@ -8,19 +8,30 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AccountBalanceStatusNominal = byte(0x00)
|
||||||
|
AccountBalanceStatusBonded = byte(0x01)
|
||||||
|
)
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Id uint64 // Numeric id of account, incrementing.
|
Id uint64 // Numeric id of account, incrementing.
|
||||||
PubKey []byte
|
PubKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadAccount(r io.Reader, n *int64, err *error) *Account {
|
func ReadAccount(r io.Reader, n *int64, err *error) Account {
|
||||||
return &Account{
|
return Account{
|
||||||
Id: ReadUInt64(r, n, err),
|
Id: ReadUInt64(r, n, err),
|
||||||
PubKey: ReadByteSlice(r, n, err),
|
PubKey: ReadByteSlice(r, n, err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (account *Account) Verify(msg []byte, sig Signature) bool {
|
func (account Account) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
WriteUInt64(w, account.Id, &n, &err)
|
||||||
|
WriteByteSlice(w, account.PubKey, &n, &err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (account Account) Verify(msg []byte, sig Signature) bool {
|
||||||
if sig.SignerId != account.Id {
|
if sig.SignerId != account.Id {
|
||||||
panic("Account.Id doesn't match sig.SignerId")
|
panic("Account.Id doesn't match sig.SignerId")
|
||||||
}
|
}
|
||||||
@ -38,6 +49,22 @@ func (account *Account) Verify(msg []byte, sig Signature) bool {
|
|||||||
type AccountBalance struct {
|
type AccountBalance struct {
|
||||||
Account
|
Account
|
||||||
Balance uint64
|
Balance uint64
|
||||||
|
Status byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadAccountBalance(r io.Reader, n *int64, err *error) *AccountBalance {
|
||||||
|
return &AccountBalance{
|
||||||
|
Account: ReadAccount(r, n, err),
|
||||||
|
Balance: ReadUInt64(r, n, err),
|
||||||
|
Status: ReadByte(r, n, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (accBal AccountBalance) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
WriteBinary(w, accBal.Account, &n, &err)
|
||||||
|
WriteUInt64(w, accBal.Balance, &n, &err)
|
||||||
|
WriteByte(w, accBal.Status, &n, &err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -50,7 +77,7 @@ type PrivAccount struct {
|
|||||||
// Generates a new account with private key.
|
// Generates a new account with private key.
|
||||||
// The Account.Id is empty since it isn't in the blockchain.
|
// The Account.Id is empty since it isn't in the blockchain.
|
||||||
func GenPrivAccount() *PrivAccount {
|
func GenPrivAccount() *PrivAccount {
|
||||||
privKey := RandBytes(32)
|
privKey := CRandBytes(32)
|
||||||
pubKey := crypto.MakePubKey(privKey)
|
pubKey := crypto.MakePubKey(privKey)
|
||||||
return &PrivAccount{
|
return &PrivAccount{
|
||||||
Account: Account{
|
Account: Account{
|
||||||
|
@ -10,7 +10,7 @@ func TestSignAndValidate(t *testing.T) {
|
|||||||
privAccount := GenPrivAccount()
|
privAccount := GenPrivAccount()
|
||||||
account := &privAccount.Account
|
account := &privAccount.Account
|
||||||
|
|
||||||
msg := RandBytes(128)
|
msg := CRandBytes(128)
|
||||||
sig := privAccount.Sign(msg)
|
sig := privAccount.Sign(msg)
|
||||||
t.Logf("msg: %X, sig: %X", msg, sig)
|
t.Logf("msg: %X, sig: %X", msg, sig)
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
. "github.com/tendermint/tendermint/binary"
|
. "github.com/tendermint/tendermint/binary"
|
||||||
. "github.com/tendermint/tendermint/blocks"
|
. "github.com/tendermint/tendermint/blocks"
|
||||||
db_ "github.com/tendermint/tendermint/db"
|
. "github.com/tendermint/tendermint/db"
|
||||||
"github.com/tendermint/tendermint/merkle"
|
"github.com/tendermint/tendermint/merkle"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ var (
|
|||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
db db_.Db
|
db DB
|
||||||
height uint32 // Last known block height
|
height uint32 // Last known block height
|
||||||
blockHash []byte // Last known block hash
|
blockHash []byte // Last known block hash
|
||||||
commitTime time.Time
|
commitTime time.Time
|
||||||
@ -28,11 +28,35 @@ type State struct {
|
|||||||
validators *ValidatorSet
|
validators *ValidatorSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenesisState(commitTime time.Time, accounts merkle.Tree, validators *ValidatorSet) *State {
|
func GenesisState(db DB, genesisTime time.Time, accountBalances []*AccountBalance) *State {
|
||||||
|
|
||||||
|
accounts := merkle.NewIAVLTree(db)
|
||||||
|
validators := map[uint64]*Validator{}
|
||||||
|
|
||||||
|
for _, account := range accountBalances {
|
||||||
|
// XXX make codec merkle tree.
|
||||||
|
//accounts.Set(account.Id, BinaryBytes(account))
|
||||||
|
validators[account.Id] = &Validator{
|
||||||
|
Account: account.Account,
|
||||||
|
BondHeight: 0,
|
||||||
|
VotingPower: account.Balance,
|
||||||
|
Accum: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validatorSet := NewValidatorSet(validators)
|
||||||
|
|
||||||
|
return &State{
|
||||||
|
db: db,
|
||||||
|
height: 0,
|
||||||
|
blockHash: nil,
|
||||||
|
commitTime: genesisTime,
|
||||||
|
accounts: accounts,
|
||||||
|
validators: validatorSet,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadState(db db_.Db) *State {
|
func LoadState(db DB) *State {
|
||||||
s := &State{}
|
s := &State{db: db}
|
||||||
buf := db.Get(stateKey)
|
buf := db.Get(stateKey)
|
||||||
if len(buf) == 0 {
|
if len(buf) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -160,7 +184,7 @@ func (s *State) Validators() *ValidatorSet {
|
|||||||
return s.validators
|
return s.validators
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) Account(accountId uint64) (*Account, error) {
|
func (s *State) AccountBalance(accountId uint64) (*AccountBalance, error) {
|
||||||
s.mtx.Lock()
|
s.mtx.Lock()
|
||||||
defer s.mtx.Unlock()
|
defer s.mtx.Unlock()
|
||||||
idBytes, err := BasicCodec.Write(accountId)
|
idBytes, err := BasicCodec.Write(accountId)
|
||||||
@ -172,6 +196,6 @@ func (s *State) Account(accountId uint64) (*Account, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
n, err := int64(0), error(nil)
|
n, err := int64(0), error(nil)
|
||||||
account := ReadAccount(bytes.NewBuffer(accountBytes), &n, &err)
|
accountBalance := ReadAccountBalance(bytes.NewBuffer(accountBytes), &n, &err)
|
||||||
return account, err
|
return accountBalance, err
|
||||||
}
|
}
|
||||||
|
42
state/state_test.go
Normal file
42
state/state_test.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/tendermint/tendermint/common"
|
||||||
|
. "github.com/tendermint/tendermint/db"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func randAccountBalance(id uint64, status byte) *AccountBalance {
|
||||||
|
return &AccountBalance{
|
||||||
|
Account: Account{
|
||||||
|
Id: id,
|
||||||
|
PubKey: CRandBytes(32),
|
||||||
|
},
|
||||||
|
Balance: RandUInt64(),
|
||||||
|
Status: status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first numValidators accounts are validators.
|
||||||
|
func randGenesisState(numAccounts int, numValidators int) *State {
|
||||||
|
db := NewMemDB()
|
||||||
|
accountBalances := make([]*AccountBalance, numAccounts)
|
||||||
|
for i := 0; i < numAccounts; i++ {
|
||||||
|
if i < numValidators {
|
||||||
|
accountBalances[i] = randAccountBalance(uint64(i), AccountBalanceStatusNominal)
|
||||||
|
} else {
|
||||||
|
accountBalances[i] = randAccountBalance(uint64(i), AccountBalanceStatusBonded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s0 := GenesisState(db, time.Now(), accountBalances)
|
||||||
|
return s0
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenesisSaveLoad(t *testing.T) {
|
||||||
|
|
||||||
|
s0 := randGenesisState(10, 5)
|
||||||
|
t.Log(s0)
|
||||||
|
|
||||||
|
}
|
@ -12,7 +12,7 @@ import (
|
|||||||
// TODO consider moving this to another common types package.
|
// TODO consider moving this to another common types package.
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
Account
|
Account
|
||||||
BondHeight uint32
|
BondHeight uint32 // TODO: is this needed?
|
||||||
VotingPower uint64
|
VotingPower uint64
|
||||||
Accum int64
|
Accum int64
|
||||||
}
|
}
|
||||||
@ -20,10 +20,7 @@ type Validator struct {
|
|||||||
// Used to persist the state of ConsensusStateControl.
|
// Used to persist the state of ConsensusStateControl.
|
||||||
func ReadValidator(r io.Reader, n *int64, err *error) *Validator {
|
func ReadValidator(r io.Reader, n *int64, err *error) *Validator {
|
||||||
return &Validator{
|
return &Validator{
|
||||||
Account: Account{
|
Account: ReadAccount(r, n, err),
|
||||||
Id: ReadUInt64(r, n, err),
|
|
||||||
PubKey: ReadByteSlice(r, n, err),
|
|
||||||
},
|
|
||||||
BondHeight: ReadUInt32(r, n, err),
|
BondHeight: ReadUInt32(r, n, err),
|
||||||
VotingPower: ReadUInt64(r, n, err),
|
VotingPower: ReadUInt64(r, n, err),
|
||||||
Accum: ReadInt64(r, n, err),
|
Accum: ReadInt64(r, n, err),
|
||||||
@ -42,8 +39,7 @@ func (v *Validator) Copy() *Validator {
|
|||||||
|
|
||||||
// Used to persist the state of ConsensusStateControl.
|
// Used to persist the state of ConsensusStateControl.
|
||||||
func (v *Validator) WriteTo(w io.Writer) (n int64, err error) {
|
func (v *Validator) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
WriteUInt64(w, v.Id, &n, &err)
|
WriteBinary(w, v.Account, &n, &err)
|
||||||
WriteByteSlice(w, v.PubKey, &n, &err)
|
|
||||||
WriteUInt32(w, v.BondHeight, &n, &err)
|
WriteUInt32(w, v.BondHeight, &n, &err)
|
||||||
WriteUInt64(w, v.VotingPower, &n, &err)
|
WriteUInt64(w, v.VotingPower, &n, &err)
|
||||||
WriteInt64(w, v.Accum, &n, &err)
|
WriteInt64(w, v.Accum, &n, &err)
|
||||||
|
Reference in New Issue
Block a user