diff --git a/cmd/api/admin_middleware.go b/cmd/api/admin_middleware.go index b7634050..1aa74860 100644 --- a/cmd/api/admin_middleware.go +++ b/cmd/api/admin_middleware.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2024 PK Lab AG +// SPDX-License-Identifier: MIT + package main import ( diff --git a/cmd/api/handler/rollup_auth.go b/cmd/api/handler/rollup_auth.go index 5700ef57..8682c4b2 100644 --- a/cmd/api/handler/rollup_auth.go +++ b/cmd/api/handler/rollup_auth.go @@ -8,6 +8,7 @@ import ( "encoding/base64" "net/http" + "github.com/celenium-io/celestia-indexer/cmd/api/handler/responses" "github.com/celenium-io/celestia-indexer/internal/storage" "github.com/celenium-io/celestia-indexer/internal/storage/postgres" enums "github.com/celenium-io/celestia-indexer/internal/storage/types" @@ -303,3 +304,51 @@ func (handler RollupAuthHandler) deleteRollup(ctx context.Context, id uint64) er return tx.Flush(ctx) } + +func (handler RollupAuthHandler) Unverified(c echo.Context) error { + rollups, err := handler.rollups.Unverified(c.Request().Context()) + if err != nil { + return handleError(c, err, handler.rollups) + } + + response := make([]responses.Rollup, len(rollups)) + for i := range rollups { + response[i] = responses.NewRollup(&rollups[i]) + } + + return returnArray(c, response) +} + +type verifyRollupRequest struct { + Id uint64 `param:"id" validate:"required,min=1"` +} + +func (handler RollupAuthHandler) Verify(c echo.Context) error { + req, err := bindAndValidate[verifyRollupRequest](c) + if err != nil { + return badRequestError(c, err) + } + + if err := handler.verify(c.Request().Context(), req.Id); err != nil { + return handleError(c, err, handler.address) + } + + return success(c) +} + +func (handler RollupAuthHandler) verify(ctx context.Context, id uint64) error { + tx, err := postgres.BeginTransaction(ctx, handler.tx) + if err != nil { + return err + } + + err = tx.UpdateRollup(ctx, &storage.Rollup{ + Id: id, + Verified: true, + }) + if err != nil { + return tx.HandleError(ctx, err) + } + + return tx.Flush(ctx) +} diff --git a/cmd/api/init.go b/cmd/api/init.go index 10554f3c..d710f7a7 100644 --- a/cmd/api/init.go +++ b/cmd/api/init.go @@ -510,6 +510,8 @@ func initHandlers(ctx context.Context, e *echo.Echo, cfg Config, db postgres.Sto rollup.POST("/new", rollupAuthHandler.Create, keyMiddleware) rollup.PATCH("/:id", rollupAuthHandler.Update, keyMiddleware) rollup.DELETE("/:id", rollupAuthHandler.Delete, keyMiddleware, adminMiddleware) + rollup.PATCH("/:id/verify", rollupAuthHandler.Verify, keyMiddleware, adminMiddleware) + rollup.GET("/unverified", rollupAuthHandler.Unverified, keyMiddleware, adminMiddleware) } } diff --git a/cmd/api/routes_test.go b/cmd/api/routes_test.go index 617d95e2..52ed74f8 100644 --- a/cmd/api/routes_test.go +++ b/cmd/api/routes_test.go @@ -53,6 +53,8 @@ func TestRoutes(t *testing.T) { "/v1/stats/changes_24h GET": {}, "/v1/rollup/count GET": {}, "/v1/auth/rollup/:id PATCH": {}, + "/v1/auth/rollup/:id/verify PATCH": {}, + "/v1/auth/rollup/unverified GET": {}, "/v1/address/:hash/undelegations GET": {}, "/v1/block/:height/messages GET": {}, "/v1/namespace/active GET": {}, diff --git a/internal/storage/mock/rollup.go b/internal/storage/mock/rollup.go index f2db2567..5e4c6f65 100644 --- a/internal/storage/mock/rollup.go +++ b/internal/storage/mock/rollup.go @@ -783,6 +783,45 @@ func (c *MockIRollupTagsCall) DoAndReturn(f func(context.Context) ([]string, err return c } +// Unverified mocks base method. +func (m *MockIRollup) Unverified(ctx context.Context) ([]storage.Rollup, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Unverified", ctx) + ret0, _ := ret[0].([]storage.Rollup) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Unverified indicates an expected call of Unverified. +func (mr *MockIRollupMockRecorder) Unverified(ctx any) *MockIRollupUnverifiedCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unverified", reflect.TypeOf((*MockIRollup)(nil).Unverified), ctx) + return &MockIRollupUnverifiedCall{Call: call} +} + +// MockIRollupUnverifiedCall wrap *gomock.Call +type MockIRollupUnverifiedCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIRollupUnverifiedCall) Return(rollups []storage.Rollup, err error) *MockIRollupUnverifiedCall { + c.Call = c.Call.Return(rollups, err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIRollupUnverifiedCall) Do(f func(context.Context) ([]storage.Rollup, error)) *MockIRollupUnverifiedCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIRollupUnverifiedCall) DoAndReturn(f func(context.Context) ([]storage.Rollup, error)) *MockIRollupUnverifiedCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // Update mocks base method. func (m_2 *MockIRollup) Update(ctx context.Context, m *storage.Rollup) error { m_2.ctrl.T.Helper() diff --git a/internal/storage/postgres/rollup.go b/internal/storage/postgres/rollup.go index b2e9a919..2d25a541 100644 --- a/internal/storage/postgres/rollup.go +++ b/internal/storage/postgres/rollup.go @@ -357,3 +357,11 @@ func (r *Rollup) Tags(ctx context.Context) (arr []string, err error) { Scan(ctx, &arr) return } + +func (r *Rollup) Unverified(ctx context.Context) (rollups []storage.Rollup, err error) { + err = r.DB().NewSelect(). + Model(&rollups). + Where("verified = false"). + Scan(ctx) + return +} diff --git a/internal/storage/postgres/rollup_test.go b/internal/storage/postgres/rollup_test.go index 28846480..c6698217 100644 --- a/internal/storage/postgres/rollup_test.go +++ b/internal/storage/postgres/rollup_test.go @@ -343,3 +343,12 @@ func (s *StorageTestSuite) TestCount() { s.Require().NoError(err) s.Require().EqualValues(3, count) } + +func (s *StorageTestSuite) TestUnverified() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + rollups, err := s.storage.Rollup.Unverified(ctx) + s.Require().NoError(err) + s.Require().EqualValues(1, len(rollups)) +} diff --git a/internal/storage/postgres/transaction.go b/internal/storage/postgres/transaction.go index 63904202..f58e3a66 100644 --- a/internal/storage/postgres/transaction.go +++ b/internal/storage/postgres/transaction.go @@ -602,7 +602,7 @@ func (tx Transaction) SaveRollup(ctx context.Context, rollup *models.Rollup) err } func (tx Transaction) UpdateRollup(ctx context.Context, rollup *models.Rollup) error { - if rollup == nil || rollup.IsEmpty() { + if rollup == nil || (rollup.IsEmpty() && !rollup.Verified) { return nil } diff --git a/internal/storage/rollup.go b/internal/storage/rollup.go index 3cdc88e8..cb7b3c58 100644 --- a/internal/storage/rollup.go +++ b/internal/storage/rollup.go @@ -45,6 +45,7 @@ type IRollup interface { BySlug(ctx context.Context, slug string) (RollupWithStats, error) RollupStatsGrouping(ctx context.Context, fltrs RollupGroupStatsFilters) ([]RollupGroupedStats, error) Tags(ctx context.Context) ([]string, error) + Unverified(ctx context.Context) (rollups []Rollup, err error) } // Rollup -