diff options
-rw-r--r-- | consensus/dexcon/dexcon.go | 42 | ||||
-rw-r--r-- | consensus/dexcon/dexcon_test.go | 10 | ||||
-rw-r--r-- | core/governance.go | 111 | ||||
-rw-r--r-- | core/vm/oracle_contract_abi.go | 21 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 49 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 88 | ||||
-rw-r--r-- | dex/app_test.go | 12 | ||||
-rw-r--r-- | dex/downloader/testchain_test.go | 4 | ||||
-rw-r--r-- | dex/governance.go | 99 | ||||
-rw-r--r-- | dex/recovery.go | 2 | ||||
-rw-r--r-- | params/config.go | 8 |
11 files changed, 294 insertions, 152 deletions
diff --git a/consensus/dexcon/dexcon.go b/consensus/dexcon/dexcon.go index c837e3a43..3e520438b 100644 --- a/consensus/dexcon/dexcon.go +++ b/consensus/dexcon/dexcon.go @@ -17,6 +17,8 @@ package dexcon import ( + "encoding/hex" + "fmt" "math/big" "github.com/dexon-foundation/dexon/common" @@ -24,11 +26,13 @@ import ( "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/log" "github.com/dexon-foundation/dexon/rpc" ) type GovernanceStateFetcher interface { GetStateForConfigAtRound(round uint64) *vm.GovernanceState + NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) } // Dexcon is a delegated proof-of-stake consensus engine. @@ -137,8 +141,39 @@ func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, sta gs := vm.GovernanceState{state} height := gs.RoundHeight(new(big.Int).SetUint64(header.Round)) + + // The first block of a round is found. if header.Round > 0 && height.Uint64() == 0 { gs.PushRoundHeight(header.Number) + + // Check for dead node and disqualify them. + // A dead node node is defined as: a notary set node that did not propose + // any block in the past round. + addrs, err := d.govStateFetcer.NotarySetNodeKeyAddresses(header.Round - 1) + if err != nil { + panic(err) + } + + gcs := d.govStateFetcer.GetStateForConfigAtRound(header.Round - 1) + + for addr := range addrs { + offset := gcs.NodesOffsetByNodeKeyAddress(addr) + if offset.Cmp(big.NewInt(0)) < 0 { + panic(fmt.Errorf("invalid notary set found, addr = %s", addr.String())) + } + + node := gcs.Node(offset) + lastHeight := gs.LastProposedHeight(node.Owner) + prevRoundHeight := gs.RoundHeight(big.NewInt(int64(header.Round - 1))) + + if lastHeight.Uint64() < prevRoundHeight.Uint64() { + log.Info("Disqualify node", "round", header.Round, "nodePubKey", hex.EncodeToString(node.PublicKey)) + err = gs.Disqualify(node) + if err != nil { + log.Error("Failed to disqualify node", "err", err) + } + } + } } // Distribute block reward and halving condition. @@ -147,16 +182,17 @@ func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, sta } else { reward := d.calculateBlockReward(int64(header.Round), state) state.AddBalance(header.Coinbase, reward) - + header.Reward = reward gs.IncTotalSupply(reward) - config := gs.Configuration() + // Record last proposed height. + gs.PutLastProposedHeight(header.Coinbase, header.Number) // Check if halving checkpoint reached. + config := gs.Configuration() if gs.TotalSupply().Cmp(config.NextHalvingSupply) >= 0 { gs.MiningHalved() } - header.Reward = reward } header.Root = state.IntermediateRoot(true) diff --git a/consensus/dexcon/dexcon_test.go b/consensus/dexcon/dexcon_test.go index f34823570..0181a80f3 100644 --- a/consensus/dexcon/dexcon_test.go +++ b/consensus/dexcon/dexcon_test.go @@ -31,14 +31,18 @@ import ( "github.com/dexon-foundation/dexon/params" ) -type GovStateFetcher struct { +type govStateFetcher struct { statedb *state.StateDB } -func (g *GovStateFetcher) GetStateForConfigAtRound(_ uint64) *vm.GovernanceState { +func (g *govStateFetcher) GetStateForConfigAtRound(_ uint64) *vm.GovernanceState { return &vm.GovernanceState{g.statedb} } +func (g *govStateFetcher) NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { + return make(map[common.Address]struct{}), nil +} + type DexconTestSuite struct { suite.Suite @@ -86,7 +90,7 @@ func (d *DexconTestSuite) SetupTest() { func (d *DexconTestSuite) TestBlockRewardCalculation() { consensus := New() - consensus.SetGovStateFetcher(&GovStateFetcher{d.stateDB}) + consensus.SetGovStateFetcher(&govStateFetcher{d.stateDB}) d.s.IncTotalStaked(big.NewInt(1e18)) diff --git a/core/governance.go b/core/governance.go index da310a1cd..bb49efb53 100644 --- a/core/governance.go +++ b/core/governance.go @@ -1,16 +1,22 @@ package core import ( + "encoding/hex" "fmt" "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/state" "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/rlp" ) @@ -41,11 +47,14 @@ func (g *governanceStateDB) StateAt(height uint64) (*state.StateDB, error) { } type Governance struct { - db GovernanceStateDB + db GovernanceStateDB + nodeSetCache *dexCore.NodeSetCache } func NewGovernance(db GovernanceStateDB) *Governance { - return &Governance{db: db} + g := &Governance{db: db} + g.nodeSetCache = dexCore.NewNodeSetCache(g) + return g } func (g *Governance) GetHeadState() *vm.GovernanceState { @@ -93,6 +102,43 @@ func (g *Governance) GetStateAtRound(round uint64) *vm.GovernanceState { return &vm.GovernanceState{StateDB: s} } +func (g *Governance) GetStateForDKGAtRound(round uint64) *vm.GovernanceState { + dkgRound := g.GetHeadState().DKGRound().Uint64() + if round > dkgRound { + return nil + } + if round == dkgRound { + return g.GetHeadState() + } + return g.GetStateAtRound(round) +} + +func (d *Governance) CRSRound() uint64 { + return d.GetHeadState().CRSRound().Uint64() +} + +// CRS returns the CRS for a given round. +func (d *Governance) CRS(round uint64) coreCommon.Hash { + if round <= dexCore.DKGDelayRound { + s := d.GetStateAtRound(0) + crs := s.CRS() + for i := uint64(0); i < round; i++ { + crs = crypto.Keccak256Hash(crs[:]) + } + return coreCommon.Hash(crs) + } + if round > d.CRSRound() { + return coreCommon.Hash{} + } + var s *vm.GovernanceState + if round == d.CRSRound() { + s = d.GetHeadState() + } else { + s = d.GetStateAtRound(round) + } + return coreCommon.Hash(s.CRS()) +} + func (g *Governance) Configuration(round uint64) *coreTypes.Config { configHelper := g.GetStateForConfigAtRound(round) c := configHelper.Configuration() @@ -110,15 +156,62 @@ func (g *Governance) GetRoundHeight(round uint64) uint64 { return g.GetHeadState().RoundHeight(big.NewInt(int64(round))).Uint64() } -func (g *Governance) GetStateForDKGAtRound(round uint64) *vm.GovernanceState { - dkgRound := g.GetHeadState().DKGRound().Uint64() - if round > dkgRound { - return nil +// NodeSet returns the current node set. +func (d *Governance) NodeSet(round uint64) []coreCrypto.PublicKey { + s := d.GetStateForConfigAtRound(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) } - if round == dkgRound { - return g.GetHeadState() + return pks +} + +func (d *Governance) NotarySet(round uint64) (map[string]struct{}, error) { + notarySet, err := d.nodeSetCache.GetNotarySet(round) + if err != nil { + return nil, err } - return g.GetStateAtRound(round) + + 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 *Governance) NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { + notarySet, err := d.nodeSetCache.GetNotarySet(round) + if err != nil { + return nil, err + } + + r := make(map[common.Address]struct{}, len(notarySet)) + for id := range notarySet { + r[vm.IdToAddress(id)] = struct{}{} + } + return r, nil +} + +func (d *Governance) 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 } func (g *Governance) DKGComplaints(round uint64) []*dkgTypes.Complaint { diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go index f0845eb7b..cd037b068 100644 --- a/core/vm/oracle_contract_abi.go +++ b/core/vm/oracle_contract_abi.go @@ -130,7 +130,7 @@ const GovernanceABIJSON = ` "type": "uint256" }, { - "name": "unstaked_at", + "name": "unstakedAt", "type": "uint256" } ], @@ -530,6 +530,25 @@ const GovernanceABIJSON = ` }, { "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "lastProposedHeight", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, "inputs": [], "name": "minGasPrice", "outputs": [ diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index c138a6b4a..ac6d7315c 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -62,6 +62,7 @@ const ( nodesLoc nodesOffsetByAddressLoc nodesOffsetByNodeKeyAddressLoc + lastProposedHeightLoc crsRoundLoc crsLoc dkgRoundLoc @@ -332,7 +333,8 @@ func (s *GovernanceState) DecTotalStaked(amount *big.Int) { // string location; // string url; // uint256 unstaked; -// uint256 unstaked_at; +// uint256 unstakedAt; +// uint256 lastProposedHeight; // } // // Node[] nodes; @@ -543,6 +545,16 @@ func (s *GovernanceState) GetNodeByID(id coreTypes.NodeID) (*nodeInfo, error) { return node, nil } +// mapping(address => uint256) public lastProposedHeight; +func (s *GovernanceState) LastProposedHeight(addr common.Address) *big.Int { + loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes()) + return s.getStateBigInt(loc) +} +func (s *GovernanceState) PutLastProposedHeight(addr common.Address, height *big.Int) { + loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes()) + s.setStateBigInt(loc, height) +} + // uint256 public crsRound; func (s *GovernanceState) CRSRound() *big.Int { return s.getStateBigInt(big.NewInt(crsRoundLoc)) @@ -960,6 +972,31 @@ func (s *GovernanceState) Register( s.IncTotalStaked(staked) } +func (s *GovernanceState) Disqualify(n *nodeInfo) error { + nodeAddr, err := publicKeyToNodeKeyAddress(n.PublicKey) + if err != nil { + return err + } + + // Node might already been unstaked in the latest state. + offset := s.NodesOffsetByNodeKeyAddress(nodeAddr) + if offset.Cmp(big.NewInt(0)) < 0 { + return errors.New("node does not exist") + } + + // Fine the node so it's staked value is 1 wei under minStake. + node := s.Node(offset) + extra := new(big.Int).Sub(new(big.Int).Sub(node.Staked, node.Fined), s.MinStake()) + amount := new(big.Int).Add(extra, big.NewInt(1)) + + if amount.Cmp(big.NewInt(0)) > 0 { + node.Fined = new(big.Int).Add(node.Fined, amount) + s.UpdateNode(offset, node) + } + + return nil +} + const decimalMultiplier = 100000000.0 // Configuration returns the current configuration. @@ -2248,6 +2285,16 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return res, nil + case "lastProposedHeight": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.LastProposedHeight(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "lockupPeriod": res, err := method.Outputs.Pack(g.state.LockupPeriod()) if err != nil { diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go index 4b25b39da..55876f9b2 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -59,10 +59,22 @@ func randomBytes(minLength, maxLength int32) []byte { return b } +func newPrefundAccount(s *state.StateDB) (*ecdsa.PrivateKey, common.Address) { + privKey, err := crypto.GenerateKey() + if err != nil { + panic(err) + } + address := crypto.PubkeyToAddress(privKey.PublicKey) + + s.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) + return privKey, address +} + type GovernanceStateTestSuite struct { suite.Suite - s *GovernanceState + stateDB *state.StateDB + s *GovernanceState } func (g *GovernanceStateTestSuite) SetupTest() { @@ -71,7 +83,13 @@ func (g *GovernanceStateTestSuite) SetupTest() { if err != nil { panic(err) } + g.stateDB = statedb g.s = &GovernanceState{statedb} + + config := params.TestnetChainConfig.Dexcon + g.s.Initialize(config, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e7))) + + statedb.Commit(true) } func (g *GovernanceStateTestSuite) TestReadWriteEraseBytes() { @@ -117,6 +135,31 @@ func (g *GovernanceStateTestSuite) TestReadWriteErase1DArray() { } } +func (g *GovernanceStateTestSuite) TestDisqualify() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + g.s.Register(addr, pk, "Test", "test@dexon.org", "Taipei", "https://test.com", g.s.MinStake()) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(uint64(0), node.Fined.Uint64()) + + // Disqualify + g.s.Disqualify(node) + node = g.s.Node(big.NewInt(0)) + g.Require().Equal(uint64(1), node.Fined.Uint64()) + + // Disqualify again should change nothing. + g.s.Disqualify(node) + node = g.s.Node(big.NewInt(0)) + g.Require().Equal(uint64(1), node.Fined.Uint64()) + + // Disqualify none exist node should return error. + privKey2, _ := newPrefundAccount(g.stateDB) + node.PublicKey = crypto.FromECDSAPub(&privKey2.PublicKey) + g.Require().Error(g.s.Disqualify(node)) +} + func TestGovernanceState(t *testing.T) { suite.Run(t, new(GovernanceStateTestSuite)) } @@ -203,17 +246,6 @@ func (g *OracleContractsTestSuite) TearDownTest() { } } -func (g *OracleContractsTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, common.Address) { - privKey, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - address := crypto.PubkeyToAddress(privKey.PublicKey) - - g.stateDB.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) - return privKey, address -} - func (g *OracleContractsTestSuite) call( contractAddr common.Address, caller common.Address, input []byte, value *big.Int) ([]byte, error) { @@ -225,7 +257,7 @@ func (g *OracleContractsTestSuite) call( } func (g *OracleContractsTestSuite) TestTransferOwnership() { - _, addr := g.newPrefundAccount() + _, addr := newPrefundAccount(g.stateDB) input, err := GovernanceABI.ABI.Pack("transferOwnership", addr) g.Require().NoError(err) @@ -241,7 +273,7 @@ func (g *OracleContractsTestSuite) TestTransferOwnership() { } func (g *OracleContractsTestSuite) TestTransferNodeOwnership() { - privKey, addr := g.newPrefundAccount() + privKey, addr := newPrefundAccount(g.stateDB) pk := crypto.FromECDSAPub(&privKey.PublicKey) nodeKeyAddr := crypto.PubkeyToAddress(privKey.PublicKey) @@ -253,14 +285,14 @@ func (g *OracleContractsTestSuite) TestTransferNodeOwnership() { offset := g.s.NodesOffsetByAddress(addr) - _, newAddr := g.newPrefundAccount() + _, newAddr := newPrefundAccount(g.stateDB) newNodeKeyAddr := crypto.PubkeyToAddress(privKey.PublicKey) input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", newAddr) g.Require().NoError(err) // Call with non-owner. - _, noneOwner := g.newPrefundAccount() + _, noneOwner := newPrefundAccount(g.stateDB) _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0)) g.Require().Error(err) @@ -273,7 +305,7 @@ func (g *OracleContractsTestSuite) TestTransferNodeOwnership() { g.Require().Equal(offset.Uint64(), g.s.NodesOffsetByNodeKeyAddress(newNodeKeyAddr).Uint64()) // Call with owner. - privKey2, addr2 := g.newPrefundAccount() + privKey2, addr2 := newPrefundAccount(g.stateDB) pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test1@dexon.org", "Taipei", "https://dexon.org") g.Require().NoError(err) @@ -288,7 +320,7 @@ func (g *OracleContractsTestSuite) TestTransferNodeOwnership() { } func (g *OracleContractsTestSuite) TestStakingMechanism() { - privKey, addr := g.newPrefundAccount() + privKey, addr := newPrefundAccount(g.stateDB) pk := crypto.FromECDSAPub(&privKey.PublicKey) // Register with some stake. @@ -374,7 +406,7 @@ func (g *OracleContractsTestSuite) TestStakingMechanism() { amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) // 2nd node Stake. - privKey2, addr2 := g.newPrefundAccount() + privKey2, addr2 := newPrefundAccount(g.stateDB) pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test2@dexon.org", "Taipei", "https://dexon.org") g.Require().NoError(err) @@ -440,7 +472,7 @@ func (g *OracleContractsTestSuite) TestStakingMechanism() { } func (g *OracleContractsTestSuite) TestFine() { - privKey, addr := g.newPrefundAccount() + privKey, addr := newPrefundAccount(g.stateDB) pk := crypto.FromECDSAPub(&privKey.PublicKey) // Stake. @@ -452,7 +484,7 @@ func (g *OracleContractsTestSuite) TestFine() { g.Require().Equal(1, len(g.s.QualifiedNodes())) g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - _, finePayer := g.newPrefundAccount() + _, finePayer := newPrefundAccount(g.stateDB) amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) // Paying to node without fine should fail. @@ -497,7 +529,7 @@ func (g *OracleContractsTestSuite) TestFine() { } func (g *OracleContractsTestSuite) TestUpdateConfiguration() { - _, addr := g.newPrefundAccount() + _, addr := newPrefundAccount(g.stateDB) input, err := GovernanceABI.ABI.Pack("updateConfiguration", new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), @@ -523,7 +555,7 @@ func (g *OracleContractsTestSuite) TestUpdateConfiguration() { } func (g *OracleContractsTestSuite) TestConfigurationReading() { - _, addr := g.newPrefundAccount() + _, addr := newPrefundAccount(g.stateDB) // CRS. input, err := GovernanceABI.ABI.Pack("crs") @@ -657,7 +689,7 @@ func (g *OracleContractsTestSuite) TestConfigurationReading() { } func (g *OracleContractsTestSuite) TestReportForkVote() { - key, addr := g.newPrefundAccount() + key, addr := newPrefundAccount(g.stateDB) pkBytes := crypto.FromECDSAPub(&key.PublicKey) // Stake. @@ -723,7 +755,7 @@ func (g *OracleContractsTestSuite) TestReportForkVote() { } func (g *OracleContractsTestSuite) TestReportForkBlock() { - key, addr := g.newPrefundAccount() + key, addr := newPrefundAccount(g.stateDB) pkBytes := crypto.FromECDSAPub(&key.PublicKey) // Stake. @@ -800,7 +832,7 @@ func (g *OracleContractsTestSuite) TestReportForkBlock() { } func (g *OracleContractsTestSuite) TestMiscVariableReading() { - privKey, addr := g.newPrefundAccount() + privKey, addr := newPrefundAccount(g.stateDB) pk := crypto.FromECDSAPub(&privKey.PublicKey) input, err := GovernanceABI.ABI.Pack("totalSupply") @@ -898,7 +930,7 @@ func (v *testTSigVerifierMock) VerifySignature(coreCommon.Hash, coreCrypto.Signa func (g *OracleContractsTestSuite) TestResetDKG() { for i := uint32(0); i < g.config.DKGSetSize; i++ { - privKey, addr := g.newPrefundAccount() + privKey, addr := newPrefundAccount(g.stateDB) pk := crypto.FromECDSAPub(&privKey.PublicKey) // Stake. @@ -1033,7 +1065,7 @@ func (g *OracleContractsTestSuite) TestResetDKG() { g.context.BlockNumber = big.NewInt( roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*80/100) - _, addr := g.newPrefundAccount() + _, addr := newPrefundAccount(g.stateDB) newCRS := randomBytes(common.HashLength, common.HashLength) input, err := GovernanceABI.ABI.Pack("resetDKG", newCRS) g.Require().NoError(err) diff --git a/dex/app_test.go b/dex/app_test.go index 7b158dd9e..e648abdbd 100644 --- a/dex/app_test.go +++ b/dex/app_test.go @@ -2299,12 +2299,10 @@ func newDexon(masterKey *ecdsa.PrivateKey, accountNum int) (*Dexon, []*ecdsa.Pri db := ethdb.NewMemDatabase() genesis := core.DefaultTestnetGenesisBlock() - genesis.Alloc = core.GenesisAlloc{ - crypto.PubkeyToAddress(masterKey.PublicKey): { - Balance: big.NewInt(100000000000000000), - Staked: big.NewInt(50000000000000000), - PublicKey: crypto.FromECDSAPub(&masterKey.PublicKey), - }, + genesis.Alloc[crypto.PubkeyToAddress(masterKey.PublicKey)] = core.GenesisAccount{ + Balance: big.NewInt(100000000000000000), + Staked: big.NewInt(50000000000000000), + PublicKey: crypto.FromECDSAPub(&masterKey.PublicKey), } var accounts []*ecdsa.PrivateKey @@ -2322,7 +2320,7 @@ func newDexon(masterKey *ecdsa.PrivateKey, accountNum int) (*Dexon, []*ecdsa.Pri } genesis.Config.Dexcon.BlockGasLimit = 2000000 - genesis.Config.Dexcon.RoundLength = 60 + genesis.Config.Dexcon.RoundLength = 600 genesis.Config.Dexcon.Owner = crypto.PubkeyToAddress(masterKey.PublicKey) chainConfig, _, err := core.SetupGenesisBlock(db, genesis) diff --git a/dex/downloader/testchain_test.go b/dex/downloader/testchain_test.go index 722159bc0..15528c509 100644 --- a/dex/downloader/testchain_test.go +++ b/dex/downloader/testchain_test.go @@ -342,3 +342,7 @@ func (g *govStateFetcher) GetStateForConfigAtRound(round uint64) *vm.GovernanceS } return nil } + +func (g *govStateFetcher) NotarySetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) { + return make(map[common.Address]struct{}), nil +} diff --git a/dex/governance.go b/dex/governance.go index c2f2918b1..0d6ca0eba 100644 --- a/dex/governance.go +++ b/dex/governance.go @@ -20,13 +20,8 @@ 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" @@ -42,11 +37,10 @@ import ( type DexconGovernance struct { *core.Governance - b *DexAPIBackend - chainConfig *params.ChainConfig - privateKey *ecdsa.PrivateKey - address common.Address - nodeSetCache *dexCore.NodeSetCache + b *DexAPIBackend + chainConfig *params.ChainConfig + privateKey *ecdsa.PrivateKey + address common.Address } // NewDexconGovernance returns a governance implementation of the DEXON @@ -61,7 +55,6 @@ func NewDexconGovernance(backend *DexAPIBackend, chainConfig *params.ChainConfig privateKey: privKey, address: crypto.PubkeyToAddress(privKey.PublicKey), } - g.nodeSetCache = dexCore.NewNodeSetCache(g) return g } @@ -110,36 +103,10 @@ func (d *DexconGovernance) sendGovTx(ctx context.Context, data []byte) error { return d.b.SendTx(ctx, tx) } -// CRS returns the CRS for a given round. -func (d *DexconGovernance) CRS(round uint64) coreCommon.Hash { - if round <= dexCore.DKGDelayRound { - s := d.GetStateAtRound(0) - crs := s.CRS() - for i := uint64(0); i < round; i++ { - crs = crypto.Keccak256Hash(crs[:]) - } - return coreCommon.Hash(crs) - } - if round > d.CRSRound() { - return coreCommon.Hash{} - } - var s *vm.GovernanceState - if round == d.CRSRound() { - s = d.GetHeadState() - } else { - s = d.GetStateAtRound(round) - } - return coreCommon.Hash(s.CRS()) -} - func (d *DexconGovernance) Round() uint64 { return d.b.CurrentBlock().Round() } -func (d *DexconGovernance) CRSRound() uint64 { - return d.GetHeadState().CRSRound().Uint64() -} - // ProposeCRS send proposals of a new CRS func (d *DexconGovernance) ProposeCRS(round uint64, signedCRS []byte) { data, err := vm.PackProposeCRS(round, signedCRS) @@ -154,21 +121,6 @@ func (d *DexconGovernance) ProposeCRS(round uint64, signedCRS []byte) { } } -// NodeSet returns the current node set. -func (d *DexconGovernance) NodeSet(round uint64) []coreCrypto.PublicKey { - s := d.GetStateForConfigAtRound(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) @@ -253,49 +205,6 @@ func (d *DexconGovernance) ReportForkBlock(block1, block2 *coreTypes.Block) { } } -func (d *DexconGovernance) NotarySet(round uint64) (map[string]struct{}, error) { - notarySet, err := d.nodeSetCache.GetNotarySet(round) - 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) NotarySetAddresses(round uint64) (map[common.Address]struct{}, error) { - notarySet, err := d.nodeSetCache.GetNotarySet(round) - if err != nil { - return nil, err - } - - r := make(map[common.Address]struct{}, len(notarySet)) - for id := range notarySet { - r[vm.IdToAddress(id)] = 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 -} - func (d *DexconGovernance) ResetDKG(newSignedCRS []byte) { data, err := vm.PackResetDKG(newSignedCRS) if err != nil { diff --git a/dex/recovery.go b/dex/recovery.go index cfc8ae203..0e5c60e1a 100644 --- a/dex/recovery.go +++ b/dex/recovery.go @@ -442,7 +442,7 @@ func (r *Recovery) Votes(height uint64) (uint64, error) { return 0, err } - notarySet, err := r.gov.NotarySetAddresses(r.gov.Round()) + notarySet, err := r.gov.NotarySetNodeKeyAddresses(r.gov.Round()) if err != nil { return 0, err } diff --git a/params/config.go b/params/config.go index f61a9b6df..1eb016019 100644 --- a/params/config.go +++ b/params/config.go @@ -26,10 +26,10 @@ import ( // Genesis hashes to enforce below configs on. var ( - MainnetGenesisHash = common.HexToHash("0x8ac8e240790046eb72225eb2a2381f3ef5a7a88291fffc702ba08503cc2a1341") - TestnetGenesisHash = common.HexToHash("0x3caf9a977e579b4de001956508b57563a4b61742c66f49323a1294ad214da29d") - TaipeiGenesisHash = common.HexToHash("0x13e85a0207f2888ac9c1746c94d5d7fd87ff637cbd080b42d5db1252341f4428") - YilanGenesisHash = common.HexToHash("0x6b1a94b5e4c24665942a3b768bd98b39d61771a5eaba97c0466644d78d8a2f11") + MainnetGenesisHash = common.HexToHash("0xa48b24e2e500e3a7f222673c240dcef6c4c4fd720e6c4653349adc6acae96fb8") + TestnetGenesisHash = common.HexToHash("0xf67217d7715cea0b2e8acada9b6a8e538fc3df0129dab32f8c1f6baff7a50034") + TaipeiGenesisHash = common.HexToHash("0xdcf32f39178f33cea762dd0e87e2be1eb9327997cb9cf20ef0645030d3ece6be") + YilanGenesisHash = common.HexToHash("0xbb48abd6cc576af3d0f84173e3476045def2f57c2e891e75a8835036d7012b82") ) // TrustedCheckpoints associates each known checkpoint with the genesis hash of |