aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei-Ning Huang <w@dexon.org>2019-03-20 11:55:01 +0800
committerWei-Ning Huang <w@byzantine-lab.io>2019-06-13 18:11:44 +0800
commita7d069aae1a4bc237a9a3a0f10efeba77c473bcb (patch)
tree74a2138655ed6e47ed77f8cb16a7f9d2a6613ec1
parent2e9584d1d6690de6a4fa1ee6da6f988b2d746681 (diff)
downloadgo-tangerine-a7d069aae1a4bc237a9a3a0f10efeba77c473bcb.tar
go-tangerine-a7d069aae1a4bc237a9a3a0f10efeba77c473bcb.tar.gz
go-tangerine-a7d069aae1a4bc237a9a3a0f10efeba77c473bcb.tar.bz2
go-tangerine-a7d069aae1a4bc237a9a3a0f10efeba77c473bcb.tar.lz
go-tangerine-a7d069aae1a4bc237a9a3a0f10efeba77c473bcb.tar.xz
go-tangerine-a7d069aae1a4bc237a9a3a0f10efeba77c473bcb.tar.zst
go-tangerine-a7d069aae1a4bc237a9a3a0f10efeba77c473bcb.zip
consensus: dexcon: disqualify dead node (#280)
Since a qualified node might fail stopped, we need to remove them from qualified nodes to maintain network integrity. We do this by inspect the previous round to see if there are dead nodes. A dead node is a notary set node that does not propose any block in the previous round. We disqualify them by fining them so their staked value is 1 wei below minStake. This make them unqualified for being notary set in the follow on rounds.
-rw-r--r--consensus/dexcon/dexcon.go42
-rw-r--r--consensus/dexcon/dexcon_test.go10
-rw-r--r--core/governance.go111
-rw-r--r--core/vm/oracle_contract_abi.go21
-rw-r--r--core/vm/oracle_contracts.go49
-rw-r--r--core/vm/oracle_contracts_test.go88
-rw-r--r--dex/app_test.go12
-rw-r--r--dex/downloader/testchain_test.go4
-rw-r--r--dex/governance.go99
-rw-r--r--dex/recovery.go2
-rw-r--r--params/config.go8
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