diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2019-04-15 11:44:04 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-15 11:44:04 +0800 |
commit | 79be89a6b0b1d24b889e7c9fe0244026af4d49d0 (patch) | |
tree | bacd2dd8a224d2cffbe9965439707df7fa2888de /core/test | |
parent | 7abe09214fbf04f9f1f7f4f6ec57cd1f924953d6 (diff) | |
download | tangerine-consensus-79be89a6b0b1d24b889e7c9fe0244026af4d49d0.tar.gz tangerine-consensus-79be89a6b0b1d24b889e7c9fe0244026af4d49d0.tar.zst tangerine-consensus-79be89a6b0b1d24b889e7c9fe0244026af4d49d0.zip |
core: Add DKGSuccess (#569)
* core: Add DKGSuccess
* core: reset if not enough of dkg success
Diffstat (limited to 'core/test')
-rw-r--r-- | core/test/governance.go | 32 | ||||
-rw-r--r-- | core/test/state-change-request.go | 1 | ||||
-rw-r--r-- | core/test/state.go | 65 | ||||
-rw-r--r-- | core/test/state_test.go | 24 | ||||
-rw-r--r-- | core/test/utils.go | 14 |
5 files changed, 120 insertions, 16 deletions
diff --git a/core/test/governance.go b/core/test/governance.go index 14b7838..204e68b 100644 --- a/core/test/governance.go +++ b/core/test/governance.go @@ -236,7 +236,7 @@ func (g *Governance) IsDKGMPKReady(round uint64) bool { if round >= uint64(len(g.configs)) { return false } - return g.stateModule.IsDKGMPKReady(round, int(g.configs[round].NotarySetSize)/3*2) + return g.stateModule.IsDKGMPKReady(round, int(g.configs[round].NotarySetSize)*2/3+1) } // AddDKGFinalize adds a DKG finalize message. @@ -264,7 +264,35 @@ func (g *Governance) IsDKGFinal(round uint64) bool { if round >= uint64(len(g.configs)) { return false } - return g.stateModule.IsDKGFinal(round, int(g.configs[round].NotarySetSize)/3*2) + return g.stateModule.IsDKGFinal(round, int(g.configs[round].NotarySetSize)*2/3+1) +} + +// AddDKGSuccess adds a DKG success message. +func (g *Governance) AddDKGSuccess(success *typesDKG.Success) { + if g.isProhibited(StateAddDKGSuccess) { + return + } + if err := g.stateModule.RequestChange(StateAddDKGSuccess, success); err != nil { + if err != ErrChangeWontApply { + panic(err) + } + } + g.broadcastPendingStateChanges() +} + +// IsDKGSuccess checks if DKG is success. +func (g *Governance) IsDKGSuccess(round uint64) bool { + if round == 0 || round == 1 { + // Round 0, 1 are genesis round, their configs should be created + // by default. + g.CatchUpWithRound(round) + } + g.lock.RLock() + defer g.lock.RUnlock() + if round >= uint64(len(g.configs)) { + return false + } + return g.stateModule.IsDKGFinal(round, int(g.configs[round].NotarySetSize)*5/6) } // ReportForkVote reports a node for forking votes. diff --git a/core/test/state-change-request.go b/core/test/state-change-request.go index fe55d6e..4ddd40f 100644 --- a/core/test/state-change-request.go +++ b/core/test/state-change-request.go @@ -40,6 +40,7 @@ const ( StateAddDKGMasterPublicKey StateAddDKGMPKReady StateAddDKGFinal + StateAddDKGSuccess StateResetDKG // Configuration related. StateChangeLambdaBA diff --git a/core/test/state.go b/core/test/state.go index 41c6b38..7597377 100644 --- a/core/test/state.go +++ b/core/test/state.go @@ -66,6 +66,9 @@ var ( // ErrStateDKGFinalsNotEqual means DKG finalizations of two states are not // equal. ErrStateDKGFinalsNotEqual = errors.New("dkg finalizations not equal") + // ErrStateDKGSuccessesNotEqual means DKG successes of two states are not + // equal. + ErrStateDKGSuccessesNotEqual = errors.New("dkg successes not equal") // ErrStateCRSsNotEqual means CRSs of two states are not equal. ErrStateCRSsNotEqual = errors.New("crs not equal") // ErrStateDKGResetCountNotEqual means dkgResetCount of two states are not @@ -103,6 +106,7 @@ type State struct { dkgMasterPublicKeys map[uint64]map[types.NodeID]*typesDKG.MasterPublicKey dkgReadys map[uint64]map[types.NodeID]*typesDKG.MPKReady dkgFinals map[uint64]map[types.NodeID]*typesDKG.Finalize + dkgSuccesses map[uint64]map[types.NodeID]*typesDKG.Success crs []common.Hash dkgResetCount map[uint64]uint64 // Other stuffs @@ -150,6 +154,8 @@ func NewState( map[uint64]map[types.NodeID]*typesDKG.MPKReady), dkgFinals: make( map[uint64]map[types.NodeID]*typesDKG.Finalize), + dkgSuccesses: make( + map[uint64]map[types.NodeID]*typesDKG.Success), dkgComplaints: make( map[uint64]map[types.NodeID][]*typesDKG.Complaint), dkgMasterPublicKeys: make( @@ -211,6 +217,9 @@ func (s *State) unpackPayload( case StateAddDKGFinal: v = &typesDKG.Finalize{} err = rlp.DecodeBytes(raw.Payload, v) + case StateAddDKGSuccess: + v = &typesDKG.Success{} + err = rlp.DecodeBytes(raw.Payload, v) case StateResetDKG: var tmp common.Hash err = rlp.DecodeBytes(raw.Payload, &tmp) @@ -393,6 +402,28 @@ func (s *State) Equal(other *State) error { } } } + // Check DKG successes. + if len(s.dkgSuccesses) != len(other.dkgSuccesses) { + return ErrStateDKGSuccessesNotEqual + } + for round, successesForRound := range s.dkgSuccesses { + otherSuccessesForRound, exists := other.dkgSuccesses[round] + if !exists { + return ErrStateDKGSuccessesNotEqual + } + if len(successesForRound) != len(otherSuccessesForRound) { + return ErrStateDKGSuccessesNotEqual + } + for nID, success := range successesForRound { + otherSuccesse, exists := otherSuccessesForRound[nID] + if !exists { + return ErrStateDKGSuccessesNotEqual + } + if !success.Equal(otherSuccesse) { + return ErrStateDKGSuccessesNotEqual + } + } + } // Check CRS part. if len(s.crs) != len(other.crs) { return ErrStateCRSsNotEqual @@ -455,6 +486,7 @@ func (s *State) Clone() (copied *State) { map[uint64]map[types.NodeID]*typesDKG.MasterPublicKey), dkgReadys: make(map[uint64]map[types.NodeID]*typesDKG.MPKReady), dkgFinals: make(map[uint64]map[types.NodeID]*typesDKG.Finalize), + dkgSuccesses: make(map[uint64]map[types.NodeID]*typesDKG.Success), appliedRequests: make(map[common.Hash]struct{}), } // Nodes @@ -493,6 +525,12 @@ func (s *State) Clone() (copied *State) { copied.dkgFinals[round][nID] = CloneDKGFinalize(final) } } + for round, successesForRound := range s.dkgSuccesses { + copied.dkgSuccesses[round] = make(map[types.NodeID]*typesDKG.Success) + for nID, success := range successesForRound { + copied.dkgSuccesses[round][nID] = CloneDKGSuccess(success) + } + } for _, crs := range s.crs { copied.crs = append(copied.crs, crs) } @@ -636,6 +674,11 @@ func (s *State) isValidRequest(req *StateChangeRequest) error { if final.Reset != s.dkgResetCount[final.Round] { return ErrChangeWontApply } + case StateAddDKGSuccess: + success := req.Payload.(*typesDKG.Success) + if success.Reset != s.dkgResetCount[success.Round] { + return ErrChangeWontApply + } case StateAddDKGMasterPublicKey: mpk := req.Payload.(*typesDKG.MasterPublicKey) if mpk.Reset != s.dkgResetCount[mpk.Round] { @@ -747,6 +790,13 @@ func (s *State) applyRequest(req *StateChangeRequest) error { s.dkgFinals[final.Round] = make(map[types.NodeID]*typesDKG.Finalize) } s.dkgFinals[final.Round][final.ProposerID] = final + case StateAddDKGSuccess: + success := req.Payload.(*typesDKG.Success) + if _, exists := s.dkgSuccesses[success.Round]; !exists { + s.dkgSuccesses[success.Round] = + make(map[types.NodeID]*typesDKG.Success) + } + s.dkgSuccesses[success.Round][success.ProposerID] = success case StateResetDKG: round := uint64(len(s.crs) - 1) s.crs[round] = req.Payload.(common.Hash) @@ -755,6 +805,7 @@ func (s *State) applyRequest(req *StateChangeRequest) error { delete(s.dkgReadys, round) delete(s.dkgComplaints, round) delete(s.dkgFinals, round) + delete(s.dkgSuccesses, round) case StateChangeLambdaBA: s.lambdaBA = time.Duration(req.Payload.(uint64)) case StateChangeLambdaDKG: @@ -799,6 +850,8 @@ func (s *State) RequestChange( payload = payload.(*typesDKG.MPKReady) case StateAddDKGFinal: payload = payload.(*typesDKG.Finalize) + case StateAddDKGSuccess: + payload = payload.(*typesDKG.Success) case StateAddDKGMasterPublicKey: payload = payload.(*typesDKG.MasterPublicKey) case StateAddDKGComplaint: @@ -873,7 +926,7 @@ func (s *State) DKGMasterPublicKeys(round uint64) []*typesDKG.MasterPublicKey { func (s *State) IsDKGMPKReady(round uint64, threshold int) bool { s.lock.RLock() defer s.lock.RUnlock() - return len(s.dkgReadys[round]) > threshold + return len(s.dkgReadys[round]) >= threshold } // IsDKGFinal checks if current received dkg finals exceeds threshold. @@ -881,7 +934,15 @@ func (s *State) IsDKGMPKReady(round uint64, threshold int) bool { func (s *State) IsDKGFinal(round uint64, threshold int) bool { s.lock.RLock() defer s.lock.RUnlock() - return len(s.dkgFinals[round]) > threshold + return len(s.dkgFinals[round]) >= threshold +} + +// IsDKGSuccess checks if current received dkg successes exceeds threshold. +// This information won't be snapshot, thus can't be cached in test.Governance. +func (s *State) IsDKGSuccess(round uint64, threshold int) bool { + s.lock.RLock() + defer s.lock.RUnlock() + return len(s.dkgSuccesses[round]) >= threshold } // DKGResetCount returns the reset count for DKG of given round. diff --git a/core/test/state_test.go b/core/test/state_test.go index e3ed9bb..63f9d27 100644 --- a/core/test/state_test.go +++ b/core/test/state_test.go @@ -282,9 +282,9 @@ func (s *StateTestSuite) TestLocalMode() { // Test adding node set, DKG complaints, final, master public key. // Make sure everything is empty before changed. req.Empty(st.DKGMasterPublicKeys(2)) - req.False(st.IsDKGMPKReady(2, 0)) + req.False(st.IsDKGMPKReady(2, 1)) req.Empty(st.DKGComplaints(2)) - req.False(st.IsDKGFinal(2, 0)) + req.False(st.IsDKGFinal(2, 1)) // Add DKG stuffs. masterPubKey := s.newDKGMasterPublicKey(2, 0) ready := s.newDKGMPKReady(2, 0) @@ -296,22 +296,22 @@ func (s *StateTestSuite) TestLocalMode() { req.Len(masterKeyForRound, 1) req.True(masterKeyForRound[0].Equal(masterPubKey)) // Check IsDKGMPKReady. - req.True(st.IsDKGMPKReady(2, 0)) + req.True(st.IsDKGMPKReady(2, 1)) // Check DKGComplaints. compForRound := st.DKGComplaints(2) req.Len(compForRound, 1) req.True(compForRound[0].Equal(comp)) // Check IsDKGFinal. - req.True(st.IsDKGFinal(2, 0)) + req.True(st.IsDKGFinal(2, 1)) // Test ResetDKG. crs = common.NewRandomHash() req.NoError(st.RequestChange(StateResetDKG, crs)) req.Equal(st.CRS(2), crs) // Make sure all DKG fields are cleared. req.Empty(st.DKGMasterPublicKeys(2)) - req.False(st.IsDKGMPKReady(2, 0)) + req.False(st.IsDKGMPKReady(2, 1)) req.Empty(st.DKGComplaints(2)) - req.False(st.IsDKGFinal(2, 0)) + req.False(st.IsDKGFinal(2, 1)) } func (s *StateTestSuite) TestPacking() { @@ -353,9 +353,9 @@ func (s *StateTestSuite) TestPacking() { s.makeDKGChanges(st, masterPubKey, ready, comp, final) // Make sure everything is empty before changed. req.Empty(st.DKGMasterPublicKeys(2)) - req.False(st.IsDKGMPKReady(2, 0)) + req.False(st.IsDKGMPKReady(2, 1)) req.Empty(st.DKGComplaints(2)) - req.False(st.IsDKGFinal(2, 0)) + req.False(st.IsDKGFinal(2, 1)) packAndApply(st) // Check if configs are changed. config, nodes := st.Snapshot() @@ -373,9 +373,9 @@ func (s *StateTestSuite) TestPacking() { req.Len(compForRound, 1) req.True(compForRound[0].Equal(comp)) // Check IsDKGMPKReady. - req.True(st.IsDKGMPKReady(2, 0)) + req.True(st.IsDKGMPKReady(2, 1)) // Check IsDKGFinal. - req.True(st.IsDKGFinal(2, 0)) + req.True(st.IsDKGFinal(2, 1)) // Test ResetDKG. crs = common.NewRandomHash() @@ -384,9 +384,9 @@ func (s *StateTestSuite) TestPacking() { req.Equal(st.CRS(2), crs) // Make sure all DKG fields are cleared. req.Empty(st.DKGMasterPublicKeys(2)) - req.False(st.IsDKGMPKReady(2, 0)) + req.False(st.IsDKGMPKReady(2, 1)) req.Empty(st.DKGComplaints(2)) - req.False(st.IsDKGFinal(2, 0)) + req.False(st.IsDKGFinal(2, 1)) } func (s *StateTestSuite) TestRequestBroadcastAndPack() { diff --git a/core/test/utils.go b/core/test/utils.go index 74cde45..e02e194 100644 --- a/core/test/utils.go +++ b/core/test/utils.go @@ -170,6 +170,20 @@ func CloneDKGFinalize(final *typesDKG.Finalize) ( return } +// CloneDKGSuccess clones a typesDKG.Success instance. +func CloneDKGSuccess(success *typesDKG.Success) ( + copied *typesDKG.Success) { + b, err := rlp.EncodeToBytes(success) + if err != nil { + panic(err) + } + copied = &typesDKG.Success{} + if err = rlp.DecodeBytes(b, copied); err != nil { + panic(err) + } + return +} + // CloneDKGPrivateShare clones a typesDKG.PrivateShare instance. func CloneDKGPrivateShare(prvShare *typesDKG.PrivateShare) ( copied *typesDKG.PrivateShare) { |