From 2f38088ecf2a0b2f5c4ab51f5e83fe288ac149a2 Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 1 Nov 2024 18:59:03 +0300 Subject: [PATCH] Feature: sudo flags in address --- cmd/api/bus/dispatcher.go | 22 ++++++- cmd/api/bus/observer.go | 29 ++++++--- cmd/api/cache/constants.go | 88 ++++++++++++++++++++++++++++ cmd/api/docs/docs.go | 8 +++ cmd/api/docs/swagger.json | 8 +++ cmd/api/docs/swagger.yaml | 6 ++ cmd/api/handler/address.go | 69 +++++++++++++--------- cmd/api/handler/address_test.go | 4 +- cmd/api/handler/responses/address.go | 7 ++- cmd/api/handler/rollup.go | 32 ++++++---- cmd/api/handler/rollup_test.go | 4 +- cmd/api/handler/search.go | 37 +++++++----- cmd/api/handler/search_test.go | 4 +- cmd/api/init.go | 32 ++++++---- cmd/api/main.go | 5 ++ internal/storage/constant.go | 6 +- internal/storage/generic.go | 7 ++- pkg/indexer/storage/storage.go | 10 ++++ 18 files changed, 289 insertions(+), 89 deletions(-) create mode 100644 cmd/api/cache/constants.go diff --git a/cmd/api/bus/dispatcher.go b/cmd/api/bus/dispatcher.go index d162e6f..b29ef41 100644 --- a/cmd/api/bus/dispatcher.go +++ b/cmd/api/bus/dispatcher.go @@ -87,7 +87,7 @@ func (d *Dispatcher) listen(ctx context.Context) { return } if notification == nil { - log.Warn().Str("channel", notification.Channel).Msg("nil notification") + log.Warn().Msg("nil notification") continue } if err := d.handleNotification(ctx, notification); err != nil { @@ -107,7 +107,9 @@ func (d *Dispatcher) handleNotification(ctx context.Context, notification *pq.No return d.handleBlock(ctx, id) case storage.ChannelHead: - return d.handleHead(ctx, notification.Extra) + return d.handleHead(notification.Extra) + case storage.ChannelConstant: + return d.handleConstant(notification.Extra) default: return errors.Errorf("unknown channel name: %s", notification.Channel) } @@ -126,7 +128,7 @@ func (d *Dispatcher) handleBlock(ctx context.Context, id uint64) error { return nil } -func (d *Dispatcher) handleHead(ctx context.Context, msg string) error { +func (d *Dispatcher) handleHead(msg string) error { var state storage.State if err := json.Unmarshal([]byte(msg), &state); err != nil { return err @@ -139,3 +141,17 @@ func (d *Dispatcher) handleHead(ctx context.Context, msg string) error { d.mx.RUnlock() return nil } + +func (d *Dispatcher) handleConstant(msg string) error { + var c storage.Constant + if err := json.Unmarshal([]byte(msg), &c); err != nil { + return err + } + + d.mx.RLock() + for i := range d.observers { + d.observers[i].notifyConstants(&c) + } + d.mx.RUnlock() + return nil +} diff --git a/cmd/api/bus/observer.go b/cmd/api/bus/observer.go index 2223975..e08fc93 100644 --- a/cmd/api/bus/observer.go +++ b/cmd/api/bus/observer.go @@ -9,11 +9,13 @@ import ( ) type Observer struct { - blocks chan *storage.Block - head chan *storage.State + blocks chan *storage.Block + head chan *storage.State + constants chan *storage.Constant - listenHead bool - listenBlocks bool + listenHead bool + listenBlocks bool + listenConstants bool g workerpool.Group } @@ -24,9 +26,10 @@ func NewObserver(channels ...string) *Observer { } observer := &Observer{ - blocks: make(chan *storage.Block, 1024), - head: make(chan *storage.State, 1024), - g: workerpool.NewGroup(), + blocks: make(chan *storage.Block, 1024), + head: make(chan *storage.State, 1024), + constants: make(chan *storage.Constant, 1024), + g: workerpool.NewGroup(), } for i := range channels { @@ -35,6 +38,8 @@ func NewObserver(channels ...string) *Observer { observer.listenBlocks = true case storage.ChannelHead: observer.listenHead = true + case storage.ChannelConstant: + observer.listenConstants = true } } @@ -45,6 +50,7 @@ func (observer Observer) Close() error { observer.g.Wait() close(observer.blocks) close(observer.head) + close(observer.constants) return nil } @@ -58,6 +64,11 @@ func (observer Observer) notifyState(state *storage.State) { observer.head <- state } } +func (observer Observer) notifyConstants(constant *storage.Constant) { + if observer.listenConstants { + observer.constants <- constant + } +} func (observer Observer) Blocks() <-chan *storage.Block { return observer.blocks @@ -66,3 +77,7 @@ func (observer Observer) Blocks() <-chan *storage.Block { func (observer Observer) Head() <-chan *storage.State { return observer.head } + +func (observer Observer) Constants() <-chan *storage.Constant { + return observer.constants +} diff --git a/cmd/api/cache/constants.go b/cmd/api/cache/constants.go new file mode 100644 index 0000000..40a82e7 --- /dev/null +++ b/cmd/api/cache/constants.go @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2024 PK Lab AG +// SPDX-License-Identifier: MIT + +package cache + +import ( + "context" + "sync" + + "github.com/celenium-io/astria-indexer/cmd/api/bus" + "github.com/celenium-io/astria-indexer/internal/storage" + "github.com/celenium-io/astria-indexer/internal/storage/types" +) + +type ConstantsCache struct { + data map[string]map[string]string + observer *bus.Observer + + wg *sync.WaitGroup + mx *sync.RWMutex +} + +func NewConstantsCache(observer *bus.Observer) *ConstantsCache { + return &ConstantsCache{ + data: make(map[string]map[string]string), + observer: observer, + wg: new(sync.WaitGroup), + mx: new(sync.RWMutex), + } +} + +func (c *ConstantsCache) Start(ctx context.Context, repo storage.IConstant) error { + constants, err := repo.All(ctx) + if err != nil { + return err + } + + for i := range constants { + c.addConstant(&constants[i]) + } + + c.wg.Add(1) + go c.listen(ctx) + + return nil +} + +func (c *ConstantsCache) listen(ctx context.Context) { + defer c.wg.Done() + + for { + select { + case <-ctx.Done(): + return + case constant := <-c.observer.Constants(): + c.addConstant(constant) + } + } +} + +func (c *ConstantsCache) addConstant(constant *storage.Constant) { + c.mx.Lock() + { + module := string(constant.Module) + if _, ok := c.data[module]; !ok { + c.data[module] = make(map[string]string) + } + c.data[module][constant.Name] = constant.Value + } + c.mx.Unlock() +} + +func (c *ConstantsCache) Get(module types.ModuleName, name string) (string, bool) { + c.mx.RLock() + defer c.mx.RUnlock() + + if m, ok := c.data[string(module)]; ok { + val, ok := m[name] + return val, ok + } + + return "", false +} + +func (c *ConstantsCache) Close() error { + c.wg.Wait() + return nil +} diff --git a/cmd/api/docs/docs.go b/cmd/api/docs/docs.go index 023422c..58b0ddc 100644 --- a/cmd/api/docs/docs.go +++ b/cmd/api/docs/docs.go @@ -2789,6 +2789,14 @@ const docTemplate = `{ "type": "boolean", "example": false }, + "is_ibc_sudo": { + "type": "boolean", + "example": false + }, + "is_sudo": { + "type": "boolean", + "example": false + }, "nonce": { "type": "integer", "example": 10 diff --git a/cmd/api/docs/swagger.json b/cmd/api/docs/swagger.json index 49f1056..3f494d8 100644 --- a/cmd/api/docs/swagger.json +++ b/cmd/api/docs/swagger.json @@ -2779,6 +2779,14 @@ "type": "boolean", "example": false }, + "is_ibc_sudo": { + "type": "boolean", + "example": false + }, + "is_sudo": { + "type": "boolean", + "example": false + }, "nonce": { "type": "integer", "example": 10 diff --git a/cmd/api/docs/swagger.yaml b/cmd/api/docs/swagger.yaml index 97a3716..b6a3ef1 100644 --- a/cmd/api/docs/swagger.yaml +++ b/cmd/api/docs/swagger.yaml @@ -63,6 +63,12 @@ definitions: is_ibc_relayer: example: false type: boolean + is_ibc_sudo: + example: false + type: boolean + is_sudo: + example: false + type: boolean nonce: example: 10 type: integer diff --git a/cmd/api/handler/address.go b/cmd/api/handler/address.go index dec3e9c..9ab5ca3 100644 --- a/cmd/api/handler/address.go +++ b/cmd/api/handler/address.go @@ -7,26 +7,29 @@ import ( "net/http" "time" + "github.com/celenium-io/astria-indexer/cmd/api/cache" "github.com/celenium-io/astria-indexer/cmd/api/handler/responses" "github.com/celenium-io/astria-indexer/internal/storage" - storageTypes "github.com/celenium-io/astria-indexer/internal/storage/types" + "github.com/celenium-io/astria-indexer/internal/storage/types" "github.com/labstack/echo/v4" "github.com/pkg/errors" ) type AddressHandler struct { - address storage.IAddress - txs storage.ITx - actions storage.IAction - rollups storage.IRollup - fees storage.IFee - bridge storage.IBridge - deposits storage.IDeposit - state storage.IState - indexerName string + constantCache *cache.ConstantsCache + address storage.IAddress + txs storage.ITx + actions storage.IAction + rollups storage.IRollup + fees storage.IFee + bridge storage.IBridge + deposits storage.IDeposit + state storage.IState + indexerName string } func NewAddressHandler( + constantCache *cache.ConstantsCache, address storage.IAddress, txs storage.ITx, actions storage.IAction, @@ -38,15 +41,16 @@ func NewAddressHandler( indexerName string, ) *AddressHandler { return &AddressHandler{ - address: address, - txs: txs, - actions: actions, - rollups: rollups, - fees: fees, - bridge: bridge, - deposits: deposits, - state: state, - indexerName: indexerName, + constantCache: constantCache, + address: address, + txs: txs, + actions: actions, + rollups: rollups, + fees: fees, + bridge: bridge, + deposits: deposits, + state: state, + indexerName: indexerName, } } @@ -78,15 +82,19 @@ func (handler *AddressHandler) Get(c echo.Context) error { return handleError(c, err, handler.address) } + sudoAddress, _ := handler.constantCache.Get(types.ModuleNameGeneric, "authority_sudo_address") + ibcSudoAddress, _ := handler.constantCache.Get(types.ModuleNameGeneric, "ibc_sudo_address") + bridge, err := handler.bridge.ByAddress(c.Request().Context(), address.Id) if err != nil { if !handler.bridge.IsNoRows(err) { return handleError(c, err, handler.address) } - return c.JSON(http.StatusOK, responses.NewAddress(address, nil)) + + return c.JSON(http.StatusOK, responses.NewAddress(address, nil, sudoAddress, ibcSudoAddress)) } - return c.JSON(http.StatusOK, responses.NewAddress(address, &bridge)) + return c.JSON(http.StatusOK, responses.NewAddress(address, &bridge, sudoAddress, ibcSudoAddress)) } type listAddressRequest struct { @@ -139,9 +147,12 @@ func (handler *AddressHandler) List(c echo.Context) error { return handleError(c, err, handler.address) } + sudoAddress, _ := handler.constantCache.Get(types.ModuleNameGeneric, "authority_sudo_address") + ibcSudoAddress, _ := handler.constantCache.Get(types.ModuleNameGeneric, "ibc_sudo_address") + response := make([]responses.Address, len(address)) for i := range address { - response[i] = responses.NewAddress(address[i], nil) + response[i] = responses.NewAddress(address[i], nil, sudoAddress, ibcSudoAddress) } return returnArray(c, response) @@ -179,8 +190,8 @@ func (p *addressTxRequest) SetDefault() { // @Param limit query integer false "Count of requested entities" minimum(1) maximum(100) // @Param offset query integer false "Offset" minimum(1) // @Param sort query string false "Sort order" Enums(asc, desc) -// @Param status query storageTypes.Status false "Comma-separated status list" -// @Param msg_type query storageTypes.ActionType false "Comma-separated message types list" +// @Param status query types.Status false "Comma-separated status list" +// @Param msg_type query types.ActionType false "Comma-separated message types list" // @Param from query integer false "Time from in unix timestamp" minimum(1) // @Param to query integer false "Time to in unix timestamp" minimum(1) // @Param height query integer false "Block number" minimum(1) @@ -207,7 +218,7 @@ func (handler *AddressHandler) Transactions(c echo.Context) error { Sort: pgSort(req.Sort), Status: req.Status, Height: req.Height, - ActionTypes: storageTypes.NewActionTypeMask(), + ActionTypes: types.NewActionTypeMask(), } if req.From > 0 { fltrs.TimeFrom = time.Unix(req.From, 0).UTC() @@ -216,7 +227,7 @@ func (handler *AddressHandler) Transactions(c echo.Context) error { fltrs.TimeTo = time.Unix(req.To, 0).UTC() } for i := range req.ActionTypes { - fltrs.ActionTypes.SetType(storageTypes.ActionType(req.ActionTypes[i])) + fltrs.ActionTypes.SetType(types.ActionType(req.ActionTypes[i])) } txs, err := handler.txs.ByAddress(c.Request().Context(), address.Id, fltrs) @@ -255,11 +266,11 @@ func (p *getAddressMessages) ToFilters() storage.AddressActionsFilter { Limit: int(p.Limit), Offset: int(p.Offset), Sort: pgSort(p.Sort), - ActionTypes: storageTypes.NewActionTypeMask(), + ActionTypes: types.NewActionTypeMask(), } for i := range p.ActionTypes { - fltrs.ActionTypes.SetType(storageTypes.ActionType(p.ActionTypes[i])) + fltrs.ActionTypes.SetType(types.ActionType(p.ActionTypes[i])) } return fltrs @@ -275,7 +286,7 @@ func (p *getAddressMessages) ToFilters() storage.AddressActionsFilter { // @Param limit query integer false "Count of requested entities" minimum(1) maximum(100) // @Param offset query integer false "Offset" minimum(1) // @Param sort query string false "Sort order" Enums(asc, desc) -// @Param action_types query storageTypes.ActionType false "Comma-separated action types list" +// @Param action_types query types.ActionType false "Comma-separated action types list" // @Produce json // @Success 200 {array} responses.Action // @Failure 400 {object} Error diff --git a/cmd/api/handler/address_test.go b/cmd/api/handler/address_test.go index 16bb891..1bdc0b5 100644 --- a/cmd/api/handler/address_test.go +++ b/cmd/api/handler/address_test.go @@ -12,6 +12,7 @@ import ( "net/url" "testing" + "github.com/celenium-io/astria-indexer/cmd/api/cache" "github.com/celenium-io/astria-indexer/cmd/api/handler/responses" "github.com/celenium-io/astria-indexer/internal/currency" "github.com/celenium-io/astria-indexer/internal/storage" @@ -54,7 +55,8 @@ func (s *AddressTestSuite) SetupSuite() { s.bridge = mock.NewMockIBridge(s.ctrl) s.deposits = mock.NewMockIDeposit(s.ctrl) s.state = mock.NewMockIState(s.ctrl) - s.handler = NewAddressHandler(s.address, s.txs, s.actions, s.rollups, s.fees, s.bridge, s.deposits, s.state, testIndexerName) + cc := cache.NewConstantsCache(nil) + s.handler = NewAddressHandler(cc, s.address, s.txs, s.actions, s.rollups, s.fees, s.bridge, s.deposits, s.state, testIndexerName) } // TearDownSuite - diff --git a/cmd/api/handler/responses/address.go b/cmd/api/handler/responses/address.go index ddf3fbd..f0aa7f1 100644 --- a/cmd/api/handler/responses/address.go +++ b/cmd/api/handler/responses/address.go @@ -20,12 +20,14 @@ type Address struct { Hash string `example:"astria1phym4uktjn6gjle226009ge7u82w0dgtszs8x2" json:"hash" swaggertype:"string"` IsBridge bool `example:"false" json:"is_bridge" swaggertype:"boolean"` IsIbcRelayer bool `example:"false" json:"is_ibc_relayer" swaggertype:"boolean"` + IsSudo bool `example:"false" json:"is_sudo" swaggertype:"boolean"` + IsIbcSudo bool `example:"false" json:"is_ibc_sudo" swaggertype:"boolean"` Balance []Balance `json:"balances"` Bridge *Bridge `json:"bridge,omitempty"` } -func NewAddress(addr storage.Address, bridge *storage.Bridge) Address { +func NewAddress(addr storage.Address, bridge *storage.Bridge, sudoAddr, ibcSudoAddr string) Address { result := Address{ Id: addr.Id, Height: addr.Height, @@ -37,6 +39,9 @@ func NewAddress(addr storage.Address, bridge *storage.Bridge) Address { Balance: make([]Balance, 0), } + result.IsSudo = sudoAddr == result.Hash + result.IsIbcSudo = ibcSudoAddr == result.Hash + for i := range addr.Balance { result.Balance = append(result.Balance, Balance{ Currency: addr.Balance[i].Currency, diff --git a/cmd/api/handler/rollup.go b/cmd/api/handler/rollup.go index 9905787..8ba86db 100644 --- a/cmd/api/handler/rollup.go +++ b/cmd/api/handler/rollup.go @@ -8,6 +8,7 @@ import ( "net/http" "time" + "github.com/celenium-io/astria-indexer/cmd/api/cache" "github.com/celenium-io/astria-indexer/cmd/api/handler/responses" "github.com/celenium-io/astria-indexer/internal/storage" "github.com/celenium-io/astria-indexer/internal/storage/types" @@ -16,15 +17,17 @@ import ( ) type RollupHandler struct { - rollups storage.IRollup - actions storage.IAction - bridge storage.IBridge - deposits storage.IDeposit - state storage.IState - indexerName string + constantCache *cache.ConstantsCache + rollups storage.IRollup + actions storage.IAction + bridge storage.IBridge + deposits storage.IDeposit + state storage.IState + indexerName string } func NewRollupHandler( + constantCache *cache.ConstantsCache, rollups storage.IRollup, actions storage.IAction, bridge storage.IBridge, @@ -33,12 +36,13 @@ func NewRollupHandler( indexerName string, ) *RollupHandler { return &RollupHandler{ - rollups: rollups, - actions: actions, - bridge: bridge, - deposits: deposits, - state: state, - indexerName: indexerName, + constantCache: constantCache, + rollups: rollups, + actions: actions, + bridge: bridge, + deposits: deposits, + state: state, + indexerName: indexerName, } } @@ -253,7 +257,9 @@ func (handler *RollupHandler) Addresses(c echo.Context) error { response := make([]responses.Address, len(addresses)) for i := range addresses { if addresses[i].Address != nil { - response[i] = responses.NewAddress(*addresses[i].Address, nil) + sudoAddress, _ := handler.constantCache.Get(types.ModuleNameGeneric, "authority_sudo_address") + ibcSudoAddress, _ := handler.constantCache.Get(types.ModuleNameGeneric, "ibc_sudo_address") + response[i] = responses.NewAddress(*addresses[i].Address, nil, sudoAddress, ibcSudoAddress) } } diff --git a/cmd/api/handler/rollup_test.go b/cmd/api/handler/rollup_test.go index 5f77195..40ff307 100644 --- a/cmd/api/handler/rollup_test.go +++ b/cmd/api/handler/rollup_test.go @@ -11,6 +11,7 @@ import ( "net/url" "testing" + "github.com/celenium-io/astria-indexer/cmd/api/cache" "github.com/celenium-io/astria-indexer/cmd/api/handler/responses" "github.com/celenium-io/astria-indexer/internal/currency" "github.com/celenium-io/astria-indexer/internal/storage" @@ -46,7 +47,8 @@ func (s *RollupTestSuite) SetupSuite() { s.bridge = mock.NewMockIBridge(s.ctrl) s.deposits = mock.NewMockIDeposit(s.ctrl) s.state = mock.NewMockIState(s.ctrl) - s.handler = NewRollupHandler(s.rollups, s.actions, s.bridge, s.deposits, s.state, testIndexerName) + cc := cache.NewConstantsCache(nil) + s.handler = NewRollupHandler(cc, s.rollups, s.actions, s.bridge, s.deposits, s.state, testIndexerName) } // TearDownSuite - diff --git a/cmd/api/handler/search.go b/cmd/api/handler/search.go index eb9a18a..8d73118 100644 --- a/cmd/api/handler/search.go +++ b/cmd/api/handler/search.go @@ -4,22 +4,26 @@ package handler import ( + "github.com/celenium-io/astria-indexer/cmd/api/cache" "github.com/celenium-io/astria-indexer/cmd/api/handler/responses" "github.com/celenium-io/astria-indexer/internal/storage" + "github.com/celenium-io/astria-indexer/internal/storage/types" "github.com/labstack/echo/v4" ) type SearchHandler struct { - search storage.ISearch - address storage.IAddress - blocks storage.IBlock - txs storage.ITx - rollups storage.IRollup - bridges storage.IBridge - validators storage.IValidator + constantCache *cache.ConstantsCache + search storage.ISearch + address storage.IAddress + blocks storage.IBlock + txs storage.ITx + rollups storage.IRollup + bridges storage.IBridge + validators storage.IValidator } func NewSearchHandler( + constantCache *cache.ConstantsCache, search storage.ISearch, address storage.IAddress, blocks storage.IBlock, @@ -29,13 +33,14 @@ func NewSearchHandler( validators storage.IValidator, ) *SearchHandler { return &SearchHandler{ - search: search, - address: address, - blocks: blocks, - txs: txs, - rollups: rollups, - bridges: bridges, - validators: validators, + constantCache: constantCache, + search: search, + address: address, + blocks: blocks, + txs: txs, + rollups: rollups, + bridges: bridges, + validators: validators, } } @@ -93,7 +98,9 @@ func (s *SearchHandler) Search(c echo.Context) error { if err != nil { return handleError(c, err, s.address) } - body = responses.NewAddress(*address, nil) + sudoAddress, _ := s.constantCache.Get(types.ModuleNameGeneric, "authority_sudo_address") + ibcSudoAddress, _ := s.constantCache.Get(types.ModuleNameGeneric, "ibc_sudo_address") + body = responses.NewAddress(*address, nil, sudoAddress, ibcSudoAddress) case "validator": validator, err := s.validators.GetByID(c.Request().Context(), results[i].Id) if err != nil { diff --git a/cmd/api/handler/search_test.go b/cmd/api/handler/search_test.go index 902b2dc..76f911b 100644 --- a/cmd/api/handler/search_test.go +++ b/cmd/api/handler/search_test.go @@ -11,6 +11,7 @@ import ( "net/url" "testing" + "github.com/celenium-io/astria-indexer/cmd/api/cache" "github.com/celenium-io/astria-indexer/cmd/api/handler/responses" "github.com/celenium-io/astria-indexer/internal/storage" "github.com/celenium-io/astria-indexer/internal/storage/mock" @@ -46,7 +47,8 @@ func (s *SearchTestSuite) SetupSuite() { s.rollups = mock.NewMockIRollup(s.ctrl) s.validators = mock.NewMockIValidator(s.ctrl) s.bridges = mock.NewMockIBridge(s.ctrl) - s.handler = NewSearchHandler(s.search, s.address, s.blocks, s.txs, s.rollups, s.bridges, s.validators) + cc := cache.NewConstantsCache(nil) + s.handler = NewSearchHandler(cc, s.search, s.address, s.blocks, s.txs, s.rollups, s.bridges, s.validators) } // TearDownSuite - diff --git a/cmd/api/init.go b/cmd/api/init.go index 52eaadd..584bd40 100644 --- a/cmd/api/init.go +++ b/cmd/api/init.go @@ -251,6 +251,8 @@ func initDatabase(cfg config.Database, viewsDir string) postgres.Storage { return db } +var constantCache *cache.ConstantsCache + func initHandlers(ctx context.Context, e *echo.Echo, cfg Config, db postgres.Storage) { v1 := e.Group("v1") @@ -260,23 +262,29 @@ func initHandlers(ctx context.Context, e *echo.Echo, cfg Config, db postgres.Sto v1.GET("/constants", constantsHandler.Get) v1.GET("/enums", constantsHandler.Enums) - searchHandler := handler.NewSearchHandler(db.Search, db.Address, db.Blocks, db.Tx, db.Rollup, db.Bridges, db.Validator) + searchHandler := handler.NewSearchHandler(constantCache, db.Search, db.Address, db.Blocks, db.Tx, db.Rollup, db.Bridges, db.Validator) v1.GET("/search", searchHandler.Search) - addressHandlers := handler.NewAddressHandler(db.Address, db.Tx, db.Action, db.Rollup, db.Fee, db.Bridges, db.Deposit, db.State, cfg.Indexer.Name) + constantObserver := dispatcher.Observe(storage.ChannelConstant) + constantCache = cache.NewConstantsCache(constantObserver) + if err := constantCache.Start(ctx, db.Constants); err != nil { + panic(err) + } + + addressHandler := handler.NewAddressHandler(constantCache, db.Address, db.Tx, db.Action, db.Rollup, db.Fee, db.Bridges, db.Deposit, db.State, cfg.Indexer.Name) addressesGroup := v1.Group("/address") { - addressesGroup.GET("", addressHandlers.List) - addressesGroup.GET("/count", addressHandlers.Count) + addressesGroup.GET("", addressHandler.List) + addressesGroup.GET("/count", addressHandler.Count) addressGroup := addressesGroup.Group("/:hash") { - addressGroup.GET("", addressHandlers.Get) - addressGroup.GET("/txs", addressHandlers.Transactions) - addressGroup.GET("/actions", addressHandlers.Actions) - addressGroup.GET("/rollups", addressHandlers.Rollups) - addressGroup.GET("/roles", addressHandlers.Roles) - addressGroup.GET("/fees", addressHandlers.Fees) - addressGroup.GET("/deposits", addressHandlers.Deposits) + addressGroup.GET("", addressHandler.Get) + addressGroup.GET("/txs", addressHandler.Transactions) + addressGroup.GET("/actions", addressHandler.Actions) + addressGroup.GET("/rollups", addressHandler.Rollups) + addressGroup.GET("/roles", addressHandler.Roles) + addressGroup.GET("/fees", addressHandler.Fees) + addressGroup.GET("/deposits", addressHandler.Deposits) } } @@ -311,7 +319,7 @@ func initHandlers(ctx context.Context, e *echo.Echo, cfg Config, db postgres.Sto } } - rollupsHandler := handler.NewRollupHandler(db.Rollup, db.Action, db.Bridges, db.Deposit, db.State, cfg.Indexer.Name) + rollupsHandler := handler.NewRollupHandler(constantCache, db.Rollup, db.Action, db.Bridges, db.Deposit, db.State, cfg.Indexer.Name) rollupsGroup := v1.Group("/rollup") { rollupsGroup.GET("", rollupsHandler.List) diff --git a/cmd/api/main.go b/cmd/api/main.go index b820ef6..202288b 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -67,6 +67,11 @@ func main() { e.Logger.Fatal(err) } } + if constantCache != nil { + if err := constantCache.Close(); err != nil { + e.Logger.Fatal(err) + } + } if dispatcher != nil { if err := dispatcher.Close(); err != nil { e.Logger.Fatal(err) diff --git a/internal/storage/constant.go b/internal/storage/constant.go index fb1c376..476989a 100644 --- a/internal/storage/constant.go +++ b/internal/storage/constant.go @@ -21,9 +21,9 @@ type IConstant interface { type Constant struct { bun.BaseModel `bun:"table:constant" comment:"Table with constants"` - Module types.ModuleName `bun:"module,pk,type:module_name" comment:"Module name which declares constant"` - Name string `bun:"name,pk,type:text" comment:"Constant name"` - Value string `bun:"value,type:text" comment:"Constant value"` + Module types.ModuleName `bun:"module,pk,type:module_name" comment:"Module name which declares constant" json:"module"` + Name string `bun:"name,pk,type:text" comment:"Constant name" json:"name"` + Value string `bun:"value,type:text" comment:"Constant value" json:"value"` } func (Constant) TableName() string { diff --git a/internal/storage/generic.go b/internal/storage/generic.go index 0d402d4..443c25c 100644 --- a/internal/storage/generic.go +++ b/internal/storage/generic.go @@ -13,9 +13,10 @@ import ( ) const ( - ChannelBlock = "blocks" - ChannelHead = "head" - ChannelTx = "tx" + ChannelBlock = "blocks" + ChannelHead = "head" + ChannelTx = "tx" + ChannelConstant = "constant" ) var Models = []any{ diff --git a/pkg/indexer/storage/storage.go b/pkg/indexer/storage/storage.go index cb27ac0..4273cee 100644 --- a/pkg/indexer/storage/storage.go +++ b/pkg/indexer/storage/storage.go @@ -238,5 +238,15 @@ func (module *Module) notify(ctx context.Context, state storage.State, block *st return err } + for i := range block.Constants { + raw, err := json.Marshal(block.Constants[i]) + if err != nil { + return err + } + if err := module.notificator.Notify(ctx, storage.ChannelConstant, string(raw)); err != nil { + return err + } + } + return nil }