package core import ( "fmt" "math/big" "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/core/state" "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/rlp" ) type GovernanceStateDB interface { State() (*state.StateDB, error) StateAt(height uint64) (*state.StateDB, error) } func NewGovernanceStateDB(bc *BlockChain) GovernanceStateDB { return &governanceStateDB{bc: bc} } type governanceStateDB struct { bc *BlockChain } func (g *governanceStateDB) State() (*state.StateDB, error) { return g.bc.State() } func (g *governanceStateDB) StateAt(height uint64) (*state.StateDB, error) { header := g.bc.GetHeaderByNumber(height) if header == nil { return nil, fmt.Errorf("header at %d not exists", height) } return g.bc.StateAt(header.Root) } type Governance struct { db GovernanceStateDB } func NewGovernance(db GovernanceStateDB) *Governance { return &Governance{db: db} } func (g *Governance) GetHeadHelper() *vm.GovernanceStateHelper { headState, err := g.db.State() if err != nil { log.Error("Governance head state not ready", "err", err) panic(err) } return &vm.GovernanceStateHelper{StateDB: headState} } func (g *Governance) getHelperAtRound(round uint64) *vm.GovernanceStateHelper { height := g.GetRoundHeight(round) // Sanity check if round != 0 && height == 0 { log.Error("Governance state incorrect", "round", round, "got height", height) panic("round != 0 but height == 0") } s, err := g.db.StateAt(height) if err != nil { log.Error("Governance state not ready", "round", round, "height", height, "err", err) panic(err) } return &vm.GovernanceStateHelper{StateDB: s} } func (g *Governance) GetConfigHelper(round uint64) *vm.GovernanceStateHelper { if round < dexCore.ConfigRoundShift { round = 0 } else { round -= dexCore.ConfigRoundShift } return g.getHelperAtRound(round) } func (g *Governance) GetRoundHeight(round uint64) uint64 { return g.GetHeadHelper().RoundHeight(big.NewInt(int64(round))).Uint64() } func (g *Governance) Configuration(round uint64) *coreTypes.Config { configHelper := g.GetConfigHelper(round) c := configHelper.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, } } func (g *Governance) DKGComplaints(round uint64) []*dkgTypes.Complaint { headHelper := g.GetHeadHelper() var dkgComplaints []*dkgTypes.Complaint for _, pk := range headHelper.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 } func (g *Governance) DKGMasterPublicKeys(round uint64) []*dkgTypes.MasterPublicKey { headHelper := g.GetHeadHelper() return headHelper.UniqueDKGMasterPublicKeys(big.NewInt(int64(round))) } func (g *Governance) IsDKGMPKReady(round uint64) bool { headHelper := g.GetHeadHelper() config := g.Configuration(round) threshold := 2*uint64(config.DKGSetSize)/3 + 1 count := headHelper.DKGMPKReadysCount(big.NewInt(int64(round))).Uint64() return count >= threshold } func (g *Governance) IsDKGFinal(round uint64) bool { headHelper := g.GetHeadHelper() config := g.Configuration(round) threshold := 2*uint64(config.DKGSetSize)/3 + 1 count := headHelper.DKGFinalizedsCount(big.NewInt(int64(round))).Uint64() return count >= threshold }