// Copyright 2018 The dexon-consensus Authors // This file is part of the dexon-consensus library. // // The dexon-consensus library is free software: you can redistribute it // and/or modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // The dexon-consensus library is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser // General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the dexon-consensus library. If not, see // . 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" 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" "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" ) 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.GetGovStateHelperAtRound(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) { data, err := vm.PackProposeCRS(round, signedCRS) if err != nil { log.Error("failed to pack proposeCRS input", "err", err) return } 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.GetGovStateHelperAtRound(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 } // AddDKGComplaint adds a DKGComplaint. func (d *DexconGovernance) AddDKGComplaint(round uint64, complaint *dkgTypes.Complaint) { data, err := vm.PackAddDKGComplaint(round, complaint) if err != nil { log.Error("failed to pack addDKGComplaint input", "err", err) return } 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) { data, err := vm.PackAddDKGMasterPublicKey(round, masterPublicKey) if err != nil { log.Error("failed to pack addDKGMasterPublicKey input", "err", err) return } err = d.sendGovTx(context.Background(), data) if err != nil { log.Error("failed to send addDKGMasterPublicKey tx", "err", err) } } // AddDKGMPKReady adds a DKG mpk ready message. func (d *DexconGovernance) AddDKGMPKReady(round uint64, ready *dkgTypes.MPKReady) { data, err := vm.PackAddDKGMPKReady(round, ready) if err != nil { log.Error("failed to pack addDKGMPKReady input", "err", err) return } err = d.sendGovTx(context.Background(), data) if err != nil { log.Error("failed to send addDKGMPKReady tx", "err", err) } } // AddDKGFinalize adds a DKG finalize message. func (d *DexconGovernance) AddDKGFinalize(round uint64, final *dkgTypes.Finalize) { data, err := vm.PackAddDKGFinalize(round, final) if err != nil { log.Error("failed to pack addDKGFinalize input", "err", err) return } err = d.sendGovTx(context.Background(), data) if err != nil { log.Error("failed to send addDKGFinalize tx", "err", err) } } // ReportForkVote reports a node for forking votes. func (d *DexconGovernance) ReportForkVote(vote1, vote2 *coreTypes.Vote) { data, err := vm.PackReportForkVote(vote1, vote2) if err != nil { log.Error("failed to pack report fork vote input", "err", err) return } err = d.sendGovTx(context.Background(), data) if err != nil { log.Error("failed to send report fork vote tx", "err", err) } } // ReportForkBlock reports a node for forking blocks. func (d *DexconGovernance) ReportForkBlock(block1, block2 *coreTypes.Block) { data, err := vm.PackReportForkBlock(block1, block2) if err != nil { log.Error("failed to pack report fork block input", "err", err) return } err = d.sendGovTx(context.Background(), data) if err != nil { log.Error("failed to send report fork block 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 }