package types
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/tendermint/tendermint/crypto"
|
|
cmn "github.com/tendermint/tendermint/libs/common"
|
|
)
|
|
|
|
// Heartbeat is a simple vote-like structure so validators can
|
|
// alert others that they are alive and waiting for transactions.
|
|
// Note: We aren't adding ",omitempty" to Heartbeat's
|
|
// json field tags because we always want the JSON
|
|
// representation to be in its canonical form.
|
|
type Heartbeat struct {
|
|
ValidatorAddress Address `json:"validator_address"`
|
|
ValidatorIndex int `json:"validator_index"`
|
|
Height int64 `json:"height"`
|
|
Round int `json:"round"`
|
|
Sequence int `json:"sequence"`
|
|
Signature []byte `json:"signature"`
|
|
}
|
|
|
|
// SignBytes returns the Heartbeat bytes for signing.
|
|
// It panics if the Heartbeat is nil.
|
|
func (heartbeat *Heartbeat) SignBytes(chainID string) []byte {
|
|
bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeHeartbeat(chainID, heartbeat))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return bz
|
|
}
|
|
|
|
// Copy makes a copy of the Heartbeat.
|
|
func (heartbeat *Heartbeat) Copy() *Heartbeat {
|
|
if heartbeat == nil {
|
|
return nil
|
|
}
|
|
heartbeatCopy := *heartbeat
|
|
return &heartbeatCopy
|
|
}
|
|
|
|
// String returns a string representation of the Heartbeat.
|
|
func (heartbeat *Heartbeat) String() string {
|
|
if heartbeat == nil {
|
|
return "nil-heartbeat"
|
|
}
|
|
|
|
return fmt.Sprintf("Heartbeat{%v:%X %v/%02d (%v) %v}",
|
|
heartbeat.ValidatorIndex, cmn.Fingerprint(heartbeat.ValidatorAddress),
|
|
heartbeat.Height, heartbeat.Round, heartbeat.Sequence,
|
|
fmt.Sprintf("/%X.../", cmn.Fingerprint(heartbeat.Signature[:])))
|
|
}
|
|
|
|
// ValidateBasic performs basic validation.
|
|
func (heartbeat *Heartbeat) ValidateBasic() error {
|
|
if len(heartbeat.ValidatorAddress) != crypto.AddressSize {
|
|
return fmt.Errorf("Expected ValidatorAddress size to be %d bytes, got %d bytes",
|
|
crypto.AddressSize,
|
|
len(heartbeat.ValidatorAddress),
|
|
)
|
|
}
|
|
if heartbeat.ValidatorIndex < 0 {
|
|
return errors.New("Negative ValidatorIndex")
|
|
}
|
|
if heartbeat.Height < 0 {
|
|
return errors.New("Negative Height")
|
|
}
|
|
if heartbeat.Round < 0 {
|
|
return errors.New("Negative Round")
|
|
}
|
|
if heartbeat.Sequence < 0 {
|
|
return errors.New("Negative Sequence")
|
|
}
|
|
if len(heartbeat.Signature) == 0 {
|
|
return errors.New("Signature is missing")
|
|
}
|
|
if len(heartbeat.Signature) > MaxSignatureSize {
|
|
return fmt.Errorf("Signature is too big (max: %d)", MaxSignatureSize)
|
|
}
|
|
return nil
|
|
}
|