Files
tendermint/pkg/metadata/id.go
2021-08-20 16:41:02 +02:00

125 lines
3.1 KiB
Go

package metadata
import (
"bytes"
"errors"
"fmt"
"github.com/tendermint/tendermint/crypto/tmhash"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
// BlockID
type BlockID struct {
Hash tmbytes.HexBytes `json:"hash"`
PartSetHeader PartSetHeader `json:"parts"`
}
// BlockIDFlag indicates which BlockID the signature is for.
type BlockIDFlag byte
const (
// BlockIDFlagAbsent - no vote was received from a validator.
BlockIDFlagAbsent BlockIDFlag = iota + 1
// BlockIDFlagCommit - voted for the Commit.BlockID.
BlockIDFlagCommit
// BlockIDFlagNil - voted for nil.
BlockIDFlagNil
)
// Equals returns true if the BlockID matches the given BlockID
func (blockID BlockID) Equals(other BlockID) bool {
return bytes.Equal(blockID.Hash, other.Hash) &&
blockID.PartSetHeader.Equals(other.PartSetHeader)
}
// Key returns a machine-readable string representation of the BlockID
func (blockID BlockID) Key() string {
pbph := blockID.PartSetHeader.ToProto()
bz, err := pbph.Marshal()
if err != nil {
panic(err)
}
return fmt.Sprint(string(blockID.Hash), string(bz))
}
// ValidateBasic performs basic validation.
func (blockID BlockID) ValidateBasic() error {
// Hash can be empty in case of POLBlockID in Proposal.
if err := ValidateHash(blockID.Hash); err != nil {
return fmt.Errorf("wrong Hash: %w", err)
}
if err := blockID.PartSetHeader.ValidateBasic(); err != nil {
return fmt.Errorf("wrong PartSetHeader: %w", err)
}
return nil
}
// IsZero returns true if this is the BlockID of a nil block.
func (blockID BlockID) IsZero() bool {
return len(blockID.Hash) == 0 &&
blockID.PartSetHeader.IsZero()
}
// IsComplete returns true if this is a valid BlockID of a non-nil block.
func (blockID BlockID) IsComplete() bool {
return len(blockID.Hash) == tmhash.Size &&
blockID.PartSetHeader.Total > 0 &&
len(blockID.PartSetHeader.Hash) == tmhash.Size
}
// String returns a human readable string representation of the BlockID.
//
// 1. hash
// 2. part set header
//
// See PartSetHeader#String
func (blockID BlockID) String() string {
return fmt.Sprintf(`%v:%v`, blockID.Hash, blockID.PartSetHeader)
}
// ToProto converts BlockID to protobuf
func (blockID *BlockID) ToProto() tmproto.BlockID {
if blockID == nil {
return tmproto.BlockID{}
}
return tmproto.BlockID{
Hash: blockID.Hash,
PartSetHeader: blockID.PartSetHeader.ToProto(),
}
}
// FromProto sets a protobuf BlockID to the given pointer.
// It returns an error if the block id is invalid.
func BlockIDFromProto(bID *tmproto.BlockID) (*BlockID, error) {
if bID == nil {
return nil, errors.New("nil BlockID")
}
blockID := new(BlockID)
ph, err := PartSetHeaderFromProto(&bID.PartSetHeader)
if err != nil {
return nil, err
}
blockID.PartSetHeader = *ph
blockID.Hash = bID.Hash
return blockID, blockID.ValidateBasic()
}
// ValidateHash returns an error if the hash is not empty, but its
// size != tmhash.Size.
func ValidateHash(h []byte) error {
if len(h) > 0 && len(h) != tmhash.Size {
return fmt.Errorf("expected size to be %d bytes, got %d bytes",
tmhash.Size,
len(h),
)
}
return nil
}