aboutsummaryrefslogblamecommitdiffstats
path: root/dex/downloader/governance.go
blob: 40233f1a89f78f2464ea56414a79dedd198eacbc (plain) (tree)









































































































































































                                                                                              
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
}