diff --git a/block/fork.go b/block/fork.go index fc5f3fc26..e0370609f 100644 --- a/block/fork.go +++ b/block/fork.go @@ -27,7 +27,6 @@ func (m *Manager) MonitorForkUpdateLoop(ctx context.Context) error { for { if err := m.checkForkUpdate(ForkMonitorMessage); err != nil { - m.logger.Error("Check for update.", err) if errors.Is(err, ErrNonRecoverable) { return err } diff --git a/block/manager.go b/block/manager.go index 758d4e53a..e9d0d9050 100644 --- a/block/manager.go +++ b/block/manager.go @@ -229,6 +229,10 @@ func (m *Manager) Start(ctx context.Context) error { if m.State.GetProposer() == nil { m.logger.Info("No proposer on the rollapp, fallback to the hub proposer, if available") err := m.UpdateProposerFromSL() + if errors.Is(err, settlement.ErrProposerIsSentinel) { + m.logger.Info("No active proposer. Chain is halted. Waiting for a new proposer.", "height", m.State.Height()) + err = m.WaitForActiveProposer(ctx) + } if err != nil { return err } @@ -316,10 +320,10 @@ func (m *Manager) Start(ctx context.Context) error { } else if errors.Is(err, gerrc.ErrFault) { // Here we handle the fault by calling the fraud handler. // it publishes a DataHealthStatus event to the pubsub and stops the block manager. - m.logger.Error("block manager exited with fault", "error", err) + m.logger.Error("block manager exited with fault") m.FraudHandler.HandleFault(err) } else if err != nil { - m.logger.Error("block manager exited with error", "error", err) + m.logger.Error("block manager exited with error") m.StopManager(err) } }() @@ -445,7 +449,6 @@ func (m *Manager) setFraudHandler(handler *FreezeHandler) { // StopManager sets the node as unhealthy and stops the block manager context func (m *Manager) StopManager(err error) { - m.logger.Info("Freezing node", "err", err) m.setUnhealthy(err) m.Cancel() } diff --git a/block/modes.go b/block/modes.go index 858b70bd1..24e419574 100644 --- a/block/modes.go +++ b/block/modes.go @@ -2,6 +2,7 @@ package block import ( "context" + "errors" "fmt" "github.com/dymensionxyz/dymint/p2p" @@ -52,7 +53,9 @@ func (m *Manager) runAsProposer(ctx context.Context, eg *errgroup.Group) error { // it is checked again whether the node is the active proposer, since this could have changed after syncing. amIProposerOnSL, err := m.AmIProposerOnSL() - if err != nil { + if errors.Is(err, settlement.ErrProposerIsSentinel) { + amIProposerOnSL = false + } else if err != nil { return fmt.Errorf("am i proposer on SL: %w", err) } if !amIProposerOnSL { diff --git a/block/sequencers.go b/block/sequencers.go index ca6155397..9f45ef0a2 100644 --- a/block/sequencers.go +++ b/block/sequencers.go @@ -3,8 +3,11 @@ package block import ( "bytes" "context" + "errors" "fmt" "time" + + "github.com/dymensionxyz/dymint/settlement" ) const ( @@ -63,6 +66,10 @@ func (m *Manager) AmIProposerOnSL() (bool, error) { localProposerKeyBytes, _ := m.LocalKey.GetPublic().Raw() // get hub proposer key SLProposer, err := m.SLClient.GetProposerAtHeight(-1) + // if no proposer set return nil + if errors.Is(err, settlement.ErrProposerIsSentinel) { + return false, nil + } if err != nil { return false, fmt.Errorf("get proposer at height: %w", err) } @@ -94,7 +101,11 @@ func (m *Manager) ShouldRotate() (bool, error) { // At this point we know that there is a next proposer, // so we should rotate only if we are the current proposer on the hub amIProposerOnSL, err := m.AmIProposerOnSL() - if err != nil { + + // if no proposer assigned, return false without error + if errors.Is(err, settlement.ErrProposerIsSentinel) { + return false, nil + } else if err != nil { return false, fmt.Errorf("am i proposer on SL: %w", err) } return amIProposerOnSL, nil @@ -185,3 +196,31 @@ func (m *Manager) UpdateProposerFromSL() error { m.State.SetProposer(SLProposer) return nil } + +func (m *Manager) WaitForActiveProposer(ctx context.Context) error { + ticker := time.NewTicker(ProposerMonitorInterval) // TODO: make this configurable + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return nil + case <-ticker.C: + + proposer, err := m.SLClient.GetProposerAtHeight(-1) + + // no next proposer yet + if errors.Is(err, settlement.ErrProposerIsSentinel) { + continue + } + + if err != nil { + return err + } + + m.logger.Info("New proposer set.", "nextSeqAddr", proposer.SettlementAddress) + m.State.SetProposer(proposer) + return nil + } + } +} diff --git a/da/weavevm/wvm.go b/da/weavevm/wvm.go index 4de01a0ba..e0188566d 100644 --- a/da/weavevm/wvm.go +++ b/da/weavevm/wvm.go @@ -553,7 +553,7 @@ func (c *DataAvailabilityLayerClient) waitForTxReceipt(ctx context.Context, txHa return nil }, retry.Context(ctx), - retry.Attempts(uint(*c.config.RetryAttempts)), + retry.Attempts(uint(*c.config.RetryAttempts)), //nolint:gosec // RetryAttempts should be always positive retry.Delay(c.config.RetryDelay), retry.DelayType(retry.FixedDelay), // Force fixed delay between attempts retry.LastErrorOnly(true), // Only log the last error diff --git a/settlement/dymension/dymension.go b/settlement/dymension/dymension.go index 02a7a2738..747b5b19e 100644 --- a/settlement/dymension/dymension.go +++ b/settlement/dymension/dymension.go @@ -347,8 +347,8 @@ func (c *Client) GetProposerAtHeight(height int64) (*types.Sequencer, error) { } } - if proposerAddr == SENTINEL_PROPOSER { - return nil, fmt.Errorf("proposer is sentinel") + if proposerAddr == "" || proposerAddr == SENTINEL_PROPOSER { + return nil, settlement.ErrProposerIsSentinel } // Find and return the matching sequencer @@ -544,7 +544,7 @@ func (c *Client) GetNextProposer() (*types.Sequencer, error) { if !found { return nil, nil } - if nextAddr == SENTINEL_PROPOSER { + if nextAddr == "" || nextAddr == SENTINEL_PROPOSER { return &types.Sequencer{}, nil } diff --git a/settlement/errors.go b/settlement/errors.go index b2b4073b7..d98310f4c 100644 --- a/settlement/errors.go +++ b/settlement/errors.go @@ -9,6 +9,9 @@ import ( // ErrBatchNotAccepted is returned when a batch is not accepted by the settlement layer. var ErrBatchNotAccepted = fmt.Errorf("batch not accepted: %w", gerrc.ErrUnknown) +// ErrProposerIsSentinel is returned when a rollapp has no sequencer assigned. +var ErrProposerIsSentinel = fmt.Errorf("proposer is sentinel") + type ErrNextSequencerAddressFraud struct { Expected string Actual string