diff options
author | Wei-Ning Huang <w@dexon.org> | 2019-03-20 11:55:01 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-20 11:55:01 +0800 |
commit | d72b0255b760b3b0ded0c1ce59985754b8000a78 (patch) | |
tree | 30f6203962b52a41bf6548aadabba569d4809e03 /core/governance.go | |
parent | d22b689fdfafc3535e1008dd4e3b05d81588f807 (diff) | |
download | dexon-d72b0255b760b3b0ded0c1ce59985754b8000a78.tar dexon-d72b0255b760b3b0ded0c1ce59985754b8000a78.tar.gz dexon-d72b0255b760b3b0ded0c1ce59985754b8000a78.tar.bz2 dexon-d72b0255b760b3b0ded0c1ce59985754b8000a78.tar.lz dexon-d72b0255b760b3b0ded0c1ce59985754b8000a78.tar.xz dexon-d72b0255b760b3b0ded0c1ce59985754b8000a78.tar.zst dexon-d72b0255b760b3b0ded0c1ce59985754b8000a78.zip |
consensus: dexcon: disqualify dead node (#280)
Since a qualified node might fail stopped, we need to remove them from
qualified nodes to maintain network integrity. We do this by inspect the
previous round to see if there are dead nodes. A dead node is a notary
set node that does not propose any block in the previous round. We
disqualify them by fining them so their staked value is 1 wei below
minStake. This make them unqualified for being notary set in the follow
on rounds.
Diffstat (limited to 'core/governance.go')
-rw-r--r-- | core/governance.go | 111 |
1 files changed, 102 insertions, 9 deletions
diff --git a/core/governance.go b/core/governance.go index db0e60b6c..68d5de821 100644 --- a/core/governance.go +++ b/core/governance.go @@ -1,16 +1,22 @@ package core import ( + "encoding/hex" "fmt" "math/big" "time" + coreCommon "github.com/dexon-foundation/dexon-consensus/common" dexCore "github.com/dexon-foundation/dexon-consensus/core" + coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" + 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" + "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/rlp" ) @@ -41,11 +47,14 @@ func (g *governanceStateDB) StateAt(height uint64) (*state.StateDB, error) { } type Governance struct { - db GovernanceStateDB + db GovernanceStateDB + nodeSetCache *dexCore.NodeSetCache } func NewGovernance(db GovernanceStateDB) *Governance { - return &Governance{db: db} + g := &Governance{db: db} + g.nodeSetCache = dexCore.NewNodeSetCache(g) + return g } func (g *Governance) GetHeadState() *vm.GovernanceState { @@ -93,6 +102,43 @@ func (g *Governance) GetStateAtRound(round uint64) *vm.GovernanceState { return &vm.GovernanceState{StateDB: s} } +func (g *Governance) GetStateForDKGAtRound(round uint64) *vm.GovernanceState { + dkgRound := g.GetHeadState().DKGRound().Uint64() + if round > dkgRound { + return nil + } + if round == dkgRound { + return g.GetHeadState() + } + return g.GetStateAtRound(round) +} + +func (d *Governance) CRSRound() uint64 { + return d.GetHeadState().CRSRound().Uint64() +} + +// CRS returns the CRS for a given round. +func (d *Governance) CRS(round uint64) coreCommon.Hash { + if round <= dexCore.DKGDelayRound { + s := d.GetStateAtRound(0) + crs := s.CRS() + for i := uint64(0); i < round; i++ { + crs = crypto.Keccak256Hash(crs[:]) + } + return coreCommon.Hash(crs) + } + if round > d.CRSRound() { + return coreCommon.Hash{} + } + var s *vm.GovernanceState + if round == d.CRSRound() { + s = d.GetHeadState() + } else { + s = d.GetStateAtRound(round) + } + return coreCommon.Hash(s.CRS()) +} + func (g *Governance) Configuration(round uint64) *coreTypes.Config { configHelper := g.GetStateForConfigAtRound(round) c := configHelper.Configuration() @@ -110,15 +156,62 @@ func (g *Governance) GetRoundHeight(round uint64) uint64 { return g.GetHeadState().RoundHeight(big.NewInt(int64(round))).Uint64() } -func (g *Governance) GetStateForDKGAtRound(round uint64) *vm.GovernanceState { - dkgRound := g.GetHeadState().DKGRound().Uint64() - if round > dkgRound { - return nil +// NodeSet returns the current node set. +func (d *Governance) NodeSet(round uint64) []coreCrypto.PublicKey { + s := d.GetStateForConfigAtRound(round) + var pks []coreCrypto.PublicKey + + for _, n := range s.QualifiedNodes() { + pk, err := coreEcdsa.NewPublicKeyFromByteSlice(n.PublicKey) + if err != nil { + panic(err) + } + pks = append(pks, pk) } - if round == dkgRound { - return g.GetHeadState() + return pks +} + +func (d *Governance) NotarySet(round uint64) (map[string]struct{}, error) { + notarySet, err := d.nodeSetCache.GetNotarySet(round) + if err != nil { + return nil, err } - return g.GetStateAtRound(round) + + r := make(map[string]struct{}, len(notarySet)) + for id := range notarySet { + if key, exists := d.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) + if err != nil { + return nil, err + } + + r := make(map[common.Address]struct{}, len(notarySet)) + for id := range notarySet { + r[vm.IdToAddress(id)] = struct{}{} + } + return r, nil +} + +func (d *Governance) DKGSet(round uint64) (map[string]struct{}, error) { + dkgSet, err := d.nodeSetCache.GetDKGSet(round) + if err != nil { + return nil, err + } + + r := make(map[string]struct{}, len(dkgSet)) + for id := range dkgSet { + if key, exists := d.nodeSetCache.GetPublicKey(id); exists { + r[hex.EncodeToString(key.Bytes())] = struct{}{} + } + } + return r, nil } func (g *Governance) DKGComplaints(round uint64) []*dkgTypes.Complaint { |