From 37257d9e7981661d3f19eae5ea5d49bcedea3698 Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Mon, 1 Apr 2019 22:03:46 +0800 Subject: dexcon: correctly fine DKGSet for not producing blocks (#325) --- consensus/dexcon/dexcon.go | 47 ++++++++++++---------- consensus/dexcon/dexcon_test.go | 2 +- core/governance.go | 46 ++++++++++++--------- dex/downloader/testchain_test.go | 2 +- dex/recovery.go | 2 +- .../dexon-consensus/core/types/dkg/dkg.go | 7 ++-- vendor/vendor.json | 42 +++++++++---------- 7 files changed, 80 insertions(+), 68 deletions(-) diff --git a/consensus/dexcon/dexcon.go b/consensus/dexcon/dexcon.go index 4e474bfa3..c4f399c43 100644 --- a/consensus/dexcon/dexcon.go +++ b/consensus/dexcon/dexcon.go @@ -21,6 +21,7 @@ import ( "fmt" "math/big" + dexCore "github.com/dexon-foundation/dexon-consensus/core" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/consensus" "github.com/dexon-foundation/dexon/core/state" @@ -32,7 +33,7 @@ import ( type GovernanceStateFetcher interface { GetStateForConfigAtRound(round uint64) *vm.GovernanceState - NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) + DKGSetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) } // Dexcon is a delegated proof-of-stake consensus engine. @@ -159,31 +160,33 @@ func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, sta if header.Round > 0 && height.Uint64() == 0 { gs.PushRoundHeight(header.Number) - // Check for dead node and disqualify them. - // A dead node node is defined as: a notary set node that did not propose - // any block in the past round. - addrs, err := d.govStateFetcer.NotarySetNodeKeyAddresses(header.Round - 1) - if err != nil { - panic(err) - } + if header.Round > dexCore.DKGDelayRound { + // Check for dead node and disqualify them. + // A dead node node is defined as: a notary set node that did not propose + // any block in the past round. + addrs, err := d.govStateFetcer.DKGSetNodeKeyAddresses(header.Round - 1) + if err != nil { + panic(err) + } - gcs := d.govStateFetcer.GetStateForConfigAtRound(header.Round - 1) + gcs := d.govStateFetcer.GetStateForConfigAtRound(header.Round - 1) - for addr := range addrs { - offset := gcs.NodesOffsetByNodeKeyAddress(addr) - if offset.Cmp(big.NewInt(0)) < 0 { - panic(fmt.Errorf("invalid notary set found, addr = %s", addr.String())) - } + for addr := range addrs { + offset := gcs.NodesOffsetByNodeKeyAddress(addr) + if offset.Cmp(big.NewInt(0)) < 0 { + panic(fmt.Errorf("invalid notary set found, addr = %s", addr.String())) + } - node := gcs.Node(offset) - lastHeight := gs.LastProposedHeight(node.Owner) - prevRoundHeight := gs.RoundHeight(big.NewInt(int64(header.Round - 1))) + node := gcs.Node(offset) + lastHeight := gs.LastProposedHeight(node.Owner) + prevRoundHeight := gs.RoundHeight(big.NewInt(int64(header.Round - 1))) - if lastHeight.Uint64() < prevRoundHeight.Uint64() { - log.Info("Disqualify node", "round", header.Round, "nodePubKey", hex.EncodeToString(node.PublicKey)) - err = gs.Disqualify(node) - if err != nil { - log.Error("Failed to disqualify node", "err", err) + if lastHeight.Uint64() < prevRoundHeight.Uint64() { + log.Info("Disqualify node", "round", header.Round, "nodePubKey", hex.EncodeToString(node.PublicKey)) + err = gs.Disqualify(node) + if err != nil { + log.Error("Failed to disqualify node", "err", err) + } } } } diff --git a/consensus/dexcon/dexcon_test.go b/consensus/dexcon/dexcon_test.go index bfded8db8..af20fbb1e 100644 --- a/consensus/dexcon/dexcon_test.go +++ b/consensus/dexcon/dexcon_test.go @@ -39,7 +39,7 @@ func (g *govStateFetcher) GetStateForConfigAtRound(_ uint64) *vm.GovernanceState return &vm.GovernanceState{g.statedb} } -func (g *govStateFetcher) NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { +func (g *govStateFetcher) DKGSetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { return make(map[common.Address]struct{}), nil } diff --git a/core/governance.go b/core/governance.go index d40432301..0ebc942be 100644 --- a/core/governance.go +++ b/core/governance.go @@ -12,6 +12,7 @@ import ( coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" + coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" @@ -113,28 +114,28 @@ func (g *Governance) GetStateForDKGAtRound(round uint64) *vm.GovernanceState { return g.GetStateAtRound(round) } -func (d *Governance) CRSRound() uint64 { - return d.GetHeadState().CRSRound().Uint64() +func (g *Governance) CRSRound() uint64 { + return g.GetHeadState().CRSRound().Uint64() } // CRS returns the CRS for a given round. -func (d *Governance) CRS(round uint64) coreCommon.Hash { +func (g *Governance) CRS(round uint64) coreCommon.Hash { if round <= dexCore.DKGDelayRound { - s := d.GetStateAtRound(0) + s := g.GetStateAtRound(0) crs := s.CRS() for i := uint64(0); i < round; i++ { crs = crypto.Keccak256Hash(crs[:]) } return coreCommon.Hash(crs) } - if round > d.CRSRound() { + if round > g.CRSRound() { return coreCommon.Hash{} } var s *vm.GovernanceState - if round == d.CRSRound() { - s = d.GetHeadState() + if round == g.CRSRound() { + s = g.GetHeadState() } else { - s = d.GetStateAtRound(round) + s = g.GetStateAtRound(round) } return coreCommon.Hash(s.CRS()) } @@ -156,8 +157,8 @@ func (g *Governance) GetRoundHeight(round uint64) uint64 { } // NodeSet returns the current node set. -func (d *Governance) NodeSet(round uint64) []coreCrypto.PublicKey { - s := d.GetStateForConfigAtRound(round) +func (g *Governance) NodeSet(round uint64) []coreCrypto.PublicKey { + s := g.GetStateForConfigAtRound(round) var pks []coreCrypto.PublicKey for _, n := range s.QualifiedNodes() { @@ -170,33 +171,40 @@ func (d *Governance) NodeSet(round uint64) []coreCrypto.PublicKey { return pks } -func (d *Governance) PurgeNotarySet(round uint64) { - d.nodeSetCache.Purge(round) +func (g *Governance) PurgeNotarySet(round uint64) { + g.nodeSetCache.Purge(round) } -func (d *Governance) NotarySet(round uint64) (map[string]struct{}, error) { - notarySet, err := d.nodeSetCache.GetNotarySet(round) +func (g *Governance) NotarySet(round uint64) (map[string]struct{}, error) { + notarySet, err := g.nodeSetCache.GetNotarySet(round) if err != nil { return nil, err } r := make(map[string]struct{}, len(notarySet)) for id := range notarySet { - if key, exists := d.nodeSetCache.GetPublicKey(id); exists { + if key, exists := g.nodeSetCache.GetPublicKey(id); exists { r[hex.EncodeToString(key.Bytes())] = struct{}{} } } return r, nil } -func (d *Governance) NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { - notarySet, err := d.nodeSetCache.GetNotarySet(round) +func (g *Governance) DKGSetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { + config := g.Configuration(round) + + mpks := g.DKGMasterPublicKeys(round) + complaints := g.DKGComplaints(round) + threshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ + NotarySetSize: config.NotarySetSize}) + + _, ids, err := dkgTypes.CalcQualifyNodes(mpks, complaints, threshold) if err != nil { return nil, err } - r := make(map[common.Address]struct{}, len(notarySet)) - for id := range notarySet { + r := make(map[common.Address]struct{}) + for id := range ids { r[vm.IdToAddress(id)] = struct{}{} } return r, nil diff --git a/dex/downloader/testchain_test.go b/dex/downloader/testchain_test.go index b59a83b2c..e5c5e4d23 100644 --- a/dex/downloader/testchain_test.go +++ b/dex/downloader/testchain_test.go @@ -343,6 +343,6 @@ func (g *govStateFetcher) GetStateForConfigAtRound(round uint64) *vm.GovernanceS return nil } -func (g *govStateFetcher) NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { +func (g *govStateFetcher) DKGSetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { return make(map[common.Address]struct{}), nil } diff --git a/dex/recovery.go b/dex/recovery.go index adeb1f612..72d3a5376 100644 --- a/dex/recovery.go +++ b/dex/recovery.go @@ -479,7 +479,7 @@ func (r *Recovery) Votes(height uint64) (uint64, error) { return 0, err } - notarySet, err := r.gov.NotarySetNodeKeyAddresses(r.gov.Round()) + notarySet, err := r.gov.DKGSetNodeKeyAddresses(r.gov.Round()) if err != nil { return 0, err } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go index 6572d1e9d..301cef7da 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go @@ -320,7 +320,8 @@ func (gpk *GroupPublicKey) VerifySignature( return gpk.GroupPublicKey.VerifySignature(hash, sig) } -func calcQualifyNodes( +// CalcQualifyNodes returns the qualified nodes. +func CalcQualifyNodes( mpks []*MasterPublicKey, complaints []*Complaint, threshold int) ( qualifyIDs cryptoDKG.IDs, qualifyNodeIDs map[types.NodeID]struct{}, err error) { if len(mpks) < threshold { @@ -371,7 +372,7 @@ func NewGroupPublicKey( threshold int) ( *GroupPublicKey, error) { qualifyIDs, qualifyNodeIDs, err := - calcQualifyNodes(mpks, complaints, threshold) + CalcQualifyNodes(mpks, complaints, threshold) if err != nil { return nil, err } @@ -417,7 +418,7 @@ func NewNodePublicKeys( threshold int) ( *NodePublicKeys, error) { qualifyIDs, qualifyNodeIDs, err := - calcQualifyNodes(mpks, complaints, threshold) + CalcQualifyNodes(mpks, complaints, threshold) if err != nil { return nil, err } diff --git a/vendor/vendor.json b/vendor/vendor.json index a3182f836..4ad0a8c6c 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -141,16 +141,16 @@ { "checksumSHA1": "In6vBHYUsX7DUIGiFN2hQggBgvI=", "path": "github.com/dexon-foundation/dexon-consensus/common", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { "checksumSHA1": "fE4+Jlw+2y4JJMHtGuHxHWqqPfY=", "path": "github.com/dexon-foundation/dexon-consensus/core", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, @@ -165,64 +165,64 @@ { "checksumSHA1": "tQSbYCu5P00lUhKsx3IbBZCuSLY=", "path": "github.com/dexon-foundation/dexon-consensus/core/crypto", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { "checksumSHA1": "mMdctxTa/jNwAwZjjYoyEZdLoF8=", "path": "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { "checksumSHA1": "BhLKK8RveoLaeXc9UyUKMwQqchU=", "path": "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { "checksumSHA1": "hj/KetWUHp+1CX+50V0QnCthfWc=", "path": "github.com/dexon-foundation/dexon-consensus/core/db", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { "checksumSHA1": "pxAzlI5kjyIAJSX+/aRGjjhR+pw=", "path": "github.com/dexon-foundation/dexon-consensus/core/syncer", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { "checksumSHA1": "TmZF8DyrzGHTTfXXIFnKlzva3mU=", "path": "github.com/dexon-foundation/dexon-consensus/core/types", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { - "checksumSHA1": "yoVRmvJDCp/1jSfY7wMt2LBQ9e8=", + "checksumSHA1": "5BskQaPpK94/ecmvy845hwM6F+8=", "path": "github.com/dexon-foundation/dexon-consensus/core/types/dkg", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, { "checksumSHA1": "pvJYiUy3EubRjeh5VYpt73Jjg1Q=", "path": "github.com/dexon-foundation/dexon-consensus/core/utils", - "revision": "ecc5e12b1ac4826e302607769f5b831ab4c27046", - "revisionTime": "2019-04-01T04:25:09Z", + "revision": "b11406ecd961bc26f4382e06c8061708a58063e0", + "revisionTime": "2019-04-01T11:36:40Z", "version": "single-chain", "versionExact": "single-chain" }, -- cgit