diff --git a/types/block.go b/types/block.go index 1d6e00fd1..1d0f176e3 100644 --- a/types/block.go +++ b/types/block.go @@ -761,17 +761,41 @@ func (commit *Commit) MaxCommitBytes() int64 { // Panics if signatures from the commit can't be added to the voteset. // Inverse of VoteSet.MakeCommit(). func CommitToVoteSet(chainID string, commit *Commit, voters *VoterSet) *VoteSet { - if commit.AggregatedSignature != nil { - panic("Aggregated commit cannot make a VoteSet") - } voteSet := NewVoteSet(chainID, commit.Height, commit.Round, PrecommitType, voters) + blsPubKeys := make([]bls.PubKeyBLS12, 0, len(commit.Signatures)) + msgs := make([][]byte, 0, len(commit.Signatures)) for idx, commitSig := range commit.Signatures { if commitSig.Absent() { continue // OK, some precommits can be missing. } - added, err := voteSet.AddVote(commit.GetVote(idx)) - if !added || err != nil { - panic(fmt.Sprintf("Failed to reconstruct LastCommit: %v", err)) + vote := commit.GetVote(idx) + if vote.Signature != nil { + added, err := voteSet.AddVote(vote) + if !added || err != nil { + panic(fmt.Sprintf("Failed to reconstruct LastCommit from Votes: %v", err)) + } + } else { + added, err := voteSet.AddAggregatedVote(vote) + if !added || err != nil { + panic(fmt.Sprintf("Failed to reconstruct LastCommit from AggregatedVotes : %v", err)) + } + // Ensure that signer is a validator. + addr, voter := voters.GetByIndex(vote.ValidatorIndex) + if voter == nil || addr == nil { + panic(fmt.Sprintf("Cannot find voter %d in voterSet of size %d", vote.ValidatorIndex, voters.Size())) + } + msg, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote(chainID, vote)) + if err != nil { + panic(fmt.Sprintf("Failed to MarshalBinaryLengthPrefixed : %v", err)) + } + blsPubKeys = append(blsPubKeys, voter.PubKey.(composite.PubKeyComposite).SignKey.(bls.PubKeyBLS12)) + msgs = append(msgs, msg) + } + } + if commit.AggregatedSignature != nil { + err := bls.VerifyAggregatedSignature(commit.AggregatedSignature, blsPubKeys, msgs) + if err != nil { + panic(fmt.Sprintf("Failed to VerifyAggregatedSignature : %v", err)) } } return voteSet diff --git a/types/vote_set.go b/types/vote_set.go index 5bcb885f5..1400d6b1d 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -7,7 +7,7 @@ import ( "sync" "github.com/pkg/errors" - + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/bits" ) @@ -148,11 +148,27 @@ func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) { voteSet.mtx.Lock() defer voteSet.mtx.Unlock() - return voteSet.addVote(vote) + return voteSet.addVote(vote, vote.Verify) +} + +func (voteSet *VoteSet) AddAggregatedVote(vote *Vote) (added bool, err error) { + if voteSet == nil { + panic("AddAggregatedVote() on nil VoteSet") + } + voteSet.mtx.Lock() + defer voteSet.mtx.Unlock() + + return voteSet.addVote(vote, func(chainID string, pubKey crypto.PubKey) (err error) { + if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) { + return ErrVoteInvalidValidatorAddress + } + return nil + }) } // NOTE: Validates as much as possible before attempting to verify the signature. -func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { +func (voteSet *VoteSet) addVote(vote *Vote, execVoteVerify func(chainID string, + pub crypto.PubKey) (err error)) (added bool, err error) { if vote == nil { return false, ErrVoteNil } @@ -200,7 +216,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { } // Check signature. - if err := vote.Verify(voteSet.chainID, voter.PubKey); err != nil { + if err := execVoteVerify(voteSet.chainID, voter.PubKey); err != nil { return false, errors.Wrapf(err, "Failed to verify vote with ChainID %s and PubKey %s", voteSet.chainID, voter.PubKey) }