Skip to content

Commit

Permalink
feat: election of ValidatorSet based on VRF #74
Browse files Browse the repository at this point in the history
feat: add voteset to state

feat: implement VoterSet

fix: test failure

fix: change validators to voters more

feat: implement select voters

feat: implement RandomSamplingToMax

feat: add test case

feat: more test

fix: fmt check failure

fix: circleci failure

fix: randValidator may create a validator having 0 voting power

fix: elect a proposer among validators not among voters

fix: apply comment; proposer must be found in validators

fix: apply comments

fix: contracts_test failure

fix: contracts_test failure

fix: apply comments
  • Loading branch information
Woosang Son authored and torao committed May 7, 2021
1 parent 910b459 commit 1281f29
Show file tree
Hide file tree
Showing 88 changed files with 2,811 additions and 1,700 deletions.
2 changes: 1 addition & 1 deletion blockchain/v0/reactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ FOR_LOOP:
// NOTE: we can probably make this more efficient, but note that calling
// first.Hash() doesn't verify the tx contents, so MakePartSet() is
// currently necessary.
err := state.Validators.VerifyCommitLight(
err := state.Voters.VerifyCommitLight(
chainID, firstID, first.Height, second.LastCommit)
if err != nil {
bcR.Logger.Error("Error in validation", "err", err)
Expand Down
2 changes: 1 addition & 1 deletion blockchain/v0/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ func makeBlock(privVal types.PrivValidator, height int64, state sm.State, lastCo
message := state.MakeHashMessage(0)
proof, _ := privVal.GenerateVRFProof(message)
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil,
types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address, 0, proof)
state.Validators.SelectProposer(state.LastProofHash, height, 0).Address, 0, proof)
return block
}

Expand Down
2 changes: 1 addition & 1 deletion blockchain/v1/reactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ func (bcR *BlockchainReactor) processBlock() error {
// NOTE: we can probably make this more efficient, but note that calling
// first.Hash() doesn't verify the tx contents, so MakePartSet() is
// currently necessary.
err = bcR.state.Validators.VerifyCommitLight(chainID, firstID, first.Height, second.LastCommit)
err = bcR.state.Voters.VerifyCommitLight(chainID, firstID, first.Height, second.LastCommit)
if err != nil {
bcR.Logger.Error("error during commit verification", "err", err,
"first", first.Height, "second", second.Height)
Expand Down
2 changes: 1 addition & 1 deletion blockchain/v1/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ func makeBlock(privVal types.PrivValidator, height int64, state sm.State, lastCo
message := state.MakeHashMessage(0)
proof, _ := privVal.GenerateVRFProof(message)
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil,
types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address, 0, proof)
state.Validators.SelectProposer(state.LastProofHash, height, 0).Address, 0, proof)
return block
}

Expand Down
2 changes: 1 addition & 1 deletion blockchain/v2/processor_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (pc *pContext) setState(state state.State) {
}

func (pc pContext) verifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error {
return pc.state.Validators.VerifyCommitLight(chainID, blockID, height, commit)
return pc.state.Voters.VerifyCommitLight(chainID, blockID, height, commit)
}

func (pc *pContext) saveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
Expand Down
2 changes: 1 addition & 1 deletion blockchain/v2/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ 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)
proposerAddr := types.SelectProposer(state.Validators, state.LastProofHash, height, 0).Address
proposerAddr := state.Validators.SelectProposer(state.LastProofHash, height, 0).Address
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, proposerAddr, 0, proof)
return block
}
Expand Down
1 change: 1 addition & 0 deletions cmd/contract_tests/unmarshaler/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package unmarshaler

import (
"encoding/json"

"gopkg.in/yaml.v3"
)

