mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-21 07:24:36 +00:00
* VoteSignBytes builds CanonicalVote * CommitVotes implements VoteSetReader - new CommitVotes struct holds both the Commit and the ValidatorSet and implements VoteSetReader - ToVote takes a ValidatorSet * fix TestCommit * use CommitSig.BlockID Commits may include votes for a different BlockID, could be nil, or different altogether. This means we can't use `commit.BlockID` for reconstructing the sign bytes, since up to -1/3 of the commits might be for independent BlockIDs. This means CommitSig will need to include an indicator for what BlockID it signed - if it's not the committed one or nil, it will need to include it fully in order to be verified. This is unfortunate but unavoidable so long as we include votes for non-committed BlockIDs (which we do to track validator liveness) * fixes from review * remove CommitVotes. CommitSig contains address * remove commit.canonicalVote method * toVote -> getVote, takes valIdx * update adr-025 * commit.ToVoteSet -> CommitToVoteSet * add test * fix from review
This commit is contained in:
committed by
Ismail Khoffi
parent
4c60ab83c8
commit
4905640e9b
+51
-12
@@ -500,6 +500,8 @@ func (cs *CommitSig) toVote() *Vote {
|
||||
return &v
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// Commit contains the evidence that a block was committed by a set of validators.
|
||||
// NOTE: Commit is empty for height 1, but never nil.
|
||||
type Commit struct {
|
||||
@@ -528,11 +530,56 @@ func NewCommit(blockID BlockID, precommits []*CommitSig) *Commit {
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a VoteSet from the Commit and validator set. Panics
|
||||
// if precommits from the commit can't be added to the voteset.
|
||||
// Inverse of VoteSet.MakeCommit().
|
||||
func CommitToVoteSet(chainID string, commit *Commit, vals *ValidatorSet) *VoteSet {
|
||||
height, round, typ := commit.Height(), commit.Round(), PrecommitType
|
||||
voteSet := NewVoteSet(chainID, height, round, typ, vals)
|
||||
for idx, precommit := range commit.Precommits {
|
||||
if precommit == nil {
|
||||
continue
|
||||
}
|
||||
added, err := voteSet.AddVote(commit.GetVote(idx))
|
||||
if !added || err != nil {
|
||||
panic(fmt.Sprintf("Failed to reconstruct LastCommit: %v", err))
|
||||
}
|
||||
}
|
||||
return voteSet
|
||||
}
|
||||
|
||||
// GetVote converts the CommitSig for the given valIdx to a Vote.
|
||||
// Returns nil if the precommit at valIdx is nil.
|
||||
// Panics if valIdx >= commit.Size().
|
||||
func (commit *Commit) GetVote(valIdx int) *Vote {
|
||||
commitSig := commit.Precommits[valIdx]
|
||||
if commitSig == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: this commitSig might be for a nil blockID,
|
||||
// so we can't just use commit.BlockID here.
|
||||
// For #1648, CommitSig will need to indicate what BlockID it's for !
|
||||
blockID := commitSig.BlockID
|
||||
commit.memoizeHeightRound()
|
||||
return &Vote{
|
||||
Type: PrecommitType,
|
||||
Height: commit.height,
|
||||
Round: commit.round,
|
||||
BlockID: blockID,
|
||||
Timestamp: commitSig.Timestamp,
|
||||
ValidatorAddress: commitSig.ValidatorAddress,
|
||||
ValidatorIndex: valIdx,
|
||||
Signature: commitSig.Signature,
|
||||
}
|
||||
}
|
||||
|
||||
// VoteSignBytes constructs the SignBytes for the given CommitSig.
|
||||
// The only unique part of the SignBytes is the Timestamp - all other fields
|
||||
// signed over are otherwise the same for all validators.
|
||||
func (commit *Commit) VoteSignBytes(chainID string, cs *CommitSig) []byte {
|
||||
return commit.ToVote(cs).SignBytes(chainID)
|
||||
// Panics if valIdx >= commit.Size().
|
||||
func (commit *Commit) VoteSignBytes(chainID string, valIdx int) []byte {
|
||||
return commit.GetVote(valIdx).SignBytes(chainID)
|
||||
}
|
||||
|
||||
// memoizeHeightRound memoizes the height and round of the commit using
|
||||
@@ -553,14 +600,6 @@ func (commit *Commit) memoizeHeightRound() {
|
||||
}
|
||||
}
|
||||
|
||||
// ToVote converts a CommitSig to a Vote.
|
||||
// If the CommitSig is nil, the Vote will be nil.
|
||||
func (commit *Commit) ToVote(cs *CommitSig) *Vote {
|
||||
// TODO: use commit.validatorSet to reconstruct vote
|
||||
// and deprecate .toVote
|
||||
return cs.toVote()
|
||||
}
|
||||
|
||||
// Height returns the height of the commit
|
||||
func (commit *Commit) Height() int64 {
|
||||
commit.memoizeHeightRound()
|
||||
@@ -602,8 +641,8 @@ func (commit *Commit) BitArray() *cmn.BitArray {
|
||||
// GetByIndex returns the vote corresponding to a given validator index.
|
||||
// Panics if `index >= commit.Size()`.
|
||||
// Implements VoteSetReader.
|
||||
func (commit *Commit) GetByIndex(index int) *Vote {
|
||||
return commit.ToVote(commit.Precommits[index])
|
||||
func (commit *Commit) GetByIndex(valIdx int) *Vote {
|
||||
return commit.GetVote(valIdx)
|
||||
}
|
||||
|
||||
// IsCommit returns true if there is at least one vote.
|
||||
|
||||
@@ -342,3 +342,27 @@ func TestBlockMaxDataBytesUnknownEvidence(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitToVoteSet(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
h := int64(3)
|
||||
|
||||
voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||
assert.NoError(t, err)
|
||||
|
||||
chainID := voteSet.ChainID()
|
||||
voteSet2 := CommitToVoteSet(chainID, commit, valSet)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
vote1 := voteSet.GetByIndex(i)
|
||||
vote2 := voteSet2.GetByIndex(i)
|
||||
vote3 := commit.GetVote(i)
|
||||
|
||||
vote1bz := cdc.MustMarshalBinaryBare(vote1)
|
||||
vote2bz := cdc.MustMarshalBinaryBare(vote2)
|
||||
vote3bz := cdc.MustMarshalBinaryBare(vote3)
|
||||
assert.Equal(t, vote1bz, vote2bz)
|
||||
assert.Equal(t, vote1bz, vote3bz)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,7 +612,7 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i
|
||||
}
|
||||
_, val := vals.GetByIndex(idx)
|
||||
// Validate signature.
|
||||
precommitSignBytes := commit.VoteSignBytes(chainID, precommit)
|
||||
precommitSignBytes := commit.VoteSignBytes(chainID, idx)
|
||||
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
|
||||
return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit)
|
||||
}
|
||||
@@ -689,14 +689,14 @@ func (vals *ValidatorSet) VerifyFutureCommit(newSet *ValidatorSet, chainID strin
|
||||
return cmn.NewError("Invalid commit -- not precommit @ index %v", idx)
|
||||
}
|
||||
// See if this validator is in oldVals.
|
||||
idx, val := oldVals.GetByAddress(precommit.ValidatorAddress)
|
||||
if val == nil || seen[idx] {
|
||||
oldIdx, val := oldVals.GetByAddress(precommit.ValidatorAddress)
|
||||
if val == nil || seen[oldIdx] {
|
||||
continue // missing or double vote...
|
||||
}
|
||||
seen[idx] = true
|
||||
seen[oldIdx] = true
|
||||
|
||||
// Validate signature.
|
||||
precommitSignBytes := commit.VoteSignBytes(chainID, precommit)
|
||||
precommitSignBytes := commit.VoteSignBytes(chainID, idx)
|
||||
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
|
||||
return cmn.NewError("Invalid commit -- invalid signature: %v", precommit)
|
||||
}
|
||||
|
||||
@@ -528,6 +528,9 @@ func (voteSet *VoteSet) sumTotalFrac() (int64, int64, float64) {
|
||||
//--------------------------------------------------------------------------------
|
||||
// Commit
|
||||
|
||||
// MakeCommit constructs a Commit from the VoteSet.
|
||||
// Panics if the vote type is not PrecommitType or if
|
||||
// there's no +2/3 votes for a single block.
|
||||
func (voteSet *VoteSet) MakeCommit() *Commit {
|
||||
if voteSet.type_ != PrecommitType {
|
||||
panic("Cannot MakeCommit() unless VoteSet.Type is PrecommitType")
|
||||
|
||||
Reference in New Issue
Block a user