tendermint/types/block.go

284 lines
6.6 KiB
Go
Raw Normal View History

package types
2014-06-04 01:40:17 -07:00
import (
2014-09-11 22:44:59 -07:00
"bytes"
2014-08-10 16:35:08 -07:00
"crypto/sha256"
2014-09-11 22:44:59 -07:00
"errors"
"fmt"
"strings"
"time"
2014-08-10 16:35:08 -07:00
2015-04-01 17:30:16 -07:00
"github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/merkle"
2014-06-04 01:40:17 -07:00
)
2014-06-05 02:34:45 -07:00
type Block struct {
2015-06-19 15:30:10 -07:00
*Header `json:"header"`
*Data `json:"data"`
LastValidation *Validation `json:"last_validation"`
2014-06-04 01:40:17 -07:00
}
2014-09-11 22:44:59 -07:00
// Basic validation that doesn't involve state data.
2015-05-29 14:53:57 -07:00
func (b *Block) ValidateBasic(chainID string, lastBlockHeight uint, lastBlockHash []byte,
lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
2015-05-29 14:53:57 -07:00
if b.ChainID != chainID {
return errors.New("Wrong Block.Header.ChainID")
}
if b.Height != lastBlockHeight+1 {
2014-12-23 01:35:54 -08:00
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) {
2014-12-23 01:35:54 -08:00
return errors.New("Wrong Block.Header.LastBlockHash")
2014-09-11 22:44:59 -07:00
}
if !b.LastBlockParts.Equals(lastBlockParts) {
2014-12-23 01:35:54 -08:00
return errors.New("Wrong Block.Header.LastBlockParts")
2014-09-11 22:44:59 -07:00
}
/* TODO: Determine bounds
See blockchain/reactor "stopSyncingDurationMinutes"
2014-12-23 01:35:54 -08:00
if !b.Time.After(lastBlockTime) {
return errors.New("Invalid Block.Header.Time")
}
*/
2014-12-17 01:37:13 -08:00
if b.Header.Height != 1 {
2015-06-19 15:30:10 -07:00
if err := b.LastValidation.ValidateBasic(); err != nil {
2014-12-17 01:37:13 -08:00
return err
}
}
2014-09-11 22:44:59 -07:00
// XXX more validation
2014-08-10 16:35:08 -07:00
return nil
}
2015-03-26 10:58:20 -07:00
// Computes and returns the block hash.
// If the block is incomplete (e.g. missing Header.StateHash)
// then the hash is nil, to prevent the usage of that hash.
2014-08-10 16:35:08 -07:00
func (b *Block) Hash() []byte {
2015-06-19 15:30:10 -07:00
if b.Header == nil || b.Data == nil || b.LastValidation == nil {
2015-03-22 12:46:53 -07:00
return nil
}
2015-03-26 10:58:20 -07:00
hashHeader := b.Header.Hash()
hashData := b.Data.Hash()
2015-06-19 15:30:10 -07:00
hashLastValidation := b.LastValidation.Hash()
2015-03-26 10:58:20 -07:00
// If hashHeader is nil, required fields are missing.
if len(hashHeader) == 0 {
return nil
2014-08-10 16:35:08 -07:00
}
2015-03-26 10:58:20 -07:00
// Merkle hash from subhashes.
2015-06-19 15:30:10 -07:00
hashes := [][]byte{hashHeader, hashData, hashLastValidation}
2015-06-18 20:19:39 -07:00
return merkle.SimpleHashFromHashes(hashes)
2014-08-10 16:35:08 -07:00
}
func (b *Block) MakePartSet() *PartSet {
return NewPartSetFromData(binary.BinaryBytes(b))
}
2014-09-14 15:37:32 -07:00
// Convenience.
// A nil block never hashes to anything.
// Nothing hashes to a nil hash.
func (b *Block) HashesTo(hash []byte) bool {
if len(hash) == 0 {
return false
2014-08-10 16:35:08 -07:00
}
2014-09-14 15:37:32 -07:00
if b == nil {
return false
}
return bytes.Equal(b.Hash(), hash)
2014-08-10 16:35:08 -07:00
}
func (b *Block) String() string {
2014-12-23 01:35:54 -08:00
return b.StringIndented("")
}
2014-12-23 01:35:54 -08:00
func (b *Block) StringIndented(indent string) string {
2015-03-22 12:46:53 -07:00
if b == nil {
return "nil-Block"
}
return fmt.Sprintf(`Block{
%s %v
%s %v
%s %v
%s}#%X`,
2014-12-23 01:35:54 -08:00
indent, b.Header.StringIndented(indent+" "),
indent, b.Data.StringIndented(indent+" "),
2015-06-19 15:30:10 -07:00
indent, b.LastValidation.StringIndented(indent+" "),
indent, b.Hash())
}
2014-12-23 01:35:54 -08:00
func (b *Block) StringShort() string {
2014-10-18 01:42:33 -07:00
if b == nil {
return "nil-Block"
} else {
return fmt.Sprintf("Block#%X", b.Hash())
}
}
2014-08-10 16:35:08 -07:00
//-----------------------------------------------------------------------------
2014-06-05 02:34:45 -07:00
type Header struct {
ChainID string `json:"chain_id"`
2015-05-01 17:26:49 -07:00
Height uint `json:"height"`
Time time.Time `json:"time"`
Fees uint64 `json:"fees"`
NumTxs uint `json:"num_txs"`
LastBlockHash []byte `json:"last_block_hash"`
LastBlockParts PartSetHeader `json:"last_block_parts"`
StateHash []byte `json:"state_hash"`
2014-06-05 02:34:45 -07:00
}
2015-03-26 10:58:20 -07:00
// NOTE: hash is nil if required fields are missing.
2014-08-10 16:35:08 -07:00
func (h *Header) Hash() []byte {
2015-03-26 10:58:20 -07:00
if len(h.StateHash) == 0 {
return nil
}
buf := new(bytes.Buffer)
hasher, n, err := sha256.New(), new(int64), new(error)
binary.WriteBinary(h, buf, n, err)
if *err != nil {
panic(err)
2014-08-10 16:35:08 -07:00
}
hasher.Write(buf.Bytes())
hash := hasher.Sum(nil)
return hash
}
2014-12-23 01:35:54 -08:00
func (h *Header) StringIndented(indent string) string {
2015-03-22 12:46:53 -07:00
if h == nil {
return "nil-Header"
}
return fmt.Sprintf(`Header{
%s ChainID: %v
2014-10-30 03:32:09 -07:00
%s Height: %v
%s Time: %v
%s Fees: %v
2014-12-23 01:35:54 -08:00
%s NumTxs: %v
2014-10-30 03:32:09 -07:00
%s LastBlockHash: %X
%s LastBlockParts: %v
%s StateHash: %X
%s}#%X`,
indent, h.ChainID,
indent, h.Height,
indent, h.Time,
indent, h.Fees,
2014-12-23 01:35:54 -08:00
indent, h.NumTxs,
indent, h.LastBlockHash,
2014-10-30 03:32:09 -07:00
indent, h.LastBlockParts,
indent, h.StateHash,
indent, h.Hash())
2014-08-10 16:35:08 -07:00
}
//-------------------------------------
2015-06-19 15:30:10 -07:00
// NOTE: Validation is empty for height 1, but never nil.
type Validation struct {
2015-06-19 15:30:10 -07:00
// NOTE: The Precommits are in order of address to preserve the bonded ValidatorSet order.
// Any peer with a block can gossip precommits by index with a peer without recalculating the
// active ValidatorSet.
Precommits []*Vote `json:"precommits"`
// Volatile
hash []byte
bitArray *BitArray
2014-06-05 11:04:56 -07:00
}
2014-06-05 02:34:45 -07:00
2015-06-19 15:30:10 -07:00
func (v *Validation) Height() uint {
if len(v.Precommits) == 0 {
return 0
}
return v.Precommits[0].Height
}
func (v *Validation) Round() uint {
if len(v.Precommits) == 0 {
return 0
}
return v.Precommits[0].Round
}
func (v *Validation) ValidateBasic() error {
2015-06-05 14:15:40 -07:00
if len(v.Precommits) == 0 {
return errors.New("No precommits in validation")
}
2015-06-19 15:30:10 -07:00
// TODO Additional validation?
return nil
}
2014-08-10 16:35:08 -07:00
func (v *Validation) Hash() []byte {
if v.hash == nil {
2015-06-05 14:15:40 -07:00
bs := make([]interface{}, 1+len(v.Precommits))
bs[0] = v.Round
for i, precommit := range v.Precommits {
bs[1+i] = precommit
2014-08-10 16:35:08 -07:00
}
2015-06-18 20:19:39 -07:00
v.hash = merkle.SimpleHashFromBinaries(bs)
}
return v.hash
}
2014-12-23 01:35:54 -08:00
func (v *Validation) StringIndented(indent string) string {
2015-03-22 12:46:53 -07:00
if v == nil {
return "nil-Validation"
}
2015-06-05 14:15:40 -07:00
precommitStrings := make([]string, len(v.Precommits))
for i, precommit := range v.Precommits {
precommitStrings[i] = precommit.String()
2014-08-10 16:35:08 -07:00
}
return fmt.Sprintf(`Validation{
2015-06-05 14:15:40 -07:00
%s Precommits: %v
%s}#%X`,
2015-06-05 14:15:40 -07:00
indent, strings.Join(precommitStrings, "\n"+indent+" "),
indent, v.hash)
2014-08-10 16:35:08 -07:00
}
func (v *Validation) BitArray() *BitArray {
if v.bitArray == nil {
2015-06-05 14:15:40 -07:00
v.bitArray = NewBitArray(uint(len(v.Precommits)))
for i, precommit := range v.Precommits {
v.bitArray.SetIndex(uint(i), !precommit.IsZero())
}
}
return v.bitArray
}
//-----------------------------------------------------------------------------
type Data struct {
2015-05-01 17:26:49 -07:00
Txs []Tx `json:"txs"`
2014-08-10 16:35:08 -07:00
// Volatile
hash []byte
2014-06-05 02:34:45 -07:00
}
func (data *Data) Hash() []byte {
if data.hash == nil {
bs := make([]interface{}, len(data.Txs))
for i, tx := range data.Txs {
2015-05-29 14:53:57 -07:00
bs[i] = account.SignBytes(config.GetString("chain_id"), tx)
2014-08-10 16:35:08 -07:00
}
2015-06-18 20:19:39 -07:00
data.hash = merkle.SimpleHashFromBinaries(bs)
2014-07-01 14:50:24 -07:00
}
return data.hash
}
2014-12-23 01:35:54 -08:00
func (data *Data) StringIndented(indent string) string {
2015-03-22 12:46:53 -07:00
if data == nil {
return "nil-Data"
}
txStrings := make([]string, len(data.Txs))
for i, tx := range data.Txs {
txStrings[i] = fmt.Sprintf("Tx:%v", tx)
}
return fmt.Sprintf(`Data{
%s %v
%s}#%X`,
indent, strings.Join(txStrings, "\n"+indent+" "),
indent, data.hash)
2014-06-05 02:34:45 -07:00
}