diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2018-12-14 20:56:24 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-14 20:56:24 +0800 |
commit | 5f32dc8d27564e1f3a105fd1dacf02130b08621a (patch) | |
tree | d2649afe0df27de2ec2eb84f4709a2c7699d3d22 | |
parent | 155e31175aeaa3685c57383e386c6e62c46318ef (diff) | |
download | dexon-consensus-5f32dc8d27564e1f3a105fd1dacf02130b08621a.tar dexon-consensus-5f32dc8d27564e1f3a105fd1dacf02130b08621a.tar.gz dexon-consensus-5f32dc8d27564e1f3a105fd1dacf02130b08621a.tar.bz2 dexon-consensus-5f32dc8d27564e1f3a105fd1dacf02130b08621a.tar.lz dexon-consensus-5f32dc8d27564e1f3a105fd1dacf02130b08621a.tar.xz dexon-consensus-5f32dc8d27564e1f3a105fd1dacf02130b08621a.tar.zst dexon-consensus-5f32dc8d27564e1f3a105fd1dacf02130b08621a.zip |
core: Fix a bug of DKGNackComplaints (#370)
* core: Fix a bug if DKGNackComplaint is added after required time.
* Duplicated NackComplaint should be only count once.
-rw-r--r-- | core/configuration-chain.go | 6 | ||||
-rw-r--r-- | core/configuration-chain_test.go | 79 | ||||
-rw-r--r-- | core/dkg-tsig-protocol.go | 13 | ||||
-rw-r--r-- | core/dkg-tsig-protocol_test.go | 42 |
4 files changed, 133 insertions, 7 deletions
diff --git a/core/configuration-chain.go b/core/configuration-chain.go index 364f2c7..3c2a4a9 100644 --- a/core/configuration-chain.go +++ b/core/configuration-chain.go @@ -153,7 +153,8 @@ func (cc *configurationChain) runDKG(round uint64) error { cc.dkgLock.Lock() // Phase 5(T = 2λ): Propose Anti nack complaint. cc.logger.Debug("Calling Governance.DKGComplaints", "round", round) - cc.dkg.processNackComplaints(cc.gov.DKGComplaints(round)) + complaints := cc.gov.DKGComplaints(round) + cc.dkg.processNackComplaints(complaints) cc.dkgLock.Unlock() <-ticker.Tick() cc.dkgLock.Lock() @@ -163,8 +164,7 @@ func (cc *configurationChain) runDKG(round uint64) error { <-ticker.Tick() cc.dkgLock.Lock() // Phase 7(T = 4λ): Enforce complaints and nack complaints. - cc.logger.Debug("Calling Governance.DKGComplaints", "round", round) - cc.dkg.enforceNackComplaints(cc.gov.DKGComplaints(round)) + cc.dkg.enforceNackComplaints(complaints) // Enforce complaint is done in `processPrivateShare`. // Phase 8(T = 5λ): DKG finalize. cc.dkgLock.Unlock() diff --git a/core/configuration-chain_test.go b/core/configuration-chain_test.go index 2e75b7f..92b47c9 100644 --- a/core/configuration-chain_test.go +++ b/core/configuration-chain_test.go @@ -323,6 +323,85 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() { } } +func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { + k := 4 + n := 10 + round := uint64(0) + lambdaDKG := 1000 * time.Millisecond + s.setupNodes(n) + + cfgChains := make(map[types.NodeID]*configurationChain) + recv := newTestCCReceiver(s) + + pks := make([]crypto.PublicKey, 0, len(s.prvKeys)) + for _, prv := range s.prvKeys { + pks = append(pks, prv.PublicKey()) + } + + for _, nID := range s.nIDs { + state := test.NewState( + pks, 100*time.Millisecond, &common.NullLogger{}, true) + gov, err := test.NewGovernance(state, ConfigRoundShift) + s.Require().NoError(err) + s.Require().NoError(state.RequestChange( + test.StateChangeLambdaDKG, lambdaDKG)) + cache := utils.NewNodeSetCache(gov) + cfgChains[nID] = newConfigurationChain( + nID, recv, gov, cache, &common.NullLogger{}) + recv.nodes[nID] = cfgChains[nID] + recv.govs[nID] = gov + } + + for _, cc := range cfgChains { + cc.registerDKG(round, k) + } + + for _, gov := range recv.govs { + s.Require().Len(gov.DKGMasterPublicKeys(round), n) + } + + errs := make(chan error, n) + wg := sync.WaitGroup{} + wg.Add(n) + for _, cc := range cfgChains { + go func(cc *configurationChain) { + defer wg.Done() + errs <- cc.runDKG(round) + }(cc) + } + go func() { + // Node 0 proposes NackComplaint to all others at 3λ but they should + // be ignored because NackComplaint shoould be proposed before 2λ. + time.Sleep(lambdaDKG * 3) + nID := s.nIDs[0] + for _, targetNode := range s.nIDs { + if targetNode == nID { + continue + } + recv.ProposeDKGComplaint(&typesDKG.Complaint{ + ProposerID: nID, + Round: round, + PrivateShare: typesDKG.PrivateShare{ + ProposerID: targetNode, + Round: round, + }, + }) + } + }() + wg.Wait() + for range cfgChains { + s.Require().NoError(<-errs) + } + for nID, cc := range cfgChains { + if _, exist := cc.gpk[round]; !exist { + s.FailNow("Should be qualifyied") + } + if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + s.FailNow("Should be qualifyied") + } + } +} + func (s *ConfigurationChainTestSuite) TestMultipleTSig() { k := 2 n := 7 diff --git a/core/dkg-tsig-protocol.go b/core/dkg-tsig-protocol.go index 6645ecb..8e03cbb 100644 --- a/core/dkg-tsig-protocol.go +++ b/core/dkg-tsig-protocol.go @@ -378,16 +378,21 @@ func NewDKGGroupPublicKey( // Calculate qualify members. disqualifyIDs := map[types.NodeID]struct{}{} - complaintsByID := map[types.NodeID]int{} + complaintsByID := map[types.NodeID]map[types.NodeID]struct{}{} for _, complaint := range complaints { if complaint.IsNack() { - complaintsByID[complaint.PrivateShare.ProposerID]++ + if _, exist := complaintsByID[complaint.PrivateShare.ProposerID]; !exist { + complaintsByID[complaint.PrivateShare.ProposerID] = + make(map[types.NodeID]struct{}) + } + complaintsByID[complaint.PrivateShare.ProposerID][complaint.ProposerID] = + struct{}{} } else { disqualifyIDs[complaint.PrivateShare.ProposerID] = struct{}{} } } - for nID, num := range complaintsByID { - if num > threshold { + for nID, complaints := range complaintsByID { + if len(complaints) > threshold { disqualifyIDs[nID] = struct{}{} } } diff --git a/core/dkg-tsig-protocol_test.go b/core/dkg-tsig-protocol_test.go index 4594ccd..2dad0e8 100644 --- a/core/dkg-tsig-protocol_test.go +++ b/core/dkg-tsig-protocol_test.go @@ -353,6 +353,48 @@ func (s *DKGTSIGProtocolTestSuite) TestComplaint() { s.Len(receiver.complaints, 0) } +// TestDuplicateComplaint tests if the duplicated complaint is process properly. +func (s *DKGTSIGProtocolTestSuite) TestDuplicateComplaint() { + k := 3 + n := 10 + round := uint64(1) + _, pubKeys, err := test.NewKeys(5) + s.Require().NoError(err) + gov, err := test.NewGovernance(test.NewState( + pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) + s.Require().NoError(err) + + receivers, _ := s.newProtocols(k, n, round) + + byzantineID := s.nIDs[0] + victomID := s.nIDs[1] + + for _, receiver := range receivers { + gov.AddDKGMasterPublicKey(round, receiver.mpk) + } + + // Test for nack complaints. + complaints := make([]*typesDKG.Complaint, k+1) + for i := range complaints { + complaints[i] = &typesDKG.Complaint{ + ProposerID: byzantineID, + Round: round, + PrivateShare: typesDKG.PrivateShare{ + ProposerID: victomID, + Round: round, + }, + } + s.Require().True(complaints[i].IsNack()) + } + + gpk, err := NewDKGGroupPublicKey(round, + gov.DKGMasterPublicKeys(round), complaints, + k, + ) + s.Require().NoError(err) + s.Require().Len(gpk.qualifyIDs, n) +} + // TestAntiComplaint tests if a nack complaint is received, // create an anti complaint. func (s *DKGTSIGProtocolTestSuite) TestAntiComplaint() { |