aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-12-14 20:56:24 +0800
committerGitHub <noreply@github.com>2018-12-14 20:56:24 +0800
commit5f32dc8d27564e1f3a105fd1dacf02130b08621a (patch)
treed2649afe0df27de2ec2eb84f4709a2c7699d3d22
parent155e31175aeaa3685c57383e386c6e62c46318ef (diff)
downloaddexon-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.go6
-rw-r--r--core/configuration-chain_test.go79
-rw-r--r--core/dkg-tsig-protocol.go13
-rw-r--r--core/dkg-tsig-protocol_test.go42
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() {