From 59787f07f47aed2f5c488186fc019ee893ba4c6a Mon Sep 17 00:00:00 2001 From: Artem Date: Sat, 5 Oct 2024 16:01:41 +0300 Subject: [PATCH] Feature: total metrics --- cmd/api/docs/docs.go | 8 ++--- cmd/api/docs/swagger.json | 8 ++--- cmd/api/docs/swagger.yaml | 8 ++--- cmd/api/handler/responses/state.go | 4 +-- cmd/api/handler/state_test.go | 5 ++- internal/storage/generic.go | 4 +-- internal/storage/mock/generic.go | 30 ++++++++-------- internal/storage/postgres/transaction.go | 36 ++++++++++++++----- internal/storage/postgres/transaction_test.go | 18 +++++++++- internal/storage/state.go | 2 +- pkg/indexer/genesis/save.go | 1 - pkg/indexer/rollback/rollback.go | 7 +++- pkg/indexer/rollback/rollback_test.go | 6 +++- pkg/indexer/storage/bridge.go | 12 +++---- pkg/indexer/storage/state.go | 4 +-- pkg/indexer/storage/state_test.go | 6 ++-- pkg/indexer/storage/storage.go | 5 +-- test/data/state.yml | 2 +- 18 files changed, 105 insertions(+), 61 deletions(-) diff --git a/cmd/api/docs/docs.go b/cmd/api/docs/docs.go index f9d2440..9fd76e0 100644 --- a/cmd/api/docs/docs.go +++ b/cmd/api/docs/docs.go @@ -3241,10 +3241,10 @@ const docTemplate = `{ "format": "int64", "example": 43 }, - "total_fee": { - "type": "string", - "format": "string", - "example": "312" + "total_bridges": { + "type": "integer", + "format": "int64", + "example": 312 }, "total_rollups": { "type": "integer", diff --git a/cmd/api/docs/swagger.json b/cmd/api/docs/swagger.json index 6789ec5..dae0a36 100644 --- a/cmd/api/docs/swagger.json +++ b/cmd/api/docs/swagger.json @@ -3231,10 +3231,10 @@ "format": "int64", "example": 43 }, - "total_fee": { - "type": "string", - "format": "string", - "example": "312" + "total_bridges": { + "type": "integer", + "format": "int64", + "example": 312 }, "total_rollups": { "type": "integer", diff --git a/cmd/api/docs/swagger.yaml b/cmd/api/docs/swagger.yaml index fd14b0b..3fdaeaf 100644 --- a/cmd/api/docs/swagger.yaml +++ b/cmd/api/docs/swagger.yaml @@ -507,10 +507,10 @@ definitions: example: 43 format: int64 type: integer - total_fee: - example: "312" - format: string - type: string + total_bridges: + example: 312 + format: int64 + type: integer total_rollups: example: 312 format: int64 diff --git a/cmd/api/handler/responses/state.go b/cmd/api/handler/responses/state.go index e5e51cf..7119852 100644 --- a/cmd/api/handler/responses/state.go +++ b/cmd/api/handler/responses/state.go @@ -22,7 +22,7 @@ type State struct { TotalTx int64 `example:"23456" format:"int64" json:"total_tx" swaggertype:"integer"` TotalAccounts int64 `example:"43" format:"int64" json:"total_accounts" swaggertype:"integer"` TotalRollups int64 `example:"312" format:"int64" json:"total_rollups" swaggertype:"integer"` - TotalFee string `example:"312" format:"string" json:"total_fee" swaggertype:"string"` + TotalBridges int64 `example:"312" format:"int64" json:"total_bridges" swaggertype:"integer"` TotalSupply string `example:"312" format:"string" json:"total_supply" swaggertype:"string"` Synced bool `example:"true" format:"boolean" json:"synced" swaggertype:"boolean"` } @@ -38,7 +38,7 @@ func NewState(state storage.State) State { TotalTx: state.TotalTx, TotalAccounts: state.TotalAccounts, TotalRollups: state.TotalRollups, - TotalFee: state.TotalFee.String(), + TotalBridges: state.TotalBridges, TotalSupply: state.TotalSupply.String(), Synced: !state.LastTime.UTC().Add(2 * time.Minute).Before(time.Now().UTC()), } diff --git a/cmd/api/handler/state_test.go b/cmd/api/handler/state_test.go index 4e372c7..c7a4978 100644 --- a/cmd/api/handler/state_test.go +++ b/cmd/api/handler/state_test.go @@ -15,7 +15,6 @@ import ( "github.com/celenium-io/astria-indexer/internal/storage" "github.com/celenium-io/astria-indexer/internal/storage/mock" "github.com/labstack/echo/v4" - "github.com/shopspring/decimal" "github.com/stretchr/testify/suite" "go.uber.org/mock/gomock" ) @@ -31,7 +30,7 @@ var ( LastTime: testTime, TotalTx: 1234, TotalAccounts: 123, - TotalFee: decimal.RequireFromString("2"), + TotalBridges: 2, TotalRollups: 30, } ) @@ -88,7 +87,7 @@ func (s *StateTestSuite) TestHead() { s.Require().EqualValues(100, state.LastHeight) s.Require().EqualValues(1234, state.TotalTx) s.Require().EqualValues(123, state.TotalAccounts) - s.Require().Equal("2", state.TotalFee) + s.Require().EqualValues(2, state.TotalBridges) s.Require().EqualValues(30, state.TotalRollups) s.Require().Equal(testTime, state.LastTime) } diff --git a/internal/storage/generic.go b/internal/storage/generic.go index 0895bf6..8573401 100644 --- a/internal/storage/generic.go +++ b/internal/storage/generic.go @@ -49,7 +49,7 @@ type Transaction interface { SaveBalances(ctx context.Context, balances ...Balance) error SaveBalanceUpdates(ctx context.Context, updates ...BalanceUpdate) error SaveBlockSignatures(ctx context.Context, signs ...BlockSignature) error - SaveBridges(ctx context.Context, bridges ...*Bridge) error + SaveBridges(ctx context.Context, bridges ...*Bridge) (int64, error) SaveConstants(ctx context.Context, constants ...Constant) error SaveRollupActions(ctx context.Context, actions ...*RollupAction) error SaveRollupAddresses(ctx context.Context, addresses ...*RollupAddress) error @@ -68,7 +68,7 @@ type Transaction interface { RollbackBlockSignatures(ctx context.Context, height types.Level) (err error) RollbackBlockStats(ctx context.Context, height types.Level) (stats BlockStats, err error) RollbackBlock(ctx context.Context, height types.Level) error - RollbackBridges(ctx context.Context, height types.Level) error + RollbackBridges(ctx context.Context, height types.Level) (int, error) RollbackRollupActions(ctx context.Context, height types.Level) (rollupActions []RollupAction, err error) RollbackRollupAddresses(ctx context.Context, height types.Level) (err error) RollbackRollups(ctx context.Context, height types.Level) ([]Rollup, error) diff --git a/internal/storage/mock/generic.go b/internal/storage/mock/generic.go index 77f9ab3..be68722 100644 --- a/internal/storage/mock/generic.go +++ b/internal/storage/mock/generic.go @@ -861,11 +861,12 @@ func (c *MockTransactionRollbackBlockStatsCall) DoAndReturn(f func(context.Conte } // RollbackBridges mocks base method. -func (m *MockTransaction) RollbackBridges(ctx context.Context, height types.Level) error { +func (m *MockTransaction) RollbackBridges(ctx context.Context, height types.Level) (int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RollbackBridges", ctx, height) - ret0, _ := ret[0].(error) - return ret0 + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 } // RollbackBridges indicates an expected call of RollbackBridges. @@ -881,19 +882,19 @@ type MockTransactionRollbackBridgesCall struct { } // Return rewrite *gomock.Call.Return -func (c *MockTransactionRollbackBridgesCall) Return(arg0 error) *MockTransactionRollbackBridgesCall { - c.Call = c.Call.Return(arg0) +func (c *MockTransactionRollbackBridgesCall) Return(arg0 int, arg1 error) *MockTransactionRollbackBridgesCall { + c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *MockTransactionRollbackBridgesCall) Do(f func(context.Context, types.Level) error) *MockTransactionRollbackBridgesCall { +func (c *MockTransactionRollbackBridgesCall) Do(f func(context.Context, types.Level) (int, error)) *MockTransactionRollbackBridgesCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockTransactionRollbackBridgesCall) DoAndReturn(f func(context.Context, types.Level) error) *MockTransactionRollbackBridgesCall { +func (c *MockTransactionRollbackBridgesCall) DoAndReturn(f func(context.Context, types.Level) (int, error)) *MockTransactionRollbackBridgesCall { c.Call = c.Call.DoAndReturn(f) return c } @@ -1427,15 +1428,16 @@ func (c *MockTransactionSaveBlockSignaturesCall) DoAndReturn(f func(context.Cont } // SaveBridges mocks base method. -func (m *MockTransaction) SaveBridges(ctx context.Context, bridges ...*storage.Bridge) error { +func (m *MockTransaction) SaveBridges(ctx context.Context, bridges ...*storage.Bridge) (int64, error) { m.ctrl.T.Helper() varargs := []any{ctx} for _, a := range bridges { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "SaveBridges", varargs...) - ret0, _ := ret[0].(error) - return ret0 + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 } // SaveBridges indicates an expected call of SaveBridges. @@ -1452,19 +1454,19 @@ type MockTransactionSaveBridgesCall struct { } // Return rewrite *gomock.Call.Return -func (c *MockTransactionSaveBridgesCall) Return(arg0 error) *MockTransactionSaveBridgesCall { - c.Call = c.Call.Return(arg0) +func (c *MockTransactionSaveBridgesCall) Return(arg0 int64, arg1 error) *MockTransactionSaveBridgesCall { + c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *MockTransactionSaveBridgesCall) Do(f func(context.Context, ...*storage.Bridge) error) *MockTransactionSaveBridgesCall { +func (c *MockTransactionSaveBridgesCall) Do(f func(context.Context, ...*storage.Bridge) (int64, error)) *MockTransactionSaveBridgesCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockTransactionSaveBridgesCall) DoAndReturn(f func(context.Context, ...*storage.Bridge) error) *MockTransactionSaveBridgesCall { +func (c *MockTransactionSaveBridgesCall) DoAndReturn(f func(context.Context, ...*storage.Bridge) (int64, error)) *MockTransactionSaveBridgesCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/internal/storage/postgres/transaction.go b/internal/storage/postgres/transaction.go index f36e96e..ed5134f 100644 --- a/internal/storage/postgres/transaction.go +++ b/internal/storage/postgres/transaction.go @@ -213,13 +213,26 @@ func (tx Transaction) SaveBalanceUpdates(ctx context.Context, updates ...models. return err } -func (tx Transaction) SaveBridges(ctx context.Context, bridges ...*models.Bridge) error { +type addedBiridge struct { + bun.BaseModel `bun:"bridge"` + *models.Bridge + + Xmax uint64 `bun:"xmax"` +} + +func (tx Transaction) SaveBridges(ctx context.Context, bridges ...*models.Bridge) (int64, error) { if len(bridges) == 0 { - return nil + return 0, nil } + var count int64 + for i := range bridges { - query := tx.Tx().NewInsert().Model(bridges[i]). + add := new(addedBiridge) + add.Bridge = bridges[i] + + query := tx.Tx().NewInsert().Model(add). + Column("rollup_id", "address_id", "asset", "fee_asset", "sudo_id", "withdrawer_id", "init_height"). On("CONFLICT (address_id) DO UPDATE") if bridges[i].SudoId > 0 { @@ -234,12 +247,16 @@ func (tx Transaction) SaveBridges(ctx context.Context, bridges ...*models.Bridge query.Set("fee_asset = ?", bridges[i].FeeAsset) } - if _, err := query.Exec(ctx); err != nil { - return err + if _, err := query.Returning("xmax, id").Exec(ctx); err != nil { + return count, err + } + + if add.Xmax == 0 { + count++ } } - return nil + return count, nil } func (tx Transaction) LastBlock(ctx context.Context) (block models.Block, err error) { @@ -296,9 +313,10 @@ func (tx Transaction) RollbackBalanceUpdates(ctx context.Context, height types.L return } -func (tx Transaction) RollbackBridges(ctx context.Context, height types.Level) (err error) { - _, err = tx.Tx().NewDelete().Model((*models.Bridge)(nil)).Where("height = ?", height).Exec(ctx) - return +func (tx Transaction) RollbackBridges(ctx context.Context, height types.Level) (int, error) { + var bridge []models.Bridge + _, err := tx.Tx().NewDelete().Model(&bridge).Where("init_height = ?", height).Returning("*").Exec(ctx) + return len(bridge), err } func (tx Transaction) RollbackAddressActions(ctx context.Context, height types.Level) (addrActions []models.AddressAction, err error) { diff --git a/internal/storage/postgres/transaction_test.go b/internal/storage/postgres/transaction_test.go index 6cdc5a7..3888864 100644 --- a/internal/storage/postgres/transaction_test.go +++ b/internal/storage/postgres/transaction_test.go @@ -412,8 +412,9 @@ func (s *TransactionTestSuite) TestSaveBridges() { bridges[i].RollupId = uint64(i + 50) } - err = tx.SaveBridges(ctx, bridges...) + count, err := tx.SaveBridges(ctx, bridges...) s.Require().NoError(err) + s.Require().EqualValues(5, count) s.Require().NoError(tx.Flush(ctx)) s.Require().NoError(tx.Close(ctx)) @@ -535,6 +536,21 @@ func (s *TransactionTestSuite) TestRollbackBlock() { s.Require().EqualValues(7964, block.Height) } +func (s *TransactionTestSuite) TestRollbackBridge() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + tx, err := BeginTransaction(ctx, s.storage.Transactable) + s.Require().NoError(err) + + count, err := tx.RollbackBridges(ctx, 7316) + s.Require().NoError(err) + s.Require().EqualValues(1, count) + + s.Require().NoError(tx.Flush(ctx)) + s.Require().NoError(tx.Close(ctx)) +} + func (s *TransactionTestSuite) TestRollbackBlockStats() { ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) defer ctxCancel() diff --git a/internal/storage/state.go b/internal/storage/state.go index a2c1345..ca43f99 100644 --- a/internal/storage/state.go +++ b/internal/storage/state.go @@ -36,7 +36,7 @@ type State struct { TotalRollups int64 `bun:"total_rollups" comment:"Rollups count" json:"rollups"` TotalValidators int `bun:"total_validators" comment:"Validators count" json:"validators"` TotalSupply decimal.Decimal `bun:"total_supply,type:numeric" comment:"Total supply" json:"supply"` - TotalFee decimal.Decimal `bun:"total_fee,type:numeric" comment:"Total paid fee" json:"fee"` + TotalBridges int64 `bun:"total_bridges" comment:"Count of bridges" json:"bridges"` } // TableName - diff --git a/pkg/indexer/genesis/save.go b/pkg/indexer/genesis/save.go index 7f6dc50..4aceffa 100644 --- a/pkg/indexer/genesis/save.go +++ b/pkg/indexer/genesis/save.go @@ -80,7 +80,6 @@ func (module *Module) save(ctx context.Context, data parsedData) error { ChainId: data.block.ChainId, TotalTx: data.block.Stats.TxCount, TotalSupply: data.block.Stats.SupplyChange, - TotalFee: data.block.Stats.Fee, TotalAccounts: totalAccounts, TotalValidators: len(data.validators), }); err != nil { diff --git a/pkg/indexer/rollback/rollback.go b/pkg/indexer/rollback/rollback.go index c397bfb..9accc35 100644 --- a/pkg/indexer/rollback/rollback.go +++ b/pkg/indexer/rollback/rollback.go @@ -218,6 +218,11 @@ func rollbackBlock(ctx context.Context, tx storage.Transaction, height types.Lev return err } + deletedBridges, err := tx.RollbackBridges(ctx, height) + if err != nil { + return errors.Wrap(err, "bridges") + } + newBlock, err := tx.LastBlock(ctx) if err != nil { return err @@ -233,8 +238,8 @@ func rollbackBlock(ctx context.Context, tx storage.Transaction, height types.Lev state.TotalTx -= blockStats.TxCount state.TotalAccounts -= int64(countDeletedAddresses) state.TotalRollups -= countDeletedRollups - state.TotalFee = state.TotalFee.Sub(blockStats.Fee) state.TotalSupply = state.TotalSupply.Sub(blockStats.SupplyChange) + state.TotalBridges -= int64(deletedBridges) if err := tx.Update(ctx, &state); err != nil { return err diff --git a/pkg/indexer/rollback/rollback_test.go b/pkg/indexer/rollback/rollback_test.go index 3327d5a..c098c78 100644 --- a/pkg/indexer/rollback/rollback_test.go +++ b/pkg/indexer/rollback/rollback_test.go @@ -262,6 +262,11 @@ func Test_rollbackBlock(t *testing.T) { Return(nil). Times(1) + tx.EXPECT(). + RollbackBridges(ctx, height). + Return(0, nil). + Times(1) + lastBlock := storage.Block{ Height: height - 1, Time: blockTime.Add(-time.Minute), @@ -291,7 +296,6 @@ func Test_rollbackBlock(t *testing.T) { TotalAccounts: 10, TotalRollups: 10, TotalSupply: decimal.RequireFromString("1000"), - TotalFee: decimal.Zero, }, nil). MaxTimes(1). MinTimes(1) diff --git a/pkg/indexer/storage/bridge.go b/pkg/indexer/storage/bridge.go index 44db3ad..e243249 100644 --- a/pkg/indexer/storage/bridge.go +++ b/pkg/indexer/storage/bridge.go @@ -15,23 +15,23 @@ func saveBridges( tx storage.Transaction, addrToId map[string]uint64, bridges []*storage.Bridge, -) error { +) (int64, error) { if len(bridges) == 0 { - return nil + return 0, nil } for i := range bridges { if id, ok := addrToId[bridges[i].Address.Hash]; ok { bridges[i].AddressId = id } else { - return errors.Errorf("unknown bridge address: %s", bridges[i].Address.Hash) + return 0, errors.Errorf("unknown bridge address: %s", bridges[i].Address.Hash) } if bridges[i].Sudo != nil { if id, ok := addrToId[bridges[i].Sudo.Hash]; ok { bridges[i].SudoId = id } else { - return errors.Errorf("unknown sudo bridge address: %s", bridges[i].Sudo.Hash) + return 0, errors.Errorf("unknown sudo bridge address: %s", bridges[i].Sudo.Hash) } } @@ -39,7 +39,7 @@ func saveBridges( if id, ok := addrToId[bridges[i].Withdrawer.Hash]; ok { bridges[i].WithdrawerId = id } else { - return errors.Errorf("unknown withdrawer bridge address: %s", bridges[i].Withdrawer.Hash) + return 0, errors.Errorf("unknown withdrawer bridge address: %s", bridges[i].Withdrawer.Hash) } } @@ -47,7 +47,7 @@ func saveBridges( if bridges[i].Rollup.Id == 0 { rollup, err := tx.GetRollup(ctx, bridges[i].Rollup.AstriaId) if err != nil { - return err + return 0, err } bridges[i].RollupId = rollup.Id } else { diff --git a/pkg/indexer/storage/state.go b/pkg/indexer/storage/state.go index c66133f..54a3b6d 100644 --- a/pkg/indexer/storage/state.go +++ b/pkg/indexer/storage/state.go @@ -8,7 +8,7 @@ import ( "github.com/celenium-io/astria-indexer/pkg/types" ) -func updateState(block *storage.Block, totalAccounts, totalRollups int64, state *storage.State) { +func updateState(block *storage.Block, totalAccounts, totalRollups, totalBridges int64, state *storage.State) { if types.Level(block.Id) <= state.LastHeight { return } @@ -19,7 +19,7 @@ func updateState(block *storage.Block, totalAccounts, totalRollups int64, state state.TotalTx += block.Stats.TxCount state.TotalAccounts += totalAccounts state.TotalRollups += totalRollups - state.TotalFee = state.TotalFee.Add(block.Stats.Fee) + state.TotalBridges += totalBridges state.TotalSupply = state.TotalSupply.Add(block.Stats.SupplyChange) state.ChainId = block.ChainId } diff --git a/pkg/indexer/storage/state_test.go b/pkg/indexer/storage/state_test.go index b57256d..cb8e73c 100644 --- a/pkg/indexer/storage/state_test.go +++ b/pkg/indexer/storage/state_test.go @@ -52,7 +52,7 @@ func Test_updateState(t *testing.T) { TotalAccounts: 2, TotalRollups: 12, TotalSupply: decimal.RequireFromString("1000"), - TotalFee: decimal.RequireFromString("10"), + TotalBridges: 10, }, }, want: storage.State{ @@ -65,13 +65,13 @@ func Test_updateState(t *testing.T) { TotalAccounts: 12, TotalRollups: 23, TotalSupply: decimal.RequireFromString("1100"), - TotalFee: decimal.RequireFromString("20"), + TotalBridges: 20, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - updateState(tt.args.block, tt.args.totalAccounts, tt.args.totalRollups, tt.args.state) + updateState(tt.args.block, tt.args.totalAccounts, tt.args.totalRollups, 10, tt.args.state) }) } } diff --git a/pkg/indexer/storage/storage.go b/pkg/indexer/storage/storage.go index e829d92..cb27ac0 100644 --- a/pkg/indexer/storage/storage.go +++ b/pkg/indexer/storage/storage.go @@ -181,7 +181,8 @@ func (module *Module) processBlockInTransaction(ctx context.Context, tx storage. return state, err } - if err := saveBridges(ctx, tx, addrToId, block.Bridges); err != nil { + totalBridges, err := saveBridges(ctx, tx, addrToId, block.Bridges) + if err != nil { return state, err } @@ -210,7 +211,7 @@ func (module *Module) processBlockInTransaction(ctx context.Context, tx storage. return state, err } - updateState(block, totalAccounts, totalRollups, &state) + updateState(block, totalAccounts, totalRollups, totalBridges, &state) if err := tx.Update(ctx, &state); err != nil { return state, err } diff --git a/test/data/state.yml b/test/data/state.yml index d2e188d..f1f22a0 100644 --- a/test/data/state.yml +++ b/test/data/state.yml @@ -8,4 +8,4 @@ total_accounts: 6 total_rollups: 1 total_supply: 1000000000000000000000 - total_fee: 0 \ No newline at end of file + total_bridges: 1 \ No newline at end of file