Skip to content

Commit

Permalink
feat(consensus): fast consensus path implementation (#1253)
Browse files Browse the repository at this point in the history
  • Loading branch information
b00f authored Jun 7, 2024
1 parent b589372 commit 0c6b91d
Show file tree
Hide file tree
Showing 102 changed files with 7,065 additions and 785 deletions.
5 changes: 3 additions & 2 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,9 @@ func makeLocalGenesis(w wallet.Wallet) *genesis.Genesis {
crypto.TreasuryAddress: acc,
}

vals := make([]*validator.Validator, 4)
for i := 0; i < 4; i++ {
genValNum := 6
vals := make([]*validator.Validator, genValNum)
for i := 0; i < genValNum; i++ {
info := w.AddressInfo(w.AddressInfos()[i].Address)
pub, _ := bls.PublicKeyFromString(info.PublicKey)
vals[i] = validator.NewValidator(pub, int32(i))
Expand Down
4 changes: 2 additions & 2 deletions committee/committee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ func TestContains(t *testing.T) {
func TestProposer(t *testing.T) {
ts := testsuite.NewTestSuite(t)

cmt, _ := ts.GenerateTestCommittee(4)
cmt, _ := ts.GenerateTestCommittee(6)

assert.Equal(t, cmt.Proposer(0).Number(), int32(0))
assert.Equal(t, cmt.Proposer(3).Number(), int32(3))
assert.Equal(t, cmt.Proposer(4).Number(), int32(0))
assert.Equal(t, cmt.Proposer(6).Number(), int32(0))

cmt.Update(0, nil)
assert.Equal(t, cmt.Proposer(0).Number(), int32(1))
Expand Down
2 changes: 1 addition & 1 deletion consensus/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (s *commitState) decide() {
certBlock := roundProposal.Block()
precommits := s.log.PrecommitVoteSet(s.round)
votes := precommits.BlockVotes(certBlock.Hash())
cert := s.makeCertificate(votes)
cert := s.makeBlockCertificate(votes)
err := s.bcState.CommitBlock(certBlock, cert)
if err != nil {
s.logger.Error("committing block failed", "block", certBlock, "error", err)
Expand Down
2 changes: 1 addition & 1 deletion consensus/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func DefaultConfig() *Config {
func (conf *Config) BasicCheck() error {
if conf.ChangeProposerTimeout <= 0 {
return ConfigError{
Reason: "timeout for change proposer must be greater than zero",
Reason: "change proposer timeout must be greater than zero",
}
}
if conf.ChangeProposerDelta <= 0 {
Expand Down
4 changes: 2 additions & 2 deletions consensus/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ func TestDefaultConfigCheck(t *testing.T) {
assert.ErrorIs(t, c2.BasicCheck(), ConfigError{Reason: "change proposer delta must be greater than zero"})

c3.ChangeProposerTimeout = 0 * time.Second
assert.ErrorIs(t, c3.BasicCheck(), ConfigError{Reason: "timeout for change proposer must be greater than zero"})
assert.ErrorIs(t, c3.BasicCheck(), ConfigError{Reason: "change proposer timeout must be greater than zero"})

c4.ChangeProposerTimeout = -1 * time.Second
assert.ErrorIs(t, c4.BasicCheck(), ConfigError{Reason: "timeout for change proposer must be greater than zero"})
assert.ErrorIs(t, c4.BasicCheck(), ConfigError{Reason: "change proposer timeout must be greater than zero"})

c5.MinimumAvailabilityScore = 1.5
assert.ErrorIs(t, c5.BasicCheck(), ConfigError{Reason: "minimum availability score can't be negative or more than 1"})
Expand Down
26 changes: 23 additions & 3 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,13 +400,25 @@ func (cs *consensus) broadcastVote(v *vote.Vote) {
message.NewVoteMessage(v))
}

func (cs *consensus) announceNewBlock(blk *block.Block, cert *certificate.Certificate) {
func (cs *consensus) announceNewBlock(blk *block.Block, cert *certificate.BlockCertificate) {
go cs.mediator.OnBlockAnnounce(cs)
cs.broadcaster(cs.valKey.Address(),
message.NewBlockAnnounceMessage(blk, cert))
}

func (cs *consensus) makeCertificate(votes map[crypto.Address]*vote.Vote) *certificate.Certificate {
func (cs *consensus) makeBlockCertificate(votes map[crypto.Address]*vote.Vote,
) *certificate.BlockCertificate {
cert := certificate.NewBlockCertificate(cs.height, cs.round, false)
cert.SetSignature(cs.signersInfo(votes))

return cert
}

// signersInfo processes a map of votes from validators and provides these information:
// - A list of all validators' numbers eligible to vote in this step.
// - A list of absentee validators' numbers who did not vote in this step.
// - An aggregated signature generated from the signatures of participating validators.
func (cs *consensus) signersInfo(votes map[crypto.Address]*vote.Vote) ([]int32, []int32, *bls.Signature) {
vals := cs.validators
committers := make([]int32, len(vals))
absentees := make([]int32, 0)
Expand All @@ -425,7 +437,15 @@ func (cs *consensus) makeCertificate(votes map[crypto.Address]*vote.Vote) *certi

aggSig := bls.SignatureAggregate(sigs...)

return certificate.NewCertificate(cs.height, cs.round, committers, absentees, aggSig)
return committers, absentees, aggSig
}

func (cs *consensus) makeVoteCertificate(votes map[crypto.Address]*vote.Vote,
) *certificate.VoteCertificate {
cert := certificate.NewVoteCertificate(cs.height, cs.round)
cert.SetSignature(cs.signersInfo(votes))

return cert
}

// IsActive checks if the consensus is in an active state and participating in the consensus algorithm.
Expand Down
75 changes: 40 additions & 35 deletions consensus/consensus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,23 +274,23 @@ func (td *testData) addPrecommitVote(cons *consensus, blockHash hash.Hash, heigh
}

func (td *testData) addCPPreVote(cons *consensus, blockHash hash.Hash, height uint32, round int16,
cpRound int16, cpVal vote.CPValue, just vote.Just, valID int,
cpVal vote.CPValue, just vote.Just, valID int,
) {
v := vote.NewCPPreVote(blockHash, height, round, cpRound, cpVal, just, td.valKeys[valID].Address())
v := vote.NewCPPreVote(blockHash, height, round, 0, cpVal, just, td.valKeys[valID].Address())
td.addVote(cons, v, valID)
}

func (td *testData) addCPMainVote(cons *consensus, blockHash hash.Hash, height uint32, round int16,
cpRound int16, cpVal vote.CPValue, just vote.Just, valID int,
cpVal vote.CPValue, just vote.Just, valID int,
) {
v := vote.NewCPMainVote(blockHash, height, round, cpRound, cpVal, just, td.valKeys[valID].Address())
v := vote.NewCPMainVote(blockHash, height, round, 0, cpVal, just, td.valKeys[valID].Address())
td.addVote(cons, v, valID)
}

func (td *testData) addCPDecidedVote(cons *consensus, blockHash hash.Hash, height uint32, round int16,
cpRound int16, cpVal vote.CPValue, just vote.Just, valID int,
cpVal vote.CPValue, just vote.Just, valID int,
) {
v := vote.NewCPDecidedVote(blockHash, height, round, cpRound, cpVal, just, td.valKeys[valID].Address())
v := vote.NewCPDecidedVote(blockHash, height, round, 0, cpVal, just, td.valKeys[valID].Address())
td.addVote(cons, v, valID)
}

Expand Down Expand Up @@ -337,23 +337,23 @@ func (*testData) enterNextRound(cons *consensus) {
cons.lk.Unlock()
}

func (td *testData) commitBlockForAllStates(t *testing.T) (*block.Block, *certificate.Certificate) {
func (td *testData) commitBlockForAllStates(t *testing.T) (*block.Block, *certificate.BlockCertificate) {
t.Helper()

height := td.consX.bcState.LastBlockHeight()
var err error
p := td.makeProposal(t, height+1, 0)
prop := td.makeProposal(t, height+1, 0)

sb := certificate.BlockCertificateSignBytes(p.Block().Hash(), height+1, 0)
cert := certificate.NewBlockCertificate(height+1, 0, false)
sb := cert.SignBytes(prop.Block().Hash())
sig1 := td.consX.valKey.Sign(sb)
sig2 := td.consY.valKey.Sign(sb)
sig3 := td.consB.valKey.Sign(sb)
sig4 := td.consP.valKey.Sign(sb)

sig := bls.SignatureAggregate(sig1, sig2, sig3, sig4)
cert := certificate.NewCertificate(height+1, 0,
[]int32{tIndexX, tIndexY, tIndexB, tIndexP}, []int32{}, sig)
blk := p.Block()
cert.SetSignature([]int32{tIndexX, tIndexY, tIndexB, tIndexP}, []int32{}, sig)
blk := prop.Block()

err = td.consX.bcState.CommitBlock(blk, cert)
assert.NoError(t, err)
Expand Down Expand Up @@ -549,43 +549,48 @@ func TestPickRandomVote(t *testing.T) {

td.enterNewHeight(td.consP)
assert.Nil(t, td.consP.PickRandomVote(0))
cpRound := int16(1)
cpRound := int16(0)

// === make valid certificate
sbPreVote := certificate.BlockCertificateSignBytes(hash.UndefHash, 1, 0)
sbPreVote = append(sbPreVote, util.StringToBytes(vote.VoteTypeCPPreVote.String())...)
sbPreVote = append(sbPreVote, util.Int16ToSlice(cpRound)...)
sbPreVote = append(sbPreVote, byte(vote.CPValueOne))
preVoteCommitters := []int32{}
preVoteSigs := []*bls.Signature{}
for i, val := range td.consP.validators {
preVoteJust := &vote.JustInitYes{}
preVote := vote.NewCPPreVote(hash.UndefHash, 1, 0, cpRound, vote.CPValueYes, preVoteJust, val.Address())
sbPreVote := preVote.SignBytes()

sbMainVote := certificate.BlockCertificateSignBytes(hash.UndefHash, 1, 0)
sbMainVote = append(sbMainVote, util.StringToBytes(vote.VoteTypeCPMainVote.String())...)
sbMainVote = append(sbMainVote, util.Int16ToSlice(cpRound)...)
sbMainVote = append(sbMainVote, byte(vote.CPValueOne))
preVoteCommitters = append(preVoteCommitters, val.Number())
preVoteSigs = append(preVoteSigs, td.valKeys[i].Sign(sbPreVote))
}
preVoteAggSig := bls.SignatureAggregate(preVoteSigs...)
certPreVote := certificate.NewVoteCertificate(1, 0)
certPreVote.SetSignature(preVoteCommitters, []int32{}, preVoteAggSig)

committers := []int32{}
preVoteSigs := []*bls.Signature{}
mainVoteCommitters := []int32{}
mainVoteSigs := []*bls.Signature{}
for i, val := range td.consP.validators {
committers = append(committers, val.Number())
preVoteSigs = append(preVoteSigs, td.valKeys[i].Sign(sbPreVote))
mainVoteJust := &vote.JustMainVoteNoConflict{
QCert: certPreVote,
}
mainVote := vote.NewCPMainVote(hash.UndefHash, 1, 0, cpRound, vote.CPValueYes, mainVoteJust, val.Address())
sbMainVote := mainVote.SignBytes()

mainVoteCommitters = append(mainVoteCommitters, val.Number())
mainVoteSigs = append(mainVoteSigs, td.valKeys[i].Sign(sbMainVote))
}

preVoteAggSig := bls.SignatureAggregate(preVoteSigs...)
mainVoteAggSig := bls.SignatureAggregate(mainVoteSigs...)

certPreVote := certificate.NewCertificate(1, 0, committers, []int32{}, preVoteAggSig)
certMainVote := certificate.NewCertificate(1, 0, committers, []int32{}, mainVoteAggSig)
certMainVote := certificate.NewVoteCertificate(1, 0)
certMainVote.SetSignature(mainVoteCommitters, []int32{}, mainVoteAggSig)
// ====

// round 0
td.addPrepareVote(td.consP, td.RandHash(), 1, 0, tIndexX)
td.addPrepareVote(td.consP, td.RandHash(), 1, 0, tIndexY)
td.addCPPreVote(td.consP, hash.UndefHash, 1, 0, cpRound+1, vote.CPValueOne,
&vote.JustPreVoteHard{QCert: certPreVote}, tIndexY)
td.addCPMainVote(td.consP, hash.UndefHash, 1, 0, cpRound, vote.CPValueOne,
td.addCPPreVote(td.consP, hash.UndefHash, 1, 0, vote.CPValueYes,
&vote.JustInitYes{}, tIndexY)
td.addCPMainVote(td.consP, hash.UndefHash, 1, 0, vote.CPValueYes,
&vote.JustMainVoteNoConflict{QCert: certPreVote}, tIndexY)
td.addCPDecidedVote(td.consP, hash.UndefHash, 1, 0, cpRound, vote.CPValueOne,
td.addCPDecidedVote(td.consP, hash.UndefHash, 1, 0, vote.CPValueYes,
&vote.JustDecided{QCert: certMainVote}, tIndexY)

assert.NotNil(t, td.consP.PickRandomVote(0))
Expand Down Expand Up @@ -881,7 +886,7 @@ func TestByzantine(t *testing.T) {
}

func checkConsensus(td *testData, height uint32, byzVotes []*vote.Vote) (
*certificate.Certificate, error,
*certificate.BlockCertificate, error,
) {
instances := []*consensus{td.consX, td.consY, td.consB, td.consP}

Expand Down
Loading

0 comments on commit 0c6b91d

Please sign in to comment.