aboutsummaryrefslogblamecommitdiffstats
path: root/dex/governance.go
blob: 766920a620eb110f1bad8c292dac524a69690979 (plain) (tree)
1
2
3
4
5
6
7
8
9


           
                 
                      
                      


                  





                                                                                 
 

                                                      
                                                   


                                                  
                                               
                                               


                              




                                          

 

                                                                       

                                                                                 
                               



                                                                       
         

                                                   

 

                                                                                              
                                       
                             
         
                                            








                                                                               
 













                                                                                       


                                               






                                                                                   













                                                                                       
         

 










                                                                              
                                             
 



                                             
                                








                                                              


                                                                            


                                  

                                                              
                            
                                                               

 




                                            
                                         
                                                                       

                                                                
                                                                           
                       
                                                                        





                                                     
                                                                     
         

 
                                          




                                                                         




                                                                           

                  

 

                                                                                   




                                                                                   
                                                                           





                                                     
                                                                        
         

 
                                       
                                                                                         

                                                                     
                                                    
                       
                                                                                




                                                                         
                                                                             





                                                     
                                                                          
         

 
                                                     
                                                                              
                            
                                               
                                                                      
                                            
                                                              




                                                        


                                                   
                                                                                                           

                                                                           
                                                          
                       
                                                                          




                                                                         
                                                                                   





                                                     
                                                                                
         


                                                                
                                                                                          
                            
                                                    
                                                                            
                                                  
                                                              




                                                      
 

                                              
                                                                                   

                                                                    
                                                
                       
                                                                               




                                                                         
                                                                            





                                                     
                                                                         
         



                                                          
                            


                                                                        
 
 

                                                              

 




                                                                     

         
                                                      
                                   
                                                                           
                                                                           
                 
         
                     

 



                                                                              

         
                                                   
                                
                                                                           
                                                                           
                 
         
                     
 
package dex

import (
    "context"
    "crypto/ecdsa"
    "encoding/hex"
    "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/types"
    "github.com/dexon-foundation/dexon/core/vm"
    "github.com/dexon-foundation/dexon/crypto"
    "github.com/dexon-foundation/dexon/log"
    "github.com/dexon-foundation/dexon/params"
    "github.com/dexon-foundation/dexon/rlp"
    "github.com/dexon-foundation/dexon/rpc"
)

type DexconGovernance struct {
    b            *DexAPIBackend
    chainConfig  *params.ChainConfig
    privateKey   *ecdsa.PrivateKey
    address      common.Address
    nodeSetCache *dexCore.NodeSetCache
}

// NewDexconGovernance retruns a governance implementation of the DEXON
// consensus governance interface.
func NewDexconGovernance(backend *DexAPIBackend, chainConfig *params.ChainConfig,
    privKey *ecdsa.PrivateKey) *DexconGovernance {
    g := &DexconGovernance{
        b:           backend,
        chainConfig: chainConfig,
        privateKey:  privKey,
        address:     crypto.PubkeyToAddress(privKey.PublicKey),
    }
    g.nodeSetCache = dexCore.NewNodeSetCache(g)
    return g
}

func (d *DexconGovernance) getRoundHeight(ctx context.Context, round uint64) (uint64, error) {
    state, _, err := d.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
    if state == nil || err != nil {
        return 0, err
    }
    s := vm.GovernanceStateHelper{state}
    return s.RoundHeight(big.NewInt(int64(round))).Uint64(), nil
}

func (d *DexconGovernance) getGovState() *vm.GovernanceStateHelper {
    ctx := context.Background()
    state, _, err := d.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
    if state == nil || err != nil {
        return nil
    }

    return &vm.GovernanceStateHelper{state}
}

