2871 remove proposalHeartbeat infrastructure (#2874)

* 2871 remove proposalHeartbeat infrastructure

* 2871 add preliminary changelog entry
This commit is contained in:
srmo
2018-11-28 14:52:35 +01:00
committed by Ethan Buchman
parent 416d143bf7
commit e291fbbebe
20 changed files with 15 additions and 521 deletions

View File

@@ -41,16 +41,6 @@ type CanonicalVote struct {
ChainID string
}
type CanonicalHeartbeat struct {
Type byte
Height int64 `binary:"fixed64"`
Round int `binary:"fixed64"`
Sequence int `binary:"fixed64"`
ValidatorAddress Address
ValidatorIndex int
ChainID string
}
//-----------------------------------
// Canonicalize the structs
@@ -91,18 +81,6 @@ func CanonicalizeVote(chainID string, vote *Vote) CanonicalVote {
}
}
func CanonicalizeHeartbeat(chainID string, heartbeat *Heartbeat) CanonicalHeartbeat {
return CanonicalHeartbeat{
Type: byte(HeartbeatType),
Height: heartbeat.Height,
Round: heartbeat.Round,
Sequence: heartbeat.Sequence,
ValidatorAddress: heartbeat.ValidatorAddress,
ValidatorIndex: heartbeat.ValidatorIndex,
ChainID: chainID,
}
}
// CanonicalTime can be used to stringify time in a canonical way.
func CanonicalTime(t time.Time) string {
// Note that sending time over amino resets it to

View File

@@ -146,10 +146,6 @@ func (b *EventBus) PublishEventTx(data EventDataTx) error {
return nil
}
func (b *EventBus) PublishEventProposalHeartbeat(data EventDataProposalHeartbeat) error {
return b.Publish(EventProposalHeartbeat, data)
}
func (b *EventBus) PublishEventNewRoundStep(data EventDataRoundState) error {
return b.Publish(EventNewRoundStep, data)
}

View File

@@ -152,7 +152,7 @@ func TestEventBusPublish(t *testing.T) {
err = eventBus.Subscribe(context.Background(), "test", tmquery.Empty{}, eventsCh)
require.NoError(t, err)
const numEventsExpected = 15
const numEventsExpected = 14
done := make(chan struct{})
go func() {
numEvents := 0
@@ -172,8 +172,6 @@ func TestEventBusPublish(t *testing.T) {
require.NoError(t, err)
err = eventBus.PublishEventVote(EventDataVote{})
require.NoError(t, err)
err = eventBus.PublishEventProposalHeartbeat(EventDataProposalHeartbeat{})
require.NoError(t, err)
err = eventBus.PublishEventNewRoundStep(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventTimeoutPropose(EventDataRoundState{})

View File

@@ -18,7 +18,6 @@ const (
EventNewRound = "NewRound"
EventNewRoundStep = "NewRoundStep"
EventPolka = "Polka"
EventProposalHeartbeat = "ProposalHeartbeat"
EventRelock = "Relock"
EventTimeoutPropose = "TimeoutPropose"
EventTimeoutWait = "TimeoutWait"
@@ -47,7 +46,6 @@ func RegisterEventDatas(cdc *amino.Codec) {
cdc.RegisterConcrete(EventDataNewRound{}, "tendermint/event/NewRound", nil)
cdc.RegisterConcrete(EventDataCompleteProposal{}, "tendermint/event/CompleteProposal", nil)
cdc.RegisterConcrete(EventDataVote{}, "tendermint/event/Vote", nil)
cdc.RegisterConcrete(EventDataProposalHeartbeat{}, "tendermint/event/ProposalHeartbeat", nil)
cdc.RegisterConcrete(EventDataValidatorSetUpdates{}, "tendermint/event/ValidatorSetUpdates", nil)
cdc.RegisterConcrete(EventDataString(""), "tendermint/event/ProposalString", nil)
}
@@ -75,10 +73,6 @@ type EventDataTx struct {
TxResult
}
type EventDataProposalHeartbeat struct {
Heartbeat *Heartbeat
}
// NOTE: This goes into the replay WAL
type EventDataRoundState struct {
Height int64 `json:"height"`
@@ -143,7 +137,6 @@ var (
EventQueryNewRound = QueryForEvent(EventNewRound)
EventQueryNewRoundStep = QueryForEvent(EventNewRoundStep)
EventQueryPolka = QueryForEvent(EventPolka)
EventQueryProposalHeartbeat = QueryForEvent(EventProposalHeartbeat)
EventQueryRelock = QueryForEvent(EventRelock)
EventQueryTimeoutPropose = QueryForEvent(EventTimeoutPropose)
EventQueryTimeoutWait = QueryForEvent(EventTimeoutWait)

View File

@@ -1,83 +0,0 @@
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
}

View File

@@ -1,104 +0,0 @@
package types
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
)
func TestHeartbeatCopy(t *testing.T) {
hb := &Heartbeat{ValidatorIndex: 1, Height: 10, Round: 1}
hbCopy := hb.Copy()
require.Equal(t, hbCopy, hb, "heartbeat copy should be the same")
hbCopy.Round = hb.Round + 10
require.NotEqual(t, hbCopy, hb, "heartbeat copy mutation should not change original")
var nilHb *Heartbeat
nilHbCopy := nilHb.Copy()
require.Nil(t, nilHbCopy, "copy of nil should also return nil")
}
func TestHeartbeatString(t *testing.T) {
var nilHb *Heartbeat
require.Contains(t, nilHb.String(), "nil", "expecting a string and no panic")
hb := &Heartbeat{ValidatorIndex: 1, Height: 11, Round: 2}
require.Equal(t, "Heartbeat{1:000000000000 11/02 (0) /000000000000.../}", hb.String())
var key ed25519.PrivKeyEd25519
sig, err := key.Sign([]byte("Tendermint"))
require.NoError(t, err)
hb.Signature = sig
require.Equal(t, "Heartbeat{1:000000000000 11/02 (0) /FF41E371B9BF.../}", hb.String())
}
func TestHeartbeatWriteSignBytes(t *testing.T) {
chainID := "test_chain_id"
{
testHeartbeat := &Heartbeat{ValidatorIndex: 1, Height: 10, Round: 1}
signBytes := testHeartbeat.SignBytes(chainID)
expected, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeHeartbeat(chainID, testHeartbeat))
require.NoError(t, err)
require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Heartbeat")
}
{
testHeartbeat := &Heartbeat{}
signBytes := testHeartbeat.SignBytes(chainID)
expected, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeHeartbeat(chainID, testHeartbeat))
require.NoError(t, err)
require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Heartbeat")
}
require.Panics(t, func() {
var nilHb *Heartbeat
signBytes := nilHb.SignBytes(chainID)
require.Equal(t, string(signBytes), "null")
})
}
func TestHeartbeatValidateBasic(t *testing.T) {
testCases := []struct {
testName string
malleateHeartBeat func(*Heartbeat)
expectErr bool
}{
{"Good HeartBeat", func(hb *Heartbeat) {}, false},
{"Invalid address size", func(hb *Heartbeat) {
hb.ValidatorAddress = nil
}, true},
{"Negative validator index", func(hb *Heartbeat) {
hb.ValidatorIndex = -1
}, true},
{"Negative height", func(hb *Heartbeat) {
hb.Height = -1
}, true},
{"Negative round", func(hb *Heartbeat) {
hb.Round = -1
}, true},
{"Negative sequence", func(hb *Heartbeat) {
hb.Sequence = -1
}, true},
{"Missing signature", func(hb *Heartbeat) {
hb.Signature = nil
}, true},
{"Signature too big", func(hb *Heartbeat) {
hb.Signature = make([]byte, MaxSignatureSize+1)
}, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
hb := &Heartbeat{
ValidatorAddress: secp256k1.GenPrivKey().PubKey().Address(),
Signature: make([]byte, 4),
ValidatorIndex: 1, Height: 10, Round: 1}
tc.malleateHeartBeat(hb)
assert.Equal(t, tc.expectErr, hb.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}

View File

@@ -10,14 +10,13 @@ import (
)
// PrivValidator defines the functionality of a local Tendermint validator
// that signs votes, proposals, and heartbeats, and never double signs.
// that signs votes and proposals, and never double signs.
type PrivValidator interface {
GetAddress() Address // redundant since .PubKey().Address()
GetPubKey() crypto.PubKey
SignVote(chainID string, vote *Vote) error
SignProposal(chainID string, proposal *Proposal) error
SignHeartbeat(chainID string, heartbeat *Heartbeat) error
}
//----------------------------------------
@@ -84,16 +83,6 @@ func (pv *MockPV) SignProposal(chainID string, proposal *Proposal) error {
return nil
}
// signHeartbeat signs the heartbeat without any checking.
func (pv *MockPV) SignHeartbeat(chainID string, heartbeat *Heartbeat) error {
sig, err := pv.privKey.Sign(heartbeat.SignBytes(chainID))
if err != nil {
return err
}
heartbeat.Signature = sig
return nil
}
// String returns a string representation of the MockPV.
func (pv *MockPV) String() string {
return fmt.Sprintf("MockPV{%v}", pv.GetAddress())
@@ -121,11 +110,6 @@ func (pv *erroringMockPV) SignProposal(chainID string, proposal *Proposal) error
return ErroringMockPVErr
}
// signHeartbeat signs the heartbeat without any checking.
func (pv *erroringMockPV) SignHeartbeat(chainID string, heartbeat *Heartbeat) error {
return ErroringMockPVErr
}
// NewErroringMockPV returns a MockPV that fails on each signing request. Again, for testing only.
func NewErroringMockPV() *erroringMockPV {
return &erroringMockPV{&MockPV{ed25519.GenPrivKey()}}

View File

@@ -6,8 +6,8 @@ import (
)
var (
// MaxSignatureSize is a maximum allowed signature size for the Heartbeat,
// Proposal and Vote.
// MaxSignatureSize is a maximum allowed signature size for the Proposal
// and Vote.
// XXX: secp256k1 does not have Size nor MaxSize defined.
MaxSignatureSize = cmn.MaxInt(ed25519.SignatureSize, 64)
)

View File

@@ -11,8 +11,6 @@ const (
// Proposals
ProposalType SignedMsgType = 0x20
// Heartbeat
HeartbeatType SignedMsgType = 0x30
)
// IsVoteTypeValid returns true if t is a valid vote type.