Skip to content

Commit

Permalink
refactor!: eliminate sdk codec dependency from remote mode (forbole#107)
Browse files Browse the repository at this point in the history
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v                               ✰  Thanks for creating a PR! ✰    
v    Before smashing the submit button please review the checkboxes.
v If a checkbox is n/a - please still include it but + a little note why
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >  -->

## Description
<!-- Small description -->
This PR eliminate the codec dependency from remote node to make Juno
chain-agnostic.

## Checklist
- [x] Targeted PR against correct branch.
- [ ] Linked to Github issue with discussion and accepted design OR link
to spec that describes this work.
- [ ] Wrote unit tests.  
- [x] Re-reviewed `Files changed` in the Github PR explorer.
  • Loading branch information
dadamu authored and dzmitryhil committed Dec 16, 2024
1 parent 84196a9 commit 47ff591
Show file tree
Hide file tree
Showing 35 changed files with 409 additions and 1,135 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ coverage.txt
# Configuration
*.toml
*.yaml

vendor/
3 changes: 0 additions & 3 deletions cmd/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ var (
// setupCfg method will be used to customize the SDK configuration. If you don't want any customization
// you can use the config.DefaultConfigSetup variable.
//
// encodingConfigBuilder is used to provide a codec that will later be used to deserialize the
// transaction messages. Make sure you register all the types you need properly.
//
// dbBuilder is used to provide the database that will be used to save the data. If you don't have any
// particular need, you can use the Create variable to build a default database instance.
func BuildDefaultExecutor(config *Config) cli.Executor {
Expand Down
2 changes: 1 addition & 1 deletion cmd/parse/blocks/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ will be replaced with the data downloaded from the node.
return err
}

workerCtx := parser.NewContext(parseCtx.EncodingConfig, parseCtx.Node, parseCtx.Database, parseCtx.Logger, parseCtx.Modules)
workerCtx := parser.NewContext(parseCtx.Node, parseCtx.Database, parseCtx.Logger, parseCtx.Modules)
worker := parser.NewWorker(workerCtx, nil, 0)

// Get the flag values
Expand Down
2 changes: 1 addition & 1 deletion cmd/parse/blocks/missing.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func newMissingCmd(parseConfig *parsecmdtypes.Config) *cobra.Command {
return err
}

workerCtx := parser.NewContext(parseCtx.EncodingConfig, parseCtx.Node, parseCtx.Database, parseCtx.Logger, parseCtx.Modules)
workerCtx := parser.NewContext(parseCtx.Node, parseCtx.Database, parseCtx.Logger, parseCtx.Modules)
worker := parser.NewWorker(workerCtx, nil, 0)

dbLastHeight, err := parseCtx.Database.GetLastBlockHeight()
Expand Down
2 changes: 1 addition & 1 deletion cmd/parse/transactions/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ You can specify a custom height range by using the %s and %s flags.
return err
}

workerCtx := parser.NewContext(parseCtx.EncodingConfig, parseCtx.Node, parseCtx.Database, parseCtx.Logger, parseCtx.Modules)
workerCtx := parser.NewContext(parseCtx.Node, parseCtx.Database, parseCtx.Logger, parseCtx.Modules)
worker := parser.NewWorker(workerCtx, nil, 0)

// Get the flag values
Expand Down
60 changes: 0 additions & 60 deletions cmd/parse/types/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,8 @@ package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/consensus"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/cosmos/cosmos-sdk/x/gov"
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
groupmodule "github.com/cosmos/cosmos-sdk/x/group/module"
"github.com/cosmos/cosmos-sdk/x/mint"
nftmodule "github.com/cosmos/cosmos-sdk/x/nft/module"
"github.com/cosmos/cosmos-sdk/x/params"
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/upgrade"
upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client"

"github.com/forbole/juno/v5/types/config"
appparams "github.com/forbole/juno/v5/types/params"
)

// SdkConfigSetup represents a method that allows to customize the given sdk.Config.
Expand All @@ -52,38 +27,3 @@ func DefaultConfigSetup(cfg config.Config, sdkConfig *sdk.Config) {
prefix+sdk.PrefixValidator+sdk.PrefixConsensus+sdk.PrefixPublic,
)
}