func (d *DexconGovernance) getGovStateAtRound(round uint64) *vm.GovernanceStateHelper {
    ctx := context.Background()
    blockHeight, err := d.getRoundHeight(ctx, round)
    if err != nil {
        return nil
    }

    state, _, err := d.b.StateAndHeaderByNumber(ctx, rpc.BlockNumber(blockHeight))
    if state == nil || err != nil {
        return nil
    }
    return &vm.GovernanceStateHelper{state}
}

// DexconConfiguration return raw config in state.
func (d *DexconGovernance) DexconConfiguration(round uint64) *params.DexconConfig {
    s := d.getGovStateAtRound(round)
    return s.Configuration()
}

// Configuration returns the system configuration for consensus core to use.
func (d *DexconGovernance) Configuration(round uint64) *coreTypes.Config {
    s := d.getGovStateAtRound(round)
    c := s.Configuration()

    return &coreTypes.Config{
        NumChains:        c.NumChains,
        LambdaBA:         time.Duration(c.LambdaBA) * time.Millisecond,
        LambdaDKG:        time.Duration(c.LambdaDKG) * time.Millisecond,
        K:                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 (d *DexconGovernance) sendGovTx(ctx context.Context, data []byte) error {
    gasPrice, err := d.b.SuggestPrice(ctx)
    if err != nil {
        return err
    }

    nonce, err := d.b.GetPoolNonce(ctx, d.address)
    if err != nil {
        return err
    }

    log.Info("sendGovTx", "nonce", nonce)

    tx := types.NewTransaction(
        nonce,
        vm.GovernanceContractAddress,
        big.NewInt(0),
        uint64(2000000),
        gasPrice,
        data)

    signer := types.NewEIP155Signer(d.chainConfig.ChainID)

    tx, err = types.SignTx(tx, signer, d.privateKey)
    if err != nil {
        return err
    }

    log.Info("Send governance transaction", "fullhash", tx.Hash().Hex())

    return d.b.SendTx(ctx, tx)
}

// CRS returns the CRS for a given round.
func (d *DexconGovernance) CRS(round uint64) coreCommon.Hash {
    s := d.getGovState()
    return coreCommon.Hash(s.CRS(big.NewInt(int64(round))))
}

func (d *DexconGovernance) LenCRS() uint64 {
    s := d.getGovState()
    return s.LenCRS().Uint64()
}

// ProposeCRS send proposals of a new CRS
func (d *DexconGovernance) ProposeCRS(round uint64, signedCRS []byte) {
    method := vm.GovernanceContractName2Method["proposeCRS"]

    res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS)
    if err != nil {
        log.Error("failed to pack proposeCRS input", "err", err)
        return
    }

    data := append(method.Id(), res...)
    err = d.sendGovTx(context.Background(), data)
    if err != nil {
        log.Error("failed to send proposeCRS tx", "err", err)
    }
}

// NodeSet returns the current notary set.
func (d *DexconGovernance) NodeSet(round uint64) []coreCrypto.PublicKey {
    s := d.getGovStateAtRound(round)
    var pks []coreCrypto.PublicKey

    for _, n := range s.Nodes() {
        pk, err := coreEcdsa.NewPublicKeyFromByteSlice(n.PublicKey)
        if err != nil {
            panic(err)
        }
        pks = append(pks, pk)
    }
    return pks
}

// NotifyRoundHeight register the mapping between round and height.
func (d *DexconGovernance) NotifyRoundHeight(targetRound, consensusHeight uint64) {
    method := vm.GovernanceContractName2Method["snapshotRound"]

    res, err := method.Inputs.Pack(
        big.NewInt(int64(targetRound)), big.NewInt(int64(consensusHeight)))
    if err != nil {
        log.Error("failed to pack snapshotRound input", "err", err)
        return
    }

    data := append(method.Id(), res...)
    err = d.sendGovTx(context.Background(), data)
    if err != nil {
        log.Error("failed to send snapshotRound tx", "err", err)
    }
}

// AddDKGComplaint adds a DKGComplaint.
func (d *DexconGovernance) AddDKGComplaint(round uint64, complaint *dkgTypes.Complaint) {
    method := vm.GovernanceContractName2Method["addDKGComplaint"]

    encoded, err := rlp.EncodeToBytes(complaint)
    if err != nil {
        log.Error("failed to RLP encode complaint to bytes", "err", err)
        return
    }

    res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded)
    if err != nil {
        log.Error("failed to pack addDKGComplaint input", "err", err)
        return
    }

    data := append(method.Id(), res...)
    err = d.sendGovTx(context.Background(), data)
    if err != nil {
        log.Error("failed to send addDKGComplaint tx", "err", err)
    }
}

