diff --git a/block/manager.go b/block/manager.go index dd1994bd2..978632ce0 100644 --- a/block/manager.go +++ b/block/manager.go @@ -173,6 +173,9 @@ func (m *Manager) Start(ctx context.Context) error { return m.PruningLoop(ctx) }) + // listen to new bonded sequencers events to add them in the sequencer set + go uevent.MustSubscribe(ctx, m.Pubsub, "newBondedSequencer", settlement.EventQueryNewBondedSequencer, m.UpdateSequencerSet, m.logger) + /* ----------------------------- full node mode ----------------------------- */ if !isProposer { // Full-nodes can sync from DA but it is not necessary to wait for it, since it can sync from P2P as well in parallel. diff --git a/block/sequencers.go b/block/sequencers.go index 4c98c4f3b..6c72d4d22 100644 --- a/block/sequencers.go +++ b/block/sequencers.go @@ -8,6 +8,7 @@ import ( "github.com/dymensionxyz/dymint/settlement" "github.com/dymensionxyz/dymint/types" + "github.com/tendermint/tendermint/libs/pubsub" ) func (m *Manager) MonitorSequencerRotation(ctx context.Context, rotateC chan string) error { @@ -179,3 +180,26 @@ func (m *Manager) UpdateProposer() error { m.State.Sequencers.SetProposer(m.SLClient.GetProposer()) return nil } + +// UpdateLastSubmittedHeight will update last height submitted height upon events. +// This may be necessary in case we crashed/restarted before getting response for our submission to the settlement layer. +func (m *Manager) UpdateSequencerSet(event pubsub.Message) { + eventData, ok := event.Data().(*settlement.EventDataNewBondedSequencer) + if !ok { + m.logger.Error("onReceivedBatch", "err", "wrong event data received") + return + } + + if m.State.Sequencers.GetByAddress(eventData.SeqAddr) != nil { + m.logger.Debug("Sequencer not added from new bonded sequencer event because already in the list.") + return + } + + newSequencer, err := m.SLClient.GetSequencerByAddress(eventData.SeqAddr) + if err != nil { + m.logger.Error("Unable to add new sequencer from event. err:%w", err) + return + } + sequencers := append(m.State.Sequencers.Sequencers, newSequencer) + m.State.Sequencers.SetSequencers(sequencers) +} diff --git a/mocks/github.com/dymensionxyz/dymint/da/avail/mock_SubstrateApiI.go b/mocks/github.com/dymensionxyz/dymint/da/avail/mock_SubstrateApiI.go index bba31b087..6a52c1df8 100644 --- a/mocks/github.com/dymensionxyz/dymint/da/avail/mock_SubstrateApiI.go +++ b/mocks/github.com/dymensionxyz/dymint/da/avail/mock_SubstrateApiI.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package avail diff --git a/mocks/github.com/dymensionxyz/dymint/da/celestia/types/mock_CelestiaRPCClient.go b/mocks/github.com/dymensionxyz/dymint/da/celestia/types/mock_CelestiaRPCClient.go index 5994cf817..4935cc66a 100644 --- a/mocks/github.com/dymensionxyz/dymint/da/celestia/types/mock_CelestiaRPCClient.go +++ b/mocks/github.com/dymensionxyz/dymint/da/celestia/types/mock_CelestiaRPCClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package types diff --git a/mocks/github.com/dymensionxyz/dymint/da/mock_DataAvailabilityLayerClient.go b/mocks/github.com/dymensionxyz/dymint/da/mock_DataAvailabilityLayerClient.go index 1480d557c..75727dd5e 100644 --- a/mocks/github.com/dymensionxyz/dymint/da/mock_DataAvailabilityLayerClient.go +++ b/mocks/github.com/dymensionxyz/dymint/da/mock_DataAvailabilityLayerClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package da diff --git a/mocks/github.com/dymensionxyz/dymint/settlement/dymension/mock_CosmosClient.go b/mocks/github.com/dymensionxyz/dymint/settlement/dymension/mock_CosmosClient.go index bebd10ade..4b14a3eaf 100644 --- a/mocks/github.com/dymensionxyz/dymint/settlement/dymension/mock_CosmosClient.go +++ b/mocks/github.com/dymensionxyz/dymint/settlement/dymension/mock_CosmosClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package dymension diff --git a/mocks/github.com/dymensionxyz/dymint/settlement/mock_ClientI.go b/mocks/github.com/dymensionxyz/dymint/settlement/mock_ClientI.go index e71cc9d27..784febab1 100644 --- a/mocks/github.com/dymensionxyz/dymint/settlement/mock_ClientI.go +++ b/mocks/github.com/dymensionxyz/dymint/settlement/mock_ClientI.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package settlement @@ -417,6 +417,62 @@ func (_c *MockClientI_GetProposer_Call) RunAndReturn(run func() *types.Sequencer return _c } +// GetSequencerByAddress provides a mock function with given fields: address +func (_m *MockClientI) GetSequencerByAddress(address string) (types.Sequencer, error) { + ret := _m.Called(address) + + if len(ret) == 0 { + panic("no return value specified for GetSequencerByAddress") + } + + var r0 types.Sequencer + var r1 error + if rf, ok := ret.Get(0).(func(string) (types.Sequencer, error)); ok { + return rf(address) + } + if rf, ok := ret.Get(0).(func(string) types.Sequencer); ok { + r0 = rf(address) + } else { + r0 = ret.Get(0).(types.Sequencer) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(address) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClientI_GetSequencerByAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSequencerByAddress' +type MockClientI_GetSequencerByAddress_Call struct { + *mock.Call +} + +// GetSequencerByAddress is a helper method to define mock.On call +// - address string +func (_e *MockClientI_Expecter) GetSequencerByAddress(address interface{}) *MockClientI_GetSequencerByAddress_Call { + return &MockClientI_GetSequencerByAddress_Call{Call: _e.mock.On("GetSequencerByAddress", address)} +} + +func (_c *MockClientI_GetSequencerByAddress_Call) Run(run func(address string)) *MockClientI_GetSequencerByAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockClientI_GetSequencerByAddress_Call) Return(_a0 types.Sequencer, _a1 error) *MockClientI_GetSequencerByAddress_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClientI_GetSequencerByAddress_Call) RunAndReturn(run func(string) (types.Sequencer, error)) *MockClientI_GetSequencerByAddress_Call { + _c.Call.Return(run) + return _c +} + // Init provides a mock function with given fields: config, rollappId, _a2, logger, options func (_m *MockClientI) Init(config settlement.Config, rollappId string, _a2 *pubsub.Server, logger types.Logger, options ...settlement.Option) error { _va := make([]interface{}, len(options)) diff --git a/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go b/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go index 3a1678d0a..010d1c41c 100644 --- a/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go +++ b/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package store @@ -579,27 +579,27 @@ func (_c *MockStore_NewBatch_Call) RunAndReturn(run func() store.KVBatch) *MockS return _c } -// PruneBlocks provides a mock function with given fields: from, to -func (_m *MockStore) PruneBlocks(from uint64, to uint64) (uint64, error) { - ret := _m.Called(from, to) +// PruneStore provides a mock function with given fields: from, to, logger +func (_m *MockStore) PruneStore(from uint64, to uint64, logger types.Logger) (uint64, error) { + ret := _m.Called(from, to, logger) if len(ret) == 0 { - panic("no return value specified for PruneBlocks") + panic("no return value specified for PruneStore") } var r0 uint64 var r1 error - if rf, ok := ret.Get(0).(func(uint64, uint64) (uint64, error)); ok { - return rf(from, to) + if rf, ok := ret.Get(0).(func(uint64, uint64, types.Logger) (uint64, error)); ok { + return rf(from, to, logger) } - if rf, ok := ret.Get(0).(func(uint64, uint64) uint64); ok { - r0 = rf(from, to) + if rf, ok := ret.Get(0).(func(uint64, uint64, types.Logger) uint64); ok { + r0 = rf(from, to, logger) } else { r0 = ret.Get(0).(uint64) } - if rf, ok := ret.Get(1).(func(uint64, uint64) error); ok { - r1 = rf(from, to) + if rf, ok := ret.Get(1).(func(uint64, uint64, types.Logger) error); ok { + r1 = rf(from, to, logger) } else { r1 = ret.Error(1) } @@ -607,31 +607,32 @@ func (_m *MockStore) PruneBlocks(from uint64, to uint64) (uint64, error) { return r0, r1 } -// MockStore_PruneBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PruneBlocks' -type MockStore_PruneBlocks_Call struct { +// MockStore_PruneStore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PruneStore' +type MockStore_PruneStore_Call struct { *mock.Call } -// PruneBlocks is a helper method to define mock.On call +// PruneStore is a helper method to define mock.On call // - from uint64 // - to uint64 -func (_e *MockStore_Expecter) PruneBlocks(from interface{}, to interface{}) *MockStore_PruneBlocks_Call { - return &MockStore_PruneBlocks_Call{Call: _e.mock.On("PruneBlocks", from, to)} +// - logger types.Logger +func (_e *MockStore_Expecter) PruneStore(from interface{}, to interface{}, logger interface{}) *MockStore_PruneStore_Call { + return &MockStore_PruneStore_Call{Call: _e.mock.On("PruneStore", from, to, logger)} } -func (_c *MockStore_PruneBlocks_Call) Run(run func(from uint64, to uint64)) *MockStore_PruneBlocks_Call { +func (_c *MockStore_PruneStore_Call) Run(run func(from uint64, to uint64, logger types.Logger)) *MockStore_PruneStore_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(uint64), args[1].(uint64)) + run(args[0].(uint64), args[1].(uint64), args[2].(types.Logger)) }) return _c } -func (_c *MockStore_PruneBlocks_Call) Return(_a0 uint64, _a1 error) *MockStore_PruneBlocks_Call { +func (_c *MockStore_PruneStore_Call) Return(_a0 uint64, _a1 error) *MockStore_PruneStore_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *MockStore_PruneBlocks_Call) RunAndReturn(run func(uint64, uint64) (uint64, error)) *MockStore_PruneBlocks_Call { +func (_c *MockStore_PruneStore_Call) RunAndReturn(run func(uint64, uint64, types.Logger) (uint64, error)) *MockStore_PruneStore_Call { _c.Call.Return(run) return _c } diff --git a/mocks/github.com/dymensionxyz/dymint/third_party/dymension/sequencer/types/mock_QueryClient.go b/mocks/github.com/dymensionxyz/dymint/third_party/dymension/sequencer/types/mock_QueryClient.go index 6b16285aa..fed52c6c5 100644 --- a/mocks/github.com/dymensionxyz/dymint/third_party/dymension/sequencer/types/mock_QueryClient.go +++ b/mocks/github.com/dymensionxyz/dymint/third_party/dymension/sequencer/types/mock_QueryClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package types diff --git a/mocks/github.com/dymensionxyz/dymint/types/pb/dymensionxyz/dymension/rollapp/mock_QueryClient.go b/mocks/github.com/dymensionxyz/dymint/types/pb/dymensionxyz/dymension/rollapp/mock_QueryClient.go index f182218a5..83c174f72 100644 --- a/mocks/github.com/dymensionxyz/dymint/types/pb/dymensionxyz/dymension/rollapp/mock_QueryClient.go +++ b/mocks/github.com/dymensionxyz/dymint/types/pb/dymensionxyz/dymension/rollapp/mock_QueryClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package rollapp diff --git a/mocks/github.com/tendermint/tendermint/abci/types/mock_Application.go b/mocks/github.com/tendermint/tendermint/abci/types/mock_Application.go index 45011bdc9..7393ef94e 100644 --- a/mocks/github.com/tendermint/tendermint/abci/types/mock_Application.go +++ b/mocks/github.com/tendermint/tendermint/abci/types/mock_Application.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package types diff --git a/mocks/github.com/tendermint/tendermint/proxy/mock_AppConnConsensus.go b/mocks/github.com/tendermint/tendermint/proxy/mock_AppConnConsensus.go index 9a28054e1..9ec6b2d18 100644 --- a/mocks/github.com/tendermint/tendermint/proxy/mock_AppConnConsensus.go +++ b/mocks/github.com/tendermint/tendermint/proxy/mock_AppConnConsensus.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package proxy diff --git a/mocks/github.com/tendermint/tendermint/proxy/mock_AppConns.go b/mocks/github.com/tendermint/tendermint/proxy/mock_AppConns.go index 120c2f698..affc90a4e 100644 --- a/mocks/github.com/tendermint/tendermint/proxy/mock_AppConns.go +++ b/mocks/github.com/tendermint/tendermint/proxy/mock_AppConns.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.42.3. DO NOT EDIT. package proxy diff --git a/settlement/dymension/dymension.go b/settlement/dymension/dymension.go index f1987c9c0..b0ab5c2dd 100644 --- a/settlement/dymension/dymension.go +++ b/settlement/dymension/dymension.go @@ -318,6 +318,45 @@ func (c *Client) GetProposer() *types.Sequencer { return &seqs[index] } +// GetSequencerByAddress returns a sequencer by its address. +func (c *Client) GetSequencerByAddress(address string) (types.Sequencer, error) { + var res *sequencertypes.QueryGetSequencerResponse + req := &sequencertypes.QueryGetSequencerRequest{ + SequencerAddress: address, + } + + err := c.RunWithRetry(func() error { + var err error + res, err = c.sequencerQueryClient.Sequencer(c.ctx, req) + if err == nil { + return nil + } + + if status.Code(err) == codes.NotFound { + return retry.Unrecoverable(errors.Join(gerrc.ErrNotFound, err)) + } + return err + }) + if err != nil { + return types.Sequencer{}, err + } + + var pubKey cryptotypes.PubKey + err = c.protoCodec.UnpackAny(res.Sequencer.DymintPubKey, &pubKey) + if err != nil { + return types.Sequencer{}, err + } + + tmPubKey, err := cryptocodec.ToTmPubKeyInterface(pubKey) + if err != nil { + return types.Sequencer{}, err + } + + sequencer := *types.NewSequencer(tmPubKey, res.Sequencer.Address) + + return sequencer, nil +} + // GetAllSequencers returns all sequencers of the given rollapp. func (c *Client) GetAllSequencers() ([]types.Sequencer, error) { var res *sequencertypes.QueryGetSequencersByRollappResponse diff --git a/settlement/grpc/grpc.go b/settlement/grpc/grpc.go index 67c62e0d3..a4889d80a 100644 --- a/settlement/grpc/grpc.go +++ b/settlement/grpc/grpc.go @@ -228,6 +228,11 @@ func (c *Client) GetProposer() *types.Sequencer { return types.NewSequencer(tmPubKey, pubKey.Address().String()) } +// GetSequencerByAddress returns all sequencer information by its address. Not implemented since it will not be used in grpc SL +func (c *Client) GetSequencerByAddress(address string) (types.Sequencer, error) { + panic("GetSequencerByAddress not implemented in grpc SL") +} + // GetAllSequencers implements settlement.ClientI. func (c *Client) GetAllSequencers() ([]types.Sequencer, error) { return c.GetBondedSequencers() diff --git a/settlement/local/local.go b/settlement/local/local.go index b085a567b..579ddfb0f 100644 --- a/settlement/local/local.go +++ b/settlement/local/local.go @@ -206,6 +206,11 @@ func (c *Client) GetProposer() *types.Sequencer { return types.NewSequencer(tmPubKey, pubKey.Address().String()) } +// GetSequencerByAddress returns all sequencer information by its address. Not implemented since it will not be used in mock SL +func (c *Client) GetSequencerByAddress(address string) (types.Sequencer, error) { + panic("GetSequencerByAddress not implemented in local SL") +} + // GetAllSequencers implements settlement.ClientI. func (c *Client) GetAllSequencers() ([]types.Sequencer, error) { return c.GetBondedSequencers() diff --git a/settlement/settlement.go b/settlement/settlement.go index 91dea7fdb..66b78e604 100644 --- a/settlement/settlement.go +++ b/settlement/settlement.go @@ -73,7 +73,8 @@ type ClientI interface { GetLatestBatch() (*ResultRetrieveBatch, error) // GetBatchAtIndex returns the batch at the given index. GetBatchAtIndex(index uint64) (*ResultRetrieveBatch, error) - + // GetSequencerByAddress returns all sequencer information by its address. + GetSequencerByAddress(address string) (types.Sequencer, error) // GetAllSequencers returns all sequencers for this rollapp (bonded and not bonded). GetAllSequencers() ([]types.Sequencer, error) // GetBondedSequencers returns the list of the bonded sequencers for this rollapp.