aboutsummaryrefslogtreecommitdiffstats
path: root/core/test
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2019-04-15 11:44:04 +0800
committerGitHub <noreply@github.com>2019-04-15 11:44:04 +0800
commit79be89a6b0b1d24b889e7c9fe0244026af4d49d0 (patch)
treebacd2dd8a224d2cffbe9965439707df7fa2888de /core/test
parent7abe09214fbf04f9f1f7f4f6ec57cd1f924953d6 (diff)
downloadtangerine-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.go32
-rw-r--r--core/test/state-change-request.go1
-rw-r--r--core/test/state.go65
-rw-r--r--core/test/state_test.go24
-rw-r--r--core/test/utils.go14
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) {