diff --git a/cmd/api/docs/docs.go b/cmd/api/docs/docs.go index b3f0e0f6..73c90d57 100644 --- a/cmd/api/docs/docs.go +++ b/cmd/api/docs/docs.go @@ -4953,6 +4953,12 @@ const docTemplate = `{ "format": "int64", "example": 11 }, + "signers": { + "type": "array", + "items": { + "type": "string" + } + }, "status": { "allOf": [ { diff --git a/cmd/api/docs/swagger.json b/cmd/api/docs/swagger.json index 0e228696..4dc829dd 100644 --- a/cmd/api/docs/swagger.json +++ b/cmd/api/docs/swagger.json @@ -4943,6 +4943,12 @@ "format": "int64", "example": 11 }, + "signers": { + "type": "array", + "items": { + "type": "string" + } + }, "status": { "allOf": [ { diff --git a/cmd/api/docs/swagger.yaml b/cmd/api/docs/swagger.yaml index 28effb73..7306b9b3 100644 --- a/cmd/api/docs/swagger.yaml +++ b/cmd/api/docs/swagger.yaml @@ -765,6 +765,10 @@ definitions: example: 11 format: int64 type: integer + signers: + items: + type: string + type: array status: allOf: - $ref: '#/definitions/github_com_celenium-io_celestia-indexer_internal_storage_types.Status' diff --git a/cmd/api/handler/responses/tx.go b/cmd/api/handler/responses/tx.go index 381d4150..3435d2fd 100644 --- a/cmd/api/handler/responses/tx.go +++ b/cmd/api/handler/responses/tx.go @@ -30,6 +30,7 @@ type Tx struct { Time time.Time `example:"2023-07-04T03:10:57+00:00" format:"date-time" json:"time" swaggertype:"string"` Messages []Message `json:"messages,omitempty"` + Signers []string `json:"signers"` MessageTypes []types.MsgType `example:"MsgSend,MsgUnjail" json:"message_types"` Status types.Status `example:"success" json:"status"` @@ -57,11 +58,15 @@ func NewTx(tx storage.Tx) Tx { MessageTypes: tx.MessageTypes.Names(), MsgTypeMask: tx.MessageTypes, Messages: make([]Message, 0), + Signers: make([]string, len(tx.Signers)), } for i := range tx.Messages { result.Messages = append(result.Messages, NewMessage(tx.Messages[i])) } + for i := range tx.Signers { + result.Signers[i] = tx.Signers[i].Address + } return result } diff --git a/cmd/api/handler/tx_test.go b/cmd/api/handler/tx_test.go index edb36d24..f464808b 100644 --- a/cmd/api/handler/tx_test.go +++ b/cmd/api/handler/tx_test.go @@ -49,6 +49,11 @@ var ( Type: types.MsgSend, }, }, + Signers: []storage.Address{ + { + Address: testAddress, + }, + }, } ) @@ -122,6 +127,8 @@ func (s *TxTestSuite) TestGet() { s.Require().Equal("memo", tx.Memo) s.Require().Equal("sdk", tx.Codespace) s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Len(tx.Signers, 1) + s.Require().Equal(testAddress, tx.Signers[0]) } func (s *TxTestSuite) TestGetInvalidTx() { @@ -183,6 +190,8 @@ func (s *TxTestSuite) TestList() { s.Require().Equal("memo", tx.Memo) s.Require().Equal("sdk", tx.Codespace) s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Len(tx.Signers, 1) + s.Require().Equal(testAddress, tx.Signers[0]) } func (s *TxTestSuite) TestListValidationStatusError() { @@ -273,6 +282,8 @@ func (s *TxTestSuite) TestListTime() { s.Require().Equal("memo", tx.Memo) s.Require().Equal("sdk", tx.Codespace) s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Len(tx.Signers, 1) + s.Require().Equal(testAddress, tx.Signers[0]) } func (s *TxTestSuite) TestListHeight() { @@ -330,6 +341,8 @@ func (s *TxTestSuite) TestListHeight() { s.Require().Equal(types.StatusSuccess, tx.Status) s.Require().Len(tx.Messages, 1) + s.Require().Len(tx.Signers, 1) + s.Require().Equal(testAddress, tx.Signers[0]) } func (s *TxTestSuite) TestListExcludedMessages() { @@ -387,6 +400,8 @@ func (s *TxTestSuite) TestListExcludedMessages() { s.Require().Equal(types.StatusSuccess, tx.Status) s.Require().Len(tx.Messages, 1) + s.Require().Len(tx.Signers, 1) + s.Require().Equal(testAddress, tx.Signers[0]) } func (s *TxTestSuite) TestGetEvents() { @@ -532,6 +547,8 @@ func (s *TxTestSuite) TestGenesis() { s.Require().EqualValues(1, tx.MessagesCount) s.Require().EqualValues(types.StatusSuccess, tx.Status) s.Require().EqualValues([]types.MsgType{types.MsgCreateValidator}, tx.MessageTypes) + + s.Require().Len(tx.Signers, 0) } func (s *TxTestSuite) TestNamespaces() { diff --git a/internal/storage/postgres/blob_log_test.go b/internal/storage/postgres/blob_log_test.go index 7a2d98e6..534fb21a 100644 --- a/internal/storage/postgres/blob_log_test.go +++ b/internal/storage/postgres/blob_log_test.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2024 PK Lab AG +// SPDX-License-Identifier: MIT + package postgres import ( diff --git a/internal/storage/postgres/core.go b/internal/storage/postgres/core.go index 921d2de4..82f29408 100644 --- a/internal/storage/postgres/core.go +++ b/internal/storage/postgres/core.go @@ -95,7 +95,6 @@ func initDatabase(ctx context.Context, conn *database.Bun) error { // register many-to-many relationships conn.DB().RegisterModel( (*models.NamespaceMessage)(nil), - (*models.Signer)(nil), (*models.MsgAddress)(nil), (*models.RollupProvider)(nil), ) diff --git a/internal/storage/postgres/storage_test.go b/internal/storage/postgres/storage_test.go index 3d8eed21..d459d80f 100644 --- a/internal/storage/postgres/storage_test.go +++ b/internal/storage/postgres/storage_test.go @@ -343,308 +343,6 @@ func (s *StorageTestSuite) TestNamespaceGetByIds() { s.Require().Len(ns, 3) } -func (s *StorageTestSuite) TestTxByHash() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txHash, err := hex.DecodeString("652452A670018D629CC116E510BA88C1CABE061336661B1F3D206D248BD558AF") - s.Require().NoError(err) - - tx, err := s.storage.Tx.ByHash(ctx, txHash) - s.Require().NoError(err) - - s.Require().EqualValues(1, tx.Id) - s.Require().EqualValues(0, tx.Position) - s.Require().EqualValues(1000, tx.Height) - s.Require().EqualValues(0, tx.TimeoutHeight) - s.Require().EqualValues(80410, tx.GasWanted) - s.Require().EqualValues(77483, tx.GasUsed) - s.Require().EqualValues(1, tx.EventsCount) - s.Require().EqualValues(2, tx.MessagesCount) - s.Require().Equal(txHash, tx.Hash) - s.Require().Equal(types.StatusSuccess, tx.Status) - s.Require().Equal("memo", tx.Memo) - s.Require().Equal("sdk", tx.Codespace) - s.Require().Equal("80410", tx.Fee.String()) -} - -func (s *StorageTestSuite) TestTxFilterSuccessUnjailAsc() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ - Sort: sdk.SortOrderAsc, - Limit: 10, - Offset: 0, - MessageTypes: types.NewMsgTypeBitMask(types.MsgUnjail), - Status: []string{string(types.StatusSuccess)}, - }) - s.Require().NoError(err) - s.Require().Len(txs, 1) - - tx := txs[0] - - s.Require().EqualValues(2, tx.Id) - s.Require().EqualValues(1, tx.Position) - s.Require().EqualValues(1000, tx.Height) - s.Require().EqualValues(0, tx.TimeoutHeight) - s.Require().EqualValues(80410, tx.GasWanted) - s.Require().EqualValues(77483, tx.GasUsed) - s.Require().EqualValues(1, tx.EventsCount) - s.Require().EqualValues(1, tx.MessagesCount) - s.Require().EqualValues("2048", tx.MessageTypes.Bits.String()) - s.Require().Equal(types.StatusSuccess, tx.Status) - s.Require().Equal("memo2", tx.Memo) - s.Require().Equal("", tx.Codespace) - s.Require().Equal("80410", tx.Fee.String()) -} - -func (s *StorageTestSuite) TestTxFilterExcludedMessageTypes() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ - Sort: sdk.SortOrderAsc, - Limit: 10, - Offset: 0, - ExcludedMessageTypes: types.NewMsgTypeBitMask(types.MsgUnjail), - Height: 1000, - }) - s.Require().NoError(err) - s.Require().Len(txs, 1) - - tx := txs[0] - - s.Require().EqualValues(1, tx.Id) - s.Require().EqualValues(0, tx.Position) - s.Require().EqualValues(1000, tx.Height) - s.Require().EqualValues(0, tx.TimeoutHeight) - s.Require().EqualValues(80410, tx.GasWanted) - s.Require().EqualValues(77483, tx.GasUsed) - s.Require().EqualValues(1, tx.EventsCount) - s.Require().EqualValues(2, tx.MessagesCount) - s.Require().Equal(types.StatusSuccess, tx.Status) - s.Require().Equal("memo", tx.Memo) - s.Require().Equal("sdk", tx.Codespace) - s.Require().Equal("80410", tx.Fee.String()) -} - -func (s *StorageTestSuite) TestTxFilterSuccessDesc() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ - Sort: sdk.SortOrderDesc, - Limit: 10, - Offset: 0, - Status: []string{string(types.StatusSuccess)}, - }) - s.Require().NoError(err) - s.Require().Len(txs, 4) - - tx := txs[1] - - s.Require().EqualValues(3, tx.Id) - s.Require().EqualValues(0, tx.Position) - s.Require().EqualValues(999, tx.Height) - s.Require().EqualValues(0, tx.TimeoutHeight) - s.Require().EqualValues(80410, tx.GasWanted) - s.Require().EqualValues(77483, tx.GasUsed) - s.Require().EqualValues(0, tx.EventsCount) - s.Require().EqualValues(1, tx.MessagesCount) - s.Require().EqualValues("32", tx.MessageTypes.Bits.String()) - s.Require().Equal(types.StatusSuccess, tx.Status) - s.Require().Equal("", tx.Memo) - s.Require().Equal("", tx.Codespace) - s.Require().Equal("80410", tx.Fee.String()) -} - -func (s *StorageTestSuite) TestTxFilterHeight() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ - Sort: sdk.SortOrderDesc, - Limit: 10, - Offset: 0, - Status: []string{string(types.StatusSuccess)}, - Height: 1000, - }) - s.Require().NoError(err) - s.Require().Len(txs, 2) - - tx := txs[0] - - s.Require().EqualValues(2, tx.Id) - s.Require().EqualValues(1, tx.Position) - s.Require().EqualValues(1000, tx.Height) - s.Require().EqualValues(0, tx.TimeoutHeight) - s.Require().EqualValues(80410, tx.GasWanted) - s.Require().EqualValues(77483, tx.GasUsed) - s.Require().EqualValues(1, tx.EventsCount) - s.Require().EqualValues(1, tx.MessagesCount) - s.Require().EqualValues("2048", tx.MessageTypes.Bits.String()) - s.Require().Equal(types.StatusSuccess, tx.Status) - s.Require().Equal("memo2", tx.Memo) - s.Require().Equal("", tx.Codespace) - s.Require().Equal("80410", tx.Fee.String()) -} - -func (s *StorageTestSuite) TestTxFilterTime() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ - Limit: 10, - TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), - }) - s.Require().NoError(err) - s.Require().Len(txs, 4) - - txs, err = s.storage.Tx.Filter(ctx, storage.TxFilter{ - Limit: 10, - TimeTo: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), - }) - s.Require().NoError(err) - s.Require().Len(txs, 0) - - txs, err = s.storage.Tx.Filter(ctx, storage.TxFilter{ - Limit: 10, - - TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), - TimeTo: time.Date(2023, 7, 5, 0, 0, 0, 0, time.UTC), - }) - s.Require().NoError(err) - s.Require().Len(txs, 4) -} - -func (s *StorageTestSuite) TestTxFilterWithRelations() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ - Limit: 1, - WithMessages: true, - }) - s.Require().NoError(err) - s.Require().Len(txs, 1) - - tx := txs[0] - s.Require().Len(tx.Messages, 2) - s.Require().EqualValues(1, tx.Messages[0].Id) - s.Require().EqualValues(2, tx.Messages[1].Id) -} - -func (s *StorageTestSuite) TestTxByIdWithRelations() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - tx, err := s.storage.Tx.ByIdWithRelations(ctx, 2) - s.Require().NoError(err) - - s.Require().EqualValues(2, tx.Id) - s.Require().EqualValues(1, tx.Position) - s.Require().EqualValues(1000, tx.Height) - s.Require().EqualValues(0, tx.TimeoutHeight) - s.Require().EqualValues(80410, tx.GasWanted) - s.Require().EqualValues(77483, tx.GasUsed) - s.Require().EqualValues(1, tx.EventsCount) - s.Require().EqualValues(1, tx.MessagesCount) - s.Require().Equal(types.StatusSuccess, tx.Status) - s.Require().Equal("memo2", tx.Memo) - s.Require().Equal("", tx.Codespace) - s.Require().Equal("80410", tx.Fee.String()) - s.Require().EqualValues("2048", tx.MessageTypes.Bits.String()) - - s.Require().Len(tx.Messages, 2) -} - -func (s *StorageTestSuite) TestTxGenesis() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.Genesis(ctx, 10, 0, sdk.SortOrderAsc) - s.Require().NoError(err) - s.Require().Len(txs, 1) - - tx := txs[0] - s.Require().EqualValues(4, tx.Id) - s.Require().EqualValues(0, tx.Position) - s.Require().EqualValues(0, tx.Height) - s.Require().EqualValues(0, tx.TimeoutHeight) - s.Require().EqualValues(0, tx.GasWanted) - s.Require().EqualValues(0, tx.GasUsed) - s.Require().EqualValues(0, tx.EventsCount) - s.Require().EqualValues(1, tx.MessagesCount) - s.Require().Equal(types.StatusSuccess, tx.Status) - s.Require().Equal("34499b1ac473fbb03894c883178ecc83f0d6eaf6@64.227.18.169:26656", tx.Memo) - s.Require().Equal("", tx.Codespace) - s.Require().Equal("0", tx.Fee.String()) - s.Require().EqualValues("32", tx.MessageTypes.Bits.String()) -} - -func (s *StorageTestSuite) TestTxByAddressAndTime() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - txs, err := s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ - Limit: 10, - TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), - }) - s.Require().NoError(err) - s.Require().Len(txs, 1) - - txs, err = s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ - Limit: 10, - TimeTo: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), - }) - s.Require().NoError(err) - s.Require().Len(txs, 0) - - txs, err = s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ - Limit: 10, - - TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), - TimeTo: time.Date(2023, 7, 5, 0, 0, 0, 0, time.UTC), - }) - s.Require().NoError(err) - s.Require().Len(txs, 1) - - txs, err = s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ - Limit: 10, - Offset: 1, - - TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), - TimeTo: time.Date(2023, 7, 5, 0, 0, 0, 0, time.UTC), - }) - s.Require().NoError(err) - s.Require().Len(txs, 0) -} - -func (s *StorageTestSuite) TestTxGas() { - ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) - defer ctxCancel() - - ts, err := time.Parse(time.RFC3339, "2023-07-04T03:10:57+00:00") - s.Require().NoError(err) - - txs, err := s.storage.Tx.Gas(ctx, 1000, ts) - s.Require().NoError(err) - s.Require().Len(txs, 2) - - tx0 := txs[0] - s.Require().EqualValues(80410, tx0.GasWanted) - s.Require().EqualValues(77483, tx0.GasUsed) - s.Require().EqualValues("80410", tx0.Fee.String()) - s.Require().EqualValues("1", tx0.GasPrice.String()) - - tx1 := txs[1] - s.Require().EqualValues(80410, tx1.GasWanted) - s.Require().EqualValues(77483, tx1.GasUsed) - s.Require().EqualValues("80410", tx1.Fee.String()) - s.Require().EqualValues("1", tx1.GasPrice.String()) -} - func (s *StorageTestSuite) TestValidatorByAddress() { ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) defer ctxCancel() diff --git a/internal/storage/postgres/tx.go b/internal/storage/postgres/tx.go index 0a3f6078..4b1e401e 100644 --- a/internal/storage/postgres/tx.go +++ b/internal/storage/postgres/tx.go @@ -12,6 +12,7 @@ import ( "github.com/dipdup-net/go-lib/database" sdk "github.com/dipdup-net/indexer-sdk/pkg/storage" "github.com/dipdup-net/indexer-sdk/pkg/storage/postgres" + "github.com/uptrace/bun" ) // Tx - @@ -26,26 +27,92 @@ func NewTx(db *database.Bun) *Tx { } } +func (tx *Tx) getSigners(ctx context.Context, txId ...uint64) (signers []storage.Signer, err error) { + subQuery := tx.DB().NewSelect(). + Model((*storage.Signer)(nil)). + Where("tx_id IN (?)", bun.In(txId)) + + err = tx.DB().NewSelect().TableExpr("(?) as signer", subQuery). + ColumnExpr("address.address as address__address"). + ColumnExpr("signer.*"). + Join("left join address on address.id = signer.address_id"). + Scan(ctx, &signers) + return +} + +func (tx *Tx) setSigners(ctx context.Context, txs []storage.Tx) error { + ids := make([]uint64, len(txs)) + for i := range ids { + ids[i] = txs[i].Id + } + + signers, err := tx.getSigners(ctx, ids...) + if err != nil { + return err + } + + for i := range signers { + for j := range txs { + if txs[j].Id == signers[i].TxId && signers[i].Address != nil { + txs[j].Signers = append(txs[j].Signers, *signers[i].Address) + break + } + } + } + return nil +} + func (tx *Tx) ByHash(ctx context.Context, hash []byte) (transaction storage.Tx, err error) { - err = tx.DB().NewSelect().Model(&transaction). + if err = tx.DB().NewSelect().Model(&transaction). Where("hash = ?", hash). - Scan(ctx) + Scan(ctx); err != nil { + return + } + + signers, err := tx.getSigners(ctx, transaction.Id) + if err != nil { + return + } + + transaction.Signers = make([]storage.Address, len(signers)) + for i := range signers { + if signers[i].Address != nil { + transaction.Signers[i] = *signers[i].Address + } + } return } func (tx *Tx) Filter(ctx context.Context, fltrs storage.TxFilter) (txs []storage.Tx, err error) { query := tx.DB().NewSelect().Model(&txs).Offset(fltrs.Offset) query = txFilter(query, fltrs) + if err = query.Scan(ctx); err != nil { + return + } - err = query.Scan(ctx) + err = tx.setSigners(ctx, txs) return } func (tx *Tx) ByIdWithRelations(ctx context.Context, id uint64) (transaction storage.Tx, err error) { - err = tx.DB().NewSelect().Model(&transaction). + if err = tx.DB().NewSelect().Model(&transaction). Where("id = ?", id). Relation("Messages"). - Scan(ctx) + Scan(ctx); err != nil { + return + } + + signers, err := tx.getSigners(ctx, transaction.Id) + if err != nil { + return + } + + transaction.Signers = make([]storage.Address, len(signers)) + for i := range signers { + if signers[i].Address != nil { + transaction.Signers[i] = *signers[i].Address + } + } return } diff --git a/internal/storage/postgres/tx_test.go b/internal/storage/postgres/tx_test.go new file mode 100644 index 00000000..f6c698d0 --- /dev/null +++ b/internal/storage/postgres/tx_test.go @@ -0,0 +1,327 @@ +// SPDX-FileCopyrightText: 2024 PK Lab AG +// SPDX-License-Identifier: MIT + +package postgres + +import ( + "context" + "encoding/hex" + "time" + + "github.com/celenium-io/celestia-indexer/internal/storage" + "github.com/celenium-io/celestia-indexer/internal/storage/types" + sdk "github.com/dipdup-net/indexer-sdk/pkg/storage" +) + +func (s *StorageTestSuite) TestTxByHash() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txHash, err := hex.DecodeString("652452A670018D629CC116E510BA88C1CABE061336661B1F3D206D248BD558AF") + s.Require().NoError(err) + + tx, err := s.storage.Tx.ByHash(ctx, txHash) + s.Require().NoError(err) + + s.Require().EqualValues(1, tx.Id) + s.Require().EqualValues(0, tx.Position) + s.Require().EqualValues(1000, tx.Height) + s.Require().EqualValues(0, tx.TimeoutHeight) + s.Require().EqualValues(80410, tx.GasWanted) + s.Require().EqualValues(77483, tx.GasUsed) + s.Require().EqualValues(1, tx.EventsCount) + s.Require().EqualValues(2, tx.MessagesCount) + s.Require().Equal(txHash, tx.Hash) + s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Equal("memo", tx.Memo) + s.Require().Equal("sdk", tx.Codespace) + s.Require().Equal("80410", tx.Fee.String()) + + s.Require().Len(tx.Signers, 1) +} + +func (s *StorageTestSuite) TestTxFilterSuccessUnjailAsc() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ + Sort: sdk.SortOrderAsc, + Limit: 10, + Offset: 0, + MessageTypes: types.NewMsgTypeBitMask(types.MsgUnjail), + Status: []string{string(types.StatusSuccess)}, + }) + s.Require().NoError(err) + s.Require().Len(txs, 1) + + tx := txs[0] + + s.Require().EqualValues(2, tx.Id) + s.Require().EqualValues(1, tx.Position) + s.Require().EqualValues(1000, tx.Height) + s.Require().EqualValues(0, tx.TimeoutHeight) + s.Require().EqualValues(80410, tx.GasWanted) + s.Require().EqualValues(77483, tx.GasUsed) + s.Require().EqualValues(1, tx.EventsCount) + s.Require().EqualValues(1, tx.MessagesCount) + s.Require().EqualValues("2048", tx.MessageTypes.Bits.String()) + s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Equal("memo2", tx.Memo) + s.Require().Equal("", tx.Codespace) + s.Require().Equal("80410", tx.Fee.String()) + + s.Require().Len(tx.Signers, 2) +} + +func (s *StorageTestSuite) TestTxFilterExcludedMessageTypes() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ + Sort: sdk.SortOrderAsc, + Limit: 10, + Offset: 0, + ExcludedMessageTypes: types.NewMsgTypeBitMask(types.MsgUnjail), + Height: 1000, + }) + s.Require().NoError(err) + s.Require().Len(txs, 1) + + tx := txs[0] + + s.Require().EqualValues(1, tx.Id) + s.Require().EqualValues(0, tx.Position) + s.Require().EqualValues(1000, tx.Height) + s.Require().EqualValues(0, tx.TimeoutHeight) + s.Require().EqualValues(80410, tx.GasWanted) + s.Require().EqualValues(77483, tx.GasUsed) + s.Require().EqualValues(1, tx.EventsCount) + s.Require().EqualValues(2, tx.MessagesCount) + s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Equal("memo", tx.Memo) + s.Require().Equal("sdk", tx.Codespace) + s.Require().Equal("80410", tx.Fee.String()) + + s.Require().Len(tx.Signers, 1) +} + +func (s *StorageTestSuite) TestTxFilterSuccessDesc() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ + Sort: sdk.SortOrderDesc, + Limit: 10, + Offset: 0, + Status: []string{string(types.StatusSuccess)}, + }) + s.Require().NoError(err) + s.Require().Len(txs, 4) + + tx := txs[1] + + s.Require().EqualValues(3, tx.Id) + s.Require().EqualValues(0, tx.Position) + s.Require().EqualValues(999, tx.Height) + s.Require().EqualValues(0, tx.TimeoutHeight) + s.Require().EqualValues(80410, tx.GasWanted) + s.Require().EqualValues(77483, tx.GasUsed) + s.Require().EqualValues(0, tx.EventsCount) + s.Require().EqualValues(1, tx.MessagesCount) + s.Require().EqualValues("32", tx.MessageTypes.Bits.String()) + s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Equal("", tx.Memo) + s.Require().Equal("", tx.Codespace) + s.Require().Equal("80410", tx.Fee.String()) + + s.Require().Len(tx.Signers, 1) +} + +func (s *StorageTestSuite) TestTxFilterHeight() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ + Sort: sdk.SortOrderDesc, + Limit: 10, + Offset: 0, + Status: []string{string(types.StatusSuccess)}, + Height: 1000, + }) + s.Require().NoError(err) + s.Require().Len(txs, 2) + + tx := txs[0] + + s.Require().EqualValues(2, tx.Id) + s.Require().EqualValues(1, tx.Position) + s.Require().EqualValues(1000, tx.Height) + s.Require().EqualValues(0, tx.TimeoutHeight) + s.Require().EqualValues(80410, tx.GasWanted) + s.Require().EqualValues(77483, tx.GasUsed) + s.Require().EqualValues(1, tx.EventsCount) + s.Require().EqualValues(1, tx.MessagesCount) + s.Require().EqualValues("2048", tx.MessageTypes.Bits.String()) + s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Equal("memo2", tx.Memo) + s.Require().Equal("", tx.Codespace) + s.Require().Equal("80410", tx.Fee.String()) + + s.Require().Len(tx.Signers, 2) +} + +func (s *StorageTestSuite) TestTxFilterTime() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ + Limit: 10, + TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), + }) + s.Require().NoError(err) + s.Require().Len(txs, 4) + + txs, err = s.storage.Tx.Filter(ctx, storage.TxFilter{ + Limit: 10, + TimeTo: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), + }) + s.Require().NoError(err) + s.Require().Len(txs, 0) + + txs, err = s.storage.Tx.Filter(ctx, storage.TxFilter{ + Limit: 10, + + TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), + TimeTo: time.Date(2023, 7, 5, 0, 0, 0, 0, time.UTC), + }) + s.Require().NoError(err) + s.Require().Len(txs, 4) +} + +func (s *StorageTestSuite) TestTxFilterWithRelations() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.Filter(ctx, storage.TxFilter{ + Limit: 1, + WithMessages: true, + }) + s.Require().NoError(err) + s.Require().Len(txs, 1) + + tx := txs[0] + s.Require().Len(tx.Messages, 2) + s.Require().EqualValues(1, tx.Messages[0].Id) + s.Require().EqualValues(2, tx.Messages[1].Id) +} + +func (s *StorageTestSuite) TestTxByIdWithRelations() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + tx, err := s.storage.Tx.ByIdWithRelations(ctx, 2) + s.Require().NoError(err) + + s.Require().EqualValues(2, tx.Id) + s.Require().EqualValues(1, tx.Position) + s.Require().EqualValues(1000, tx.Height) + s.Require().EqualValues(0, tx.TimeoutHeight) + s.Require().EqualValues(80410, tx.GasWanted) + s.Require().EqualValues(77483, tx.GasUsed) + s.Require().EqualValues(1, tx.EventsCount) + s.Require().EqualValues(1, tx.MessagesCount) + s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Equal("memo2", tx.Memo) + s.Require().Equal("", tx.Codespace) + s.Require().Equal("80410", tx.Fee.String()) + s.Require().EqualValues("2048", tx.MessageTypes.Bits.String()) + + s.Require().Len(tx.Messages, 2) + s.Require().Len(tx.Signers, 2) +} + +func (s *StorageTestSuite) TestTxGenesis() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.Genesis(ctx, 10, 0, sdk.SortOrderAsc) + s.Require().NoError(err) + s.Require().Len(txs, 1) + + tx := txs[0] + s.Require().EqualValues(4, tx.Id) + s.Require().EqualValues(0, tx.Position) + s.Require().EqualValues(0, tx.Height) + s.Require().EqualValues(0, tx.TimeoutHeight) + s.Require().EqualValues(0, tx.GasWanted) + s.Require().EqualValues(0, tx.GasUsed) + s.Require().EqualValues(0, tx.EventsCount) + s.Require().EqualValues(1, tx.MessagesCount) + s.Require().Equal(types.StatusSuccess, tx.Status) + s.Require().Equal("34499b1ac473fbb03894c883178ecc83f0d6eaf6@64.227.18.169:26656", tx.Memo) + s.Require().Equal("", tx.Codespace) + s.Require().Equal("0", tx.Fee.String()) + s.Require().EqualValues("32", tx.MessageTypes.Bits.String()) +} + +func (s *StorageTestSuite) TestTxByAddressAndTime() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + txs, err := s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ + Limit: 10, + TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), + }) + s.Require().NoError(err) + s.Require().Len(txs, 3) + + txs, err = s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ + Limit: 10, + TimeTo: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), + }) + s.Require().NoError(err) + s.Require().Len(txs, 0) + + txs, err = s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ + Limit: 10, + + TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), + TimeTo: time.Date(2023, 7, 5, 0, 0, 0, 0, time.UTC), + }) + s.Require().NoError(err) + s.Require().Len(txs, 3) + + txs, err = s.storage.Tx.ByAddress(ctx, 1, storage.TxFilter{ + Limit: 10, + Offset: 1, + + TimeFrom: time.Date(2023, 7, 4, 0, 0, 0, 0, time.UTC), + TimeTo: time.Date(2023, 7, 5, 0, 0, 0, 0, time.UTC), + }) + s.Require().NoError(err) + s.Require().Len(txs, 2) +} + +func (s *StorageTestSuite) TestTxGas() { + ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer ctxCancel() + + ts, err := time.Parse(time.RFC3339, "2023-07-04T03:10:57+00:00") + s.Require().NoError(err) + + txs, err := s.storage.Tx.Gas(ctx, 1000, ts) + s.Require().NoError(err) + s.Require().Len(txs, 2) + + tx0 := txs[0] + s.Require().EqualValues(80410, tx0.GasWanted) + s.Require().EqualValues(77483, tx0.GasUsed) + s.Require().EqualValues("80410", tx0.Fee.String()) + s.Require().EqualValues("1", tx0.GasPrice.String()) + + tx1 := txs[1] + s.Require().EqualValues(80410, tx1.GasWanted) + s.Require().EqualValues(77483, tx1.GasUsed) + s.Require().EqualValues("80410", tx1.Fee.String()) + s.Require().EqualValues("1", tx1.GasPrice.String()) +} diff --git a/internal/storage/tx.go b/internal/storage/tx.go index aeea03e6..e7e056af 100644 --- a/internal/storage/tx.go +++ b/internal/storage/tx.go @@ -77,10 +77,10 @@ type Tx struct { Messages []Message `bun:"rel:has-many,join:id=tx_id"` Events []Event `bun:"rel:has-many"` - Signers []Address `bun:"m2m:signer,join:Tx=Address"` - BlobsSize int64 `bun:"-"` - BytesSize int64 `bun:"-"` + Signers []Address `bun:"-"` + BlobsSize int64 `bun:"-"` + BytesSize int64 `bun:"-"` } // TableName - diff --git a/test/data/signer.yml b/test/data/signer.yml index 8f7d2da8..f022fcae 100644 --- a/test/data/signer.yml +++ b/test/data/signer.yml @@ -1,2 +1,8 @@ - tx_id: 1 + address_id: 1 +- tx_id: 2 + address_id: 1 +- tx_id: 2 + address_id: 2 +- tx_id: 3 address_id: 1 \ No newline at end of file