Expand Down
4 changes: 2 additions & 2 deletions consensus/byzantine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ func TestByzantine(t *testing.T) {

// find proposer of current height and round from State
func findProposer(state *State) (int32, *types.Validator) {
proposer := types.SelectProposer(state.Validators, state.state.LastProofHash, state.Height, state.Round)
return state.Validators.GetByAddress(proposer.PubKey.Address())
proposer := state.Validators.SelectProposer(state.state.LastProofHash, state.Height, state.Round)
return state.Voters.GetByAddress(proposer.PubKey.Address())
}

//-------------------------------
Expand Down
2 changes: 1 addition & 1 deletion consensus/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ func forceProposer(cs *State, vals []*validatorStub, index []int, height []int64
mustBe = false
}
pubKey, _ := curVal.GetPubKey()
if pubKey.Equals(types.SelectProposer(cs.Validators, currentHash, height[j], round[j]).PubKey) !=
if pubKey.Equals(cs.Validators.SelectProposer(currentHash, height[j], round[j]).PubKey) !=
mustBe {
allMatch = false
break
Expand Down
109 changes: 55 additions & 54 deletions consensus/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,29 @@ type Metrics struct {
// Height of the chain.
Height metrics.Gauge

// ValidatorLastSignedHeight of a validator.
ValidatorLastSignedHeight metrics.Gauge
// VoterLastSignedHeight of a voter.
VoterLastSignedHeight metrics.Gauge

// Number of rounds.
Rounds metrics.Gauge

// Number of validators.
Validators metrics.Gauge
// Total power of all validators.
ValidatorsPower metrics.Gauge
// Power of a validator.
ValidatorPower metrics.Gauge
// Amount of blocks missed by a validator.
ValidatorMissedBlocks metrics.Gauge
// Number of validators who did not sign.
MissingValidators metrics.Gauge
// Total power of the missing validators.
MissingValidatorsPower metrics.Gauge
// Number of validators who tried to double sign.
ByzantineValidators metrics.Gauge
// Total power of the byzantine validators.
ByzantineValidatorsPower metrics.Gauge
// ValidatorOrVoter: voter
// Number of voters.
Voters metrics.Gauge
// Total power of all voters.
VotersPower metrics.Gauge
// Power of a voter.
VoterPower metrics.Gauge
// Amount of blocks missed by a voter.
VoterMissedBlocks metrics.Gauge
// Number of voters who did not sign.
MissingVoters metrics.Gauge
// Total power of the missing voters.
MissingVotersPower metrics.Gauge
// Number of voters who tried to double sign.
ByzantineVoters metrics.Gauge
// Total power of the byzantine voters.
ByzantineVotersPower metrics.Gauge

// Time between this and the last block.
BlockIntervalSeconds metrics.Histogram
Expand Down Expand Up @@ -84,59 +85,59 @@ func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
Help: "Number of rounds.",
}, labels).With(labelsAndValues...),

Validators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Voters: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validators",
Help: "Number of validators.",
Name: "voters",
Help: "Number of voters.",
}, labels).With(labelsAndValues...),
ValidatorLastSignedHeight: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
VoterLastSignedHeight: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validator_last_signed_height",
Help: "Last signed height for a validator",
Name: "voter_last_signed_height",
Help: "Last signed height for a voter",
}, append(labels, "validator_address")).With(labelsAndValues...),
ValidatorMissedBlocks: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
VoterMissedBlocks: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validator_missed_blocks",
Help: "Total missed blocks for a validator",
Name: "voter_missed_blocks",
Help: "Total missed blocks for a voter",
}, append(labels, "validator_address")).With(labelsAndValues...),
ValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
VotersPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validators_power",
Help: "Total power of all validators.",
Name: "voters_power",
Help: "Total power of all voters.",
}, labels).With(labelsAndValues...),
ValidatorPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
VoterPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validator_power",
Help: "Power of a validator",
Name: "voter_power",
Help: "Power of a voter",
}, append(labels, "validator_address")).With(labelsAndValues...),
MissingValidators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
MissingVoters: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "missing_validators",
Help: "Number of validators who did not sign.",
Name: "missing_voters",
Help: "Number of voters who did not sign.",
}, labels).With(labelsAndValues...),
MissingValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
MissingVotersPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "missing_validators_power",
Help: "Total power of the missing validators.",
Name: "missing_voters_power",
Help: "Total power of the missing voters.",
}, labels).With(labelsAndValues...),
ByzantineValidators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
ByzantineVoters: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "byzantine_validators",
Help: "Number of validators who tried to double sign.",
Name: "byzantine_voters",
Help: "Number of voters who tried to double sign.",
}, labels).With(labelsAndValues...),
ByzantineValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
ByzantineVotersPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "byzantine_validators_power",
Help: "Total power of the byzantine validators.",
Name: "byzantine_voters_power",
Help: "Total power of the byzantine voters.",
}, labels).With(labelsAndValues...),
BlockIntervalSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Expand Down Expand Up @@ -194,18 +195,18 @@ func NopMetrics() *Metrics {
return &Metrics{
Height: discard.NewGauge(),

ValidatorLastSignedHeight: discard.NewGauge(),
VoterLastSignedHeight: discard.NewGauge(),

Rounds: discard.NewGauge(),

Validators: discard.NewGauge(),
ValidatorsPower: discard.NewGauge(),
ValidatorPower: discard.NewGauge(),
ValidatorMissedBlocks: discard.NewGauge(),
MissingValidators: discard.NewGauge(),
MissingValidatorsPower: discard.NewGauge(),
ByzantineValidators: discard.NewGauge(),
ByzantineValidatorsPower: discard.NewGauge(),
Voters: discard.NewGauge(),
VotersPower: discard.NewGauge(),
VoterPower: discard.NewGauge(),
VoterMissedBlocks: discard.NewGauge(),
MissingVoters: discard.NewGauge(),
MissingVotersPower: discard.NewGauge(),
ByzantineVoters: discard.NewGauge(),
ByzantineVotersPower: discard.NewGauge(),

BlockIntervalSeconds: discard.NewHistogram(),

Expand Down
28 changes: 14 additions & 14 deletions consensus/reactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,9 @@ func (conR *Reactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
case *VoteMessage:
cs := conR.conS
cs.mtx.RLock()
height, valSize, lastCommitSize := cs.Height, cs.Validators.Size(), cs.LastCommit.Size()
height, voterSize, lastCommitSize := cs.Height, cs.Voters.Size(), cs.LastCommit.Size()
cs.mtx.RUnlock()
ps.EnsureVoteBitArrays(height, valSize)
ps.EnsureVoteBitArrays(height, voterSize)
ps.EnsureVoteBitArrays(height-1, lastCommitSize)
ps.SetHasVote(msg.Vote)

Expand Down Expand Up @@ -1140,7 +1140,7 @@ func (ps *PeerState) getVoteBitArray(height int64, round int32, votesType tmprot
}

// 'round': A round for which we have a +2/3 commit.
func (ps *PeerState) ensureCatchupCommitRound(height int64, round int32, numValidators int) {
func (ps *PeerState) ensureCatchupCommitRound(height int64, round int32, numVoters int) {
if ps.PRS.Height != height {
return
}
Expand All @@ -1164,37 +1164,37 @@ func (ps *PeerState) ensureCatchupCommitRound(height int64, round int32, numVali
if round == ps.PRS.Round {
ps.PRS.CatchupCommit = ps.PRS.Precommits
} else {
ps.PRS.CatchupCommit = bits.NewBitArray(numValidators)
ps.PRS.CatchupCommit = bits.NewBitArray(numVoters)
}
}

// EnsureVoteBitArrays ensures the bit-arrays have been allocated for tracking
// what votes this peer has received.
// NOTE: It's important to make sure that numValidators actually matches
// what the node sees as the number of validators for height.
func (ps *PeerState) EnsureVoteBitArrays(height int64, numValidators int) {
// NOTE: It's important to make sure that numVoters actually matches
// what the node sees as the number of voters for height.
func (ps *PeerState) EnsureVoteBitArrays(height int64, numVoters int) {
ps.mtx.Lock()
defer ps.mtx.Unlock()
ps.ensureVoteBitArrays(height, numValidators)
ps.ensureVoteBitArrays(height, numVoters)
}

func (ps *PeerState) ensureVoteBitArrays(height int64, numValidators int) {
func (ps *PeerState) ensureVoteBitArrays(height int64, numVoters int) {
if ps.PRS.Height == height {
if ps.PRS.Prevotes == nil {
ps.PRS.Prevotes = bits.NewBitArray(numValidators)
ps.PRS.Prevotes = bits.NewBitArray(numVoters)
}
if ps.PRS.Precommits == nil {
ps.PRS.Precommits = bits.NewBitArray(numValidators)
ps.PRS.Precommits = bits.NewBitArray(numVoters)
}
if ps.PRS.CatchupCommit == nil {
ps.PRS.CatchupCommit = bits.NewBitArray(numValidators)
ps.PRS.CatchupCommit = bits.NewBitArray(numVoters)
}
if ps.PRS.ProposalPOL == nil {
ps.PRS.ProposalPOL = bits.NewBitArray(numValidators)
ps.PRS.ProposalPOL = bits.NewBitArray(numVoters)
}
} else if ps.PRS.Height == height+1 {
if ps.PRS.LastCommit == nil {
ps.PRS.LastCommit = bits.NewBitArray(numValidators)
ps.PRS.LastCommit = bits.NewBitArray(numVoters)
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions consensus/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,48 +353,48 @@ func TestReactorVotingPowerChange(t *testing.T) {
val1PubKeyABCI, err := cryptoenc.PubKeyToProto(val1PubKey)
require.NoError(t, err)
updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKeyABCI, 25)
previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower()
previousTotalVotingPower := css[0].GetRoundState().LastVoters.TotalVotingPower()

waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css, updateValidatorTx)
waitForAndValidateBlockWithTx(t, nVals, activeVals, blocksSubs, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)

if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
if css[0].GetRoundState().LastVoters.TotalVotingPower() == previousTotalVotingPower {
t.Fatalf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[0].GetRoundState().LastValidators.TotalVotingPower())
css[0].GetRoundState().LastVoters.TotalVotingPower())
}

updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 2)
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
previousTotalVotingPower = css[0].GetRoundState().LastVoters.TotalVotingPower()

waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css, updateValidatorTx)
waitForAndValidateBlockWithTx(t, nVals, activeVals, blocksSubs, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)

if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
if css[0].GetRoundState().LastVoters.TotalVotingPower() == previousTotalVotingPower {
t.Fatalf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[0].GetRoundState().LastValidators.TotalVotingPower())
css[0].GetRoundState().LastVoters.TotalVotingPower())
}

updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 26)
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
previousTotalVotingPower = css[0].GetRoundState().LastVoters.TotalVotingPower()

waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css, updateValidatorTx)
waitForAndValidateBlockWithTx(t, nVals, activeVals, blocksSubs, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)

if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
if css[0].GetRoundState().LastVoters.TotalVotingPower() == previousTotalVotingPower {
t.Fatalf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[0].GetRoundState().LastValidators.TotalVotingPower())
css[0].GetRoundState().LastVoters.TotalVotingPower())
}
}

Expand Down Expand Up @@ -464,18 +464,18 @@ func TestReactorValidatorSetChanges(t *testing.T) {
updatePubKey1ABCI, err := cryptoenc.PubKeyToProto(updateValidatorPubKey1)
require.NoError(t, err)
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower()
previousTotalVotingPower := css[nVals].GetRoundState().LastVoters.TotalVotingPower()

waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css, updateValidatorTx1)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, css, updateValidatorTx1)
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css)
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, css)

if css[nVals].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
if css[nVals].GetRoundState().LastVoters.TotalVotingPower() == previousTotalVotingPower {
t.Errorf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[nVals].GetRoundState().LastValidators.TotalVotingPower())
css[nVals].GetRoundState().LastVoters.TotalVotingPower())
}

//---------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit 1281f29

Please sign in to comment.