Skip to content

Commit

Permalink
feat: add message_type module and store msg types inside `message_t…
Browse files Browse the repository at this point in the history
…ype` table (#702)

Closes: #XXXX

<!-- Add a description of the changes that this PR introduces and the
files that
are the most critical to review. -->

Changes:
- Added `message_type` module
- Added msg handler to store message types inside `message_type` table
- Added new `messages_by_type` function to allow to query messages by
their types
- Added `v5` migrator to parse all msg types already stored in db and
save them inside `message_type` table

---

*All items are required. Please add a note to the item if the item is
not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type
prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json)
in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [x] targeted the correct branch
- [x] provided a link to the relevant issue or specification
- [x] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go
code](https://blog.golang.org/godoc)
- [x] updated the relevant documentation or specification
- [x] reviewed "Files changed" and left comments if necessary
- [x] confirmed all CI checks have passed

*All items are required. Please add a note if the item is not applicable
and please add
your handle next to the items reviewed if you only reviewed selected
items.*

I have...

- [ ] confirmed the correct [type
prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json)
in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
  • Loading branch information
MonikaCat committed Feb 5, 2024
1 parent 1d49e99 commit 220d132
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## Unreleased
- ([\#702](https://github.com/forbole/bdjuno/pull/702)) Add `message_type` module and store msg types inside `message_type` table, add `messages_by_type` function to allow to query messages by their types

### Changes

#### CI
Expand Down
2 changes: 2 additions & 0 deletions cmd/migrate/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (
"github.com/spf13/cobra"

v3 "github.com/forbole/bdjuno/v4/cmd/migrate/v3"
v5 "github.com/forbole/bdjuno/v4/cmd/migrate/v5"
)

type Migrator func(parseCfg *parsecmdtypes.Config) error

var (
migrations = map[string]Migrator{
"v3": v3.RunMigration,
"v5": v5.RunMigration,
}
)

Expand Down
43 changes: 43 additions & 0 deletions cmd/migrate/v5/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package v5

import (
"fmt"

v5db "github.com/forbole/bdjuno/v4/database/migrate/v5"
parse "github.com/forbole/juno/v4/cmd/parse/types"
"github.com/forbole/juno/v4/database"
"github.com/forbole/juno/v4/database/postgresql"
"github.com/forbole/juno/v4/types/config"
)

// RunMigration runs the migrations to v5
func RunMigration(parseConfig *parse.Config) error {
cfg, err := GetConfig()
if err != nil {
return fmt.Errorf("error while reading config: %s", err)
}

// Migrate the database
err = migrateDb(cfg, parseConfig)
if err != nil {
return fmt.Errorf("error while migrating database: %s", err)
}

return nil
}

func migrateDb(cfg config.Config, parseConfig *parse.Config) error {
// Build the codec
encodingConfig := parseConfig.GetEncodingConfigBuilder()()

// Get the db
databaseCtx := database.NewContext(cfg.Database, &encodingConfig, parseConfig.GetLogger())
db, err := postgresql.Builder(databaseCtx)
if err != nil {
return fmt.Errorf("error while building the db: %s", err)
}

// Build the migrator and perform the migrations
migrator := v5db.NewMigrator(db.(*postgresql.Database))
return migrator.Migrate()
}
29 changes: 29 additions & 0 deletions cmd/migrate/v5/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package v5

import (
"fmt"
"os"
"path"

"github.com/forbole/juno/v4/types/config"
"gopkg.in/yaml.v3"
)

// GetConfig returns the configuration reading it from the config.yaml file present inside the home directory
func GetConfig() (config.Config, error) {
file := path.Join(config.HomePath, "config.yaml")

// Make sure the path exists
if _, err := os.Stat(file); os.IsNotExist(err) {
return config.Config{}, fmt.Errorf("config file does not exist")
}

bz, err := os.ReadFile(file)
if err != nil {
return config.Config{}, fmt.Errorf("error while reading config file: %s", err)
}

var cfg config.Config
err = yaml.Unmarshal(bz, &cfg)
return cfg, err
}
16 changes: 16 additions & 0 deletions database/message_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package database

import (
types "github.com/forbole/bdjuno/v4/types"
)

// SaveMessageType stores the given message type inside the database
func (db *Db) SaveMessageType(msg *types.MessageType) error {
stmt := `
INSERT INTO message_type(type, module, label, height)
VALUES ($1, $2, $3, $4)
ON CONFLICT (type) DO NOTHING`

_, err := db.SQL.Exec(stmt, msg.Type, msg.Module, msg.Label, msg.Height)
return err
}
53 changes: 53 additions & 0 deletions database/migrate/v5/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package v5

import (
"fmt"

utils "github.com/forbole/bdjuno/v4/modules/utils"
"github.com/forbole/bdjuno/v4/types"
)

// Migrate implements database.Migrator
func (db *Migrator) Migrate() error {
msgTypes, err := db.getMsgTypesFromMessageTable()
if err != nil {
return fmt.Errorf("error while getting message types rows: %s", err)
}

for _, msgType := range msgTypes {
// migrate message types
err = db.migrateMsgTypes(types.NewMessageType(
msgType.Type,
utils.GetModuleNameFromTypeURL(msgType.Type),
utils.GetMsgFromTypeURL(msgType.Type),
msgType.Height))

if err != nil {
return err
}
}
return nil
}

// getMsgTypesFromMessageTable retrieves messages types stored in database inside message table
func (db *Migrator) getMsgTypesFromMessageTable() ([]MessageRow, error) {
smt := "SELECT DISTINCT ON (type) type, transaction_hash, height FROM message ORDER BY type DESC"
var rows []MessageRow
err := db.SQL.Select(&rows, smt)
if err != nil {
return nil, err
}

return rows, nil
}

// migrateMsgTypes stores the given message type inside the database
func (db *Migrator) migrateMsgTypes(msg *types.MessageType) error {
stmt := `
INSERT INTO message_type(type, module, label, height)
VALUES ($1, $2, $3, $4)
ON CONFLICT (type) DO NOTHING`

_, err := db.SQL.Exec(stmt, msg.Type, msg.Module, msg.Label, msg.Height)
return err
}
21 changes: 21 additions & 0 deletions database/migrate/v5/migrator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package v5

import (
"github.com/jmoiron/sqlx"

"github.com/forbole/juno/v4/database"
"github.com/forbole/juno/v4/database/postgresql"
)

var _ database.Migrator = &Migrator{}

// Migrator represents the database migrator that should be used to migrate from v4 of the database to v5
type Migrator struct {
SQL *sqlx.DB
}

func NewMigrator(db *postgresql.Database) *Migrator {
return &Migrator{
SQL: db.SQL,
}
}
10 changes: 10 additions & 0 deletions database/migrate/v5/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package v5

type MessageRow struct {
TransactionHash string `db:"transaction_hash"`
Index int64 `db:"index"`
Type string `db:"type"`
Value string `db:"value"`
InvolvedAccountsAddresses string `db:"involved_accounts_addresses"`
Height int64 `db:"height"`
}
23 changes: 22 additions & 1 deletion database/schema/00-cosmos.sql
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,21 @@ CREATE INDEX transaction_hash_index ON transaction (hash);
CREATE INDEX transaction_height_index ON transaction (height);
CREATE INDEX transaction_partition_id_index ON transaction (partition_id);

CREATE TABLE message_type
(
type TEXT NOT NULL UNIQUE,
module TEXT NOT NULL,
label TEXT NOT NULL,
height BIGINT NOT NULL
);
CREATE INDEX message_type_module_index ON message_type (module);
CREATE INDEX message_type_type_index ON message_type (type);

CREATE TABLE message
(
transaction_hash TEXT NOT NULL,
index BIGINT NOT NULL,
type TEXT NOT NULL,
type TEXT NOT NULL REFERENCES message_type(type),
value JSONB NOT NULL,
involved_accounts_addresses TEXT[] NOT NULL,

Expand Down Expand Up @@ -101,6 +111,17 @@ WHERE (cardinality(types) = 0 OR type = ANY (types))
ORDER BY height DESC LIMIT "limit" OFFSET "offset"
$$ LANGUAGE sql STABLE;

CREATE FUNCTION messages_by_type(
types text [],
"limit" bigint DEFAULT 100,
"offset" bigint DEFAULT 0)
RETURNS SETOF message AS
$$
SELECT * FROM message
WHERE (cardinality(types) = 0 OR type = ANY (types))
ORDER BY height DESC LIMIT "limit" OFFSET "offset"
$$ LANGUAGE sql STABLE;

CREATE TABLE pruning
(
last_pruned_height BIGINT NOT NULL
Expand Down
27 changes: 27 additions & 0 deletions modules/message_type/handle_msg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package message_type

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/gogo/protobuf/proto"
utils "github.com/forbole/bdjuno/v4/modules/utils"
msgtypes "github.com/forbole/bdjuno/v4/types"

"github.com/forbole/juno/v4/types"
)

// HandleMsg represents a message handler that stores the given message inside the proper database table
func (m *Module) HandleMsg(
index int, msg sdk.Msg, tx *types.Tx) error {
// Save message type
err := m.db.SaveMessageType(msgtypes.NewMessageType(
proto.MessageName(msg),
utils.GetModuleNameFromTypeURL(proto.MessageName(msg)),
utils.GetMsgFromTypeURL(proto.MessageName(msg)),
tx.Height))

if err != nil {
return err
}

return nil
}
32 changes: 32 additions & 0 deletions modules/message_type/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package message_type

import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/forbole/bdjuno/v4/database"
"github.com/forbole/juno/v4/modules"
"github.com/forbole/juno/v4/modules/messages"
)

var (
_ modules.Module = &Module{}
_ modules.MessageModule = &Module{}
)

type Module struct {
cdc codec.Codec
db *database.Db
parser messages.MessageAddressesParser
}

func NewModule(parser messages.MessageAddressesParser, cdc codec.Codec, db *database.Db) *Module {
return &Module{
parser: parser,
cdc: cdc,
db: db,
}
}

// Name implements modules.Module
func (m *Module) Name() string {
return "message_type"
}
3 changes: 3 additions & 0 deletions modules/registrar.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

dailyrefetch "github.com/forbole/bdjuno/v4/modules/daily_refetch"
"github.com/forbole/bdjuno/v4/modules/gov"
messagetype "github.com/forbole/bdjuno/v4/modules/message_type"
"github.com/forbole/bdjuno/v4/modules/mint"
"github.com/forbole/bdjuno/v4/modules/modules"
"github.com/forbole/bdjuno/v4/modules/pricefeed"
Expand Down Expand Up @@ -80,6 +81,7 @@ func (r *Registrar) BuildModules(ctx registrar.Context) jmodules.Modules {
dailyRefetchModule := dailyrefetch.NewModule(ctx.Proxy, db)
distrModule := distribution.NewModule(sources.DistrSource, cdc, db)
feegrantModule := feegrant.NewModule(cdc, db)
messagetypeModule := messagetype.NewModule(r.parser, cdc, db)
mintModule := mint.NewModule(sources.MintSource, cdc, db)
slashingModule := slashing.NewModule(sources.SlashingSource, cdc, db)
stakingModule := staking.NewModule(sources.StakingSource, cdc, db)
Expand All @@ -100,6 +102,7 @@ func (r *Registrar) BuildModules(ctx registrar.Context) jmodules.Modules {
feegrantModule,
govModule,
mintModule,
messagetypeModule,
modules.NewModule(ctx.JunoConfig.Chain, db),
pricefeed.NewModule(ctx.JunoConfig, cdc, db),
slashingModule,
Expand Down
30 changes: 30 additions & 0 deletions modules/utils/message_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package utils

import (
"fmt"
"strings"
)

func GetModuleNameFromTypeURL(input string) string {
moduleName := strings.Split(input, ".")
if len(moduleName) > 1 {
switch {
case strings.Contains(moduleName[0], "cosmos"):
return moduleName[1] // e.g. "cosmos.bank.v1beta1.MsgSend" => "bank"
case strings.Contains(moduleName[0], "ibc"):
return fmt.Sprintf("%s %s %s", moduleName[0], moduleName[1], moduleName[2]) // e.g. "ibc.core.client.v1.MsgUpdateClient" => "ibc core client"
default:
return fmt.Sprintf("%s %s", moduleName[0], moduleName[1]) // e.g. "cosmwasm.wasm.v1.MsgExecuteContract" => "cosmwasm wasm"
}
}

return ""
}

func GetMsgFromTypeURL(input string) string {
messageName := strings.Split(input, ".")
if len(messageName) > 1 {
return messageName[len(messageName)-1] // e.g. "cosmos.bank.v1beta1.MsgSend" => "MsgSend"
}
return ""
}
19 changes: 19 additions & 0 deletions types/message_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package types

// MessageType represents the data of a single message type
type MessageType struct {
Type string
Module string
Label string
Height int64
}

// NewMessageType allows to build a new MessageType instance
func NewMessageType(msgType string, module string, label string, height int64) *MessageType {
return &MessageType{
Type: msgType,
Module: module,
Label: label,
Height: height,
}
}

0 comments on commit 220d132

Please sign in to comment.