Sign over canonical vote extension

Signed-off-by: Thane Thomson <connect@thanethomson.com>
This commit is contained in:
Thane Thomson
2022-03-29 11:57:35 -04:00
parent 3fabdee2ef
commit 27c920c277
4 changed files with 38 additions and 13 deletions

View File

@@ -369,6 +369,7 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
}
signBytes := types.VoteSignBytes(chainID, vote)
extSignBytes := types.VoteExtensionSignBytes(chainID, vote)
// We might crash before writing to the wal,
// causing us to try to re-sign for the same HRS.
@@ -398,18 +399,15 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
if err != nil {
return err
}
if err = pv.saveSigned(height, round, step, signBytes, sig); err != nil {
if err := pv.saveSigned(height, round, step, signBytes, sig); err != nil {
return err
}
vote.Signature = sig
// Sign the vote extension, if any
if len(vote.Extension) > 0 {
var err error
vote.ExtensionSignature, err = pv.Key.PrivKey.Sign(vote.Extension)
if err != nil {
return err
}
// Sign the vote extension, regardless of whether it's present or not
vote.ExtensionSignature, err = pv.Key.PrivKey.Sign(extSignBytes)
if err != nil {
return err
}
return nil

View File

@@ -65,6 +65,19 @@ func CanonicalizeVote(chainID string, vote *tmproto.Vote) tmproto.CanonicalVote
}
}
// CanonicalizeVoteExtension extracts the vote extension from the given vote
// and constructs a CanonicalizeVoteExtension struct, whose representation in
// bytes is what is signed in order to produce the vote extension's signature.
func CanonicalizeVoteExtension(chainID string, vote *tmproto.Vote) tmproto.CanonicalVoteExtension {
return tmproto.CanonicalVoteExtension{
Extension: vote.Extension,
Height: vote.Height,
Round: vote.Round,
ChainId: chainID,
Address: vote.ValidatorAddress,
}
}
// 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

@@ -90,16 +90,15 @@ func (pv MockPV) SignVote(ctx context.Context, chainID string, vote *tmproto.Vot
}
signBytes := VoteSignBytes(useChainID, vote)
extSignBytes := VoteExtensionSignBytes(useChainID, vote)
sig, err := pv.PrivKey.Sign(signBytes)
if err != nil {
return err
}
vote.Signature = sig
if len(vote.Extension) > 0 {
vote.ExtensionSignature, err = pv.PrivKey.Sign(vote.Extension)
if err != nil {
return err
}
vote.ExtensionSignature, err = pv.PrivKey.Sign(extSignBytes)
if err != nil {
return err
}
return nil
}

View File

@@ -103,6 +103,21 @@ func VoteSignBytes(chainID string, vote *tmproto.Vote) []byte {
return bz
}
// VoteExtensionSignBytes returns the proto-encoding of the canonicalized vote
// extension for signing. Panics if the marshaling fails.
//
// Similar to VoteSignBytes, the encoded Protobuf message is varint
// length-prefixed for backwards-compatibility with the Amino encoding.
func VoteExtensionSignBytes(chainID string, vote *tmproto.Vote) []byte {
pb := CanonicalizeVoteExtension(chainID, vote)
bz, err := protoio.MarshalDelimited(&pb)
if err != nil {
panic(err)
}
return bz
}
func (vote *Vote) Copy() *Vote {
voteCopy := *vote
return &voteCopy