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 }