diff --git a/blockchain/v0/reactor_test.go b/blockchain/v0/reactor_test.go index f631e89e2..c82225801 100644 --- a/blockchain/v0/reactor_test.go +++ b/blockchain/v0/reactor_test.go @@ -348,7 +348,8 @@ func makeTxs(height int64) (txs []types.Tx) { func makeBlock(privVal types.PrivValidator, height int64, state sm.State, lastCommit *types.Commit) *types.Block { message := state.MakeHashMessage(0) proof, _ := privVal.GenerateVRFProof(message) - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address, 0, proof) + block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, + types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address, 0, proof) return block } diff --git a/blockchain/v1/reactor_test.go b/blockchain/v1/reactor_test.go index f9298d2f3..3a35e6582 100644 --- a/blockchain/v1/reactor_test.go +++ b/blockchain/v1/reactor_test.go @@ -422,7 +422,8 @@ func makeTxs(height int64) (txs []types.Tx) { func makeBlock(privVal types.PrivValidator, height int64, state sm.State, lastCommit *types.Commit) *types.Block { message := state.MakeHashMessage(0) proof, _ := privVal.GenerateVRFProof(message) - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address, 0, proof) + block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, + types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address, 0, proof) return block } diff --git a/consensus/replay.go b/consensus/replay.go index e301a6ade..1453849cc 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -305,8 +305,7 @@ func (h *Handshaker) ReplayBlocks( for i, val := range h.genDoc.Validators { validators[i] = types.NewValidator(val.PubKey, val.Power) } - roundHash := types.MakeRoundHash(h.genDoc.Hash(), 0, 0) - validatorSet := types.NewRandomValidatorSet(validators, roundHash) + validatorSet := types.NewValidatorSet(validators) nextVals := types.TM2PB.ValidatorUpdates(validatorSet) csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams) req := abci.RequestInitChain{ diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 94bf729c4..5f9f14b48 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -920,7 +920,8 @@ func makeBlock(state sm.State, lastBlock *types.Block, lastBlockMeta *types.Bloc message := state.MakeHashMessage(0) proof, _ := privVal.GenerateVRFProof(message) - return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address, 0, proof) + return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, + types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address, 0, proof) } type badApp struct { diff --git a/consensus/state.go b/consensus/state.go index 2e6600d9f..19976df58 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -827,21 +827,13 @@ func (cs *State) enterNewRound(height int64, round int) { logger.Info(fmt.Sprintf("enterNewRound(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) - // Increment validators if necessary - validators := cs.Validators - if cs.Round < round { - validators = validators.Copy() - validators.IncrementProposerPriority(round - cs.Round) - } - // Select the current height and round Proposer - validators.SelectProposerWithRound(cs.state.LastProofHash, height, round) + cs.Proposer = types.SelectProposer(cs.Validators, cs.state.LastProofHash, height, round) // Setup new round // we don't fire newStep for this step, // but we fire an event, so update the round step first cs.updateRoundStep(round, cstypes.RoundStepNewRound) - cs.Validators = validators if round == 0 { // We've already reset these upon new height, // and meanwhile we might have received a proposal @@ -934,21 +926,21 @@ func (cs *State) enterPropose(height int64, round int) { if cs.isProposer(address) { logger.Info("enterPropose: Our turn to propose", "proposer", - cs.Validators.GetProposer().Address, + cs.Proposer.Address, "privValidator", cs.privValidator) cs.decideProposal(height, round) } else { logger.Info("enterPropose: Not our turn to propose", "proposer", - cs.Validators.GetProposer().Address, + cs.Proposer.Address, "privValidator", cs.privValidator) } } func (cs *State) isProposer(address []byte) bool { - return bytes.Equal(cs.Validators.GetProposer().Address, address) + return bytes.Equal(cs.Proposer.Address, address) } func (cs *State) defaultDecideProposal(height int64, round int) { @@ -1559,7 +1551,7 @@ func (cs *State) defaultSetProposal(proposal *types.Proposal) error { } // Verify signature - if !cs.Validators.GetProposer().PubKey.VerifyBytes(proposal.SignBytes(cs.state.ChainID), proposal.Signature) { + if !cs.Proposer.PubKey.VerifyBytes(proposal.SignBytes(cs.state.ChainID), proposal.Signature) { return ErrInvalidProposalSignature } diff --git a/consensus/state_test.go b/consensus/state_test.go index df720a6bc..54184894a 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -67,7 +67,7 @@ func TestStateProposerSelection0(t *testing.T) { ensureNewRound(newRoundCh, height, round) // Commit a block and ensure proposer for the next height is correct. - prop := cs1.GetRoundState().Validators.GetProposer() + prop := cs1.GetRoundState().Proposer address := cs1.privValidator.GetPubKey().Address() if !bytes.Equal(prop.Address, address) { t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address) @@ -82,7 +82,7 @@ func TestStateProposerSelection0(t *testing.T) { // Wait for new round so next validator is set. ensureNewRound(newRoundCh, height+1, 0) - prop = cs1.GetRoundState().Validators.GetProposer() + prop = cs1.GetRoundState().Proposer addr := vss[1].GetPubKey().Address() if !bytes.Equal(prop.Address, addr) { panic(fmt.Sprintf("expected proposer to be validator %d. Got %X", 1, prop.Address)) @@ -109,7 +109,7 @@ func TestStateProposerSelection2(t *testing.T) { // everyone just votes nil. we get a new proposer each round for i := 0; i < len(vss); i++ { - prop := cs1.GetRoundState().Validators.GetProposer() + prop := cs1.GetRoundState().Proposer addr := vss[(i+round)%len(vss)].GetPubKey().Address() correctProposer := addr if !bytes.Equal(prop.Address, correctProposer) { @@ -1033,6 +1033,9 @@ func TestValidateValidBlockOnCommit(t *testing.T) { addr := cs1.privValidator.GetPubKey().Address() voteCh := subscribeToVoter(cs1, addr) + // Set the proofHash value arbitrarily to ensure that the first vss is elected proposer. + cs1.state.LastProofHash = []byte{2} + // start round and wait for propose and prevote startTestRound(cs1, cs1.Height, round) ensureNewRound(newRoundCh, height, round) @@ -1438,6 +1441,8 @@ func TestCommitFromPreviousRound(t *testing.T) { validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock) proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) + // Set the proofHash value arbitrarily to ensure that the first vss is elected proposer. + cs1.state.LastProofHash = []byte{2} prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round) propBlockHash := propBlock.Hash() propBlockParts := propBlock.MakePartSet(partSize) diff --git a/consensus/types/round_state.go b/consensus/types/round_state.go index 0a18b6d04..35c58f698 100644 --- a/consensus/types/round_state.go +++ b/consensus/types/round_state.go @@ -73,6 +73,7 @@ type RoundState struct { // Subjective time when +2/3 precommits for Block at Round were found CommitTime time.Time `json:"commit_time"` Validators *types.ValidatorSet `json:"validators"` + Proposer *types.Validator `json:"proposer"` Proposal *types.Proposal `json:"proposal"` ProposalBlock *types.Block `json:"proposal_block"` ProposalBlockParts *types.PartSet `json:"proposal_block_parts"` @@ -111,7 +112,7 @@ func (rs *RoundState) RoundStateSimple() RoundStateSimple { panic(err) } - addr := rs.Validators.GetProposer().Address + addr := rs.Proposer.Address idx, _ := rs.Validators.GetByAddress(addr) return RoundStateSimple{ @@ -130,7 +131,7 @@ func (rs *RoundState) RoundStateSimple() RoundStateSimple { // NewRoundEvent returns the RoundState with proposer information as an event. func (rs *RoundState) NewRoundEvent() types.EventDataNewRound { - addr := rs.Validators.GetProposer().Address + addr := rs.Proposer.Address idx, _ := rs.Validators.GetByAddress(addr) return types.EventDataNewRound{ @@ -182,6 +183,7 @@ func (rs *RoundState) StringIndented(indent string) string { %s StartTime: %v %s CommitTime: %v %s Validators: %v +%s Proposer: %v %s Proposal: %v %s ProposalBlock: %v %v %s LockedRound: %v @@ -196,6 +198,7 @@ func (rs *RoundState) StringIndented(indent string) string { indent, rs.StartTime, indent, rs.CommitTime, indent, rs.Validators.StringIndented(indent+" "), + indent, rs.Proposer.String(), indent, rs.Proposal, indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(), indent, rs.LockedRound, diff --git a/evidence/pool_test.go b/evidence/pool_test.go index 283566378..7224f9d17 100644 --- a/evidence/pool_test.go +++ b/evidence/pool_test.go @@ -31,8 +31,8 @@ func initializeValidatorState(valAddr []byte, height int64) dbm.DB { state := sm.State{ LastBlockHeight: 0, LastBlockTime: tmtime.Now(), - Validators: types.NewRandomValidatorSet(vals, types.MakeRoundHash([]byte{}, 1, 0)), - NextValidators: types.NewRandomValidatorSet(vals, types.MakeRoundHash([]byte{}, 2, 0)), + Validators: types.NewValidatorSet(vals), + NextValidators: types.NewValidatorSet(vals), LastHeightValidatorsChanged: 1, ConsensusParams: types.ConsensusParams{ Evidence: types.EvidenceParams{ diff --git a/state/execution_test.go b/state/execution_test.go index 402dbf5d6..b9d6ab1bb 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -37,7 +37,7 @@ func TestApplyBlock(t *testing.T) { blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mock.Mempool{}, sm.MockEvidencePool{}) - block := makeBlockWithPrivVal(state, privVals[state.Validators.Proposer.Address.String()], 1) + block := makeBlockWithPrivVal(state, privVals[state.Validators.Validators[0].Address.String()], 1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} //nolint:ineffassign @@ -88,11 +88,12 @@ func TestBeginBlockValidators(t *testing.T) { for _, tc := range testCases { lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs) + proposer := types.SelectProposer(state.Validators, state.LastProofHash, 1, 0) message := state.MakeHashMessage(0) - proof, _ := privVals[state.Validators.GetProposer().Address.String()].GenerateVRFProof(message) + proof, _ := privVals[proposer.Address.String()].GenerateVRFProof(message) // block for height 2 - block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address, 0, proof) + block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, proposer.Address, 0, proof) _, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB) require.Nil(t, err, tc.desc) @@ -160,8 +161,9 @@ func TestBeginBlockByzantineValidators(t *testing.T) { lastCommit := types.NewCommit(9, 0, prevBlockID, commitSigs) for _, tc := range testCases { message := state.MakeHashMessage(0) - proof, _ := privVals[state.Validators.GetProposer().Address.String()].GenerateVRFProof(message) - block, _ := state.MakeBlock(10, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address, 0, proof) + proposer := types.SelectProposer(state.Validators, state.LastProofHash, 1, 0) + proof, _ := privVals[proposer.Address.String()].GenerateVRFProof(message) + block, _ := state.MakeBlock(10, makeTxs(2), lastCommit, nil, proposer.Address, 0, proof) block.Time = now block.Evidence.Evidence = tc.evidence _, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB) @@ -351,7 +353,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) { ) require.NoError(t, err) - block := makeBlockWithPrivVal(state, privVals[state.Validators.Proposer.Address.String()], 1) + block := makeBlockWithPrivVal(state, privVals[state.Validators.Validators[0].Address.String()], 1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} pubkey := ed25519.GenPrivKey().PubKey() diff --git a/state/helpers_test.go b/state/helpers_test.go index 032f96f8f..f7cff0f0f 100644 --- a/state/helpers_test.go +++ b/state/helpers_test.go @@ -45,8 +45,9 @@ func makeAndCommitGoodBlock( privVals map[string]types.PrivValidator, evidence []types.Evidence) (sm.State, types.BlockID, *types.Commit, error) { // A good block passes - state, blockID, err := makeAndApplyGoodBlock(state, privVals[state.Validators.Proposer.Address.String()], height, - lastCommit, proposerAddr, blockExec, evidence) + state, blockID, err := makeAndApplyGoodBlock(state, + privVals[types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address.String()], + height, lastCommit, proposerAddr, blockExec, evidence) if err != nil { return state, types.BlockID{}, nil, err } @@ -151,7 +152,7 @@ func makeBlockWithPrivVal(state sm.State, privVal types.PrivValidator, height in makeTxs(state.LastBlockHeight), new(types.Commit), nil, - state.Validators.GetProposer().Address, + privVal.GetPubKey().Address(), 0, proof, ) diff --git a/state/state.go b/state/state.go index 9ddfcf708..e1e748419 100644 --- a/state/state.go +++ b/state/state.go @@ -240,8 +240,8 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) { for i, val := range genDoc.Validators { validators[i] = types.NewValidator(val.PubKey, val.Power) } - validatorSet = types.NewRandomValidatorSet(validators, types.MakeRoundHash(genDoc.Hash(), 1, 0)) - nextValidatorSet = types.NewRandomValidatorSet(validators, types.MakeRoundHash(genDoc.Hash(), 2, 0)) + validatorSet = types.NewValidatorSet(validators) + nextValidatorSet = types.NewValidatorSet(validators) } return State{ @@ -257,7 +257,7 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) { NextValidators: nextValidatorSet, Validators: validatorSet, - LastValidators: types.NewRandomValidatorSet(nil, types.MakeRoundHash(genDoc.Hash(), 1, 0)), + LastValidators: types.NewValidatorSet(nil), LastHeightValidatorsChanged: 1, ConsensusParams: *genDoc.ConsensusParams, diff --git a/state/state_test.go b/state/state_test.go index 9b7083355..d9ce994b1 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -267,6 +267,7 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) { } func TestProposerFrequency(t *testing.T) { + t.Skip("This test is for priority based proposer. Vrf selection based proposer skips this test.") // some explicit test cases testCases := []struct { @@ -364,7 +365,7 @@ func testProposerFreq(t *testing.T, caseNum int, valSet *types.ValidatorSet) { runs := int(totalPower) * runMult freqs := make([]int, N) for i := 0; i < runs; i++ { - prop := valSet.GetProposer() + prop := types.SelectProposer(valSet, []byte{}, 1, i) idx, _ := valSet.GetByAddress(prop.Address) freqs[idx]++ valSet.IncrementProposerPriority(1) @@ -499,6 +500,7 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { } func TestProposerPriorityProposerAlternates(t *testing.T) { + t.Skip("This test is for priority based proposer. Vrf selection based proposer skips this test.") // Regression test that would fail if the inner workings of // IncrementProposerPriority change. // Additionally, make sure that same power validators alternate if both @@ -513,7 +515,8 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { state.Validators = types.NewValidatorSet([]*types.Validator{val1}) state.NextValidators = state.Validators // we only have one validator: - assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address) + assert.Equal(t, val1PubKey.Address(), + types.SelectProposer(state.Validators, []byte{}, state.LastBlockHeight+1, 0).Address) block := makeBlock(state, state.LastBlockHeight+1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} @@ -531,7 +534,7 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { totalPower := val1VotingPower wantVal1Prio := 0 + val1VotingPower - totalPower assert.Equal(t, wantVal1Prio, updatedState.NextValidators.Validators[0].ProposerPriority) - assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Proposer.Address) + assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Validators[0].Address) // add a validator with the same voting power as the first val2PubKey := ed25519.GenPrivKey().PubKey() @@ -546,10 +549,10 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { assert.Equal(t, updatedState2.Validators, updatedState.NextValidators) // val1 will still be proposer as val2 just got added: - assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Proposer.Address) - assert.Equal(t, updatedState2.Validators.Proposer.Address, updatedState2.NextValidators.Proposer.Address) - assert.Equal(t, updatedState2.Validators.Proposer.Address, val1PubKey.Address()) - assert.Equal(t, updatedState2.NextValidators.Proposer.Address, val1PubKey.Address()) + assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Validators[0].Address) + assert.Equal(t, updatedState2.Validators.Validators[0].Address, updatedState2.NextValidators.Validators[0].Address) + assert.Equal(t, updatedState2.Validators.Validators[0].Address, val1PubKey.Address()) + assert.Equal(t, updatedState2.NextValidators.Validators[0].Address, val1PubKey.Address()) _, updatedVal1 := updatedState2.NextValidators.GetByAddress(val1PubKey.Address()) _, oldVal1 := updatedState2.Validators.GetByAddress(val1PubKey.Address()) @@ -585,14 +588,14 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { updatedState3, err := sm.UpdateState(updatedState2, blockID, &block.Header, abciResponses, validatorUpdates) assert.NoError(t, err) - assert.Equal(t, updatedState3.Validators.Proposer.Address, updatedState3.NextValidators.Proposer.Address) + assert.Equal(t, updatedState3.Validators.Validators[0].Address, updatedState3.NextValidators.Validators[0].Address) assert.Equal(t, updatedState3.Validators, updatedState2.NextValidators) _, updatedVal1 = updatedState3.NextValidators.GetByAddress(val1PubKey.Address()) _, updatedVal2 = updatedState3.NextValidators.GetByAddress(val2PubKey.Address()) // val1 will still be proposer: - assert.Equal(t, val1PubKey.Address(), updatedState3.NextValidators.Proposer.Address) + assert.Equal(t, val1PubKey.Address(), updatedState3.NextValidators.Validators[0].Address) // check if expected proposer prio is matched: // Increment @@ -644,22 +647,23 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // alternate (and cyclic priorities): assert.NotEqual( t, - updatedState.Validators.Proposer.Address, - updatedState.NextValidators.Proposer.Address, + updatedState.Validators.Validators[0].Address, + updatedState.NextValidators.Validators[0].Address, "iter: %v", i, ) - assert.Equal(t, oldState.Validators.Proposer.Address, updatedState.NextValidators.Proposer.Address, "iter: %v", i) + assert.Equal(t, oldState.Validators.Validators[0].Address, + updatedState.NextValidators.Validators[0].Address, "iter: %v", i) _, updatedVal1 = updatedState.NextValidators.GetByAddress(val1PubKey.Address()) _, updatedVal2 = updatedState.NextValidators.GetByAddress(val2PubKey.Address()) if i%2 == 0 { - assert.Equal(t, updatedState.Validators.Proposer.Address, val2PubKey.Address()) + assert.Equal(t, updatedState.Validators.Validators[0].Address, val2PubKey.Address()) assert.Equal(t, expectedVal1Prio, updatedVal1.ProposerPriority) // -19 assert.Equal(t, expectedVal2Prio, updatedVal2.ProposerPriority) // 0 } else { - assert.Equal(t, updatedState.Validators.Proposer.Address, val1PubKey.Address()) + assert.Equal(t, updatedState.Validators.Validators[0].Address, val1PubKey.Address()) assert.Equal(t, expectedVal1Prio2, updatedVal1.ProposerPriority) // -9 assert.Equal(t, expectedVal2Prio2, updatedVal2.ProposerPriority) // -10 } @@ -705,7 +709,8 @@ func TestLargeGenesisValidator(t *testing.T) { // than -Total == -Voting) // -> no change in ProposerPrio (stays zero): assert.EqualValues(t, oldState.NextValidators, updatedState.NextValidators) - assert.EqualValues(t, 0, updatedState.NextValidators.Proposer.ProposerPriority) + assert.EqualValues(t, 0, + types.SelectProposer(updatedState.NextValidators, []byte{}, block.Height, 0).ProposerPriority) oldState = updatedState } @@ -803,7 +808,8 @@ func TestLargeGenesisValidator(t *testing.T) { blockID = types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} curState, err = sm.UpdateState(curState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) - if !bytes.Equal(curState.Validators.Proposer.Address, curState.NextValidators.Proposer.Address) { + if !bytes.Equal(types.SelectProposer(curState.Validators, []byte{}, int64(count), 0).Address, + types.SelectProposer(curState.NextValidators, []byte{}, int64(count+1), 0).Address) { isProposerUnchanged = false } count++ @@ -830,9 +836,9 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) if i > numVals { // expect proposers to cycle through after the first iteration (of numVals blocks): if proposers[i%numVals] == nil { - proposers[i%numVals] = updatedState.NextValidators.Proposer + proposers[i%numVals] = updatedState.NextValidators.Validators[0] } else { - assert.Equal(t, proposers[i%numVals], updatedState.NextValidators.Proposer) + assert.Equal(t, proposers[i%numVals], updatedState.NextValidators.Validators[0]) } } } @@ -843,9 +849,9 @@ func TestStoreLoadValidatorsIncrementsProposerPriority(t *testing.T) { tearDown, stateDB, state := setupTestCase(t) defer tearDown(t) state.Validators = genValSet(valSetSize) - state.Validators.SelectProposerWithRound([]byte{}, 1, 0) + types.SelectProposer(state.Validators, []byte{}, 1, 0) state.NextValidators = state.Validators.Copy() - state.NextValidators.SelectProposerWithRound([]byte{}, 2, 0) + types.SelectProposer(state.NextValidators, []byte{}, 2, 0) sm.SaveState(stateDB, state) nextHeight := state.LastBlockHeight + 1 @@ -869,9 +875,9 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) { defer tearDown(t) require.Equal(t, int64(0), state.LastBlockHeight) state.Validators = genValSet(valSetSize) - state.Validators.SelectProposerWithRound([]byte{}, 1, 0) + types.SelectProposer(state.Validators, []byte{}, 1, 0) state.NextValidators = state.Validators.Copy() - state.NextValidators.SelectProposerWithRound([]byte{}, 2, 0) + types.SelectProposer(state.NextValidators, []byte{}, 2, 0) sm.SaveState(stateDB, state) _, valOld := state.Validators.GetByIndex(0) @@ -916,13 +922,11 @@ func TestStateMakeBlock(t *testing.T) { tearDown, _, state := setupTestCase(t) defer tearDown(t) - proposerAddress := state.Validators.GetProposer().Address stateVersion := state.Version.Consensus block := makeBlock(state, 2) // test we set some fields assert.Equal(t, stateVersion, block.Version) - assert.Equal(t, proposerAddress, block.ProposerAddress) } // TestConsensusParamsChangesSaveLoad tests saving and loading consensus params diff --git a/state/store_test.go b/state/store_test.go index 795b49b43..596f479ed 100644 --- a/state/store_test.go +++ b/state/store_test.go @@ -47,9 +47,9 @@ func BenchmarkLoadValidators(b *testing.B) { b.Fatal(err) } state.Validators = genValSet(valSetSize) - state.Validators.SelectProposerWithRound([]byte{}, 1, 0) + types.SelectProposer(state.Validators, []byte{}, 1, 0) state.NextValidators = state.Validators.Copy() - state.NextValidators.SelectProposerWithRound([]byte{}, 2, 0) + types.SelectProposer(state.NextValidators, []byte{}, 2, 0) sm.SaveState(stateDB, state) for i := 10; i < 10000000000; i *= 10 { // 10, 100, 1000, ... diff --git a/state/validation.go b/state/validation.go index 6f4628e29..a2760d532 100644 --- a/state/validation.go +++ b/state/validation.go @@ -151,7 +151,14 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, round ) } - // TODO: verify right proposer using ElectProposer + // validate proposer + if !bytes.Equal(block.ProposerAddress.Bytes(), + types.SelectProposer(state.Validators, state.LastProofHash, block.Height, block.Round).Address.Bytes()) { + return fmt.Errorf("block.ProposerAddress, %X, is not the proposer %X", + block.ProposerAddress, + types.SelectProposer(state.Validators, state.LastProofHash, block.Height, block.Round).Address, + ) + } // validate round // The block round must be less than or equal to the current round diff --git a/state/validation_test.go b/state/validation_test.go index c05f6a011..83331c314 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -67,7 +67,7 @@ func TestValidateBlockHeader(t *testing.T) { // Build up state for multiple heights for height := int64(1); height < validationTestsStopHeight; height++ { - proposerAddr := state.Validators.GetProposer().Address + proposerAddr := types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address /* Invalid blocks don't pass */ @@ -107,7 +107,7 @@ func TestValidateBlockCommit(t *testing.T) { badPrivVal := types.NewMockPV() for height := int64(1); height < validationTestsStopHeight; height++ { - proposerAddr := state.Validators.GetProposer().Address + proposerAddr := types.SelectProposer(state.Validators, []byte{}, height, 0).Address if height > 1 { /* #2589: ensure state.LastValidators.VerifyCommit fails here @@ -203,7 +203,7 @@ func TestValidateBlockEvidence(t *testing.T) { lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) for height := int64(1); height < validationTestsStopHeight; height++ { - proposerAddr := state.Validators.GetProposer().Address + proposerAddr := types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address proposerIdx, _ := state.Validators.GetByAddress(proposerAddr) goodEvidence := types.NewMockEvidence(height, time.Now(), proposerIdx, proposerAddr) if height > 1 { diff --git a/store/store_test.go b/store/store_test.go index 41503c3a5..970628e58 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -46,7 +46,8 @@ func makeTxs(height int64) (txs []types.Tx) { } func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address, 0, nil) + block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, + types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address, 0, nil) return block } diff --git a/types/block_test.go b/types/block_test.go index cbb2e9f47..d15ab698e 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -13,7 +13,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" @@ -69,7 +68,9 @@ func TestBlockValidateBasic(t *testing.T) { expErr bool }{ {"Make Block", func(blk *Block) {}, false}, - {"Make Block w/ proposer Addr", func(blk *Block) { blk.ProposerAddress = valSet.GetProposer().Address }, false}, + {"Make Block w/ proposer Addr", func(blk *Block) { + blk.ProposerAddress = SelectProposer(valSet, []byte{}, blk.Height, 0).Address + }, false}, {"Negative Height", func(blk *Block) { blk.Height = -1 }, true}, {"Remove 1/2 the commits", func(blk *Block) { blk.LastCommit.Signatures = commit.Signatures[:commit.Size()/2] @@ -92,7 +93,7 @@ func TestBlockValidateBasic(t *testing.T) { i := i t.Run(tc.testName, func(t *testing.T) { block := MakeBlock(h, txs, commit, evList) - block.ProposerAddress = valSet.GetProposer().Address + block.ProposerAddress = SelectProposer(valSet, []byte{}, block.Height, 0).Address tc.malleateBlock(block) err = block.ValidateBasic() assert.Equal(t, tc.expErr, err != nil, "#%d: %v", i, err) diff --git a/types/genesis.go b/types/genesis.go index 0b9f2bbca..7ca328c9a 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -59,7 +59,7 @@ func (genDoc *GenesisDoc) ValidatorHash() []byte { for i, v := range genDoc.Validators { vals[i] = NewValidator(v.PubKey, v.Power) } - vset := NewRandomValidatorSet(vals, genDoc.Hash()) + vset := NewValidatorSet(vals) return vset.Hash() } diff --git a/types/protobuf_test.go b/types/protobuf_test.go index 3551a6518..b688716b5 100644 --- a/types/protobuf_test.go +++ b/types/protobuf_test.go @@ -42,7 +42,7 @@ func TestABCIValidators(t *testing.T) { assert.Nil(t, err) assert.Equal(t, tmValExpected, tmVals[0]) - abciVals := TM2PB.ValidatorUpdates(NewRandomValidatorSet(tmVals, []byte{})) + abciVals := TM2PB.ValidatorUpdates(NewValidatorSet(tmVals)) assert.Equal(t, []abci.ValidatorUpdate{abciVal}, abciVals) // val with address @@ -139,7 +139,7 @@ func TestABCIEvidence(t *testing.T) { } abciEv := TM2PB.Evidence( ev, - NewRandomValidatorSet([]*Validator{NewValidator(pubKey, 10)}, []byte{}), + NewValidatorSet([]*Validator{NewValidator(pubKey, 10)}), time.Now(), ) diff --git a/types/validator_set.go b/types/validator_set.go index b63c396cd..5fb1f8e4b 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -44,7 +44,6 @@ const ( type ValidatorSet struct { // NOTE: persisted via reflect, must be exported. Validators []*Validator `json:"validators"` - Proposer *Validator `json:"proposer"` // cached (unexported) totalVotingPower int64 @@ -58,20 +57,11 @@ type ValidatorSet struct { // Note the validator set size has an implied limit equal to that of the MaxVotesCount - // commits by a validator set larger than this will fail validation. func NewValidatorSet(valz []*Validator) *ValidatorSet { - return NewRandomValidatorSet(valz, []byte{}) -} - -// NewRandomValidatorSet adds the ability to specify a round hash to select Proposer randomly to NewValidatorSet. -func NewRandomValidatorSet(valz []*Validator, hash []byte) *ValidatorSet { vals := &ValidatorSet{} err := vals.updateWithChangeSet(valz, false) if err != nil { panic(fmt.Sprintf("cannot create validator set: %s", err)) } - if !vals.IsNilOrEmpty() { - vals.IncrementProposerPriority(1) - vals.SelectProposerWithHash(hash) - } return vals } @@ -80,6 +70,14 @@ func (vals *ValidatorSet) IsNilOrEmpty() bool { return vals == nil || len(vals.Validators) == 0 } +// CopyIncrementProposerPriority increments ProposerPriority and updates the +// proposer on a copy, and returns it. +func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet { + copy := vals.Copy() + copy.IncrementProposerPriority(times) + return copy +} + // TODO The current random selection by VRF uses VotingPower, so the processing on ProposerPriority can be removed, // TODO but it remains for later verification of random selection based on ProposerPriority. // IncrementProposerPriority increments ProposerPriority of each validator and updates the @@ -100,47 +98,10 @@ func (vals *ValidatorSet) IncrementProposerPriority(times int) { vals.RescalePriorities(diffMax) vals.shiftByAvgProposerPriority() - var proposer *Validator // Call IncrementProposerPriority(1) times times. for i := 0; i < times; i++ { - proposer = vals.incrementProposerPriority() + _ = vals.incrementProposerPriority() } - - vals.Proposer = proposer -} - -// MakeRoundHash combines the VRF hash, block height, and round to create a hash value for each round. This value is -// used for random sampling of the Proposer. -func MakeRoundHash(proofHash []byte, height int64, round int) []byte { - b := make([]byte, 16) - binary.LittleEndian.PutUint64(b, uint64(height)) - binary.LittleEndian.PutUint64(b[8:], uint64(round)) - hash := tmhash.New() - hash.Write(proofHash) - hash.Write(b[:8]) - hash.Write(b[8:16]) - return hash.Sum(nil) -} - -func (vals *ValidatorSet) SelectProposerWithRound(proofHash []byte, height int64, round int) *Validator { - return vals.SelectProposerWithHash(MakeRoundHash(proofHash, height, round)) -} - -func (vals *ValidatorSet) SelectProposerWithHash(hash []byte) *Validator { - if vals.IsNilOrEmpty() { - panic("empty validator set") - } - seed := hashToSeed(hash) - proposer := vals.selectProposerAtRandom(seed) - vals.Proposer = proposer - return proposer -} - -func hashToSeed(hash []byte) uint64 { - for len(hash) < 8 { - hash = append(hash, byte(0)) - } - return binary.LittleEndian.Uint64(hash[:8]) } // RescalePriorities rescales the priorities such that the distance between the maximum and minimum @@ -254,7 +215,6 @@ func validatorListCopy(valsList []*Validator) []*Validator { func (vals *ValidatorSet) Copy() *ValidatorSet { return &ValidatorSet{ Validators: validatorListCopy(vals.Validators), - Proposer: vals.Proposer, totalVotingPower: vals.totalVotingPower, } } @@ -324,25 +284,6 @@ func (vals *ValidatorSet) TotalVotingPower() int64 { return vals.totalVotingPower } -// GetProposer returns the current proposer. If the validator set is empty, or proposer hasn't yet made a decision, -// is returned. -func (vals *ValidatorSet) GetProposer() (proposer *Validator) { - if len(vals.Validators) == 0 || vals.Proposer == nil { - return nil - } - return vals.Proposer.Copy() -} - -func (vals *ValidatorSet) findProposer() *Validator { - var proposer *Validator - for _, val := range vals.Validators { - if proposer == nil || !bytes.Equal(val.Address, proposer.Address) { - proposer = proposer.CompareProposerPriority(val) - } - } - return proposer -} - func (v *Validator) Priority() uint64 { // TODO Is it possible to have a negative VotingPower? if v.VotingPower < 0 { @@ -359,16 +300,6 @@ func (v *Validator) LessThan(other tmrand.Candidate) bool { return bytes.Compare(v.Address, o.Address) < 0 } -func (vals *ValidatorSet) selectProposerAtRandom(seed uint64) (proposer *Validator) { - candidates := make([]tmrand.Candidate, len(vals.Validators)) - for i := 0; i < len(candidates); i++ { - candidates[i] = vals.Validators[i] - } - validators := tmrand.RandomSamplingWithPriority(seed, candidates, 1, uint64(vals.TotalVotingPower())) - proposer = validators[0].(*Validator) - return -} - // Hash returns the Merkle root hash build using validators (as leaves) in the // set. func (vals *ValidatorSet) Hash() []byte { @@ -665,9 +596,6 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes vals.RescalePriorities(PriorityWindowSizeFactor * vals.TotalVotingPower()) vals.shiftByAvgProposerPriority() - // Reset proposer - vals.Proposer = nil - return nil } @@ -921,13 +849,10 @@ func (vals *ValidatorSet) StringIndented(indent string) string { return false }) return fmt.Sprintf(`ValidatorSet{ -%s Proposer: %v %s Validators: %s %v %s}`, - indent, vals.GetProposer().String(), - indent, - indent, strings.Join(valStrings, "\n"+indent+" "), + indent, indent, strings.Join(valStrings, "\n"+indent+" "), indent) } @@ -966,7 +891,7 @@ func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []Pr valz[i] = val privValidators[i] = privValidator } - vals := NewRandomValidatorSet(valz, []byte{}) + vals := NewValidatorSet(valz) sort.Sort(PrivValidatorsByAddress(privValidators)) return vals, privValidators } @@ -1013,3 +938,36 @@ func safeSubClip(a, b int64) int64 { } return c } + +func SelectProposer(validators *ValidatorSet, proofHash []byte, height int64, round int) *Validator { + if validators.IsNilOrEmpty() { + panic("empty validator set") + } + seed := hashToSeed(MakeRoundHash(proofHash, height, round)) + candidates := make([]tmrand.Candidate, len(validators.Validators)) + for i := 0; i < len(candidates); i++ { + candidates[i] = validators.Validators[i] + } + vals := tmrand.RandomSamplingWithPriority(seed, candidates, 1, uint64(validators.TotalVotingPower())) + return vals[0].(*Validator) +} + +func hashToSeed(hash []byte) uint64 { + for len(hash) < 8 { + hash = append(hash, byte(0)) + } + return binary.LittleEndian.Uint64(hash[:8]) +} + +// MakeRoundHash combines the VRF hash, block height, and round to create a hash value for each round. This value is +// used for random sampling of the Proposer. +func MakeRoundHash(proofHash []byte, height int64, round int) []byte { + b := make([]byte, 16) + binary.LittleEndian.PutUint64(b, uint64(height)) + binary.LittleEndian.PutUint64(b[8:], uint64(round)) + hash := tmhash.New() + hash.Write(proofHash) + hash.Write(b[:8]) + hash.Write(b[8:16]) + return hash.Sum(nil) +} diff --git a/types/validator_set_test.go b/types/validator_set_test.go index 3c17dc8e7..dc61defba 100644 --- a/types/validator_set_test.go +++ b/types/validator_set_test.go @@ -12,7 +12,6 @@ import ( "testing/quick" "github.com/stretchr/testify/assert" - "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" tmmath "github.com/tendermint/tendermint/libs/math" @@ -23,13 +22,13 @@ import ( func TestValidatorSetBasic(t *testing.T) { // empty or nil validator lists are allowed, // but attempting to IncrementProposerPriority on them will panic. - vset := NewRandomValidatorSet([]*Validator{}, []byte{}) + vset := NewValidatorSet([]*Validator{}) assert.Panics(t, func() { vset.IncrementProposerPriority(1) }) - assert.Panics(t, func() { vset.SelectProposerWithHash([]byte{}) }) + assert.Panics(t, func() { SelectProposer(vset, []byte{}, 1, 0) }) - vset = NewRandomValidatorSet(nil, []byte{}) + vset = NewValidatorSet(nil) assert.Panics(t, func() { vset.IncrementProposerPriority(1) }) - assert.Panics(t, func() { vset.SelectProposerWithHash([]byte{}) }) + assert.Panics(t, func() { SelectProposer(vset, []byte{}, 1, 0) }) assert.EqualValues(t, vset, vset.Copy()) assert.False(t, vset.HasAddress([]byte("some val"))) @@ -47,7 +46,6 @@ func TestValidatorSetBasic(t *testing.T) { assert.Nil(t, val) assert.Zero(t, vset.Size()) assert.Equal(t, int64(0), vset.TotalVotingPower()) - assert.Nil(t, vset.GetProposer()) assert.Nil(t, vset.Hash()) // add @@ -63,7 +61,7 @@ func TestValidatorSetBasic(t *testing.T) { assert.Equal(t, val.VotingPower, vset.TotalVotingPower()) assert.NotNil(t, vset.Hash()) assert.NotPanics(t, func() { vset.IncrementProposerPriority(1) }) - assert.Equal(t, val.Address, vset.GetProposer().Address) + assert.Equal(t, val.Address, SelectProposer(vset, []byte{}, 1, 0).Address) // update val = randValidator(vset.TotalVotingPower()) @@ -96,11 +94,11 @@ func TestCopy(t *testing.T) { // Test that IncrementProposerPriority requires positive times. func TestIncrementProposerPriorityPositiveTimes(t *testing.T) { - vset := NewRandomValidatorSet([]*Validator{ + vset := NewValidatorSet([]*Validator{ newValidator([]byte("foo"), 1000), newValidator([]byte("bar"), 300), newValidator([]byte("baz"), 330), - }, []byte{}) + }) assert.Panics(t, func() { vset.IncrementProposerPriority(-1) }) assert.Panics(t, func() { vset.IncrementProposerPriority(0) }) @@ -143,11 +141,11 @@ func bytesToInt(b []byte) int { func verifyWinningRate(t *testing.T, vals *ValidatorSet, tries int, error float64) { selected := make([]int, len(vals.Validators)) for i := 0; i < tries; i++ { - vals.SelectProposerWithHash(intToBytes(i)) - prop := vals.GetProposer() + prop := SelectProposer(vals, []byte{}, int64(i), 0) for j := 0; j < len(vals.Validators); j++ { if bytes.Equal(prop.Address, vals.Validators[j].Address) { selected[j]++ + break } } } @@ -166,23 +164,20 @@ func verifyWinningRate(t *testing.T, vals *ValidatorSet, tries int, error float6 } func TestProposerSelection1(t *testing.T) { - vset := NewRandomValidatorSet([]*Validator{ + vset := NewValidatorSet([]*Validator{ newValidator([]byte("foo"), 1000), newValidator([]byte("bar"), 300), newValidator([]byte("baz"), 330), - }, []byte{}) + }) var proposers []string for i := 0; i < 99; i++ { - val := vset.GetProposer() + val := SelectProposer(vset, []byte{}, int64(i), 0) proposers = append(proposers, string(val.Address)) - hash := intToBytes(i) - vset.SelectProposerWithHash(hash) } - expected := `baz baz foo foo foo bar baz foo baz foo foo foo baz foo foo bar foo baz foo foo` + - ` foo foo foo foo bar foo foo foo foo foo foo foo baz bar foo foo foo bar foo bar foo` + - ` foo foo foo foo bar bar foo bar foo foo foo baz bar foo foo bar foo foo bar foo foo` + - ` foo foo foo baz foo foo baz foo baz baz baz foo baz foo foo baz baz baz foo foo foo` + - ` foo foo baz bar baz bar foo baz bar bar foo bar bar bar baz baz` + expected := `foo foo foo foo bar bar foo bar foo baz bar foo baz baz baz foo foo bar foo bar baz bar foo baz foo ` + + `foo baz foo foo baz foo foo baz bar foo foo foo baz foo baz baz bar foo foo foo foo baz bar bar bar bar foo ` + + `foo foo baz foo foo foo foo foo foo baz foo foo baz bar bar foo bar foo foo baz bar foo foo baz foo foo baz ` + + `foo foo bar foo foo baz foo foo foo bar foo foo baz baz foo foo bar baz foo baz` if expected != strings.Join(proposers, " ") { t.Errorf("expected sequence of proposers was\n%v\nbut got \n%v", expected, strings.Join(proposers, " ")) } @@ -196,41 +191,39 @@ func TestProposerSelection2(t *testing.T) { // when all voting power is same, the order is random but deterministic val0, val1, val2 := newValidator(addr0, 100), newValidator(addr1, 100), newValidator(addr2, 100) valList := []*Validator{val0, val1, val2} - vals := NewRandomValidatorSet(valList, []byte{}) - expected := []int{2, 0, 0, 0, 2, 2, 1, 2, 0, 1, 0, 1, 0, 1, 2} + vals := NewValidatorSet(valList) + expected := []int{0, 1, 0, 0, 2, 2, 0, 2, 1, 2, 2, 1, 2, 2, 2} for i := 0; i < len(valList)*5; i++ { - vals.SelectProposerWithHash(intToBytes(i)) - prop := vals.GetProposer() + prop := SelectProposer(vals, []byte{}, int64(i), 0) if bytesToInt(prop.Address) != expected[i] { t.Fatalf("(%d): Expected %d. Got %d", i, expected[i], bytesToInt(prop.Address)) } } - verifyWinningRate(t, vals, 100, 0.2) + verifyWinningRate(t, vals, 10000, 0.01) // One validator has more than the others *val2 = *newValidator(addr2, 400) - vals = NewRandomValidatorSet(valList, intToBytes(0)) - verifyWinningRate(t, vals, 100, 0.2) + vals = NewValidatorSet(valList) + verifyWinningRate(t, vals, 10000, 0.01) // One validator has more than the others *val2 = *newValidator(addr2, 401) - vals = NewRandomValidatorSet(valList, []byte{}) - verifyWinningRate(t, vals, 100, 0.2) + vals = NewValidatorSet(valList) + verifyWinningRate(t, vals, 100000, 0.01) // each validator should be the proposer a proportional number of times val0, val1, val2 = newValidator(addr0, 4), newValidator(addr1, 5), newValidator(addr2, 3) valList = []*Validator{val0, val1, val2} propCount := make([]int, 3) - vals = NewRandomValidatorSet(valList, []byte{}) + vals = NewValidatorSet(valList) N := 4 + 5 + 3 for i := 0; i < 10000*N; i++ { - prop := vals.GetProposer() + prop := SelectProposer(vals, []byte{}, int64(i), 0) propCount[bytesToInt(prop.Address)]++ - vals.SelectProposerWithHash(intToBytes(i)) } fmt.Printf("%v", propCount) - if propCount[0] != 40185 { + if propCount[0] != 40257 { t.Fatalf( "Expected prop count for validator with 4/12 of voting power to be %d/%d. Got %d/%d", 40185, @@ -239,7 +232,7 @@ func TestProposerSelection2(t *testing.T) { 10000*N, ) } - if propCount[1] != 49681 { + if propCount[1] != 50017 { t.Fatalf( "Expected prop count for validator with 5/12 of voting power to be %d/%d. Got %d/%d", 40185, @@ -248,7 +241,7 @@ func TestProposerSelection2(t *testing.T) { 10000*N, ) } - if propCount[2] != 30134 { + if propCount[2] != 29726 { t.Fatalf( "Expected prop count for validator with 3/12 of voting power to be %d/%d. Got %d/%d", 40185, @@ -284,7 +277,7 @@ func randValidatorSet(numValidators int) *ValidatorSet { validators[i] = randValidator(totalVotingPower) totalVotingPower += validators[i].VotingPower } - return NewRandomValidatorSet(validators, []byte{}) + return NewValidatorSet(validators) } func (vals *ValidatorSet) toBytes() []byte { @@ -309,11 +302,11 @@ func TestValidatorSetTotalVotingPowerPanicsOnOverflow(t *testing.T) { // NewValidatorSet calls IncrementProposerPriority which calls TotalVotingPower() // which should panic on overflows: shouldPanic := func() { - NewRandomValidatorSet([]*Validator{ + NewValidatorSet([]*Validator{ {Address: []byte("a"), VotingPower: math.MaxInt64, ProposerPriority: 0}, {Address: []byte("b"), VotingPower: math.MaxInt64, ProposerPriority: 0}, {Address: []byte("c"), VotingPower: math.MaxInt64, ProposerPriority: 0}, - }, []byte{}) + }) } assert.Panics(t, shouldPanic) @@ -389,7 +382,6 @@ func TestAveragingInIncrementProposerPriority(t *testing.T) { for i, tc := range tcs { // work on copy to have the old ProposerPriorities: newVset := tc.vs.Copy() - newVset.SelectProposerWithRound([]byte{}, int64(tc.times*i), 0) for _, val := range tc.vs.Validators { _, updatedVal := newVset.GetByAddress(val.Address) assert.Equal(t, updatedVal.ProposerPriority, val.ProposerPriority-tc.avg, "test case: %v", i) @@ -457,7 +449,7 @@ func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) { 0 + 5*vp1 - total, // now this val is mostest for the 1st time (hence -12==totalVotingPower) 0 + 5*vp2}, 5, - vals.Validators[1]}, + vals.Validators[2]}, 5: { vals.Copy(), []int64{ @@ -465,7 +457,7 @@ func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) { 0 + 6*vp1 - total, // mostest once up to here 0 + 6*vp2}, 6, - vals.Validators[0]}, + vals.Validators[2]}, 6: { vals.Copy(), []int64{ @@ -481,7 +473,7 @@ func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) { 0 + 8*vp1 - total, 0 + 8*vp2}, 8, - vals.Validators[0]}, + vals.Validators[2]}, 8: { vals.Copy(), []int64{ @@ -489,7 +481,7 @@ func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) { 0 + 9*vp1 - total, 0 + 9*vp2 - total}, // mostest 9, - vals.Validators[2]}, + vals.Validators[0]}, 9: { vals.Copy(), []int64{ @@ -505,15 +497,14 @@ func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) { 0 + 11*vp1 - total, // after 6 iters this val is "mostest" once and not in between 0 + 11*vp2 - total}, // after 10 iters this val is "mostest" once 11, - vals.Validators[0]}, + vals.Validators[1]}, } for i, tc := range tcs { tc.vals.IncrementProposerPriority(tc.times) - assert.Equal(t, tc.wantProposer.Address, tc.vals.GetProposer().Address, + assert.Equal(t, tc.wantProposer.Address, SelectProposer(tc.vals, []byte{}, int64(i), 0).Address, "test case: %v", i) - for valIdx, val := range tc.vals.Validators { assert.Equal(t, tc.wantProposerPrioritys[valIdx], @@ -554,7 +545,7 @@ func TestValidatorSetVerifyCommit(t *testing.T) { privKey := ed25519.GenPrivKey() pubKey := privKey.PubKey() v1 := NewValidator(pubKey, 1000) - vset := NewRandomValidatorSet([]*Validator{v1}, []byte{}) + vset := NewValidatorSet([]*Validator{v1}) // good var ( @@ -611,12 +602,11 @@ func TestValidatorSetVerifyCommit(t *testing.T) { func TestEmptySet(t *testing.T) { var valList []*Validator - valSet := NewRandomValidatorSet(valList, []byte{}) + valSet := NewValidatorSet(valList) assert.Panics(t, func() { valSet.IncrementProposerPriority(1) }) assert.Panics(t, func() { valSet.RescalePriorities(100) }) assert.Panics(t, func() { valSet.shiftByAvgProposerPriority() }) assert.Panics(t, func() { assert.Zero(t, computeMaxMinPriorityDiff(valSet)) }) - valSet.GetProposer() // Add to empty set v1 := newValidator([]byte("v1"), 100) @@ -640,7 +630,7 @@ func TestUpdatesForNewValidatorSet(t *testing.T) { v1 := newValidator([]byte("v1"), 100) v2 := newValidator([]byte("v2"), 100) valList := []*Validator{v1, v2} - valSet := NewRandomValidatorSet(valList, []byte{}) + valSet := NewValidatorSet(valList) verifyValidatorSet(t, valSet) // Verify duplicates are caught in NewValidatorSet() and it panics @@ -648,21 +638,21 @@ func TestUpdatesForNewValidatorSet(t *testing.T) { v112 := newValidator([]byte("v1"), 123) v113 := newValidator([]byte("v1"), 234) valList = []*Validator{v111, v112, v113} - assert.Panics(t, func() { NewRandomValidatorSet(valList, []byte{}) }) + assert.Panics(t, func() { NewValidatorSet(valList) }) // Verify set including validator with voting power 0 cannot be created v1 = newValidator([]byte("v1"), 0) v2 = newValidator([]byte("v2"), 22) v3 := newValidator([]byte("v3"), 33) valList = []*Validator{v1, v2, v3} - assert.Panics(t, func() { NewRandomValidatorSet(valList, []byte{}) }) + assert.Panics(t, func() { NewValidatorSet(valList) }) // Verify set including validator with negative voting power cannot be created v1 = newValidator([]byte("v1"), 10) v2 = newValidator([]byte("v2"), -20) v3 = newValidator([]byte("v3"), 30) valList = []*Validator{v1, v2, v3} - assert.Panics(t, func() { NewRandomValidatorSet(valList, []byte{}) }) + assert.Panics(t, func() { NewValidatorSet(valList) }) } @@ -692,7 +682,7 @@ func createNewValidatorList(testValList []testVal) []*Validator { } func createNewValidatorSet(testValList []testVal) *ValidatorSet { - return NewRandomValidatorSet(createNewValidatorList(testValList), []byte{}) + return NewValidatorSet(createNewValidatorList(testValList)) } func valSetTotalProposerPriority(valSet *ValidatorSet) int64 {