// -----------------------------------------------------------------

// EncodingConfigBuilder represents a function that is used to return the proper encoding config.
type EncodingConfigBuilder func() appparams.EncodingConfig

var (
ModuleBasics = module.NewBasicManager(
auth.AppModuleBasic{},
genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
bank.AppModuleBasic{},
capability.AppModuleBasic{},
staking.AppModuleBasic{},
mint.AppModuleBasic{},
distr.AppModuleBasic{},
gov.NewAppModuleBasic(
[]govclient.ProposalHandler{
paramsclient.ProposalHandler,
upgradeclient.LegacyProposalHandler,
upgradeclient.LegacyCancelProposalHandler,
},
),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
slashing.AppModuleBasic{},
feegrantmodule.AppModuleBasic{},
upgrade.AppModuleBasic{},
evidence.AppModuleBasic{},
authzmodule.AppModuleBasic{},
groupmodule.AppModuleBasic{},
vesting.AppModuleBasic{},
nftmodule.AppModuleBasic{},
consensus.AppModuleBasic{},
)
)
12 changes: 5 additions & 7 deletions cmd/parse/types/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ import (

// GetParserContext setups all the things that can be used to later parse the chain state
func GetParserContext(cfg config.Config, parseConfig *Config) (*parser.Context, error) {
// Build the codec
encodingConfig := parseConfig.GetEncodingConfigBuilder()()

// Setup the SDK configuration
sdkConfig, sealed := getConfig()
if !sealed {
Expand All @@ -29,14 +26,15 @@ func GetParserContext(cfg config.Config, parseConfig *Config) (*parser.Context,
}

// Get the db
databaseCtx := database.NewContext(cfg.Database, encodingConfig, parseConfig.GetLogger())
databaseCtx := database.NewContext(cfg.Database, parseConfig.GetLogger())
db, err := parseConfig.GetDBBuilder()(databaseCtx)
if err != nil {
return nil, err
}

// Init the client
cp, err := nodebuilder.BuildNode(cfg.Node, encodingConfig)
// Juno itself does not support local node type, so we can safely set codec and txConfig to nil
cp, err := nodebuilder.BuildNode(cfg.Node, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to start client: %s", err)
}
Expand All @@ -53,11 +51,11 @@ func GetParserContext(cfg config.Config, parseConfig *Config) (*parser.Context,
}

// Get the modules
context := modsregistrar.NewContext(cfg, sdkConfig, encodingConfig, db, cp, parseConfig.GetLogger())
context := modsregistrar.NewContext(cfg, sdkConfig, db, cp, parseConfig.GetLogger())
mods := parseConfig.GetRegistrar().BuildModules(context)
registeredModules := modsregistrar.GetModules(mods, cfg.Chain.Modules, parseConfig.GetLogger())

return parser.NewContext(encodingConfig, cp, db, parseConfig.GetLogger(), registeredModules), nil
return parser.NewContext(cp, db, parseConfig.GetLogger(), registeredModules), nil
}

// getConfig returns the SDK Config instance as well as if it's sealed or not
Expand Down
35 changes: 5 additions & 30 deletions cmd/parse/types/types.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package types

import (
"github.com/cosmos/cosmos-sdk/std"

"github.com/forbole/juno/v5/logging"
"github.com/forbole/juno/v5/types/config"
"github.com/forbole/juno/v5/types/params"

"github.com/forbole/juno/v5/database"
"github.com/forbole/juno/v5/database/builder"
Expand All @@ -14,12 +11,11 @@ import (

// Config contains all the configuration for the "parse" command
type Config struct {
registrar registrar.Registrar
configParser config.Parser
encodingConfigBuilder EncodingConfigBuilder
setupCfg SdkConfigSetup
buildDb database.Builder
logger logging.Logger
registrar registrar.Registrar
configParser config.Parser
setupCfg SdkConfigSetup
buildDb database.Builder
logger logging.Logger
}

// NewConfig allows to build a new Config instance
Expand Down Expand Up @@ -55,27 +51,6 @@ func (cfg *Config) GetConfigParser() config.Parser {
return cfg.configParser
}

// WithEncodingConfigBuilder sets the configurations builder to be used
func (cfg *Config) WithEncodingConfigBuilder(b EncodingConfigBuilder) *Config {
cfg.encodingConfigBuilder = b
return cfg
}

// GetEncodingConfigBuilder returns the encoding config builder to be used
func (cfg *Config) GetEncodingConfigBuilder() EncodingConfigBuilder {
if cfg.encodingConfigBuilder == nil {
return func() params.EncodingConfig {
encodingConfig := params.MakeTestEncodingConfig()
std.RegisterLegacyAminoCodec(encodingConfig.Amino)
std.RegisterInterfaces(encodingConfig.InterfaceRegistry)
ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino)
ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry)
return encodingConfig
}
}
return cfg.encodingConfigBuilder
}

// WithSetupConfig sets the SDK setup configurator to be used
func (cfg *Config) WithSetupConfig(s SdkConfigSetup) *Config {
cfg.setupCfg = s
Expand Down
17 changes: 7 additions & 10 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package database

import (
"github.com/forbole/juno/v5/logging"
"github.com/forbole/juno/v5/types/params"

databaseconfig "github.com/forbole/juno/v5/database/config"

Expand Down Expand Up @@ -33,7 +32,7 @@ type Database interface {

// SaveTx will be called to save each transaction contained inside a block.
// An error is returned if the operation fails.
SaveTx(tx *types.Tx) error
SaveTx(tx *types.Transaction) error

// HasValidator returns true if a given validator by consensus address exists.
// An error is returned if the operation fails.
Expand All @@ -49,7 +48,7 @@ type Database interface {

// SaveMessage stores a single message.
// An error is returned if the operation fails.
SaveMessage(msg *types.Message) error
SaveMessage(height int64, txHash string, msg types.Message, addresses []string) error

// Close closes the connection to the database
Close()
Expand All @@ -69,17 +68,15 @@ type PruningDb interface {

// Context contains the data that might be used to build a Database instance
type Context struct {
Cfg databaseconfig.Config
EncodingConfig params.EncodingConfig
Logger logging.Logger
Cfg databaseconfig.Config
Logger logging.Logger
}

// NewContext allows to build a new Context instance
func NewContext(cfg databaseconfig.Config, encodingConfig params.EncodingConfig, logger logging.Logger) *Context {
func NewContext(cfg databaseconfig.Config, logger logging.Logger) *Context {
return &Context{
Cfg: cfg,
EncodingConfig: encodingConfig,
Logger: logger,
Cfg: cfg,
Logger: logger,
}
}

Expand Down
36 changes: 13 additions & 23 deletions database/postgresql/postgresql.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package postgresql
import (
"database/sql"
"encoding/base64"
"encoding/json"
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/jmoiron/sqlx"

"github.com/forbole/juno/v5/logging"
Expand Down Expand Up @@ -46,9 +46,6 @@ func Builder(ctx *database.Context) (database.Database, error) {
postgresDb.SetMaxIdleConns(ctx.Cfg.MaxIdleConnections)

return &Database{
Cdc: ctx.EncodingConfig.Codec,
Amino: ctx.EncodingConfig.Amino,

SQL: postgresDb,
Logger: ctx.Logger,
}, nil
Expand All @@ -60,9 +57,6 @@ var _ database.Database = &Database{}
// Database defines a wrapper around a SQL database and implements functionality
// for data aggregation and exporting.
type Database struct {
Cdc codec.Codec
Amino *codec.LegacyAmino

SQL *sqlx.DB
Logger logging.Logger
}
Expand Down Expand Up @@ -153,12 +147,12 @@ func (db *Database) GetTotalBlocks() int64 {
}

// SaveTx implements database.Database
func (db *Database) SaveTx(tx *types.Tx) error {
func (db *Database) SaveTx(tx *types.Transaction) error {
var partitionID int64

partitionSize := config.Cfg.Database.PartitionSize
if partitionSize > 0 {
partitionID = tx.Height / partitionSize
partitionID = int64(tx.Height) / partitionSize
err := db.CreatePartitionIfNotExists("transaction", partitionID)
if err != nil {
return err
Expand All @@ -169,7 +163,7 @@ func (db *Database) SaveTx(tx *types.Tx) error {
}

// saveTxInsidePartition stores the given transaction inside the partition having the given id
func (db *Database) saveTxInsidePartition(tx *types.Tx, partitionID int64) error {
func (db *Database) saveTxInsidePartition(tx *types.Transaction, partitionID int64) error {
sqlStatement := `
INSERT INTO transaction
(hash, height, success, messages, memo, signatures, signer_infos, fee, gas_wanted, gas_used, raw_log, logs, partition_id)
Expand All @@ -194,30 +188,26 @@ ON CONFLICT (hash, partition_id) DO UPDATE

var msgs = make([]string, len(tx.Body.Messages))
for index, msg := range tx.Body.Messages {
bz, err := db.Cdc.MarshalJSON(msg)
if err != nil {
return err
}
msgs[index] = string(bz)
msgs[index] = string(msg.GetBytes())
}
msgsBz := fmt.Sprintf("[%s]", strings.Join(msgs, ","))

feeBz, err := db.Cdc.MarshalJSON(tx.AuthInfo.Fee)
feeBz, err := json.Marshal(tx.AuthInfo.Fee)
if err != nil {
return fmt.Errorf("failed to JSON encode tx fee: %s", err)
}

var sigInfos = make([]string, len(tx.AuthInfo.SignerInfos))
for index, info := range tx.AuthInfo.SignerInfos {
bz, err := db.Cdc.MarshalJSON(info)
bz, err := json.Marshal(info)
if err != nil {
return err
}
sigInfos[index] = string(bz)
}
sigInfoBz := fmt.Sprintf("[%s]", strings.Join(sigInfos, ","))

logsBz, err := db.Amino.MarshalJSON(tx.Logs)
logsBz, err := json.Marshal(tx.Logs)
if err != nil {
return err
}
Expand Down Expand Up @@ -285,22 +275,22 @@ func (db *Database) SaveCommitSignatures(signatures []*types.CommitSig) error {
}

// SaveMessage implements database.Database
func (db *Database) SaveMessage(msg *types.Message) error {
func (db *Database) SaveMessage(height int64, txHash string, msg types.Message, addresses []string) error {
var partitionID int64
partitionSize := config.Cfg.Database.PartitionSize
if partitionSize > 0 {
partitionID = msg.Height / partitionSize
partitionID = height / partitionSize
err := db.CreatePartitionIfNotExists("message", partitionID)
if err != nil {
return err
}
}

return db.saveMessageInsidePartition(msg, partitionID)
return db.saveMessageInsidePartition(height, txHash, addresses, msg, partitionID)
}

// saveMessageInsidePartition stores the given message inside the partition having the provided id
func (db *Database) saveMessageInsidePartition(msg *types.Message, partitionID int64) error {
func (db *Database) saveMessageInsidePartition(height int64, txHash string, addresses []string, msg types.Message, partitionID int64) error {
stmt := `
INSERT INTO message(transaction_hash, index, type, value, involved_accounts_addresses, height, partition_id)
VALUES ($1, $2, $3, $4, $5, $6, $7)
Expand All @@ -310,7 +300,7 @@ ON CONFLICT (transaction_hash, index, partition_id) DO UPDATE
value = excluded.value,
involved_accounts_addresses = excluded.involved_accounts_addresses`

_, err := db.SQL.Exec(stmt, msg.TxHash, msg.Index, msg.Type, msg.Value, pq.Array(msg.Addresses), msg.Height, partitionID)
_, err := db.SQL.Exec(stmt, txHash, msg.GetIndex(), msg.GetType(), msg.GetBytes(), pq.Array(addresses), height, partitionID)
return err
}

Expand Down
Loading

0 comments on commit 47ff591

Please sign in to comment.