priv validator returns last sign bytes if h/r/s matches

since now we have time in the msgs and we might crash between writing
the priv val and writing to wal.

Refs #984
This commit is contained in:
Anton Kaliaev
2017-12-20 14:18:15 -06:00
parent 67c3af3bf8
commit a1cc9ac642
2 changed files with 17 additions and 25 deletions

View File

@ -193,8 +193,8 @@ func (privVal *PrivValidatorFS) Reset() {
privVal.Save() privVal.Save()
} }
// SignVote signs a canonical representation of the vote, along with the chainID. // SignVote signs a canonical representation of the vote, along with the
// Implements PrivValidator. // chainID. Implements PrivValidator.
func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error { func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error {
privVal.mtx.Lock() privVal.mtx.Lock()
defer privVal.mtx.Unlock() defer privVal.mtx.Unlock()
@ -206,8 +206,8 @@ func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error {
return nil return nil
} }
// SignProposal signs a canonical representation of the proposal, along with the chainID. // SignProposal signs a canonical representation of the proposal, along with
// Implements PrivValidator. // the chainID. Implements PrivValidator.
func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) error { func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) error {
privVal.mtx.Lock() privVal.mtx.Lock()
defer privVal.mtx.Unlock() defer privVal.mtx.Unlock()
@ -219,40 +219,36 @@ func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal)
return nil return nil
} }
// signBytesHRS signs the given signBytes if the height/round/step (HRS) // signBytesHRS signs the given signBytes if the height/round/step (HRS) are
// are greater than the latest state. If the HRS are equal, // greater than the latest state. If the HRS are equal, it returns the
// it returns the privValidator.LastSignature. // privValidator.LastSignature.
func (privVal *PrivValidatorFS) signBytesHRS(height int64, round int, step int8, signBytes []byte) (crypto.Signature, error) { func (privVal *PrivValidatorFS) signBytesHRS(height int64, round int, step int8, signBytes []byte) (crypto.Signature, error) {
sig := crypto.Signature{} sig := crypto.Signature{}
// If height regression, err
if privVal.LastHeight > height { if privVal.LastHeight > height {
return sig, errors.New("Height regression") return sig, errors.New("Height regression")
} }
// More cases for when the height matches
if privVal.LastHeight == height { if privVal.LastHeight == height {
// If round regression, err
if privVal.LastRound > round { if privVal.LastRound > round {
return sig, errors.New("Round regression") return sig, errors.New("Round regression")
} }
// If step regression, err
if privVal.LastRound == round { if privVal.LastRound == round {
if privVal.LastStep > step { if privVal.LastStep > step {
return sig, errors.New("Step regression") return sig, errors.New("Step regression")
} else if privVal.LastStep == step { } else if privVal.LastStep == step {
if privVal.LastSignBytes != nil { if privVal.LastSignBytes != nil {
if privVal.LastSignature.Empty() { if privVal.LastSignature.Empty() {
cmn.PanicSanity("privVal: LastSignature is nil but LastSignBytes is not!") panic("privVal: LastSignature is nil but LastSignBytes is not!")
}
// so we dont sign a conflicting vote or proposal
// NOTE: proposals are non-deterministic (include time),
// so we can actually lose them, but will still never sign conflicting ones
if bytes.Equal(privVal.LastSignBytes, signBytes) {
// log.Notice("Using privVal.LastSignature", "sig", privVal.LastSignature)
return privVal.LastSignature, nil
} }
// NOTE: we might crash between writing the priv val and writing to
// wal. since we have time in votes and proposals, signBytes can be
// different from LastSignBytes. we might be signing conflicting
// bytes here.
return privVal.LastSignature, nil
} }
return sig, errors.New("Step regression") return sig, errors.New("No LastSignature found")
} }
} }
} }

View File

@ -99,7 +99,6 @@ func TestSignVote(t *testing.T) {
privVal := GenPrivValidatorFS(tempFilePath) privVal := GenPrivValidatorFS(tempFilePath)
block1 := BlockID{[]byte{1, 2, 3}, PartSetHeader{}} block1 := BlockID{[]byte{1, 2, 3}, PartSetHeader{}}
block2 := BlockID{[]byte{3, 2, 1}, PartSetHeader{}}
height, round := int64(10), 1 height, round := int64(10), 1
voteType := VoteTypePrevote voteType := VoteTypePrevote
@ -117,7 +116,6 @@ func TestSignVote(t *testing.T) {
newVote(privVal.Address, 0, height, round-1, voteType, block1), // round regression newVote(privVal.Address, 0, height, round-1, voteType, block1), // round regression
newVote(privVal.Address, 0, height-1, round, voteType, block1), // height regression newVote(privVal.Address, 0, height-1, round, voteType, block1), // height regression
newVote(privVal.Address, 0, height-2, round+4, voteType, block1), // height regression and different round newVote(privVal.Address, 0, height-2, round+4, voteType, block1), // height regression and different round
newVote(privVal.Address, 0, height, round, voteType, block2), // different block
} }
for _, c := range cases { for _, c := range cases {
@ -133,7 +131,6 @@ func TestSignProposal(t *testing.T) {
privVal := GenPrivValidatorFS(tempFilePath) privVal := GenPrivValidatorFS(tempFilePath)
block1 := PartSetHeader{5, []byte{1, 2, 3}} block1 := PartSetHeader{5, []byte{1, 2, 3}}
block2 := PartSetHeader{10, []byte{3, 2, 1}}
height, round := int64(10), 1 height, round := int64(10), 1
// sign a proposal for first time // sign a proposal for first time
@ -150,7 +147,6 @@ func TestSignProposal(t *testing.T) {
newProposal(height, round-1, block1), // round regression newProposal(height, round-1, block1), // round regression
newProposal(height-1, round, block1), // height regression newProposal(height-1, round, block1), // height regression
newProposal(height-2, round+4, block1), // height regression and different round newProposal(height-2, round+4, block1), // height regression and different round
newProposal(height, round, block2), // different block
} }
for _, c := range cases { for _, c := range cases {