mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-26 15:22:15 +00:00
Documented Block, some renames
This commit is contained in:
parent
403d24a4b2
commit
62ff48c02b
61
block/README.md
Normal file
61
block/README.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# `tendermint/block`
|
||||||
|
|
||||||
|
## Block
|
||||||
|
|
||||||
|
TODO: document
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
|
||||||
|
### Data
|
||||||
|
|
||||||
|
## PartSet
|
||||||
|
|
||||||
|
PartSet is used to split a byteslice of data into parts (pieces) for transmission.
|
||||||
|
By splitting data into smaller parts and computing a Merkle root hash on the list,
|
||||||
|
you can verify that a part is legitimately part of the complete data, and the
|
||||||
|
part can be forwarded to other peers before all the parts are known. In short,
|
||||||
|
it's a fast way to propagate a large file over a gossip network.
|
||||||
|
|
||||||
|
PartSet was inspired by the LibSwift project.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
data := RandBytes(2 << 20) // Something large
|
||||||
|
|
||||||
|
partSet := NewPartSetFromData(data)
|
||||||
|
partSet.Total() // Total number of 4KB parts
|
||||||
|
partSet.Count() // Equal to the Total, since we already have all the parts
|
||||||
|
partSet.Hash() // The Merkle root hash
|
||||||
|
partSet.BitArray() // A BitArray of partSet.Total() 1's
|
||||||
|
|
||||||
|
header := partSet.Header() // Send this to the peer
|
||||||
|
header.Total // Total number of parts
|
||||||
|
header.Hash // The merkle root hash
|
||||||
|
|
||||||
|
// Now we'll reconstruct the data from the parts
|
||||||
|
partSet2 := NewPartSetFromHeader(header)
|
||||||
|
partSet2.Total() // Same total as partSet.Total()
|
||||||
|
partSet2.Count() // Zero, since this PartSet doesn't have any parts yet.
|
||||||
|
partSet2.Hash() // Same hash as in partSet.Hash()
|
||||||
|
partSet2.BitArray() // A BitArray of partSet.Total() 0's
|
||||||
|
|
||||||
|
// In a gossip network the parts would arrive in arbitrary order, perhaps
|
||||||
|
// in response to explicit requests for parts, or optimistically in response
|
||||||
|
// to the receiving peer's partSet.BitArray().
|
||||||
|
for !partSet2.IsComplete() {
|
||||||
|
part := receivePartFromGossipNetwork()
|
||||||
|
added, err := partSet2.AddPart(part)
|
||||||
|
if err != nil {
|
||||||
|
// A wrong part,
|
||||||
|
// the merkle trail does not hash to partSet2.Hash()
|
||||||
|
} else if !added {
|
||||||
|
// A duplicate part already received
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data2, _ := ioutil.ReadAll(partSet2.GetReader())
|
||||||
|
bytes.Equal(data, data2) // true
|
||||||
|
```
|
@ -28,20 +28,25 @@ type Block struct {
|
|||||||
func (b *Block) ValidateBasic(lastBlockHeight uint, lastBlockHash []byte,
|
func (b *Block) ValidateBasic(lastBlockHeight uint, lastBlockHash []byte,
|
||||||
lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
|
lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
|
||||||
if b.Network != Config.Network {
|
if b.Network != Config.Network {
|
||||||
return errors.New("Invalid block network")
|
return errors.New("Wrong Block.Header.Network")
|
||||||
}
|
}
|
||||||
if b.Height != lastBlockHeight+1 {
|
if b.Height != lastBlockHeight+1 {
|
||||||
return errors.New("Invalid block height")
|
return errors.New("Wrong Block.Header.Height")
|
||||||
|
}
|
||||||
|
if b.NumTxs != uint(len(b.Data.Txs)) {
|
||||||
|
return errors.New("Wrong Block.Header.NumTxs")
|
||||||
}
|
}
|
||||||
if !bytes.Equal(b.LastBlockHash, lastBlockHash) {
|
if !bytes.Equal(b.LastBlockHash, lastBlockHash) {
|
||||||
return errors.New("Invalid block hash")
|
return errors.New("Wrong Block.Header.LastBlockHash")
|
||||||
}
|
}
|
||||||
if !b.LastBlockParts.Equals(lastBlockParts) {
|
if !b.LastBlockParts.Equals(lastBlockParts) {
|
||||||
return errors.New("Invalid block parts header")
|
return errors.New("Wrong Block.Header.LastBlockParts")
|
||||||
}
|
}
|
||||||
|
/* TODO: Determine bounds.
|
||||||
if !b.Time.After(lastBlockTime) {
|
if !b.Time.After(lastBlockTime) {
|
||||||
return errors.New("Invalid block time")
|
return errors.New("Invalid Block.Header.Time")
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if b.Header.Height != 1 {
|
if b.Header.Height != 1 {
|
||||||
if err := b.Validation.ValidateBasic(); err != nil {
|
if err := b.Validation.ValidateBasic(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -78,22 +83,22 @@ func (b *Block) HashesTo(hash []byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) String() string {
|
func (b *Block) String() string {
|
||||||
return b.StringWithIndent("")
|
return b.StringIndented("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) StringWithIndent(indent string) string {
|
func (b *Block) StringIndented(indent string) string {
|
||||||
return fmt.Sprintf(`Block{
|
return fmt.Sprintf(`Block{
|
||||||
%s %v
|
%s %v
|
||||||
%s %v
|
%s %v
|
||||||
%s %v
|
%s %v
|
||||||
%s}#%X`,
|
%s}#%X`,
|
||||||
indent, b.Header.StringWithIndent(indent+" "),
|
indent, b.Header.StringIndented(indent+" "),
|
||||||
indent, b.Validation.StringWithIndent(indent+" "),
|
indent, b.Validation.StringIndented(indent+" "),
|
||||||
indent, b.Data.StringWithIndent(indent+" "),
|
indent, b.Data.StringIndented(indent+" "),
|
||||||
indent, b.hash)
|
indent, b.hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) Description() string {
|
func (b *Block) StringShort() string {
|
||||||
if b == nil {
|
if b == nil {
|
||||||
return "nil-Block"
|
return "nil-Block"
|
||||||
} else {
|
} else {
|
||||||
@ -108,6 +113,7 @@ type Header struct {
|
|||||||
Height uint
|
Height uint
|
||||||
Time time.Time
|
Time time.Time
|
||||||
Fees uint64
|
Fees uint64
|
||||||
|
NumTxs uint
|
||||||
LastBlockHash []byte
|
LastBlockHash []byte
|
||||||
LastBlockParts PartSetHeader
|
LastBlockParts PartSetHeader
|
||||||
StateHash []byte
|
StateHash []byte
|
||||||
@ -128,12 +134,13 @@ func (h *Header) Hash() []byte {
|
|||||||
return h.hash
|
return h.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) StringWithIndent(indent string) string {
|
func (h *Header) StringIndented(indent string) string {
|
||||||
return fmt.Sprintf(`Header{
|
return fmt.Sprintf(`Header{
|
||||||
%s Network: %v
|
%s Network: %v
|
||||||
%s Height: %v
|
%s Height: %v
|
||||||
%s Time: %v
|
%s Time: %v
|
||||||
%s Fees: %v
|
%s Fees: %v
|
||||||
|
%s NumTxs: %v
|
||||||
%s LastBlockHash: %X
|
%s LastBlockHash: %X
|
||||||
%s LastBlockParts: %v
|
%s LastBlockParts: %v
|
||||||
%s StateHash: %X
|
%s StateHash: %X
|
||||||
@ -142,6 +149,7 @@ func (h *Header) StringWithIndent(indent string) string {
|
|||||||
indent, h.Height,
|
indent, h.Height,
|
||||||
indent, h.Time,
|
indent, h.Time,
|
||||||
indent, h.Fees,
|
indent, h.Fees,
|
||||||
|
indent, h.NumTxs,
|
||||||
indent, h.LastBlockHash,
|
indent, h.LastBlockHash,
|
||||||
indent, h.LastBlockParts,
|
indent, h.LastBlockParts,
|
||||||
indent, h.StateHash,
|
indent, h.StateHash,
|
||||||
@ -166,8 +174,8 @@ func (commit Commit) String() string {
|
|||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
// NOTE: The Commits are in order of address to preserve the active ValidatorSet order.
|
// NOTE: The Commits are in order of address to preserve the bonded ValidatorSet order.
|
||||||
// Any peer with a block can gossip commits by index with a peer catching up without recalculating the
|
// Any peer with a block can gossip commits by index with a peer without recalculating the
|
||||||
// active ValidatorSet.
|
// active ValidatorSet.
|
||||||
type Validation struct {
|
type Validation struct {
|
||||||
Commits []Commit // Commits (or nil) of all active validators in address order.
|
Commits []Commit // Commits (or nil) of all active validators in address order.
|
||||||
@ -212,7 +220,7 @@ func (v *Validation) Hash() []byte {
|
|||||||
return v.hash
|
return v.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) StringWithIndent(indent string) string {
|
func (v *Validation) StringIndented(indent string) string {
|
||||||
commitStrings := make([]string, len(v.Commits))
|
commitStrings := make([]string, len(v.Commits))
|
||||||
for i, commit := range v.Commits {
|
for i, commit := range v.Commits {
|
||||||
commitStrings[i] = commit.String()
|
commitStrings[i] = commit.String()
|
||||||
@ -254,7 +262,7 @@ func (data *Data) Hash() []byte {
|
|||||||
return data.hash
|
return data.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (data *Data) StringWithIndent(indent string) string {
|
func (data *Data) StringIndented(indent string) string {
|
||||||
txStrings := make([]string, len(data.Txs))
|
txStrings := make([]string, len(data.Txs))
|
||||||
for i, tx := range data.Txs {
|
for i, tx := range data.Txs {
|
||||||
txStrings[i] = fmt.Sprintf("Tx:%v", tx)
|
txStrings[i] = fmt.Sprintf("Tx:%v", tx)
|
||||||
|
@ -46,10 +46,10 @@ func (part *Part) Hash() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (part *Part) String() string {
|
func (part *Part) String() string {
|
||||||
return part.StringWithIndent("")
|
return part.StringIndented("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (part *Part) StringWithIndent(indent string) string {
|
func (part *Part) StringIndented(indent string) string {
|
||||||
trailStrings := make([]string, len(part.Trail))
|
trailStrings := make([]string, len(part.Trail))
|
||||||
for i, hash := range part.Trail {
|
for i, hash := range part.Trail {
|
||||||
trailStrings[i] = fmt.Sprintf("%X", hash)
|
trailStrings[i] = fmt.Sprintf("%X", hash)
|
||||||
@ -96,8 +96,8 @@ type PartSet struct {
|
|||||||
count uint
|
count uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an immutable, full PartSet.
|
// Returns an immutable, full PartSet from the data bytes.
|
||||||
// TODO Name is confusing, Data/Header clash with Block.Data/Header
|
// The data bytes are split into "partSize" chunks, and merkle tree computed.
|
||||||
func NewPartSetFromData(data []byte) *PartSet {
|
func NewPartSetFromData(data []byte) *PartSet {
|
||||||
// divide data into 4kb parts.
|
// divide data into 4kb parts.
|
||||||
total := (len(data) + partSize - 1) / partSize
|
total := (len(data) + partSize - 1) / partSize
|
||||||
@ -128,7 +128,6 @@ func NewPartSetFromData(data []byte) *PartSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns an empty PartSet ready to be populated.
|
// Returns an empty PartSet ready to be populated.
|
||||||
// TODO Name is confusing, Data/Header clash with Block.Data/Header
|
|
||||||
func NewPartSetFromHeader(header PartSetHeader) *PartSet {
|
func NewPartSetFromHeader(header PartSetHeader) *PartSet {
|
||||||
return &PartSet{
|
return &PartSet{
|
||||||
total: header.Total,
|
total: header.Total,
|
||||||
@ -239,7 +238,7 @@ func (ps *PartSet) GetReader() io.Reader {
|
|||||||
return bytes.NewReader(buf)
|
return bytes.NewReader(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PartSet) Description() string {
|
func (ps *PartSet) StringShort() string {
|
||||||
if ps == nil {
|
if ps == nil {
|
||||||
return "nil-PartSet"
|
return "nil-PartSet"
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,10 +11,17 @@ import (
|
|||||||
db_ "github.com/tendermint/tendermint/db"
|
db_ "github.com/tendermint/tendermint/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Simple low level store for blocks, which is actually stored as separte parts (wire format).
|
Simple low level store for blocks.
|
||||||
|
|
||||||
|
There are three types of information stored:
|
||||||
|
- BlockMeta: Meta information about each block
|
||||||
|
- Block part: Parts of each block, aggregated w/ PartSet
|
||||||
|
- Validation: The Validation part of each block, for gossiping commit votes
|
||||||
|
|
||||||
|
Currently the commit signatures are duplicated in the Block parts as
|
||||||
|
well as the Validation. In the future this may change, perhaps by moving
|
||||||
|
the Validation data outside the Block.
|
||||||
*/
|
*/
|
||||||
type BlockStore struct {
|
type BlockStore struct {
|
||||||
height uint
|
height uint
|
||||||
@ -22,7 +29,7 @@ type BlockStore struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockStore(db db_.DB) *BlockStore {
|
func NewBlockStore(db db_.DB) *BlockStore {
|
||||||
bsjson := LoadBlockStoreJSON(db)
|
bsjson := LoadBlockStoreStateJSON(db)
|
||||||
return &BlockStore{
|
return &BlockStore{
|
||||||
height: bsjson.Height,
|
height: bsjson.Height,
|
||||||
db: db,
|
db: db,
|
||||||
@ -99,23 +106,24 @@ func (bs *BlockStore) SaveBlock(block *Block, blockParts *PartSet) {
|
|||||||
if !blockParts.IsComplete() {
|
if !blockParts.IsComplete() {
|
||||||
Panicf("BlockStore can only save complete block part sets")
|
Panicf("BlockStore can only save complete block part sets")
|
||||||
}
|
}
|
||||||
meta := &BlockMeta{
|
|
||||||
Hash: block.Hash(),
|
|
||||||
Parts: blockParts.Header(),
|
|
||||||
Header: block.Header,
|
|
||||||
}
|
|
||||||
// Save block meta
|
// Save block meta
|
||||||
|
meta := makeBlockMeta(block, blockParts)
|
||||||
metaBytes := BinaryBytes(meta)
|
metaBytes := BinaryBytes(meta)
|
||||||
bs.db.Set(calcBlockMetaKey(height), metaBytes)
|
bs.db.Set(calcBlockMetaKey(height), metaBytes)
|
||||||
|
|
||||||
// Save block parts
|
// Save block parts
|
||||||
for i := uint(0); i < blockParts.Total(); i++ {
|
for i := uint(0); i < blockParts.Total(); i++ {
|
||||||
bs.saveBlockPart(height, i, blockParts.GetPart(i))
|
bs.saveBlockPart(height, i, blockParts.GetPart(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save block validation (duplicate and separate)
|
// Save block validation (duplicate and separate)
|
||||||
validationBytes := BinaryBytes(block.Validation)
|
validationBytes := BinaryBytes(block.Validation)
|
||||||
bs.db.Set(calcBlockValidationKey(height), validationBytes)
|
bs.db.Set(calcBlockValidationKey(height), validationBytes)
|
||||||
// Save new BlockStoreJSON descriptor
|
|
||||||
BlockStoreJSON{Height: height}.Save(bs.db)
|
// Save new BlockStoreStateJSON descriptor
|
||||||
|
BlockStoreStateJSON{Height: height}.Save(bs.db)
|
||||||
|
|
||||||
// Done!
|
// Done!
|
||||||
bs.height = height
|
bs.height = height
|
||||||
}
|
}
|
||||||
@ -131,9 +139,17 @@ func (bs *BlockStore) saveBlockPart(height uint, index uint, part *Part) {
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
type BlockMeta struct {
|
type BlockMeta struct {
|
||||||
Hash []byte // The BlockHash
|
Hash []byte // The block hash
|
||||||
Parts PartSetHeader // The PartSetHeader, for transfer
|
|
||||||
Header *Header // The block's Header
|
Header *Header // The block's Header
|
||||||
|
Parts PartSetHeader // The PartSetHeader, for transfer
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBlockMeta(block *Block, blockParts *PartSet) *BlockMeta {
|
||||||
|
return &BlockMeta{
|
||||||
|
Hash: block.Hash(),
|
||||||
|
Header: block.Header,
|
||||||
|
Parts: blockParts.Header(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -154,11 +170,11 @@ func calcBlockValidationKey(height uint) []byte {
|
|||||||
|
|
||||||
var blockStoreKey = []byte("blockStore")
|
var blockStoreKey = []byte("blockStore")
|
||||||
|
|
||||||
type BlockStoreJSON struct {
|
type BlockStoreStateJSON struct {
|
||||||
Height uint
|
Height uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsj BlockStoreJSON) Save(db db_.DB) {
|
func (bsj BlockStoreStateJSON) Save(db db_.DB) {
|
||||||
bytes, err := json.Marshal(bsj)
|
bytes, err := json.Marshal(bsj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Panicf("Could not marshal state bytes: %v", err)
|
Panicf("Could not marshal state bytes: %v", err)
|
||||||
@ -166,14 +182,14 @@ func (bsj BlockStoreJSON) Save(db db_.DB) {
|
|||||||
db.Set(blockStoreKey, bytes)
|
db.Set(blockStoreKey, bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadBlockStoreJSON(db db_.DB) BlockStoreJSON {
|
func LoadBlockStoreStateJSON(db db_.DB) BlockStoreStateJSON {
|
||||||
bytes := db.Get(blockStoreKey)
|
bytes := db.Get(blockStoreKey)
|
||||||
if bytes == nil {
|
if bytes == nil {
|
||||||
return BlockStoreJSON{
|
return BlockStoreStateJSON{
|
||||||
Height: 0,
|
Height: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bsj := BlockStoreJSON{}
|
bsj := BlockStoreStateJSON{}
|
||||||
err := json.Unmarshal(bytes, &bsj)
|
err := json.Unmarshal(bytes, &bsj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Panicf("Could not unmarshal bytes: %X", bytes)
|
Panicf("Could not unmarshal bytes: %X", bytes)
|
||||||
|
28
block/tx.go
28
block/tx.go
@ -10,21 +10,31 @@ import (
|
|||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrTxInvalidAddress = errors.New("Error invalid address")
|
||||||
|
ErrTxDuplicateAddress = errors.New("Error duplicate address")
|
||||||
|
ErrTxInvalidAmount = errors.New("Error invalid amount")
|
||||||
|
ErrTxInsufficientFunds = errors.New("Error insufficient funds")
|
||||||
|
ErrTxInvalidSignature = errors.New("Error invalid signature")
|
||||||
|
ErrTxInvalidSequence = errors.New("Error invalid sequence")
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Tx (Transaction) is an atomic operation on the ledger state.
|
Tx (Transaction) is an atomic operation on the ledger state.
|
||||||
|
|
||||||
Account Txs:
|
Account Txs:
|
||||||
1. SendTx Send coins to address
|
- SendTx Send coins to address
|
||||||
|
|
||||||
Validation Txs:
|
Validation Txs:
|
||||||
1. BondTx New validator posts a bond
|
- BondTx New validator posts a bond
|
||||||
2. UnbondTx Validator leaves
|
- UnbondTx Validator leaves
|
||||||
3. DupeoutTx Validator dupes out (equivocates)
|
- DupeoutTx Validator dupes out (equivocates)
|
||||||
*/
|
*/
|
||||||
type Tx interface {
|
type Tx interface {
|
||||||
WriteSignBytes(w io.Writer, n *int64, err *error)
|
WriteSignBytes(w io.Writer, n *int64, err *error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Types of Tx implementations
|
||||||
const (
|
const (
|
||||||
// Account transactions
|
// Account transactions
|
||||||
TxTypeSend = byte(0x01)
|
TxTypeSend = byte(0x01)
|
||||||
@ -36,14 +46,8 @@ const (
|
|||||||
TxTypeDupeout = byte(0x14)
|
TxTypeDupeout = byte(0x14)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
//-------------------------------------
|
||||||
ErrTxInvalidAddress = errors.New("Error invalid address")
|
// for binary.readReflect
|
||||||
ErrTxDuplicateAddress = errors.New("Error duplicate address")
|
|
||||||
ErrTxInvalidAmount = errors.New("Error invalid amount")
|
|
||||||
ErrTxInsufficientFunds = errors.New("Error insufficient funds")
|
|
||||||
ErrTxInvalidSignature = errors.New("Error invalid signature")
|
|
||||||
ErrTxInvalidSequence = errors.New("Error invalid sequence")
|
|
||||||
)
|
|
||||||
|
|
||||||
func TxDecoder(r io.Reader, n *int64, err *error) interface{} {
|
func TxDecoder(r io.Reader, n *int64, err *error) interface{} {
|
||||||
switch t := ReadByte(r, n, err); t {
|
switch t := ReadByte(r, n, err); t {
|
||||||
|
@ -10,12 +10,6 @@ import (
|
|||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
VoteTypePrevote = byte(0x00)
|
|
||||||
VoteTypePrecommit = byte(0x01)
|
|
||||||
VoteTypeCommit = byte(0x02)
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrVoteUnexpectedStep = errors.New("Unexpected step")
|
ErrVoteUnexpectedStep = errors.New("Unexpected step")
|
||||||
ErrVoteInvalidAccount = errors.New("Invalid round vote account")
|
ErrVoteInvalidAccount = errors.New("Invalid round vote account")
|
||||||
@ -24,7 +18,7 @@ var (
|
|||||||
ErrVoteConflictingSignature = errors.New("Conflicting round vote signature")
|
ErrVoteConflictingSignature = errors.New("Conflicting round vote signature")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Represents a prevote, precommit, or commit vote for proposals from validators.
|
// Represents a prevote, precommit, or commit vote from validators for consensus.
|
||||||
// Commit votes get aggregated into the next block's Validaiton.
|
// Commit votes get aggregated into the next block's Validaiton.
|
||||||
// See the whitepaper for details.
|
// See the whitepaper for details.
|
||||||
type Vote struct {
|
type Vote struct {
|
||||||
@ -36,6 +30,13 @@ type Vote struct {
|
|||||||
Signature SignatureEd25519
|
Signature SignatureEd25519
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Types of votes
|
||||||
|
const (
|
||||||
|
VoteTypePrevote = byte(0x00)
|
||||||
|
VoteTypePrecommit = byte(0x01)
|
||||||
|
VoteTypeCommit = byte(0x02)
|
||||||
|
)
|
||||||
|
|
||||||
func (vote *Vote) WriteSignBytes(w io.Writer, n *int64, err *error) {
|
func (vote *Vote) WriteSignBytes(w io.Writer, n *int64, err *error) {
|
||||||
WriteUvarint(vote.Height, w, n, err)
|
WriteUvarint(vote.Height, w, n, err)
|
||||||
WriteUvarint(vote.Round, w, n, err)
|
WriteUvarint(vote.Round, w, n, err)
|
||||||
|
@ -139,10 +139,10 @@ func (bA BitArray) PickRandom() (uint, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bA BitArray) String() string {
|
func (bA BitArray) String() string {
|
||||||
return bA.StringWithIndent("")
|
return bA.StringIndented("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bA BitArray) StringWithIndent(indent string) string {
|
func (bA BitArray) StringIndented(indent string) string {
|
||||||
lines := []string{}
|
lines := []string{}
|
||||||
bits := ""
|
bits := ""
|
||||||
for i := uint(0); i < bA.Bits; i++ {
|
for i := uint(0); i < bA.Bits; i++ {
|
||||||
|
@ -86,7 +86,7 @@ func (pol *POL) Verify(valSet *state.ValidatorSet) error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pol *POL) Description() string {
|
func (pol *POL) StringShort() string {
|
||||||
if pol == nil {
|
if pol == nil {
|
||||||
return "nil-POL"
|
return "nil-POL"
|
||||||
} else {
|
} else {
|
||||||
|
@ -131,10 +131,10 @@ type RoundState struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RoundState) String() string {
|
func (rs *RoundState) String() string {
|
||||||
return rs.StringWithIndent("")
|
return rs.StringIndented("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RoundState) StringWithIndent(indent string) string {
|
func (rs *RoundState) StringIndented(indent string) string {
|
||||||
return fmt.Sprintf(`RoundState{
|
return fmt.Sprintf(`RoundState{
|
||||||
%s H:%v R:%v S:%v
|
%s H:%v R:%v S:%v
|
||||||
%s StartTime: %v
|
%s StartTime: %v
|
||||||
@ -153,20 +153,20 @@ func (rs *RoundState) StringWithIndent(indent string) string {
|
|||||||
indent, rs.Height, rs.Round, rs.Step,
|
indent, rs.Height, rs.Round, rs.Step,
|
||||||
indent, rs.StartTime,
|
indent, rs.StartTime,
|
||||||
indent, rs.CommitTime,
|
indent, rs.CommitTime,
|
||||||
indent, rs.Validators.StringWithIndent(indent+" "),
|
indent, rs.Validators.StringIndented(indent+" "),
|
||||||
indent, rs.Proposal,
|
indent, rs.Proposal,
|
||||||
indent, rs.ProposalBlockParts.Description(), rs.ProposalBlock.Description(),
|
indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(),
|
||||||
indent, rs.ProposalPOLParts.Description(), rs.ProposalPOL.Description(),
|
indent, rs.ProposalPOLParts.StringShort(), rs.ProposalPOL.StringShort(),
|
||||||
indent, rs.LockedBlockParts.Description(), rs.LockedBlock.Description(),
|
indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(),
|
||||||
indent, rs.LockedPOL.Description(),
|
indent, rs.LockedPOL.StringShort(),
|
||||||
indent, rs.Prevotes.StringWithIndent(indent+" "),
|
indent, rs.Prevotes.StringIndented(indent+" "),
|
||||||
indent, rs.Precommits.StringWithIndent(indent+" "),
|
indent, rs.Precommits.StringIndented(indent+" "),
|
||||||
indent, rs.Commits.StringWithIndent(indent+" "),
|
indent, rs.Commits.StringIndented(indent+" "),
|
||||||
indent, rs.LastCommits.Description(),
|
indent, rs.LastCommits.StringShort(),
|
||||||
indent)
|
indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RoundState) Description() string {
|
func (rs *RoundState) StringShort() string {
|
||||||
return fmt.Sprintf(`RS{%v/%v/%X %v}`,
|
return fmt.Sprintf(`RS{%v/%v/%X %v}`,
|
||||||
rs.Height, rs.Round, rs.Step, rs.StartTime)
|
rs.Height, rs.Round, rs.Step, rs.StartTime)
|
||||||
}
|
}
|
||||||
@ -306,7 +306,7 @@ ACTION_LOOP:
|
|||||||
|
|
||||||
height, round, action := roundAction.Height, roundAction.Round, roundAction.Action
|
height, round, action := roundAction.Height, roundAction.Round, roundAction.Action
|
||||||
rs := cs.GetRoundState()
|
rs := cs.GetRoundState()
|
||||||
log.Info("Running round action A:%X %v", action, rs.Description())
|
log.Info("Running round action A:%X %v", action, rs.StringShort())
|
||||||
|
|
||||||
// Continue if action is not relevant
|
// Continue if action is not relevant
|
||||||
if height != rs.Height {
|
if height != rs.Height {
|
||||||
@ -545,6 +545,7 @@ func (cs *ConsensusState) RunActionPropose(height uint, round uint) {
|
|||||||
Height: cs.Height,
|
Height: cs.Height,
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Fees: 0, // TODO fees
|
Fees: 0, // TODO fees
|
||||||
|
NumTxs: uint(len(txs)),
|
||||||
LastBlockHash: cs.state.LastBlockHash,
|
LastBlockHash: cs.state.LastBlockHash,
|
||||||
LastBlockParts: cs.state.LastBlockParts,
|
LastBlockParts: cs.state.LastBlockParts,
|
||||||
StateHash: nil, // Will set afterwards.
|
StateHash: nil, // Will set afterwards.
|
||||||
|
@ -247,14 +247,14 @@ func (voteSet *VoteSet) MakeValidation() *Validation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) String() string {
|
func (voteSet *VoteSet) String() string {
|
||||||
return voteSet.StringWithIndent("")
|
return voteSet.StringIndented("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) StringWithIndent(indent string) string {
|
func (voteSet *VoteSet) StringIndented(indent string) string {
|
||||||
voteStrings := make([]string, len(voteSet.votes))
|
voteStrings := make([]string, len(voteSet.votes))
|
||||||
for i, vote := range voteSet.votes {
|
for i, vote := range voteSet.votes {
|
||||||
if vote == nil {
|
if vote == nil {
|
||||||
voteStrings[i] = "nil"
|
voteStrings[i] = "nil-Vote"
|
||||||
} else {
|
} else {
|
||||||
voteStrings[i] = vote.String()
|
voteStrings[i] = vote.String()
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ func (voteSet *VoteSet) StringWithIndent(indent string) string {
|
|||||||
indent)
|
indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) Description() string {
|
func (voteSet *VoteSet) StringShort() string {
|
||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
return "nil-VoteSet"
|
return "nil-VoteSet"
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ func TestGenesisSaveLoad(t *testing.T) {
|
|||||||
Height: 1,
|
Height: 1,
|
||||||
Time: s0.LastBlockTime.Add(time.Minute),
|
Time: s0.LastBlockTime.Add(time.Minute),
|
||||||
Fees: 0,
|
Fees: 0,
|
||||||
|
NumTxs: 0,
|
||||||
LastBlockHash: s0.LastBlockHash,
|
LastBlockHash: s0.LastBlockHash,
|
||||||
LastBlockParts: s0.LastBlockParts,
|
LastBlockParts: s0.LastBlockParts,
|
||||||
StateHash: nil,
|
StateHash: nil,
|
||||||
|
@ -197,10 +197,10 @@ func (valSet *ValidatorSet) Iterate(fn func(index uint, val *Validator) bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (valSet *ValidatorSet) String() string {
|
func (valSet *ValidatorSet) String() string {
|
||||||
return valSet.StringWithIndent("")
|
return valSet.StringIndented("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (valSet *ValidatorSet) StringWithIndent(indent string) string {
|
func (valSet *ValidatorSet) StringIndented(indent string) string {
|
||||||
valStrings := []string{}
|
valStrings := []string{}
|
||||||
valSet.Iterate(func(index uint, val *Validator) bool {
|
valSet.Iterate(func(index uint, val *Validator) bool {
|
||||||
valStrings = append(valStrings, val.String())
|
valStrings = append(valStrings, val.String())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user