consensus: remove logic to unlock block on 2/3 prevote for nil (#6954)

This commit is contained in:
William Banfield
2022-01-13 22:49:39 -05:00
committed by William Banfield
parent 76c935e325
commit 6d2cb8ba8e
11 changed files with 409 additions and 282 deletions
+9 -11
View File
@@ -547,14 +547,6 @@ func ensureNoNewRoundStep(t *testing.T, stepCh <-chan tmpubsub.Message) {
"We should be stuck waiting, not receiving NewRoundStep event")
}
func ensureNoNewUnlock(t *testing.T, unlockCh <-chan tmpubsub.Message) {
t.Helper()
ensureNoNewEvent(t,
unlockCh,
ensureTimeout,
"We should be stuck waiting, not receiving Unlock event")
}
func ensureNoNewTimeout(t *testing.T, stepCh <-chan tmpubsub.Message, timeout int64) {
t.Helper()
timeoutDuration := time.Duration(timeout*10) * time.Nanosecond
@@ -653,10 +645,16 @@ func ensureNewBlockHeader(t *testing.T, blockCh <-chan tmpubsub.Message, height
}
}
func ensureNewUnlock(t *testing.T, unlockCh <-chan tmpubsub.Message, height int64, round int32) {
func ensureLock(t *testing.T, lockCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
ensureNewEvent(t, unlockCh, height, round, ensureTimeout,
"Timeout expired while waiting for NewUnlock event")
ensureNewEvent(t, lockCh, height, round, ensureTimeout,
"Timeout expired while waiting for LockValue event")
}
func ensureRelock(t *testing.T, relockCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
ensureNewEvent(t, relockCh, height, round, ensureTimeout,
"Timeout expired while waiting for RelockValue event")
}
func ensureProposal(t *testing.T, proposalCh <-chan tmpubsub.Message, height int64, round int32, propID types.BlockID) {
+16 -56
View File
@@ -1413,7 +1413,6 @@ func (cs *State) enterPrevoteWait(ctx context.Context, height int64, round int32
// Enter: `timeoutPrecommit` after any +2/3 precommits.
// Enter: +2/3 precomits for block or nil.
// Lock & precommit the ProposalBlock if we have enough prevotes for it (a POL in this round)
// else, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
// else, precommit nil otherwise.
func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32) {
logger := cs.logger.With("height", height, "round", round)
@@ -1460,21 +1459,9 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32)
panic(fmt.Sprintf("this POLRound should be %v but got %v", round, polRound))
}
// +2/3 prevoted nil. Unlock and precommit nil.
if len(blockID.Hash) == 0 {
if cs.LockedBlock == nil {
logger.Debug("precommit step; +2/3 prevoted for nil")
} else {
logger.Debug("precommit step; +2/3 prevoted for nil; unlocking")
cs.LockedRound = -1
cs.LockedBlock = nil
cs.LockedBlockParts = nil
if err := cs.eventBus.PublishEventUnlock(ctx, cs.RoundStateEvent()); err != nil {
logger.Error("failed publishing event unlock", "err", err)
}
}
// +2/3 prevoted nil. Precommit nil.
if blockID.IsNil() {
logger.Debug("precommit step; +2/3 prevoted for nil")
cs.signAddVote(ctx, tmproto.PrecommitType, nil, types.PartSetHeader{})
return
}
@@ -1494,7 +1481,9 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32)
return
}
// If +2/3 prevoted for proposal block, stage and precommit it
// If greater than 2/3 of the voting power on the network prevoted for
// the proposed block, update our locked block to this block and issue a
// precommit vote for it.
if cs.ProposalBlock.HashesTo(blockID.Hash) {
logger.Debug("precommit step; +2/3 prevoted proposal block; locking", "hash", blockID.Hash)
@@ -1516,23 +1505,14 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32)
}
// There was a polka in this round for a block we don't have.
// Fetch that block, unlock, and precommit nil.
// The +2/3 prevotes for this round is the POL for our unlock.
// Fetch that block, and precommit nil.
logger.Debug("precommit step; +2/3 prevotes for a block we do not have; voting nil", "block_id", blockID)
cs.LockedRound = -1
cs.LockedBlock = nil
cs.LockedBlockParts = nil
if !cs.ProposalBlockParts.HasHeader(blockID.PartSetHeader) {
cs.ProposalBlock = nil
cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartSetHeader)
}
if err := cs.eventBus.PublishEventUnlock(ctx, cs.RoundStateEvent()); err != nil {
logger.Error("failed publishing event unlock", "err", err)
}
cs.signAddVote(ctx, tmproto.PrecommitType, nil, types.PartSetHeader{})
}
@@ -1640,7 +1620,7 @@ func (cs *State) tryFinalizeCommit(ctx context.Context, height int64) {
}
blockID, ok := cs.Votes.Precommits(cs.CommitRound).TwoThirdsMajority()
if !ok || len(blockID.Hash) == 0 {
if !ok || blockID.IsNil() {
logger.Error("failed attempt to finalize commit; there was no +2/3 majority or +2/3 was for nil")
return
}
@@ -1967,7 +1947,7 @@ func (cs *State) addProposalBlockPart(
// Update Valid* if we can.
prevotes := cs.Votes.Prevotes(cs.Round)
blockID, hasTwoThirds := prevotes.TwoThirdsMajority()
if hasTwoThirds && !blockID.IsZero() && (cs.ValidRound < cs.Round) {
if hasTwoThirds && !blockID.IsNil() && (cs.ValidRound < cs.Round) {
if cs.ProposalBlock.HashesTo(blockID.Hash) {
cs.logger.Debug(
"updating valid block to new proposal block",
@@ -2120,33 +2100,13 @@ func (cs *State) addVote(
prevotes := cs.Votes.Prevotes(vote.Round)
cs.logger.Debug("added vote to prevote", "vote", vote, "prevotes", prevotes.StringShort())
// If +2/3 prevotes for a block or nil for *any* round:
if blockID, ok := prevotes.TwoThirdsMajority(); ok {
// There was a polka!
// If we're locked but this is a recent polka, unlock.
// If it matches our ProposalBlock, update the ValidBlock
// Unlock if `cs.LockedRound < vote.Round <= cs.Round`
// NOTE: If vote.Round > cs.Round, we'll deal with it when we get to vote.Round
if (cs.LockedBlock != nil) &&
(cs.LockedRound < vote.Round) &&
(vote.Round <= cs.Round) &&
!cs.LockedBlock.HashesTo(blockID.Hash) {
cs.logger.Debug("unlocking because of POL", "locked_round", cs.LockedRound, "pol_round", vote.Round)
cs.LockedRound = -1
cs.LockedBlock = nil
cs.LockedBlockParts = nil
if err := cs.eventBus.PublishEventUnlock(ctx, cs.RoundStateEvent()); err != nil {
return added, err
}
}
// Check to see if >2/3 of the voting power on the network voted for any non-nil block.
if blockID, ok := prevotes.TwoThirdsMajority(); ok && !blockID.IsNil() {
// Greater than 2/3 of the voting power on the network voted for some
// non-nil block
// Update Valid* if we can.
// NOTE: our proposal block may be nil or not what received a polka..
if len(blockID.Hash) != 0 && (cs.ValidRound < vote.Round) && (vote.Round == cs.Round) {
if cs.ValidRound < vote.Round && vote.Round == cs.Round {
if cs.ProposalBlock.HashesTo(blockID.Hash) {
cs.logger.Debug("updating valid block because of POL", "valid_round", cs.ValidRound, "pol_round", vote.Round)
cs.ValidRound = vote.Round
@@ -2182,7 +2142,7 @@ func (cs *State) addVote(
case cs.Round == vote.Round && cstypes.RoundStepPrevote <= cs.Step: // current round
blockID, ok := prevotes.TwoThirdsMajority()
if ok && (cs.isProposalComplete() || len(blockID.Hash) == 0) {
if ok && (cs.isProposalComplete() || blockID.IsNil()) {
cs.enterPrecommit(ctx, height, vote.Round)
} else if prevotes.HasTwoThirdsAny() {
cs.enterPrevoteWait(ctx, height, vote.Round)
@@ -2210,7 +2170,7 @@ func (cs *State) addVote(
cs.enterNewRound(ctx, height, vote.Round)
cs.enterPrecommit(ctx, height, vote.Round)
if len(blockID.Hash) != 0 {
if !blockID.IsNil() {
cs.enterCommit(ctx, height, vote.Round)
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
cs.enterNewRound(ctx, cs.Height, 0)
+367 -189
View File
@@ -35,16 +35,22 @@ x * TestFullRound1 - 1 val, full successful round
x * TestFullRoundNil - 1 val, full round of nil
x * TestFullRound2 - 2 vals, both required for full round
LockSuite
x * TestLockNoPOL - 2 vals, 4 rounds. one val locked, precommits nil every round except first.
x * TestLockPOLRelock - 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
x * TestLockPOLUnlock - 4 vals, one precommits, other 3 polka nil at next round, so we unlock and precomit nil
x * TestLockPOLSafety1 - 4 vals. We shouldn't change lock based on polka at earlier round
x * TestLockPOLSafety2 - 4 vals. After unlocking, we shouldn't relock based on polka at earlier round
x * TestStateLock_NoPOL - 2 vals, 4 rounds. one val locked, precommits nil every round except first.
x * TestStateLock_POLUpdateLock - 4 vals, one precommits,
other 3 polka at next round, so we unlock and precomit the polka
x * TestStateLock_POLRelock - 4 vals, polka in round 1 and polka in round 2.
Ensure validator updates locked round.
x_*_TestStateLock_POLDoesNotUnlock 4 vals, one precommits, other 3 polka nil at
next round, so we precommit nil but maintain lock
x * TestStateLock_MissingProposalWhenPOLSeenDoesNotUpdateLock - 4 vals, 1 misses proposal but sees POL.
x * TestStateLock_MissingProposalWhenPOLSeenDoesNotUnlock - 4 vals, 1 misses proposal but sees POL.
x * TestStateLock_POLSafety1 - 4 vals. We shouldn't change lock based on polka at earlier round
x * TestStateLock_POLSafety2 - 4 vals. After unlocking, we shouldn't relock based on polka at earlier round
* TestNetworkLock - once +1/3 precommits, network should be locked
* TestNetworkLockPOL - once +1/3 precommits, the block with more recent polka is committed
SlashingSuite
x * TestSlashingPrevotes - a validator prevoting twice in a round gets slashed
x * TestSlashingPrecommits - a validator precomitting twice in a round gets slashed
x * TestStateSlashing_Prevotes - a validator prevoting twice in a round gets slashed
x * TestStateSlashing_Precommits - a validator precomitting twice in a round gets slashed
CatchupSuite
* TestCatchup - if we might be behind and we've seen any 2/3 prevotes, round skip to new round, precommit, or prevote
HaltSuite
@@ -139,8 +145,7 @@ func TestStateProposerSelection2(t *testing.T) {
int(i+2)%len(vss),
prop.Address)
rs := cs1.GetRoundState()
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, rs.ProposalBlockParts.Header(), vss[1:]...)
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vss[1:]...)
ensureNewRound(t, newRoundCh, height, i+round+1) // wait for the new round event each round
incrementRound(vss[1:]...)
}
@@ -462,7 +467,7 @@ func TestStateFullRound2(t *testing.T) {
// two validators, 4 rounds.
// two vals take turns proposing. val1 locks on first one, precommits nil on everything else
func TestStateLockNoPOL(t *testing.T) {
func TestStateLock_NoPOL(t *testing.T) {
config := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -668,11 +673,12 @@ func TestStateLockNoPOL(t *testing.T) {
ensurePrecommit(t, voteCh, height, round)
}
// 4 vals in two rounds,
// in round one: v1 precommits, other 3 only prevote so the block isn't committed
// in round two: v1 prevotes the same block that the node is locked on
// the others prevote a new block hence v1 changes lock and precommits the new block with the others
func TestStateLockPOLRelock(t *testing.T) {
// TestStateLock_POLUpdateLock tests that a validator maintains updates its locked
// block if the following conditions are met within a round:
// 1. The validator received a valid proposal for the block
// 2. The validator received prevotes representing greater than 2/3 of the voting
// power on the network for the block.
func TestStateLock_POLUpdateLock(t *testing.T) {
config := configSetup(t)
logger := log.TestingLogger()
@@ -691,16 +697,18 @@ func TestStateLockPOLRelock(t *testing.T) {
require.NoError(t, err)
addr := pv1.Address()
voteCh := subscribeToVoter(ctx, t, cs1, addr)
lockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryLock)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
newBlockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewBlockHeader)
// everything done from perspective of cs1
/*
Round1 (cs1, B) // B B B B// B nil B nil
Round 0:
cs1 creates a proposal for block B.
Send a prevote for B from each of the validators to cs1.
Send a precommit for nil from all of the validators to cs1.
eg. vs2 and vs4 didn't see the 2/3 prevotes
This ensures that cs1 will lock on B in this round but not precommit it.
*/
t.Log("### Starting Round 0")
// start round and wait for propose and prevote
startTestRound(ctx, cs1, height, round)
@@ -711,99 +719,211 @@ func TestStateLockPOLRelock(t *testing.T) {
theBlockHash := rs.ProposalBlock.Hash()
theBlockParts := rs.ProposalBlockParts.Header()
ensurePrevote(t, voteCh, height, round) // prevote
ensurePrevote(t, voteCh, height, round)
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, theBlockHash, theBlockParts, vs2, vs3, vs4)
ensurePrecommit(t, voteCh, height, round) // our precommit
// the proposed block should now be locked and our precommit added
// check that the validator generates a Lock event.
ensureLock(t, lockCh, height, round)
// the proposed block should now be locked and our precommit added.
ensurePrecommit(t, voteCh, height, round)
validatePrecommit(ctx, t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
// add precommits from the rest
// add precommits from the rest of the validators.
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
// before we timeout to the new round set the new proposal
cs2 := newState(ctx, t, logger, cs1.state, vs2, kvstore.NewApplication())
prop, propBlock := decideProposal(ctx, t, cs2, vs2, vs2.Height, vs2.Round+1)
if prop == nil || propBlock == nil {
t.Fatal("Failed to create proposal block with vs2")
}
propBlockParts, err := propBlock.MakePartSet(partSize)
require.NoError(t, err)
propBlockHash := propBlock.Hash()
require.NotEqual(t, propBlockHash, theBlockHash)
incrementRound(vs2, vs3, vs4)
// timeout to new round
// timeout to new round.
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
round++ // moving to the next round
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
if err := cs1.SetProposalAndBlock(ctx, prop, propBlock, propBlockParts, "some peer"); err != nil {
/*
Round 1:
Create a block, D and send a proposal for it to cs1
Send a prevote for D from each of the validators to cs1.
Send a precommit for nil from all of the validtors to cs1.
Check that cs1 is now locked on the new block, D and no longer on the old block.
*/
t.Log("### Starting Round 1")
incrementRound(vs2, vs3, vs4)
round++
// Generate a new proposal block.
cs2 := newState(ctx, t, logger, cs1.state, vs2, kvstore.NewApplication())
require.NoError(t, err)
propR1, propBlockR1 := decideProposal(ctx, t, cs2, vs2, vs2.Height, vs2.Round)
propBlockR1Parts, err := propBlockR1.MakePartSet(partSize)
require.NoError(t, err)
propBlockR1Hash := propBlockR1.Hash()
require.NotEqual(t, propBlockR1Hash, theBlockHash)
if err := cs1.SetProposalAndBlock(ctx, propR1, propBlockR1, propBlockR1Parts, "some peer"); err != nil {
t.Fatal(err)
}
ensureNewRound(t, newRoundCh, height, round)
t.Log("### ONTO ROUND 1")
/*
Round2 (vs2, C) // B C C C // C C C _)
cs1 changes lock!
*/
// now we're on a new round and not the proposer
// but we should receive the proposal
// ensure that the validator receives the proposal.
ensureNewProposal(t, proposalCh, height, round)
// go to prevote, node should prevote for locked block (not the new proposal) - this is relocking
// Prevote our locked block.
// TODO: Ensure we prevote for the proposal if it is valid and from a round greater than
// the valid round: https://github.com/tendermint/tendermint/issues/6850.
ensurePrevote(t, voteCh, height, round)
validatePrevote(ctx, t, cs1, round, vss[0], theBlockHash)
// now lets add prevotes from everyone else for the new block
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
// Add prevotes from the remainder of the validators for the new locked block.
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, propBlockR1Hash, propBlockR1Parts.Header(), vs2, vs3, vs4)
// Check that we lock on a new block.
ensureLock(t, lockCh, height, round)
ensurePrecommit(t, voteCh, height, round)
// we should have unlocked and locked on the new block, sending a precommit for this new block
validatePrecommit(ctx, t, cs1, round, round, vss[0], propBlockHash, propBlockHash)
// more prevote creating a majority on the new block and this is then committed
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, propBlockHash, propBlockParts.Header(), vs2, vs3)
ensureNewBlockHeader(t, newBlockCh, height, propBlockHash)
ensureNewRound(t, newRoundCh, height+1, 0)
// We should now be locked on the new block and prevote it since we saw a sufficient amount
// prevote for the block.
validatePrecommit(ctx, t, cs1, round, round, vss[0], propBlockR1Hash, propBlockR1Hash)
}
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestStateLockPOLUnlock(t *testing.T) {
config := configSetup(t)
// TestStateLock_POLRelock tests that a validator updates its locked round if
// it receives votes representing over 2/3 of the voting power on the network
// for a block that it is already locked in.
func TestStateLock_POLRelock(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
config := configSetup(t)
cs1, vss := randState(ctx, t, config, log.TestingLogger(), 4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
height, round := cs1.Height, cs1.Round
partSize := types.BlockPartSizeBytes
proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal)
timeoutWaitCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryUnlock)
proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal)
pv1, err := cs1.privValidator.GetPubKey(ctx)
require.NoError(t, err)
addr := pv1.Address()
voteCh := subscribeToVoter(ctx, t, cs1, addr)
// everything done from perspective of cs1
lockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryLock)
relockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryRelock)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
/*
Round1 (cs1, B) // B B B B // B nil B nil
eg. didn't see the 2/3 prevotes
Round 0:
cs1 creates a proposal for block B.
Send a prevote for B from each of the validators to cs1.
Send a precommit for nil from all of the validators to cs1.
This ensures that cs1 will lock on B in this round but not precommit it.
*/
t.Log("### Starting Round 0")
startTestRound(ctx, cs1, height, round)
ensureNewRound(t, newRoundCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
rs := cs1.GetRoundState()
theBlock := rs.ProposalBlock
theBlockHash := rs.ProposalBlock.Hash()
theBlockParts := rs.ProposalBlockParts
ensurePrevote(t, voteCh, height, round)
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, theBlockHash, theBlockParts.Header(), vs2, vs3, vs4)
// check that the validator generates a Lock event.
ensureLock(t, lockCh, height, round)
// the proposed block should now be locked and our precommit added.
ensurePrecommit(t, voteCh, height, round)
validatePrecommit(ctx, t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
// add precommits from the rest of the validators.
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
// timeout to new round.
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
/*
Round 1:
Create a proposal for block B, the same block from round 1.
Send a prevote for B from each of the validators to cs1.
Send a precommit for nil from all of the validtors to cs1.
Check that cs1 updates its 'locked round' value to the current round.
*/
t.Log("### Starting Round 1")
incrementRound(vs2, vs3, vs4)
round++
propBlockID := types.BlockID{Hash: theBlockHash, PartSetHeader: theBlockParts.Header()}
propR1 := types.NewProposal(height, round, cs1.ValidRound, propBlockID)
p := propR1.ToProto()
if err := vs2.SignProposal(context.Background(), cs1.state.ChainID, p); err != nil {
t.Fatalf("error signing proposal: %s", err)
}
propR1.Signature = p.Signature
if err := cs1.SetProposalAndBlock(ctx, propR1, theBlock, theBlockParts, ""); err != nil {
t.Fatal(err)
}
ensureNewRound(t, newRoundCh, height, round)
// ensure that the validator receives the proposal.
ensureNewProposal(t, proposalCh, height, round)
// Prevote our locked block.
// TODO: Ensure we prevote for the proposal if it is valid and from a round greater than
// the valid round: https://github.com/tendermint/tendermint/issues/6850.
ensurePrevote(t, voteCh, height, round)
validatePrevote(ctx, t, cs1, round, vss[0], theBlockHash)
// Add prevotes from the remainder of the validators for the locked block.
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, theBlockHash, theBlockParts.Header(), vs2, vs3, vs4)
// Check that we relock.
ensureRelock(t, relockCh, height, round)
ensurePrecommit(t, voteCh, height, round)
// We should now be locked on the same block but with an updated locked round.
validatePrecommit(ctx, t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
}
// TestStateLock_POLDoesNotUnlock tests that a validator maintains its locked block
// despite receiving +2/3 nil prevotes and nil precommits from other validators.
// Tendermint used to 'unlock' its locked block when greater than 2/3 prevotes
// for a nil block were seen. This behavior has been removed and this test ensures
// that it has been completely removed.
func TestStateLock_POLDoesNotUnlock(t *testing.T) {
config := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
/*
All of the assertions in this test occur on the `cs1` validator.
The test sends signed votes from the other validators to cs1 and
cs1's state is then examined to verify that it now matches the expected
state.
*/
cs1, vss := randState(ctx, t, config, log.TestingLogger(), 4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
height, round := cs1.Height, cs1.Round
proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal)
timeoutWaitCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
lockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryLock)
pv1, err := cs1.privValidator.GetPubKey(context.Background())
require.NoError(t, err)
addr := pv1.Address()
voteCh := subscribeToVoter(ctx, t, cs1, addr)
/*
Round 0:
Create a block, B
Send a prevote for B from each of the validators to `cs1`.
Send a precommit for B from one of the validtors to `cs1`.
This ensures that cs1 will lock on B in this round.
*/
t.Log("#### ONTO ROUND 0")
// start round and wait for propose and prevote
startTestRound(ctx, cs1, height, round)
@@ -819,63 +939,98 @@ func TestStateLockPOLUnlock(t *testing.T) {
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, theBlockHash, theBlockParts, vs2, vs3, vs4)
// the validator should have locked a block in this round.
ensureLock(t, lockCh, height, round)
ensurePrecommit(t, voteCh, height, round)
// the proposed block should now be locked and our precommit added
// the proposed block should now be locked and our should be for this locked block.
validatePrecommit(ctx, t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
// add precommits from the rest
// Add precommits from the other validators.
// We only issue 1/2 Precommits for the block in this round.
// This ensures that the validator being tested does not commit the block.
// We do not want the validator to commit the block because we want the test
// test to proceeds to the next consensus round.
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs4)
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs3)
// before we time out into new round, set next proposal block
prop, propBlock := decideProposal(ctx, t, cs1, vs2, vs2.Height, vs2.Round+1)
propBlockParts, err := propBlock.MakePartSet(partSize)
require.NoError(t, err)
// timeout to new round
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
rs = cs1.GetRoundState()
lockedBlockHash := rs.LockedBlock.Hash()
incrementRound(vs2, vs3, vs4)
round++ // moving to the next round
ensureNewRound(t, newRoundCh, height, round)
t.Log("#### ONTO ROUND 1")
/*
Round2 (vs2, C) // B nil nil nil // nil nil nil _
cs1 unlocks!
Round 1:
Send a prevote for nil from >2/3 of the validators to `cs1`.
Check that cs1 maintains its lock on B but precommits nil.
Send a precommit for nil from >2/3 of the validators to `cs1`.
*/
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
if err := cs1.SetProposalAndBlock(ctx, prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Log("#### ONTO ROUND 1")
round++
incrementRound(vs2, vs3, vs4)
prop, propBlock := decideProposal(ctx, t, cs1, vs2, vs2.Height, vs2.Round)
propBlockParts, err := propBlock.MakePartSet(types.BlockPartSizeBytes)
require.NoError(t, err)
if err := cs1.SetProposalAndBlock(ctx, prop, propBlock, propBlockParts, ""); err != nil {
t.Fatal(err)
}
ensureNewRound(t, newRoundCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
// go to prevote, prevote for locked block (not proposal)
// prevote for the locked block. We do not currently prevote for the
// proposal.
// TODO: do not prevote the locked block if it does not match the proposal.
// (https://github.com/tendermint/tendermint/issues/6850)
ensurePrevote(t, voteCh, height, round)
validatePrevote(ctx, t, cs1, round, vss[0], lockedBlockHash)
// now lets add prevotes from everyone else for nil (a polka!)
validatePrevote(ctx, t, cs1, round, vss[0], theBlockHash)
// add >2/3 prevotes for nil from all other validators
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
// the polka makes us unlock and precommit nil
ensureNewUnlock(t, unlockCh, height, round)
ensurePrecommit(t, voteCh, height, round)
// we should have unlocked and committed nil
// NOTE: since we don't relock on nil, the lock round is -1
validatePrecommit(ctx, t, cs1, round, -1, vss[0], nil, nil)
// verify that we haven't update our locked block since the first round
validatePrecommit(ctx, t, cs1, round, 0, vss[0], nil, theBlockHash)
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
/*
Round 2:
The validator cs1 saw >2/3 precommits for nil in the previous round.
Send the validator >2/3 prevotes for nil and ensure that it did not
unlock its block at the end of the previous round.
*/
t.Log("#### ONTO ROUND 2")
round++
incrementRound(vs2, vs3, vs4)
prop, propBlock = decideProposal(ctx, t, cs1, vs3, vs3.Height, vs3.Round)
propBlockParts, err = propBlock.MakePartSet(types.BlockPartSizeBytes)
require.NoError(t, err)
if err := cs1.SetProposalAndBlock(ctx, prop, propBlock, propBlockParts, ""); err != nil {
t.Fatal(err)
}
ensureNewRound(t, newRoundCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
ensurePrevote(t, voteCh, height, round)
validatePrevote(ctx, t, cs1, round, vss[0], theBlockHash)
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
ensurePrecommit(t, voteCh, height, round)
// verify that we haven't update our locked block since the first round
validatePrecommit(ctx, t, cs1, round, 0, vss[0], nil, theBlockHash)
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3)
ensureNewRound(t, newRoundCh, height, round+1)
}
// 4 vals, v1 locks on proposed block in the first round but the other validators only prevote
// In the second round, v1 misses the proposal but sees a majority prevote an unknown block so
// v1 should unlock and precommit nil. In the third round another block is proposed, all vals
// prevote and now v1 can lock onto the third block and precommit that
func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) {
// TestStateLock_MissingProposalWhenPOLSeenDoesNotUnlock tests that observing
// a two thirds majority for a block does not cause a validator to upate its lock on the
// new block if a proposal was not seen for that block.
func TestStateLock_MissingProposalWhenPOLSeenDoesNotUpdateLock(t *testing.T) {
config := configSetup(t)
logger := log.TestingLogger()
ctx, cancel := context.WithCancel(context.Background())
@@ -895,13 +1050,15 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) {
addr := pv1.Address()
voteCh := subscribeToVoter(ctx, t, cs1, addr)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
// everything done from perspective of cs1
/*
Round0 (cs1, A) // A A A A// A nil nil nil
*/
Round 0:
cs1 creates a proposal for block B.
Send a prevote for B from each of the validators to cs1.
Send a precommit for nil from all of the validators to cs1.
// start round and wait for propose and prevote
This ensures that cs1 will lock on B in this round but not precommit it.
*/
t.Log("### Starting Round 0")
startTestRound(ctx, cs1, height, round)
ensureNewRound(t, newRoundCh, height, round)
@@ -921,9 +1078,22 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) {
// add precommits from the rest
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
// before we timeout to the new round set the new proposal
// timeout to new round
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
/*
Round 1:
Create a new block, D but do not send it to cs1.
Send a prevote for D from each of the validators to cs1.
Check that cs1 does not update its locked block to this missed block D.
*/
t.Log("### Starting Round 1")
incrementRound(vs2, vs3, vs4)
round++
cs2 := newState(ctx, t, logger, cs1.state, vs2, kvstore.NewApplication())
prop, propBlock := decideProposal(ctx, t, cs2, vs2, vs2.Height, vs2.Round+1)
require.NoError(t, err)
prop, propBlock := decideProposal(ctx, t, cs2, vs2, vs2.Height, vs2.Round)
if prop == nil || propBlock == nil {
t.Fatal("Failed to create proposal block with vs2")
}
@@ -933,21 +1103,7 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) {
secondBlockHash := propBlock.Hash()
require.NotEqual(t, secondBlockHash, firstBlockHash)
incrementRound(vs2, vs3, vs4)
// timeout to new round
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
round++ // moving to the next round
ensureNewRound(t, newRoundCh, height, round)
t.Log("### ONTO ROUND 1")
/*
Round1 (vs2, B) // A B B B // nil nil nil nil)
*/
// now we're on a new round but v1 misses the proposal
// go to prevote, node should prevote for locked block (not the new proposal) - this is relocking
ensurePrevote(t, voteCh, height, round)
@@ -957,61 +1113,89 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) {
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, secondBlockHash, secondBlockParts.Header(), vs2, vs3, vs4)
ensurePrecommit(t, voteCh, height, round)
// we should have unlocked and locked on the new block, sending a precommit for this new block
validatePrecommit(ctx, t, cs1, round, 0, vss[0], nil, firstBlockHash)
}
// TestStateLock_DoesNotLockOnOldProposal tests that observing
// a two thirds majority for a block does not cause a validator to lock on the
// block if a proposal was not seen for that block in the current round, but
// was seen in a previous round.
func TestStateLock_DoesNotLockOnOldProposal(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
config := configSetup(t)
cs1, vss := randState(ctx, t, config, log.TestingLogger(), 4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
height, round := cs1.Height, cs1.Round
timeoutWaitCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryTimeoutWait)
proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal)
pv1, err := cs1.privValidator.GetPubKey(context.Background())
require.NoError(t, err)
addr := pv1.Address()
voteCh := subscribeToVoter(ctx, t, cs1, addr)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
/*
Round 0:
cs1 creates a proposal for block B.
Send a prevote for nil from each of the validators to cs1.
Send a precommit for nil from all of the validators to cs1.
This ensures that cs1 will not lock on B.
*/
t.Log("### Starting Round 0")
startTestRound(ctx, cs1, height, round)
ensureNewRound(t, newRoundCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
rs := cs1.GetRoundState()
firstBlockHash := rs.ProposalBlock.Hash()
firstBlockParts := rs.ProposalBlockParts.Header()
ensurePrevote(t, voteCh, height, round)
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
// The proposed block should not have been locked.
ensurePrecommit(t, voteCh, height, round)
validatePrecommit(ctx, t, cs1, round, -1, vss[0], nil, nil)
if err := cs1.SetProposalAndBlock(ctx, prop, propBlock, secondBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
// more prevote creating a majority on the new block and this is then committed
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
// before we timeout to the new round set the new proposal
cs3 := newState(ctx, t, logger, cs1.state, vs3, kvstore.NewApplication())
require.NoError(t, err)
prop, propBlock = decideProposal(ctx, t, cs3, vs3, vs3.Height, vs3.Round+1)
if prop == nil || propBlock == nil {
t.Fatal("Failed to create proposal block with vs2")
}
thirdPropBlockParts, err := propBlock.MakePartSet(partSize)
require.NoError(t, err)
thirdPropBlockHash := propBlock.Hash()
require.NotEqual(t, secondBlockHash, thirdPropBlockHash)
incrementRound(vs2, vs3, vs4)
// timeout to new round
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
round++ // moving to the next round
ensureNewRound(t, newRoundCh, height, round)
t.Log("### ONTO ROUND 2")
/*
Round2 (vs3, C) // C C C C // C nil nil nil)
Round 1:
No proposal new proposal is created.
Send a prevote for B, the block from round 0, from each of the validators to cs1.
Send a precommit for nil from all of the validators to cs1.
cs1 saw a POL for the block it saw in round 0. We ensure that it does not
lock on this block, since it did not see a proposal for it in this round.
*/
if err := cs1.SetProposalAndBlock(ctx, prop, propBlock, thirdPropBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
t.Log("### Starting Round 1")
round++
ensureNewRound(t, newRoundCh, height, round)
ensurePrevote(t, voteCh, height, round)
// we are no longer locked to the first block so we should be able to prevote
validatePrevote(ctx, t, cs1, round, vss[0], thirdPropBlockHash)
validatePrevote(ctx, t, cs1, round, vss[0], nil) // All validators prevote for the old block.
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, thirdPropBlockHash, thirdPropBlockParts.Header(), vs2, vs3, vs4)
// All validators prevote for the old block.
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, firstBlockHash, firstBlockParts, vs2, vs3, vs4)
// Make sure that cs1 did not lock on the block since it did not receive a proposal for it.
ensurePrecommit(t, voteCh, height, round)
// we have a majority, now vs1 can change lock to the third block
validatePrecommit(ctx, t, cs1, round, round, vss[0], thirdPropBlockHash, thirdPropBlockHash)
validatePrecommit(ctx, t, cs1, round, -1, vss[0], nil, nil)
}
// 4 vals
// a polka at round 1 but we miss it
// then a polka at round 2 that we lock on
// then we see the polka from round 1 but shouldn't unlock
func TestStateLockPOLSafety1(t *testing.T) {
func TestStateLock_POLSafety1(t *testing.T) {
config := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -1139,7 +1323,7 @@ func TestStateLockPOLSafety1(t *testing.T) {
// What we want:
// dont see P0, lock on P1 at R1, dont unlock using P0 at R2
func TestStateLockPOLSafety2(t *testing.T) {
func TestStateLock_POLSafety2(t *testing.T) {
config := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -1153,7 +1337,6 @@ func TestStateLockPOLSafety2(t *testing.T) {
proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal)
timeoutWaitCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryUnlock)
pv1, err := cs1.privValidator.GetPubKey(ctx)
require.NoError(t, err)
addr := pv1.Address()
@@ -1231,23 +1414,22 @@ func TestStateLockPOLSafety2(t *testing.T) {
*/
ensureNewProposal(t, proposalCh, height, round)
ensureNoNewUnlock(t, unlockCh)
ensurePrevote(t, voteCh, height, round)
validatePrevote(ctx, t, cs1, round, vss[0], propBlockHash1)
}
// 4 vals.
// polka P0 at R0 for B0. We lock B0 on P0 at R0. P0 unlocks value at R1.
// polka P0 at R0 for B0. We lock B0 on P0 at R0.
// What we want:
// P0 proposes B0 at R3.
func TestProposeValidBlock(t *testing.T) {
config := configSetup(t)
cfg := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cs1, vss := randState(ctx, t, config, log.TestingLogger(), 4)
cs1, vss := randState(ctx, t, cfg, log.TestingLogger(), 4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
height, round := cs1.Height, cs1.Round
@@ -1257,7 +1439,6 @@ func TestProposeValidBlock(t *testing.T) {
timeoutWaitCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryTimeoutWait)
timeoutProposeCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryTimeoutPropose)
newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryUnlock)
pv1, err := cs1.privValidator.GetPubKey(ctx)
require.NoError(t, err)
addr := pv1.Address()
@@ -1278,15 +1459,16 @@ func TestProposeValidBlock(t *testing.T) {
// the others sign a polka
bps, err := propBlock.MakePartSet(partSize)
require.NoError(t, err)
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType,
signAddVotes(ctx, t, cfg, cs1, tmproto.PrevoteType,
propBlockHash, bps.Header(), vs2,
vs3, vs4)
ensurePrecommit(t, voteCh, height, round)
// we should have precommitted
// we should have precommitted the proposed block in this round.
validatePrecommit(ctx, t, cs1, round, round, vss[0], propBlockHash, propBlockHash)
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
signAddVotes(ctx, t, cfg, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
@@ -1294,8 +1476,7 @@ func TestProposeValidBlock(t *testing.T) {
round++ // moving to the next round
ensureNewRound(t, newRoundCh, height, round)
t.Log("### ONTO ROUND 2")
t.Log("### ONTO ROUND 1")
// timeout of propose
ensureNewTimeout(t, timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
@@ -1303,20 +1484,19 @@ func TestProposeValidBlock(t *testing.T) {
ensurePrevote(t, voteCh, height, round)
validatePrevote(ctx, t, cs1, round, vss[0], propBlockHash)
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
ensureNewUnlock(t, unlockCh, height, round)
signAddVotes(ctx, t, cfg, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
ensurePrecommit(t, voteCh, height, round)
// we should have precommitted
validatePrecommit(ctx, t, cs1, round, -1, vss[0], nil, nil)
// we should have precommitted nil during this round because we received
// >2/3 precommits for nil from the other validators.
validatePrecommit(ctx, t, cs1, round, 0, vss[0], nil, propBlockHash)
incrementRound(vs2, vs3, vs4)
incrementRound(vs2, vs3, vs4)
signAddVotes(ctx, t, config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
signAddVotes(ctx, t, cfg, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
round += 2 // moving to the next round
round += 2 // increment by multiple rounds
ensureNewRound(t, newRoundCh, height, round)
t.Log("### ONTO ROUND 3")
@@ -1327,8 +1507,6 @@ func TestProposeValidBlock(t *testing.T) {
ensureNewRound(t, newRoundCh, height, round)
t.Log("### ONTO ROUND 4")
ensureNewProposal(t, proposalCh, height, round)
rs = cs1.GetRoundState()
@@ -1341,11 +1519,11 @@ func TestProposeValidBlock(t *testing.T) {
// What we want:
// P0 miss to lock B but set valid block to B after receiving delayed prevote.
func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
config := configSetup(t)
cfg := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cs1, vss := randState(ctx, t, config, log.TestingLogger(), 4)
cs1, vss := randState(ctx, t, cfg, log.TestingLogger(), 4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
height, round := cs1.Height, cs1.Round
@@ -1375,10 +1553,10 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
validatePrevote(ctx, t, cs1, round, vss[0], propBlockHash)
// vs2 send prevote for propBlock
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2)
signAddVotes(ctx, t, cfg, cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2)
// vs3 send prevote nil
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs3)
signAddVotes(ctx, t, cfg, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs3)
ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds())
@@ -1393,7 +1571,7 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
assert.True(t, rs.ValidRound == -1)
// vs2 send (delayed) prevote for propBlock
signAddVotes(ctx, t, config, cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs4)
signAddVotes(ctx, t, cfg, cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs4)
ensureNewValidBlock(t, validBlockCh, height, round)
@@ -1835,7 +2013,7 @@ func TestResetTimeoutPrecommitUponNewHeight(t *testing.T) {
// TODO: Slashing
/*
func TestStateSlashingPrevotes(t *testing.T) {
func TestStateSlashing_Prevotes(t *testing.T) {
cs1, vss := randState(2)
vs2 := vss[1]
@@ -1870,7 +2048,7 @@ func TestStateSlashingPrevotes(t *testing.T) {
// XXX: Check for existence of Dupeout info
}
func TestStateSlashingPrecommits(t *testing.T) {
func TestStateSlashing_Precommits(t *testing.T) {
cs1, vss := randState(2)
vs2 := vss[1]
-4
View File
@@ -185,10 +185,6 @@ func (b *EventBus) PublishEventPolka(ctx context.Context, data types.EventDataRo
return b.Publish(ctx, types.EventPolkaValue, data)
}
func (b *EventBus) PublishEventUnlock(ctx context.Context, data types.EventDataRoundState) error {
return b.Publish(ctx, types.EventUnlockValue, data)
}
func (b *EventBus) PublishEventRelock(ctx context.Context, data types.EventDataRoundState) error {
return b.Publish(ctx, types.EventRelockValue, data)
}
-3
View File
@@ -385,7 +385,6 @@ func TestEventBusPublish(t *testing.T) {
require.NoError(t, eventBus.PublishEventNewRound(ctx, types.EventDataNewRound{}))
require.NoError(t, eventBus.PublishEventCompleteProposal(ctx, types.EventDataCompleteProposal{}))
require.NoError(t, eventBus.PublishEventPolka(ctx, types.EventDataRoundState{}))
require.NoError(t, eventBus.PublishEventUnlock(ctx, types.EventDataRoundState{}))
require.NoError(t, eventBus.PublishEventRelock(ctx, types.EventDataRoundState{}))
require.NoError(t, eventBus.PublishEventLock(ctx, types.EventDataRoundState{}))
require.NoError(t, eventBus.PublishEventValidatorSetUpdates(ctx, types.EventDataValidatorSetUpdates{}))
@@ -487,7 +486,6 @@ var events = []string{
types.EventTimeoutProposeValue,
types.EventCompleteProposalValue,
types.EventPolkaValue,
types.EventUnlockValue,
types.EventLockValue,
types.EventRelockValue,
types.EventTimeoutWaitValue,
@@ -508,7 +506,6 @@ var queries = []tmpubsub.Query{
types.EventQueryTimeoutPropose,
types.EventQueryCompleteProposal,
types.EventQueryPolka,
types.EventQueryUnlock,
types.EventQueryLock,
types.EventQueryRelock,
types.EventQueryTimeoutWait,
+1 -1
View File
@@ -51,7 +51,7 @@ func MakeHeader(t *testing.T, h *types.Header) *types.Header {
if h.Height == 0 {
h.Height = 1
}
if h.LastBlockID.IsZero() {
if h.LastBlockID.IsNil() {
h.LastBlockID = MakeBlockID()
}
if h.ChainID == "" {
+3 -3
View File
@@ -883,7 +883,7 @@ func (commit *Commit) ValidateBasic() error {
}
if commit.Height >= 1 {
if commit.BlockID.IsZero() {
if commit.BlockID.IsNil() {
return errors.New("commit cannot be for nil block")
}
@@ -1204,8 +1204,8 @@ func (blockID BlockID) ValidateBasic() error {
return nil
}
// IsZero returns true if this is the BlockID of a nil block.
func (blockID BlockID) IsZero() bool {
// IsNil returns true if this is the BlockID of a nil block.
func (blockID BlockID) IsNil() bool {
return len(blockID.Hash) == 0 &&
blockID.PartSetHeader.IsZero()
}
+1 -1
View File
@@ -21,7 +21,7 @@ func CanonicalizeBlockID(bid tmproto.BlockID) *tmproto.CanonicalBlockID {
panic(err)
}
var cbid *tmproto.CanonicalBlockID
if rbid == nil || rbid.IsZero() {
if rbid == nil || rbid.IsNil() {
cbid = nil
} else {
cbid = &tmproto.CanonicalBlockID{
-2
View File
@@ -39,7 +39,6 @@ const (
EventStateSyncStatusValue = "StateSyncStatus"
EventTimeoutProposeValue = "TimeoutPropose"
EventTimeoutWaitValue = "TimeoutWait"
EventUnlockValue = "Unlock"
EventValidBlockValue = "ValidBlock"
EventVoteValue = "Vote"
)
@@ -224,7 +223,6 @@ var (
EventQueryTimeoutPropose = QueryForEvent(EventTimeoutProposeValue)
EventQueryTimeoutWait = QueryForEvent(EventTimeoutWaitValue)
EventQueryTx = QueryForEvent(EventTxValue)
EventQueryUnlock = QueryForEvent(EventUnlockValue)
EventQueryValidatorSetUpdates = QueryForEvent(EventValidatorSetUpdatesValue)
EventQueryValidBlock = QueryForEvent(EventValidBlockValue)
EventQueryVote = QueryForEvent(EventVoteValue)
+2 -2
View File
@@ -68,7 +68,7 @@ func (vote *Vote) CommitSig() CommitSig {
switch {
case vote.BlockID.IsComplete():
blockIDFlag = BlockIDFlagCommit
case vote.BlockID.IsZero():
case vote.BlockID.IsNil():
blockIDFlag = BlockIDFlagNil
default:
panic(fmt.Sprintf("Invalid vote %v - expected BlockID to be either empty or complete", vote))
@@ -177,7 +177,7 @@ func (vote *Vote) ValidateBasic() error {
// BlockID.ValidateBasic would not err if we for instance have an empty hash but a
// non-empty PartsSetHeader:
if !vote.BlockID.IsZero() && !vote.BlockID.IsComplete() {
if !vote.BlockID.IsNil() && !vote.BlockID.IsComplete() {
return fmt.Errorf("blockID must be either empty or complete, got: %v", vote.BlockID)
}
+10 -10
View File
@@ -31,7 +31,7 @@ func TestVoteSet_AddVote_Good(t *testing.T) {
assert.Nil(t, voteSet.GetByAddress(val0Addr))
assert.False(t, voteSet.BitArray().GetIndex(0))
blockID, ok := voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
vote := &Vote{
ValidatorAddress: val0Addr,
@@ -48,7 +48,7 @@ func TestVoteSet_AddVote_Good(t *testing.T) {
assert.NotNil(t, voteSet.GetByAddress(val0Addr))
assert.True(t, voteSet.BitArray().GetIndex(0))
blockID, ok = voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
}
func TestVoteSet_AddVote_Bad(t *testing.T) {
@@ -155,7 +155,7 @@ func TestVoteSet_2_3Majority(t *testing.T) {
require.NoError(t, err)
}
blockID, ok := voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
// 7th validator voted for some blockhash
{
@@ -166,7 +166,7 @@ func TestVoteSet_2_3Majority(t *testing.T) {
_, err = signAddVote(ctx, privValidators[6], withBlockHash(vote, tmrand.Bytes(32)), voteSet)
require.NoError(t, err)
blockID, ok = voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
}
// 8th validator voted for nil.
@@ -178,7 +178,7 @@ func TestVoteSet_2_3Majority(t *testing.T) {
_, err = signAddVote(ctx, privValidators[7], vote, voteSet)
require.NoError(t, err)
blockID, ok = voteSet.TwoThirdsMajority()
assert.True(t, ok || blockID.IsZero(), "there should be 2/3 majority for nil")
assert.True(t, ok || blockID.IsNil(), "there should be 2/3 majority for nil")
}
}
@@ -213,7 +213,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
require.NoError(t, err)
}
blockID, ok := voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(),
assert.False(t, ok || !blockID.IsNil(),
"there should be no 2/3 majority")
// 67th validator voted for nil
@@ -225,7 +225,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
_, err = signAddVote(ctx, privValidators[66], withBlockHash(vote, nil), voteSet)
require.NoError(t, err)
blockID, ok = voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(),
assert.False(t, ok || !blockID.IsNil(),
"there should be no 2/3 majority: last vote added was nil")
}
@@ -239,7 +239,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
_, err = signAddVote(ctx, privValidators[67], withBlockPartSetHeader(vote, blockPartsHeader), voteSet)
require.NoError(t, err)
blockID, ok = voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(),
assert.False(t, ok || !blockID.IsNil(),
"there should be no 2/3 majority: last vote added had different PartSetHeader Hash")
}
@@ -253,7 +253,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
_, err = signAddVote(ctx, privValidators[68], withBlockPartSetHeader(vote, blockPartsHeader), voteSet)
require.NoError(t, err)
blockID, ok = voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(),
assert.False(t, ok || !blockID.IsNil(),
"there should be no 2/3 majority: last vote added had different PartSetHeader Total")
}
@@ -266,7 +266,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
_, err = signAddVote(ctx, privValidators[69], withBlockHash(vote, tmrand.Bytes(32)), voteSet)
require.NoError(t, err)
blockID, ok = voteSet.TwoThirdsMajority()
assert.False(t, ok || !blockID.IsZero(),
assert.False(t, ok || !blockID.IsNil(),
"there should be no 2/3 majority: last vote added had different BlockHash")
}