package dex import ( "context" "crypto/ecdsa" "encoding/hex" "math/big" 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" dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core" "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" ) type DexconGovernance struct { *core.Governance b *DexAPIBackend chainConfig *params.ChainConfig privateKey *ecdsa.PrivateKey address common.Address nodeSetCache *dexCore.NodeSetCache } // NewDexconGovernance returns a governance implementation of the DEXON // consensus governance interface. func NewDexconGovernance(backend *DexAPIBackend, chainConfig *params.ChainConfig, privKey *ecdsa.PrivateKey) *DexconGovernance { g := &DexconGovernance{ Governance: core.NewGovernance( core.NewGovernanceStateDB(backend.dex.BlockChain())), b: backend, chainConfig: chainConfig, privateKey: privKey, address: crypto.PubkeyToAddress(privKey.PublicKey), } g.nodeSetCache = dexCore.NewNodeSetCache(g) return g } // DexconConfiguration return raw config in state. func (d *DexconGovernance) DexconConfiguration(round uint64) *params.DexconConfig { return d.GetConfigHelper(round).Configuration() } 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 } // Increase gasPrice to 10 times of suggested gas price to make sure it will // be included in time. gasPrice = new(big.Int).Mul(gasPrice, big.NewInt(10)) tx := types.NewTransaction( nonce, vm.GovernanceContractAddress, big.NewInt(0), uint64(10000000), 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(), "nonce", nonce) return d.b.SendTx(ctx, tx) } // CRS returns the CRS for a given round. func (d *DexconGovernance) CRS(round uint64) coreCommon.Hash { s := d.GetHeadHelper() return coreCommon.Hash(s.CRS(big.NewInt(int64(round)))) } func (d *DexconGovernance) LenCRS() uint64 { s := d.GetHeadHelper() 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 node set. func (d *DexconGovernance) NodeSet(round uint64) []coreCrypto.PublicKey { s := d.GetConfigHelper(round) var pks []coreCrypto.PublicKey for _, n := range s.QualifiedNodes() { 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) } } // 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) } } // 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) } } 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())] = 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())] = struct{}{} } } return r, nil }