From 5dbb706e2c875e23a151fb0650260f51f989679f Mon Sep 17 00:00:00 2001 From: William Banfield Date: Fri, 13 May 2022 15:12:06 -0400 Subject: [PATCH] add boolean parameter to vote set --- internal/consensus/reactor_test.go | 2 +- internal/consensus/state.go | 24 +++++++------------ internal/consensus/types/height_vote_set.go | 16 +++++++------ .../consensus/types/height_vote_set_test.go | 2 +- internal/evidence/verify_test.go | 12 +++++----- internal/statesync/reactor_test.go | 2 +- node/node_test.go | 2 +- test/e2e/runner/evidence.go | 2 +- types/block.go | 6 ++--- types/block_test.go | 2 +- types/vote_set.go | 4 ++-- types/vote_set_test.go | 4 ++-- 12 files changed, 36 insertions(+), 42 deletions(-) diff --git a/internal/consensus/reactor_test.go b/internal/consensus/reactor_test.go index 81a9de379..b87f6784e 100644 --- a/internal/consensus/reactor_test.go +++ b/internal/consensus/reactor_test.go @@ -665,7 +665,7 @@ func TestSwitchToConsensusVoteExtensions(t *testing.T) { blockParts, err := propBlock.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) - voteSet := types.NewVoteSet(cs.state.ChainID, testCase.storedHeight, 0, tmproto.PrecommitType, cs.state.Validators) + voteSet := types.NewVoteSet(cs.state.ChainID, testCase.storedHeight, 0, tmproto.PrecommitType, cs.state.Validators, false) signedVote := signVote(ctx, t, validator, tmproto.PrecommitType, cs.state.ChainID, types.BlockID{ Hash: propBlock.Hash(), PartSetHeader: blockParts.Header(), diff --git a/internal/consensus/state.go b/internal/consensus/state.go index 3d30b0240..0aadab05c 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -695,12 +695,8 @@ func (cs *State) sendInternalMessage(ctx context.Context, mi msgInfo) { // Reconstruct LastCommit from SeenCommit, which we saved along with the block, // (which happens even before saving the state) func (cs *State) reconstructLastCommit(state sm.State) { - requireExtensions := false - requireHeight := cs.state.ConsensusParams.Vote.ExtensionRequireHeight - if requireHeight != 0 && state.LastBlockHeight >= requireHeight { - requireExtensions = true - } - votes, err := cs.votesFromExtendedCommit(state) + requireExtensions := requireVoteExtensions(cs.state.ConsensusParams.Vote.ExtensionRequireHeight, state.LastBlockHeight) + votes, err := cs.votesFromExtendedCommit(state, requireExtensions) if err == nil { cs.LastCommit = votes return @@ -715,15 +711,12 @@ func (cs *State) reconstructLastCommit(state sm.State) { cs.LastCommit = votes } -func (cs *State) votesFromExtendedCommit(state sm.State) (*types.VoteSet, error) { +func (cs *State) votesFromExtendedCommit(state sm.State, requireExtensions bool) (*types.VoteSet, error) { ec := cs.blockStore.LoadExtendedCommit(state.LastBlockHeight) if ec == nil { return nil, fmt.Errorf("commit for height %v not found", state.LastBlockHeight) } - if err := ec.EnsureExtensions(); err != nil { - return nil, fmt.Errorf("invalid vote extensions: %v", err) - } - vs := ec.ToVoteSet(state.ChainID, state.LastValidators) + vs := ec.ToVoteSet(state.ChainID, state.LastValidators, requireExtensions) if !vs.HasTwoThirdsMajority() { return nil, errors.New("seen commit does not have +2/3 majority") } @@ -845,7 +838,7 @@ func (cs *State) updateToState(state sm.State) { cs.ValidRound = -1 cs.ValidBlock = nil cs.ValidBlockParts = nil - cs.Votes = cstypes.NewHeightVoteSet(state.ChainID, height, validators) + cs.Votes = cstypes.NewHeightVoteSet(state.ChainID, height, validators, requireVoteExtensions(state.ConsensusParams.Vote.ExtensionRequireHeight, height)) cs.CommitRound = -1 cs.LastValidators = state.LastValidators cs.TriggeredTimeoutPrecommit = false @@ -2397,7 +2390,7 @@ func (cs *State) addVote( if !errors.Is(err, types.ErrVoteExtensionAbsent) { return false, err } - if cs.requireVoteExtension() { + if requireVoteExtensions(cs.state.ConsensusParams.Vote.ExtensionRequireHeight, cs.Height) { return false, err } } @@ -2797,9 +2790,8 @@ func (cs *State) calculateProposalTimestampDifferenceMetric() { } } -func (cs *State) requireVoteExtension() bool { - requireHeight := cs.state.ConsensusParams.Vote.ExtensionRequireHeight - if requireHeight == 0 || cs.Height < requireHeight { +func requireVoteExtensions(requireHeight, currentHeight int64) bool { + if requireHeight == 0 || currentHeight < requireHeight { return false } return true diff --git a/internal/consensus/types/height_vote_set.go b/internal/consensus/types/height_vote_set.go index 661c5120e..0c432e80d 100644 --- a/internal/consensus/types/height_vote_set.go +++ b/internal/consensus/types/height_vote_set.go @@ -38,9 +38,10 @@ We let each peer provide us with up to 2 unexpected "catchup" rounds. One for their LastCommit round, and another for the official commit round. */ type HeightVoteSet struct { - chainID string - height int64 - valSet *types.ValidatorSet + chainID string + height int64 + valSet *types.ValidatorSet + requireExtensions bool mtx sync.Mutex round int32 // max tracked round @@ -48,9 +49,10 @@ type HeightVoteSet struct { peerCatchupRounds map[types.NodeID][]int32 // keys: peer.ID; values: at most 2 rounds } -func NewHeightVoteSet(chainID string, height int64, valSet *types.ValidatorSet) *HeightVoteSet { +func NewHeightVoteSet(chainID string, height int64, valSet *types.ValidatorSet, requireExtensions bool) *HeightVoteSet { hvs := &HeightVoteSet{ - chainID: chainID, + chainID: chainID, + requireExtensions: requireExtensions, } hvs.Reset(height, valSet) return hvs @@ -107,8 +109,8 @@ func (hvs *HeightVoteSet) addRound(round int32) { panic("addRound() for an existing round") } // log.Debug("addRound(round)", "round", round) - prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, tmproto.PrevoteType, hvs.valSet) - precommits := types.NewVoteSet(hvs.chainID, hvs.height, round, tmproto.PrecommitType, hvs.valSet) + prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, tmproto.PrevoteType, hvs.valSet, hvs.requireExtensions) + precommits := types.NewVoteSet(hvs.chainID, hvs.height, round, tmproto.PrecommitType, hvs.valSet, hvs.requireExtensions) hvs.roundVoteSets[round] = RoundVoteSet{ Prevotes: prevotes, Precommits: precommits, diff --git a/internal/consensus/types/height_vote_set_test.go b/internal/consensus/types/height_vote_set_test.go index acffa794c..b21895409 100644 --- a/internal/consensus/types/height_vote_set_test.go +++ b/internal/consensus/types/height_vote_set_test.go @@ -27,7 +27,7 @@ func TestPeerCatchupRounds(t *testing.T) { valSet, privVals := factory.ValidatorSet(ctx, t, 10, 1) chainID := cfg.ChainID() - hvs := NewHeightVoteSet(chainID, 1, valSet) + hvs := NewHeightVoteSet(chainID, 1, valSet, false) vote999_0 := makeVoteHR(ctx, t, 1, 0, 999, privVals, chainID) added, err := hvs.AddVote(vote999_0, "peer1") diff --git a/internal/evidence/verify_test.go b/internal/evidence/verify_test.go index 2ed84fa69..c811125e9 100644 --- a/internal/evidence/verify_test.go +++ b/internal/evidence/verify_test.go @@ -233,7 +233,7 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) { // we are simulating a duplicate vote attack where all the validators in the conflictingVals set // except the last validator vote twice blockID := factory.MakeBlockIDWithHash(conflictingHeader.Hash()) - voteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals) + voteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals, false) extCommit, err := factory.MakeExtendedCommit(ctx, blockID, 10, 1, voteSet, conflictingPrivVals[:4], defaultEvidenceTime) require.NoError(t, err) commit := extCommit.StripExtensions() @@ -253,7 +253,7 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) { } trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash")) - trustedVoteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals) + trustedVoteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals, false) trustedExtCommit, err := factory.MakeExtendedCommit(ctx, trustedBlockID, 10, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) @@ -336,7 +336,7 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) { // we are simulating an amnesia attack where all the validators in the conflictingVals set // except the last validator vote twice. However this time the commits are of different rounds. blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash")) - voteSet := types.NewVoteSet(evidenceChainID, height, 0, tmproto.SignedMsgType(2), conflictingVals) + voteSet := types.NewVoteSet(evidenceChainID, height, 0, tmproto.SignedMsgType(2), conflictingVals, false) extCommit, err := factory.MakeExtendedCommit(ctx, blockID, height, 0, voteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) commit := extCommit.StripExtensions() @@ -356,7 +356,7 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) { } trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash")) - trustedVoteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), conflictingVals) + trustedVoteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), conflictingVals, false) trustedExtCommit, err := factory.MakeExtendedCommit(ctx, trustedBlockID, height, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) @@ -553,7 +553,7 @@ func makeLunaticEvidence( }) blockID := factory.MakeBlockIDWithHash(conflictingHeader.Hash()) - voteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), conflictingVals) + voteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), conflictingVals, false) extCommit, err := factory.MakeExtendedCommit(ctx, blockID, height, 1, voteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) commit := extCommit.StripExtensions() @@ -582,7 +582,7 @@ func makeLunaticEvidence( } trustedBlockID := factory.MakeBlockIDWithHash(trustedHeader.Hash()) trustedVals, privVals := factory.ValidatorSet(ctx, t, totalVals, defaultVotingPower) - trustedVoteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), trustedVals) + trustedVoteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), trustedVals, false) trustedExtCommit, err := factory.MakeExtendedCommit(ctx, trustedBlockID, height, 1, trustedVoteSet, privVals, defaultEvidenceTime) require.NoError(t, err) trustedCommit := trustedExtCommit.StripExtensions() diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index 904fb2b74..38a829f8d 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -855,7 +855,7 @@ func mockLB(ctx context.Context, t *testing.T, height int64, time time.Time, las header.NextValidatorsHash = nextVals.Hash() header.ConsensusHash = types.DefaultConsensusParams().HashConsensusParams() lastBlockID = factory.MakeBlockIDWithHash(header.Hash()) - voteSet := types.NewVoteSet(factory.DefaultTestChainID, height, 0, tmproto.PrecommitType, currentVals) + voteSet := types.NewVoteSet(factory.DefaultTestChainID, height, 0, tmproto.PrecommitType, currentVals, false) extCommit, err := factory.MakeExtendedCommit(ctx, lastBlockID, height, 0, voteSet, currentPrivVals, time) require.NoError(t, err) return nextVals, nextPrivVals, &types.LightBlock{ diff --git a/node/node_test.go b/node/node_test.go index b1d7a9481..2386f6884 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -526,7 +526,7 @@ func TestMaxProposalBlockSize(t *testing.T) { } state.ChainID = maxChainID - voteSet := types.NewVoteSet(state.ChainID, math.MaxInt64-1, math.MaxInt32, tmproto.PrecommitType, state.Validators) + voteSet := types.NewVoteSet(state.ChainID, math.MaxInt64-1, math.MaxInt32, tmproto.PrecommitType, state.Validators, false) // add maximum amount of signatures to a single commit for i := 0; i < types.MaxVotesCount; i++ { diff --git a/test/e2e/runner/evidence.go b/test/e2e/runner/evidence.go index a71ea14fb..551906c1e 100644 --- a/test/e2e/runner/evidence.go +++ b/test/e2e/runner/evidence.go @@ -165,7 +165,7 @@ func generateLightClientAttackEvidence( // create a commit for the forged header blockID := makeBlockID(header.Hash(), 1000, []byte("partshash")) - voteSet := types.NewVoteSet(chainID, forgedHeight, 0, tmproto.SignedMsgType(2), conflictingVals) + voteSet := types.NewVoteSet(chainID, forgedHeight, 0, tmproto.SignedMsgType(2), conflictingVals, false) commit, err := factory.MakeExtendedCommit(ctx, blockID, forgedHeight, 0, voteSet, pv, forgedTime) if err != nil { diff --git a/types/block.go b/types/block.go index 1a067fc3a..61fac70e3 100644 --- a/types/block.go +++ b/types/block.go @@ -1020,8 +1020,8 @@ func (ec *ExtendedCommit) Clone() *ExtendedCommit { // ToVoteSet constructs a VoteSet from the Commit and validator set. // Panics if signatures from the commit can't be added to the voteset. // Inverse of VoteSet.MakeExtendedCommit(). -func (ec *ExtendedCommit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet { - voteSet := NewVoteSet(chainID, ec.Height, ec.Round, tmproto.PrecommitType, vals) +func (ec *ExtendedCommit) ToVoteSet(chainID string, vals *ValidatorSet, requireExtensions bool) *VoteSet { + voteSet := NewVoteSet(chainID, ec.Height, ec.Round, tmproto.PrecommitType, vals, requireExtensions) for idx, ecs := range ec.ExtendedSignatures { if ecs.BlockIDFlag == BlockIDFlagAbsent { continue // OK, some precommits can be missing. @@ -1042,7 +1042,7 @@ func (ec *ExtendedCommit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet // Panics if signatures from the commit can't be added to the voteset. // Inverse of VoteSet.MakeCommit(). func (c *Commit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet { - voteSet := NewVoteSet(chainID, c.Height, c.Round, tmproto.PrecommitType, vals) + voteSet := NewVoteSet(chainID, c.Height, c.Round, tmproto.PrecommitType, vals, false) for idx, cs := range c.Signatures { if cs.BlockIDFlag == BlockIDFlagAbsent { continue // OK, some precommits can be missing. diff --git a/types/block_test.go b/types/block_test.go index 092be95e2..ff56b09f2 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -660,7 +660,7 @@ func TestExtendedCommitToVoteSet(t *testing.T) { } chainID := voteSet.ChainID() - voteSet2 := extCommit.ToVoteSet(chainID, valSet) + voteSet2 := extCommit.ToVoteSet(chainID, valSet, true) for i := int32(0); int(i) < len(vals); i++ { vote1 := voteSet.GetByIndex(i) diff --git a/types/vote_set.go b/types/vote_set.go index 9ea2d59ca..8027f70fc 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -71,7 +71,7 @@ type VoteSet struct { // Constructs a new VoteSet struct used to accumulate votes for given height/round. func NewVoteSet(chainID string, height int64, round int32, - signedMsgType tmproto.SignedMsgType, valSet *ValidatorSet) *VoteSet { + signedMsgType tmproto.SignedMsgType, valSet *ValidatorSet, requireExtensions bool) *VoteSet { if height == 0 { panic("Cannot make VoteSet for height == 0, doesn't make sense.") } @@ -81,7 +81,7 @@ func NewVoteSet(chainID string, height int64, round int32, round: round, signedMsgType: signedMsgType, valSet: valSet, - requireExtensions: false, + requireExtensions: requireExtensions, votesBitArray: bits.NewBitArray(valSet.Size()), votes: make([]*Vote, valSet.Size()), sum: 0, diff --git a/types/vote_set_test.go b/types/vote_set_test.go index 8d166d508..b90102986 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -510,7 +510,7 @@ func randVoteSet( ) (*VoteSet, *ValidatorSet, []PrivValidator) { t.Helper() valSet, privValidators := randValidatorPrivValSet(ctx, t, numValidators, votingPower) - return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators + return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet, false), valSet, privValidators } func deterministicVoteSet( @@ -523,7 +523,7 @@ func deterministicVoteSet( ) (*VoteSet, *ValidatorSet, []PrivValidator) { t.Helper() valSet, privValidators := deterministicValidatorSet(ctx, t) - return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators + return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet, false), valSet, privValidators } func randValidatorPrivValSet(ctx context.Context, t testing.TB, numValidators int, votingPower int64) (*ValidatorSet, []PrivValidator) {