From 205f419c2e05ddcd5a5f8ca29374c733adcc9732 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:07:17 +0200 Subject: [PATCH] feat(dash): connect to all other quorum members --- config/config.go | 35 ++++++++++++++++++------ config/toml.go | 9 ++++++ dash/quorum/selectpeers/allvalidators.go | 31 +++++++++++++++++++++ dash/quorum/validator_conn_executor.go | 34 ++++++++++++++++++++++- node/node.go | 4 ++- 5 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 dash/quorum/selectpeers/allvalidators.go diff --git a/config/config.go b/config/config.go index 82557e8412..9c0e835c4a 100644 --- a/config/config.go +++ b/config/config.go @@ -32,6 +32,11 @@ const ( ModeFull = "full" ModeValidator = "validator" ModeSeed = "seed" + + // ValidatorConnectionAlgorithmAll is a name of the peer selection algorithm that selects all validators + ValidatorConnectionAlgorithmAll = "all" + // ValidatorConnectionAlgorithmDIP6 is a name of the peer selection algorithm that selects validators based on DIP-6 + ValidatorConnectionAlgorithmDIP6 = "dip6" ) // NOTE: Most of the structs & relevant comments + the @@ -1111,7 +1116,15 @@ type ConsensusConfig struct { PeerGossipSleepDuration time.Duration `mapstructure:"peer-gossip-sleep-duration"` PeerQueryMaj23SleepDuration time.Duration `mapstructure:"peer-query-maj23-sleep-duration"` - DoubleSignCheckHeight int64 `mapstructure:"double-sign-check-height"` + // ValidatorConnectionAlgorithm defines the algorithm used to select the + // validators to which direct connection should be established. + // Possible values are: + // - "all" - validators establish direct connections to all other validators in the current quorum + // - "dip6" - validators establish direct connections to a subset of other validators, determined according to DIP-6 + // + // Defaults to "dip6". + ValidatorConnectionAlgorithm string `mapstructure:"validator-connection-algorithm"` + DoubleSignCheckHeight int64 `mapstructure:"double-sign-check-height"` DeprecatedQuorumType btcjson.LLMQType `mapstructure:"quorum-type"` @@ -1152,14 +1165,15 @@ type ConsensusConfig struct { // DefaultConsensusConfig returns a default configuration for the consensus service func DefaultConsensusConfig() *ConsensusConfig { return &ConsensusConfig{ - WalPath: filepath.Join(defaultDataDir, "cs.wal", "wal"), - WalSkipRoundsToLast: false, - CreateEmptyBlocks: true, - CreateEmptyBlocksInterval: 0 * time.Second, - PeerGossipSleepDuration: 100 * time.Millisecond, - PeerQueryMaj23SleepDuration: 2000 * time.Millisecond, - DoubleSignCheckHeight: int64(0), - DontAutoPropose: false, + WalPath: filepath.Join(defaultDataDir, "cs.wal", "wal"), + WalSkipRoundsToLast: false, + CreateEmptyBlocks: true, + CreateEmptyBlocksInterval: 0 * time.Second, + PeerGossipSleepDuration: 100 * time.Millisecond, + PeerQueryMaj23SleepDuration: 2000 * time.Millisecond, + DoubleSignCheckHeight: int64(0), + DontAutoPropose: false, + ValidatorConnectionAlgorithm: ValidatorConnectionAlgorithmDIP6, } } @@ -1220,6 +1234,9 @@ func (cfg *ConsensusConfig) ValidateBasic() error { if cfg.DoubleSignCheckHeight < 0 { return errors.New("double-sign-check-height can't be negative") } + if cfg.ValidatorConnectionAlgorithm != ValidatorConnectionAlgorithmAll && cfg.ValidatorConnectionAlgorithm != ValidatorConnectionAlgorithmDIP6 { + return fmt.Errorf("validator-connection-algorithm must be either 'all' or 'dip6'") + } return nil } diff --git a/config/toml.go b/config/toml.go index 90d3163f38..57de7cf962 100644 --- a/config/toml.go +++ b/config/toml.go @@ -553,6 +553,15 @@ create-empty-blocks-interval = "{{ .Consensus.CreateEmptyBlocksInterval }}" peer-gossip-sleep-duration = "{{ .Consensus.PeerGossipSleepDuration }}" peer-query-maj23-sleep-duration = "{{ .Consensus.PeerQueryMaj23SleepDuration }}" +# ValidatorConnectionAlgorithm defines the algorithm used to select the +# validators to which direct connection should be established. +# Possible values are: +# - "all" - validators establish direct connections to all other validators in the current quorum +# - "dip6" - validators establish direct connections to a subset of other validators, determined according to DIP-6 +# +# Defaults to "dip6". +validator-connection-algorithm = "{{ .Consensus.ValidatorConnectionAlgorithm }}" + ### Unsafe Timeout Overrides ### # These fields provide temporary overrides for the Timeout consensus parameters. diff --git a/dash/quorum/selectpeers/allvalidators.go b/dash/quorum/selectpeers/allvalidators.go new file mode 100644 index 0000000000..be1e175468 --- /dev/null +++ b/dash/quorum/selectpeers/allvalidators.go @@ -0,0 +1,31 @@ +package selectpeers + +import ( + "github.com/dashpay/tenderdash/types" +) + +type allValidatorsSelector struct { +} + +var _ ValidatorSelector = (*allValidatorsSelector)(nil) + +// NewAllValidatorsSelector creates new implementation of validator selector algorithm +// that selects all validators except local node +func NewAllValidatorsSelector() ValidatorSelector { + return &allValidatorsSelector{} +} + +// SelectValidators implements ValidtorSelector. +// SelectValidators selects all validators from `validatorSetMembers`, except local node +func (s *allValidatorsSelector) SelectValidators( + validatorSetMembers []*types.Validator, + me *types.Validator, +) ([]*types.Validator, error) { + ret := make([]*types.Validator, 0, len(validatorSetMembers)-1) + for _, val := range validatorSetMembers { + if !val.ProTxHash.Equal(me.ProTxHash) { + ret = append(ret, val) + } + } + return ret, nil +} diff --git a/dash/quorum/validator_conn_executor.go b/dash/quorum/validator_conn_executor.go index 5bb7a56384..7870c2c826 100644 --- a/dash/quorum/validator_conn_executor.go +++ b/dash/quorum/validator_conn_executor.go @@ -4,12 +4,14 @@ import ( "context" "errors" "fmt" + "strings" "time" sync "github.com/sasha-s/go-deadlock" "github.com/hashicorp/go-multierror" + "github.com/dashpay/tenderdash/config" "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/dash/quorum/selectpeers" "github.com/dashpay/tenderdash/internal/eventbus" @@ -70,6 +72,10 @@ type ValidatorConnExecutor struct { // EventBusCapacity sets event bus buffer capacity, defaults to 10 EventBusCapacity int + + // selectionAlgorithm determines how to select validators to connect to + // Supported values: "all", "dip6" + selectionAlgorithm string } var ( @@ -93,6 +99,7 @@ func NewValidatorConnExecutor( validatorSetMembers: validatorMap{}, connectedValidators: validatorMap{}, quorumHash: make(tmbytes.HexBytes, crypto.QuorumHashSize), + selectionAlgorithm: config.ValidatorConnectionAlgorithmDIP6, } vc.nodeIDResolvers = map[string]p2p.NodeIDResolver{ resolverAddressBook: vc.dialer, @@ -106,6 +113,7 @@ func NewValidatorConnExecutor( return nil, err } } + return vc, nil } @@ -141,8 +149,23 @@ func WithLogger(logger log.Logger) func(vc *ValidatorConnExecutor) error { } } +// WithSelectionAlgorithm sets the algorithm used to select validators to connect to +func WithSelectionAlgorithm(algorithm string) func(vc *ValidatorConnExecutor) error { + return func(vc *ValidatorConnExecutor) error { + algorithm := strings.ToLower(algorithm) + + if algorithm != config.ValidatorConnectionAlgorithmAll && algorithm != config.ValidatorConnectionAlgorithmDIP6 { + return fmt.Errorf("invalid selection algorithm: %s", algorithm) + } + + vc.selectionAlgorithm = algorithm + return nil + } +} + // OnStart implements Service to subscribe to Validator Update events func (vc *ValidatorConnExecutor) OnStart(ctx context.Context) error { + vc.logger.Debug("ValidatorConnExecutor starting with selection algorithm " + vc.selectionAlgorithm) // initial setup of validators, if state store is provided if vc.stateStore != nil { valset, err := vc.stateStore.Load() @@ -314,7 +337,16 @@ func (vc *ValidatorConnExecutor) selectValidators() (validatorMap, error) { return validatorMap{}, fmt.Errorf("current node is not member of active validator set") } - selector := selectpeers.NewDIP6ValidatorSelector(vc.quorumHash) + var selector selectpeers.ValidatorSelector + switch vc.selectionAlgorithm { + case config.ValidatorConnectionAlgorithmAll: + selector = selectpeers.NewAllValidatorsSelector() + case config.ValidatorConnectionAlgorithmDIP6: + selector = selectpeers.NewDIP6ValidatorSelector(vc.quorumHash) + default: + return validatorMap{}, fmt.Errorf("invalid selection algorithm: %s", vc.selectionAlgorithm) + } + selectedValidators, err := selector.SelectValidators(activeValidators.values(), me) if err != nil { return validatorMap{}, err diff --git a/node/node.go b/node/node.go index c1d2553d68..bc5089e5db 100644 --- a/node/node.go +++ b/node/node.go @@ -444,7 +444,9 @@ func makeNode( dcm, dashquorum.WithLogger(vcLogger), dashquorum.WithValidatorsSet(state.Validators), - dashquorum.WithStateStore(stateStore)) + dashquorum.WithStateStore(stateStore), + dashquorum.WithSelectionAlgorithm(cfg.Consensus.ValidatorConnectionAlgorithm), + ) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) }