privval: update signing logic to cater for vote extensions

Signed-off-by: Thane Thomson <connect@thanethomson.com>
This commit is contained in:
Thane Thomson
2022-04-13 18:49:47 -04:00
parent d2d87485ca
commit 8b104e456b
+26 -14
View File
@@ -117,6 +117,14 @@ type FilePVLastSignState struct {
filePath string
}
func (lss *FilePVLastSignState) reset() {
lss.Height = 0
lss.Round = 0
lss.Step = 0
lss.Signature = nil
lss.SignBytes = nil
}
// checkHRS checks the given height, round, step (HRS) against that of the
// FilePVLastSignState. It returns an error if the arguments constitute a regression,
// or if they match but the SignBytes are empty.
@@ -328,12 +336,7 @@ func (pv *FilePV) Save() error {
// Reset resets all fields in the FilePV.
// NOTE: Unsafe!
func (pv *FilePV) Reset() error {
var sig []byte
pv.LastSignState.Height = 0
pv.LastSignState.Round = 0
pv.LastSignState.Step = 0
pv.LastSignState.Signature = sig
pv.LastSignState.SignBytes = nil
pv.LastSignState.reset()
return pv.Save()
}
@@ -370,6 +373,11 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
signBytes := types.VoteSignBytes(chainID, vote)
extSignBytes := types.VoteExtensionSignBytes(chainID, vote)
// We always sign the vote extension. See below for details.
extSig, err := pv.Key.PrivKey.Sign(extSignBytes)
if err != nil {
return err
}
// We might crash before writing to the wal,
// causing us to try to re-sign for the same HRS.
@@ -380,6 +388,8 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
if bytes.Equal(signBytes, lss.SignBytes) {
vote.Signature = lss.Signature
} else {
// Compares the canonicalized votes (i.e. without vote extensions
// or vote extension signatures).
timestamp, ok, err := checkVotesOnlyDifferByTimestamp(lss.SignBytes, signBytes)
if err != nil {
return err
@@ -391,6 +401,12 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
vote.Timestamp = timestamp
vote.Signature = lss.Signature
}
// Vote extensions are non-deterministic, so it's possible that an
// application may have created a different extension. We therefore
// always re-sign the vote extension.
vote.ExtensionSignature = extSig
return nil
}
@@ -403,12 +419,6 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
return err
}
vote.Signature = sig
// Sign the vote extension, regardless of whether it's present or not
extSig, err := pv.Key.PrivKey.Sign(extSignBytes)
if err != nil {
return err
}
vote.ExtensionSignature = extSig
return nil
@@ -462,8 +472,10 @@ func (pv *FilePV) saveSigned(height int64, round int32, step int8, signBytes []b
//-----------------------------------------------------------------------------------------
// returns the timestamp from the lastSignBytes.
// returns true if the only difference in the votes is their timestamp.
// Returns the timestamp from the lastSignBytes.
// Returns true if the only difference in the votes is their timestamp.
// Performs these checks on the canonical votes (excluding the vote extension
// and vote extension signatures).
func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool, error) {
var lastVote, newVote tmproto.CanonicalVote
if err := protoio.UnmarshalDelimited(lastSignBytes, &lastVote); err != nil {