diff options
Diffstat (limited to 'dex/downloader/governance.go')
-rw-r--r-- | dex/downloader/governance.go | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/dex/downloader/governance.go b/dex/downloader/governance.go new file mode 100644 index 000000000..40233f1a8 --- /dev/null +++ b/dex/downloader/governance.go @@ -0,0 +1,170 @@ +package downloader + +import ( + "math/big" + "sync" + "time" + + dexCore "github.com/dexon-foundation/dexon-consensus/core" + 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/types" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/ethdb" + "github.com/dexon-foundation/dexon/log" + "github.com/dexon-foundation/dexon/rlp" + "github.com/dexon-foundation/dexon/trie" +) + +// This is a goverance for fast sync +type governance struct { + db ethdb.Database + headRoot common.Hash + headHeight uint64 + height2Root map[uint64]common.Hash + mu sync.Mutex +} + +func newGovernance(headState *types.GovState) *governance { + db := ethdb.NewMemDatabase() + g := &governance{ + db: db, + headRoot: headState.Root, + headHeight: headState.Number.Uint64(), + height2Root: make(map[uint64]common.Hash), + } + g.StoreState(headState) + + statedb, err := state.New(headState.Root, state.NewDatabase(g.db)) + if statedb == nil || err != nil { + log.Error("New governance fail", "statedb == nil", statedb == nil, "err", err) + } + return g +} + +func (g *governance) getHeadHelper() *vm.GovernanceStateHelper { + return g.getHelper(g.headRoot) +} + +func (g *governance) getHelperByRound(round uint64) *vm.GovernanceStateHelper { + height := g.GetRoundHeight(round) + root, exists := g.height2Root[height] + if !exists { + log.Debug("Gov get helper by round", "round", round, "exists", exists) + return nil + } + return g.getHelper(root) +} + +func (g *governance) getHelper(root common.Hash) *vm.GovernanceStateHelper { + statedb, err := state.New(root, state.NewDatabase(g.db)) + if statedb == nil || err != nil { + return nil + } + return &vm.GovernanceStateHelper{statedb} +} + +func (g *governance) GetRoundHeight(round uint64) uint64 { + var h uint64 + if helper := g.getHeadHelper(); helper != nil { + h = helper.RoundHeight(big.NewInt(int64(round))).Uint64() + } + return h +} + +func (g *governance) StoreState(s *types.GovState) { + g.mu.Lock() + defer g.mu.Unlock() + + // store the hight -> root mapping + g.height2Root[s.Number.Uint64()] = s.Root + + // store the account + for _, node := range s.Proof { + g.db.Put(crypto.Keccak256(node), node) + } + + // store the storage + triedb := trie.NewDatabase(g.db) + t, err := trie.New(common.Hash{}, triedb) + if err != nil { + panic(err) + } + for _, kv := range s.Storage { + t.TryUpdate(kv[0], kv[1]) + } + t.Commit(nil) + triedb.Commit(t.Hash(), false) + + if s.Number.Uint64() > g.headHeight { + log.Debug("Gov head root changed", "number", s.Number.Uint64()) + g.headRoot = s.Root + g.headHeight = s.Number.Uint64() + } +} + +// Return the genesis configuration if round == 0. +func (g *governance) Configuration(round uint64) *coreTypes.Config { + if round < dexCore.ConfigRoundShift { + round = 0 + } else { + round -= dexCore.ConfigRoundShift + } + helper := g.getHelperByRound(round) + if helper == nil { + log.Warn("Get config helper fail", "round - round shift", round) + return nil + } + c := helper.Configuration() + return &coreTypes.Config{ + NumChains: c.NumChains, + LambdaBA: time.Duration(c.LambdaBA) * time.Millisecond, + LambdaDKG: time.Duration(c.LambdaDKG) * time.Millisecond, + K: int(c.K), + PhiRatio: c.PhiRatio, + NotarySetSize: c.NotarySetSize, + DKGSetSize: c.DKGSetSize, + RoundInterval: time.Duration(c.RoundInterval) * time.Millisecond, + MinBlockInterval: time.Duration(c.MinBlockInterval) * time.Millisecond, + } +} + +// DKGComplaints gets all the DKGComplaints of round. +func (g *governance) DKGComplaints(round uint64) []*dkgTypes.Complaint { + helper := g.getHeadHelper() + var dkgComplaints []*dkgTypes.Complaint + for _, pk := range helper.DKGComplaints(big.NewInt(int64(round))) { + x := new(dkgTypes.Complaint) + if err := rlp.DecodeBytes(pk, x); err != nil { + panic(err) + } + dkgComplaints = append(dkgComplaints, x) + } + return dkgComplaints +} + +// DKGMasterPublicKeys gets all the DKGMasterPublicKey of round. +func (g *governance) DKGMasterPublicKeys(round uint64) []*dkgTypes.MasterPublicKey { + helper := g.getHeadHelper() + var dkgMasterPKs []*dkgTypes.MasterPublicKey + for _, pk := range helper.DKGMasterPublicKeys(big.NewInt(int64(round))) { + x := new(dkgTypes.MasterPublicKey) + if err := rlp.DecodeBytes(pk, x); err != nil { + panic(err) + } + dkgMasterPKs = append(dkgMasterPKs, x) + } + return dkgMasterPKs +} + +// IsDKGFinal checks if DKG is final. +func (g *governance) IsDKGFinal(round uint64) bool { + helper := g.getHeadHelper() + threshold := 2*uint64(g.Configuration(round).DKGSetSize)/3 + 1 + count := helper.DKGFinalizedsCount(big.NewInt(int64(round))).Uint64() + return count >= threshold +} |