From 58c04bb7a58230be8ea7659d45934c84b11574af Mon Sep 17 00:00:00 2001 From: lklimek <842586+lklimek@users.noreply.github.com> Date: Mon, 29 Jul 2024 13:31:48 +0200 Subject: [PATCH] fix: validators form islands on genesis (#850) --- dash/quorum/validator_conn_executor.go | 29 +++++++++++++++++ node/node.go | 45 +++++++++++++------------- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/dash/quorum/validator_conn_executor.go b/dash/quorum/validator_conn_executor.go index bcef5c333..5bb7a5638 100644 --- a/dash/quorum/validator_conn_executor.go +++ b/dash/quorum/validator_conn_executor.go @@ -15,6 +15,7 @@ import ( "github.com/dashpay/tenderdash/internal/eventbus" "github.com/dashpay/tenderdash/internal/p2p" tmpubsub "github.com/dashpay/tenderdash/internal/pubsub" + "github.com/dashpay/tenderdash/internal/state" tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/libs/service" @@ -62,6 +63,9 @@ type ValidatorConnExecutor struct { // mux is a mutex to ensure only one goroutine is processing connections mux sync.Mutex + // state store used on start to setup initial validators + stateStore state.Store + // *** configuration *** // // EventBusCapacity sets event bus buffer capacity, defaults to 10 @@ -120,6 +124,15 @@ func WithValidatorsSet(valSet *types.ValidatorSet) func(vc *ValidatorConnExecuto } } +// WithStateStore sets state store to be used when setting up initial validators +// Can be nil, in which case no initial validators will be set up. +func WithStateStore(store state.Store) func(vc *ValidatorConnExecutor) error { + return func(vc *ValidatorConnExecutor) error { + vc.stateStore = store + return nil + } +} + // WithLogger sets a logger func WithLogger(logger log.Logger) func(vc *ValidatorConnExecutor) error { return func(vc *ValidatorConnExecutor) error { @@ -130,6 +143,22 @@ func WithLogger(logger log.Logger) func(vc *ValidatorConnExecutor) error { // OnStart implements Service to subscribe to Validator Update events func (vc *ValidatorConnExecutor) OnStart(ctx context.Context) error { + // initial setup of validators, if state store is provided + if vc.stateStore != nil { + valset, err := vc.stateStore.Load() + if err != nil { + return fmt.Errorf("cannot load initial state from state store: %w", err) + } + if err = vc.handleValidatorUpdateEvent(types.EventDataValidatorSetUpdate{ + ValidatorSetUpdates: valset.Validators.Validators, + ThresholdPublicKey: valset.Validators.ThresholdPublicKey, + QuorumHash: valset.Validators.QuorumHash, + }); err != nil { + // not fatal, but we should log it + vc.logger.Warn("cannot handle initial validator set, skipping", "err", err) + } + } + if err := vc.subscribe(); err != nil { return err } diff --git a/node/node.go b/node/node.go index e4ba7e630..2634b5022 100644 --- a/node/node.go +++ b/node/node.go @@ -271,28 +271,6 @@ func makeNode( }, } - // Start Dash connection executor - if len(proTxHash) > 0 { - var validatorConnExecutor *dashquorum.ValidatorConnExecutor - - vcLogger := logger.With("node_proTxHash", proTxHash.ShortString(), "module", "ValidatorConnExecutor") - dcm := p2p.NewRouterDashDialer(peerManager, vcLogger) - validatorConnExecutor, err = dashquorum.NewValidatorConnExecutor( - proTxHash, - eventBus, - dcm, - dashquorum.WithLogger(vcLogger), - dashquorum.WithValidatorsSet(state.Validators), - ) - if err != nil { - return nil, combineCloseError(err, makeCloser(closers)) - } - - node.services = append(node.services, validatorConnExecutor) - } else { - logger.Debug("ProTxHash not set, so we are not a validator; skipping ValidatorConnExecutor initialization") - } - node.router, err = createRouter(logger, nodeMetrics.p2p, node.NodeInfo, nodeKey, peerManager, cfg, proxyApp) if err != nil { return nil, combineCloseError( @@ -453,6 +431,29 @@ func makeNode( node.rpcEnv.ProTxHash = proTxHash } + // Start Dash connection executor + // We do it at the end, as we require the state to be loaded and network routing to be set up + if len(proTxHash) > 0 { + var validatorConnExecutor *dashquorum.ValidatorConnExecutor + + vcLogger := logger.With("node_proTxHash", proTxHash.ShortString(), "module", "ValidatorConnExecutor") + dcm := p2p.NewRouterDashDialer(peerManager, vcLogger) + validatorConnExecutor, err = dashquorum.NewValidatorConnExecutor( + proTxHash, + eventBus, + dcm, + dashquorum.WithLogger(vcLogger), + dashquorum.WithValidatorsSet(state.Validators), + dashquorum.WithStateStore(stateStore)) + if err != nil { + return nil, combineCloseError(err, makeCloser(closers)) + } + + node.services = append(node.services, validatorConnExecutor) + } else { + logger.Debug("ProTxHash not set, so we are not a validator; skipping ValidatorConnExecutor initialization") + } + node.BaseService = *service.NewBaseService(logger, "Node", node) return node, nil