From 40f6bf0d063c9a340119d8f936b5325ff76adaf5 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 10 Dec 2024 17:16:50 +0100 Subject: [PATCH 1/3] sentinel management --- block/manager.go | 9 +++++++-- block/modes.go | 4 +++- block/sequencers.go | 10 +++++++++- p2p/block.go | 1 + settlement/dymension/dymension.go | 6 +++--- settlement/errors.go | 3 +++ 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/block/manager.go b/block/manager.go index da2b46ae8..2ebb2048f 100644 --- a/block/manager.go +++ b/block/manager.go @@ -232,7 +232,9 @@ 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 err != nil { + if errors.Is(err, settlement.ErrProposerIsSentinel) { + m.freezeNode(fmt.Errorf("unable to start without new proposer at height %d", m.State.NextHeight())) + } else if err != nil { return err } _, err = m.Store.SaveState(m.State, nil) @@ -246,7 +248,10 @@ func (m *Manager) Start(ctx context.Context) error { // for this case, 2 nodes will get `true` for `AmIProposer` so the l2 proposer can produce blocks and the hub proposer can submit his last batch. // The hub proposer, after sending the last state update, will panic and restart as full node. 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) } diff --git a/block/modes.go b/block/modes.go index adfd56432..f16f7bb7f 100644 --- a/block/modes.go +++ b/block/modes.go @@ -58,7 +58,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..0a5ff8fb7 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,7 @@ func (m *Manager) AmIProposerOnSL() (bool, error) { localProposerKeyBytes, _ := m.LocalKey.GetPublic().Raw() // get hub proposer key SLProposer, err := m.SLClient.GetProposerAtHeight(-1) + if err != nil { return false, fmt.Errorf("get proposer at height: %w", err) } @@ -94,7 +98,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 diff --git a/p2p/block.go b/p2p/block.go index d6da3da96..031827ba5 100644 --- a/p2p/block.go +++ b/p2p/block.go @@ -55,6 +55,7 @@ func (b *BlockData) FromProto(other *pb.BlockData) error { // Validate run basic validation on the p2p block received func (b *BlockData) Validate(proposerPubKey tmcrypto.PubKey) error { + if err := b.Block.ValidateBasic(); err != nil { return err } diff --git a/settlement/dymension/dymension.go b/settlement/dymension/dymension.go index 6a995ef69..65c33ae7e 100644 --- a/settlement/dymension/dymension.go +++ b/settlement/dymension/dymension.go @@ -346,8 +346,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 @@ -538,7 +538,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 From 796b93453dba030bc3c4b10f985d75e106c96d48 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 10 Dec 2024 17:18:54 +0100 Subject: [PATCH 2/3] minor edit --- block/sequencers.go | 1 - 1 file changed, 1 deletion(-) diff --git a/block/sequencers.go b/block/sequencers.go index 0a5ff8fb7..2e23c18d9 100644 --- a/block/sequencers.go +++ b/block/sequencers.go @@ -66,7 +66,6 @@ func (m *Manager) AmIProposerOnSL() (bool, error) { localProposerKeyBytes, _ := m.LocalKey.GetPublic().Raw() // get hub proposer key SLProposer, err := m.SLClient.GetProposerAtHeight(-1) - if err != nil { return false, fmt.Errorf("get proposer at height: %w", err) } From d3ca8c9ebcda9c26ccbad1b4077b1f9d8eaccb1d Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 10 Dec 2024 17:19:25 +0100 Subject: [PATCH 3/3] minor edit --- block/manager.go | 1 - 1 file changed, 1 deletion(-) diff --git a/block/manager.go b/block/manager.go index 2ebb2048f..d7f9cc5c6 100644 --- a/block/manager.go +++ b/block/manager.go @@ -248,7 +248,6 @@ func (m *Manager) Start(ctx context.Context) error { // for this case, 2 nodes will get `true` for `AmIProposer` so the l2 proposer can produce blocks and the hub proposer can submit his last batch. // The hub proposer, after sending the last state update, will panic and restart as full node. amIProposerOnSL, err := m.AmIProposerOnSL() - if errors.Is(err, settlement.ErrProposerIsSentinel) { amIProposerOnSL = false } else if err != nil {