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 Kynea0b committed May 6, 2021
1 parent 6134756 commit 1689dcc
Show file tree
Hide file tree
Showing 88 changed files with 2,412 additions and 1,374 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
16 changes: 8 additions & 8 deletions consensus/byzantine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func TestByzantine(t *testing.T) {
// enable txs so we can create different proposals
assertMempool(css[i].txNotifier).EnableTxsAvailable()
// make first val byzantine
if int32(i) == proposerIdx {
if i == proposerIdx {
// NOTE: Now, test validators are MockPV, which by default doesn't
// do any safety checks.
css[i].privValidator.(*types.MockPV).DisableChecks()
Expand Down Expand Up @@ -346,7 +346,7 @@ func TestByzantine(t *testing.T) {
var conRI p2p.Reactor = conR

// make first val byzantine
if int32(i) == proposerIdx {
if i == proposerIdx {
conRI = NewByzantineReactor(conR)
}

Expand All @@ -373,7 +373,7 @@ func TestByzantine(t *testing.T) {
return switches[i]
}, func(sws []*p2p.Switch, i, j int) {
// the network starts partitioned with globally active adversary
if int32(i) != proposerIdx && int32(j) != proposerIdx {
if i != proposerIdx && j != proposerIdx {
return
}
p2p.Connect2Switches(sws, i, j)
Expand All @@ -382,7 +382,7 @@ func TestByzantine(t *testing.T) {
// start the non-byz state machines.
// note these must be started before the byz
for i := 0; i < N; i++ {
if int32(i) != proposerIdx {
if i != proposerIdx {
cr := reactors[i].(*Reactor)
cr.SwitchToConsensus(cr.conS.GetState(), false)
}
Expand Down Expand Up @@ -418,7 +418,7 @@ func TestByzantine(t *testing.T) {
// (one of them already has)
wg := new(sync.WaitGroup)
for i := 0; i < N-1; i++ {
if int32(i) != proposerIdx {
if i != proposerIdx {
wg.Add(1)
go func(j int) {
<-blocksSubs[j].Out()
Expand Down Expand Up @@ -446,9 +446,9 @@ 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())
func findProposer(state *State) (int, *types.Validator) {
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
Loading

0 comments on commit 1689dcc

Please sign in to comment.