// DKGComplaints gets all the DKGComplaints of round.
func (d *DexconGovernance) DKGComplaints(round uint64) []*dkgTypes.Complaint {
    s := d.getGovState()
    var dkgComplaints []*dkgTypes.Complaint
    for _, pk := range s.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
}

// AddDKGMasterPublicKey adds a DKGMasterPublicKey.
func (d *DexconGovernance) AddDKGMasterPublicKey(round uint64, masterPublicKey *dkgTypes.MasterPublicKey) {
    method := vm.GovernanceContractName2Method["addDKGMasterPublicKey"]

    encoded, err := rlp.EncodeToBytes(masterPublicKey)
    if err != nil {
        log.Error("failed to RLP encode mpk to bytes", "err", err)
        return
    }

    res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded)
    if err != nil {
        log.Error("failed to pack addDKGMasterPublicKey input", "err", err)
        return
    }

    data := append(method.Id(), res...)
    err = d.sendGovTx(context.Background(), data)
    if err != nil {
        log.Error("failed to send addDKGMasterPublicKey tx", "err", err)
    }
}

// DKGMasterPublicKeys gets all the DKGMasterPublicKey of round.
func (d *DexconGovernance) DKGMasterPublicKeys(round uint64) []*dkgTypes.MasterPublicKey {
    s := d.getGovState()
    var dkgMasterPKs []*dkgTypes.MasterPublicKey
    for _, pk := range s.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
}

// AddDKGFinalize adds a DKG finalize message.
func (d *DexconGovernance) AddDKGFinalize(round uint64, final *dkgTypes.Finalize) {
    method := vm.GovernanceContractName2Method["addDKGFinalize"]

    encoded, err := rlp.EncodeToBytes(final)
    if err != nil {
        log.Error("failed to RLP encode finalize to bytes", "err", err)
        return
    }

    res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded)
    if err != nil {
        log.Error("failed to pack addDKGFinalize input", "err", err)
        return
    }

    data := append(method.Id(), res...)
    err = d.sendGovTx(context.Background(), data)
    if err != nil {
        log.Error("failed to send addDKGFinalize tx", "err", err)
    }
}

// IsDKGFinal checks if DKG is final.
func (d *DexconGovernance) IsDKGFinal(round uint64) bool {
    s := d.getGovState()
    threshold := 2*s.DKGSetSize().Uint64()/3 + 1
    count := s.DKGFinalizedsCount(big.NewInt(int64(round))).Uint64()
    return count >= threshold
}

func (d *DexconGovernance) GetNumChains(round uint64) uint32 {
    return d.Configuration(round).NumChains
}

func (d *DexconGovernance) NotarySet(
    round uint64, chainID uint32) (map[string]struct{}, error) {
    notarySet, err := d.nodeSetCache.GetNotarySet(round, chainID)
    if err != nil {
        return nil, err
    }

    r := make(map[string]struct{}, len(notarySet))
    for id := range notarySet {
        if key, exists := d.nodeSetCache.GetPublicKey(id); exists {
            r[hex.EncodeToString(key.Bytes()[1:])] = struct{}{}
        }
    }
    return r, nil
}

func (d *DexconGovernance) 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()[1:])] = struct{}{}
        }
    }
    return r, nil
}