From 8c33027b943e08de21b7bddb82fecc2b2a5664a2 Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Tue, 18 Sep 2018 17:57:36 +0800 Subject: core: refine governance interface to reduce Get* methods (#114) Since we have a bunch of static configurations in the governance contract, instead of using a Get* method for each of them, we instead implement a GetConfiguration() method to return a structure of the configurations. --- core/consensus.go | 34 ++++++++++-------- core/consensus_test.go | 10 +++--- core/interfaces.go | 28 +++------------ core/test/governance.go | 72 +++++++++++++------------------------- core/ticker.go | 2 +- core/types/config.go | 35 +++++++++++++++++++ integration_test/utils.go | 4 +-- integration_test/validator.go | 4 +-- simulation/governance.go | 80 +++++++++++++------------------------------ 9 files changed, 116 insertions(+), 153 deletions(-) create mode 100644 core/types/config.go diff --git a/core/consensus.go b/core/consensus.go index 6f59638..5179baf 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -116,6 +116,7 @@ type Consensus struct { ID types.ValidatorID app Application gov Governance + config *types.Config baModules []*agreement receivers []*consensusReceiver rbModule *reliableBroadcast @@ -140,11 +141,13 @@ func NewConsensus( network Network, prv crypto.PrivateKey, sigToPub SigToPubFn) *Consensus { - validatorSet := gov.GetValidatorSet() + + config := gov.GetConfiguration(0) + validatorSet := gov.GetNotarySet() // Setup acking by information returned from Governace. rb := newReliableBroadcast() - rb.setChainNum(gov.GetNumChains()) + rb.setChainNum(config.NumChains) for vID := range validatorSet { rb.addValidator(vID) } @@ -157,9 +160,9 @@ func NewConsensus( validators = append(validators, vID) } to := newTotalOrdering( - uint64(gov.GetTotalOrderingK()), - uint64(float32(len(validatorSet)-1)*gov.GetPhiRatio()+1), - gov.GetNumChains()) + uint64(config.K), + uint64(float32(len(validatorSet)-1)*config.PhiRatio+1), + config.NumChains) con := &Consensus{ ID: types.NewValidatorID(prv.PublicKey()), @@ -169,6 +172,7 @@ func NewConsensus( ccModule: newCompactionChain(db, sigToPub), app: newNonBlockingApplication(app), gov: gov, + config: config, db: db, network: network, tickerObj: newTicker(gov), @@ -178,9 +182,9 @@ func NewConsensus( ctxCancel: ctxCancel, } - con.baModules = make([]*agreement, con.gov.GetNumChains()) - con.receivers = make([]*consensusReceiver, con.gov.GetNumChains()) - for i := uint32(0); i < con.gov.GetNumChains(); i++ { + con.baModules = make([]*agreement, con.config.NumChains) + con.receivers = make([]*consensusReceiver, con.config.NumChains) + for i := uint32(0); i < con.config.NumChains; i++ { chainID := i con.receivers[chainID] = &consensusReceiver{ consensus: con, @@ -196,7 +200,7 @@ func NewConsensus( con.ID, con.receivers[chainID], validators, - newGenesisLeaderSelector(con.gov.GetGenesisCRS(), con.sigToPub), + newGenesisLeaderSelector(con.config.GenesisCRS, con.sigToPub), con.sigToPub, blockProposer, ) @@ -206,8 +210,8 @@ func NewConsensus( // Run starts running DEXON Consensus. func (con *Consensus) Run() { - ticks := make([]chan struct{}, 0, con.gov.GetNumChains()) - for i := uint32(0); i < con.gov.GetNumChains(); i++ { + ticks := make([]chan struct{}, 0, con.config.NumChains) + for i := uint32(0); i < con.config.NumChains; i++ { tick := make(chan struct{}) ticks = append(ticks, tick) go con.runBA(i, tick) @@ -226,7 +230,7 @@ func (con *Consensus) Run() { func (con *Consensus) runBA(chainID uint32, tick <-chan struct{}) { // TODO(jimmy-dexon): move this function inside agreement. - validatorSet := con.gov.GetValidatorSet() + validatorSet := con.gov.GetNotarySet() validators := make(types.ValidatorIDs, 0, len(validatorSet)) for vID := range validatorSet { validators = append(validators, vID) @@ -270,8 +274,8 @@ func (con *Consensus) RunLegacy() { go con.processMsg(con.network.ReceiveChan(), con.ProcessBlock) chainID := uint32(0) - hashes := make(common.Hashes, 0, len(con.gov.GetValidatorSet())) - for vID := range con.gov.GetValidatorSet() { + hashes := make(common.Hashes, 0, len(con.gov.GetNotarySet())) + for vID := range con.gov.GetNotarySet() { hashes = append(hashes, vID.Hash) } sort.Sort(hashes) @@ -551,7 +555,7 @@ func (con *Consensus) PrepareGenesisBlock(b *types.Block, // ProcessNotaryAck is the entry point to submit one notary ack. func (con *Consensus) ProcessNotaryAck(notaryAck *types.NotaryAck) (err error) { notaryAck = notaryAck.Clone() - if _, exists := con.gov.GetValidatorSet()[notaryAck.ProposerID]; !exists { + if _, exists := con.gov.GetNotarySet()[notaryAck.ProposerID]; !exists { err = ErrProposerNotValidator return } diff --git a/core/consensus_test.go b/core/consensus_test.go index e799675..dd64cc2 100644 --- a/core/consensus_test.go +++ b/core/consensus_test.go @@ -81,8 +81,8 @@ func (s *ConsensusTestSuite) prepareConsensus( app := test.NewApp() db, err := blockdb.NewMemBackedBlockDB() s.Require().Nil(err) - prv, exist := gov.PrivateKeys[vID] - s.Require().True(exist) + prv, exist := gov.GetPrivateKey(vID) + s.Require().Nil(exist) con := NewConsensus(app, gov, db, &network{}, prv, eth.SigToPub) return &con.app, con } @@ -107,7 +107,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { ) s.Require().Nil(err) - for vID := range gov.GetValidatorSet() { + for vID := range gov.GetNotarySet() { validators = append(validators, vID) } @@ -329,7 +329,7 @@ func (s *ConsensusTestSuite) TestPrepareBlock() { validators []types.ValidatorID ) s.Require().Nil(err) - for vID := range gov.GetValidatorSet() { + for vID := range gov.GetNotarySet() { validators = append(validators, vID) } // Setup core.Consensus and test.App. @@ -384,7 +384,7 @@ func (s *ConsensusTestSuite) TestPrepareGenesisBlock() { validators []types.ValidatorID ) s.Require().Nil(err) - for vID := range gov.GetValidatorSet() { + for vID := range gov.GetNotarySet() { validators = append(validators, vID) } _, con := s.prepareConsensus(gov, validators[0]) diff --git a/core/interfaces.go b/core/interfaces.go index 2b616ab..0a8ca8f 100644 --- a/core/interfaces.go +++ b/core/interfaces.go @@ -20,8 +20,6 @@ package core import ( "time" - "github.com/shopspring/decimal" - "github.com/dexon-foundation/dexon-consensus-core/common" "github.com/dexon-foundation/dexon-consensus-core/core/types" ) @@ -75,29 +73,13 @@ type Network interface { // Note that there are a lot more methods in the governance contract, that this // interface only define those that are required to run the consensus algorithm. type Governance interface { - // Get the current validator set and it's corresponding stake. - GetValidatorSet() map[types.ValidatorID]decimal.Decimal - - // Get K. - GetTotalOrderingK() int - - // Get PhiRatio. - GetPhiRatio() float32 - - // Get Number of shards. - GetNumShards() uint32 - - // Get Number of chains. - GetNumChains() uint32 - - // Get Genesis CRS. - GetGenesisCRS() string + // GetConfiguration returns the configuration at a given block height. + GetConfiguration(blockHeight uint64) *types.Config - // Get configuration change events after an epoch. - GetConfigurationChangeEvent(epoch int) []types.ConfigurationChangeEvent + // Get the current validator set. + GetNotarySet() map[types.ValidatorID]struct{} - // Get lambda for BA. - GetLambda() time.Duration + //// DKG-related methods. // AddDKGComplaint adds a DKGComplaint. AddDKGComplaint(complaint *types.DKGComplaint) diff --git a/core/test/governance.go b/core/test/governance.go index 1658e46..c5746cb 100644 --- a/core/test/governance.go +++ b/core/test/governance.go @@ -24,7 +24,6 @@ import ( "github.com/dexon-foundation/dexon-consensus-core/core/types" "github.com/dexon-foundation/dexon-consensus-core/crypto" "github.com/dexon-foundation/dexon-consensus-core/crypto/eth" - "github.com/shopspring/decimal" ) var ( @@ -35,9 +34,9 @@ var ( // Governance is an implementation of Goverance for testing purpose. type Governance struct { - Lambda time.Duration - Validators map[types.ValidatorID]decimal.Decimal - PrivateKeys map[types.ValidatorID]crypto.PrivateKey + lambda time.Duration + notarySet map[types.ValidatorID]struct{} + privateKeys map[types.ValidatorID]crypto.PrivateKey DKGComplaint map[uint64][]*types.DKGComplaint DKGMasterPublicKey map[uint64][]*types.DKGMasterPublicKey } @@ -46,9 +45,9 @@ type Governance struct { func NewGovernance(validatorCount int, lambda time.Duration) ( g *Governance, err error) { g = &Governance{ - Lambda: lambda, - Validators: make(map[types.ValidatorID]decimal.Decimal), - PrivateKeys: make(map[types.ValidatorID]crypto.PrivateKey), + lambda: lambda, + notarySet: make(map[types.ValidatorID]struct{}), + privateKeys: make(map[types.ValidatorID]crypto.PrivateKey), DKGComplaint: make(map[uint64][]*types.DKGComplaint), DKGMasterPublicKey: make(map[uint64][]*types.DKGMasterPublicKey), } @@ -58,53 +57,28 @@ func NewGovernance(validatorCount int, lambda time.Duration) ( return nil, err } vID := types.NewValidatorID(prv.PublicKey()) - g.Validators[vID] = decimal.NewFromFloat(0) - g.PrivateKeys[vID] = prv + g.notarySet[vID] = struct{}{} + g.privateKeys[vID] = prv } return } -// GetValidatorSet implements Governance interface to return current -// validator set. -func (g *Governance) GetValidatorSet() map[types.ValidatorID]decimal.Decimal { - return g.Validators +// GetNotarySet implements Governance interface to return current +// notary set. +func (g *Governance) GetNotarySet() map[types.ValidatorID]struct{} { + return g.notarySet } -// GetTotalOrderingK returns K. -func (g *Governance) GetTotalOrderingK() int { - return 0 -} - -// GetPhiRatio returns phi ratio. -func (g *Governance) GetPhiRatio() float32 { - return 0.667 -} - -// GetNumShards returns the number of shards. -func (g *Governance) GetNumShards() uint32 { - return 1 -} - -// GetNumChains returns the number of chains. -func (g *Governance) GetNumChains() uint32 { - return uint32(len(g.Validators)) -} - -// GetConfigurationChangeEvent Get configuration change events after a certain -// epoch. -func (g *Governance) GetConfigurationChangeEvent( - epoch int) []types.ConfigurationChangeEvent { - return nil -} - -// GetGenesisCRS returns the CRS string. -func (g *Governance) GetGenesisCRS() string { - return "🆕 DEXON" -} - -// GetLambda returns lambda for BA. -func (g *Governance) GetLambda() time.Duration { - return g.Lambda +// GetConfiguration returns the configuration at a given block height. +func (g *Governance) GetConfiguration(blockHeight uint64) *types.Config { + return &types.Config{ + NumShards: 1, + NumChains: uint32(len(g.notarySet)), + GenesisCRS: "__ DEXON", + Lambda: g.lambda, + K: 0, + PhiRatio: 0.667, + } } // GetPrivateKey return the private key for that validator, this function @@ -112,7 +86,7 @@ func (g *Governance) GetLambda() time.Duration { func (g *Governance) GetPrivateKey( vID types.ValidatorID) (key crypto.PrivateKey, err error) { - key, exists := g.PrivateKeys[vID] + key, exists := g.privateKeys[vID] if !exists { err = ErrPrivateKeyNotExists return diff --git a/core/ticker.go b/core/ticker.go index dffd676..bb5afb4 100644 --- a/core/ticker.go +++ b/core/ticker.go @@ -52,7 +52,7 @@ func newTicker(gov Governance) (t Ticker) { t = gen.NewTicker() } if t == nil { - t = newDefaultTicker(gov.GetLambda()) + t = newDefaultTicker(gov.GetConfiguration(0).Lambda) } return } diff --git a/core/types/config.go b/core/types/config.go new file mode 100644 index 0000000..1392ec5 --- /dev/null +++ b/core/types/config.go @@ -0,0 +1,35 @@ +// Copyright 2018 The dexon-consensus-core Authors +// This file is part of the dexon-consensus-core library. +// +// The dexon-consensus-core 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-core 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-core library. If not, see +// . + +package types + +import "time" + +// Config stands for Current Configuration Parameters. +type Config struct { + // Network related. + NumShards uint32 + NumChains uint32 + GenesisCRS string + + // Byzantine agreement related. + Lambda time.Duration + + // Total ordering related. + K int + PhiRatio float32 +} diff --git a/integration_test/utils.go b/integration_test/utils.go index 57bb2bc..c526bc2 100644 --- a/integration_test/utils.go +++ b/integration_test/utils.go @@ -31,7 +31,7 @@ func PrepareValidators( if err != nil { return } - for vID := range gov.GetValidatorSet() { + for vID := range gov.GetNotarySet() { apps[vID] = test.NewApp() if db, err = blockdb.NewMemBackedBlockDB(); err != nil { @@ -39,7 +39,7 @@ func PrepareValidators( } dbs[vID] = db } - for vID := range gov.GetValidatorSet() { + for vID := range gov.GetNotarySet() { if key, err = gov.GetPrivateKey(vID); err != nil { return } diff --git a/integration_test/validator.go b/integration_test/validator.go index 18e5c00..112f986 100644 --- a/integration_test/validator.go +++ b/integration_test/validator.go @@ -83,7 +83,7 @@ func NewValidator( proposingLatency test.LatencyModel) *Validator { hashes := make(common.Hashes, 0) - for vID := range gov.GetValidatorSet() { + for vID := range gov.GetNotarySet() { hashes = append(hashes, vID.Hash) } sort.Sort(hashes) @@ -137,7 +137,7 @@ func (v *Validator) handleProposeBlock(when time.Time, piggyback interface{}) ( return } // Create 'block received' event for each other validators. - for vID := range v.gov.GetValidatorSet() { + for vID := range v.gov.GetNotarySet() { if vID == v.ID { continue } diff --git a/simulation/governance.go b/simulation/governance.go index 79c9119..ebfd32b 100644 --- a/simulation/governance.go +++ b/simulation/governance.go @@ -24,14 +24,13 @@ import ( "github.com/dexon-foundation/dexon-consensus-core/core/types" "github.com/dexon-foundation/dexon-consensus-core/simulation/config" - "github.com/shopspring/decimal" ) // simGovernance is a simulated governance contract implementing the // core.Governance interface. type simGovernance struct { lock sync.RWMutex - validatorSet map[types.ValidatorID]decimal.Decimal + notarySet map[types.ValidatorID]struct{} expectedNumValidators int k int phiRatio float32 @@ -46,7 +45,7 @@ type simGovernance struct { func newSimGovernance( numValidators int, consensusConfig config.Consensus) *simGovernance { return &simGovernance{ - validatorSet: make(map[types.ValidatorID]decimal.Decimal), + notarySet: make(map[types.ValidatorID]struct{}), expectedNumValidators: numValidators, k: consensusConfig.K, phiRatio: consensusConfig.PhiRatio, @@ -58,61 +57,30 @@ func newSimGovernance( } } -// GetValidatorSet returns the validator set. -func (g *simGovernance) GetValidatorSet() ( - ret map[types.ValidatorID]decimal.Decimal) { +// GetNotarySet returns the current notary set. +func (g *simGovernance) GetNotarySet() map[types.ValidatorID]struct{} { g.lock.RLock() defer g.lock.RUnlock() - // Return the cloned validatorSet. - ret = make(map[types.ValidatorID]decimal.Decimal) - for k, v := range g.validatorSet { - ret[k] = v + // Return the cloned notarySet. + ret := make(map[types.ValidatorID]struct{}) + for k := range g.notarySet { + ret[k] = struct{}{} + } + return ret +} + +// GetConfiguration returns the configuration at a given block height. +func (g *simGovernance) GetConfiguration(blockHeight uint64) *types.Config { + return &types.Config{ + NumShards: 1, + NumChains: g.chainNum, + GenesisCRS: g.crs, + Lambda: g.lambda, + K: g.k, + PhiRatio: g.phiRatio, } - return -} - -// GetTotalOrderingK returns K. -func (g *simGovernance) GetTotalOrderingK() int { - return g.k -} - -// GetTotalOrderingK returns PhiRatio. -func (g *simGovernance) GetPhiRatio() float32 { - return g.phiRatio -} - -// GetBlockProposingInterval returns block proposing interval. -func (g *simGovernance) GetBlockProposingInterval() int { - return 0 -} - -// GetNumShards returns number of shards. -func (g *simGovernance) GetNumShards() uint32 { - return 1 -} - -// GetNumChains returns number of chains. -func (g *simGovernance) GetNumChains() uint32 { - return g.chainNum -} - -// GetConfigurationChangeEvent returns configuration change event since last -// epoch. -func (g *simGovernance) GetConfigurationChangeEvent( - epoch int) []types.ConfigurationChangeEvent { - return nil -} - -// GetGenesisCRS returns CRS. -func (g *simGovernance) GetGenesisCRS() string { - return g.crs -} - -// GetLambda return lambda for BA. -func (g *simGovernance) GetLambda() time.Duration { - return g.lambda } // addValidator add a new validator into the simulated governance contract. @@ -120,13 +88,13 @@ func (g *simGovernance) addValidator(vID types.ValidatorID) { g.lock.Lock() defer g.lock.Unlock() - if _, exists := g.validatorSet[vID]; exists { + if _, exists := g.notarySet[vID]; exists { return } - if len(g.validatorSet) == g.expectedNumValidators { + if len(g.notarySet) == g.expectedNumValidators { panic(fmt.Errorf("attempt to add validator when ready")) } - g.validatorSet[vID] = decimal.NewFromFloat(0) + g.notarySet[vID] = struct{}{} } // AddDKGComplaint adds a DKGComplaint. -- cgit v1.2.3