Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add genmsg module #1495

Merged
merged 20 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#1500](https://github.com/NibiruChain/nibiru/pull/1500) - refactor(perp): clean up reverse market order mechanics
* [#1506](https://github.com/NibiruChain/nibiru/pull/1506) - refactor(oracle): Implement OrderedMap and use it for iterating through maps in x/oracle
* [#1502](https://github.com/NibiruChain/nibiru/pull/1502) - feat: add ledger build support
* [#1495](https://github.com/NibiruChain/nibiru/pull/1495) - feat: add genmsg module
* [#1517](https://github.com/NibiruChain/nibiru/pull/1517) - test: add more tests to x/hooks
* [#1518](https://github.com/NibiruChain/nibiru/pull/1518) - test: add more tests to x/perp

Expand Down
8 changes: 3 additions & 5 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"os"
"path/filepath"

"github.com/NibiruChain/nibiru/x/genmsg"

"github.com/NibiruChain/nibiru/x/sudo/keeper"

sudotypes "github.com/NibiruChain/nibiru/x/sudo/types"
Expand Down Expand Up @@ -123,11 +125,6 @@ const (
DisplayDenom = "NIBI"
)

// IBC application testing ports
const (
MockFeePort string = ibcmock.ModuleName + ibcfeetypes.ModuleName
)

var (
// DefaultNodeHome default home directories for the application daemon
DefaultNodeHome string
Expand Down Expand Up @@ -172,6 +169,7 @@ var (
sudo.AppModuleBasic{},
wasm.AppModuleBasic{},
ibcfee.AppModuleBasic{},
genmsg.AppModule{},
)

// module account permissions
Expand Down
7 changes: 7 additions & 0 deletions app/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package app
import (
"path/filepath"

"github.com/NibiruChain/nibiru/x/genmsg"

"github.com/NibiruChain/nibiru/x/sudo/keeper"

sudotypes "github.com/NibiruChain/nibiru/x/sudo/types"
Expand Down Expand Up @@ -490,6 +492,7 @@ func (app *NibiruApp) AppModules(
app.InflationKeeper, app.AccountKeeper, *app.stakingKeeper,
)
sudoModule := sudo.NewAppModule(appCodec, app.SudoKeeper)
genMsgModule := genmsg.NewAppModule(app.MsgServiceRouter())

return []module.AppModule{
genutil.NewAppModule(
Expand Down Expand Up @@ -519,6 +522,7 @@ func (app *NibiruApp) AppModules(
inflationModule,
sudoModule,
perpv2Module,
genMsgModule,

// ibc
evidence.NewAppModule(app.evidenceKeeper),
Expand Down Expand Up @@ -587,6 +591,9 @@ func OrderedModuleNames() []string {
// --------------------------------------------------------------------
// CosmWasm
wasm.ModuleName,

// Should be before genmsg
genmsg.ModuleName,
}
}

Expand Down
11 changes: 6 additions & 5 deletions contrib/scripts/localnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,13 @@ else
fi

# set validator as sudoer
$BINARY genesis add-sudo-root-account "$val_address"
add_genesis_param '.app_state.sudo.sudoers.root = "'"$val_address"'"'

# set local oracle params
add_genesis_param '.app_state.oracle.params.twap_lookback_window = "900s"'
add_genesis_param '.app_state.oracle.params.vote_period = "10"'
add_genesis_param '.app_state.oracle.params.min_voters = "1"'
# hack for localnet since we don't have a pricefeeder yet
add_genesis_param '.app_state.oracle.exchange_rates[0].pair = "ubtc:unusd"'
add_genesis_param '.app_state.oracle.exchange_rates[0].exchange_rate = "'"$price_btc"'"'
add_genesis_param '.app_state.oracle.exchange_rates[1].pair = "ueth:unusd"'
add_genesis_param '.app_state.oracle.exchange_rates[1].exchange_rate = "'"$price_eth"'"'

# Start the network
echo_info "Starting $CHAIN_ID in $CHAIN_DIR..."
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/gogoproto v1.4.10
github.com/cosmos/ibc-go/v7 v7.2.0
github.com/gogo/protobuf v1.3.3
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
github.com/google/gofuzz v1.2.0
Expand Down Expand Up @@ -88,7 +89,6 @@ require (
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.3 // indirect
github.com/golang/glog v1.1.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
Expand Down
15 changes: 9 additions & 6 deletions x/common/testutil/testapp/test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ func GenesisStateWithSingleValidator(codec codec.Codec, genesisState nibiruapp.G
// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
balances := []banktypes.Balance{
{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
},
}

var bankGenesis banktypes.GenesisState
codec.MustUnmarshalJSON(genesisState[banktypes.ModuleName], &bankGenesis)
balances := bankGenesis.Balances

balances = append(balances, banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
})

genesisState, err = genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balances...)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion x/epochs/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

// GetQueryCmd returns the cli query commands for this module.
func GetQueryCmd(queryRoute string) *cobra.Command {
func GetQueryCmd() *cobra.Command {
// Group epochs queries under a subcommand
cmd := &cobra.Command{
Use: types.ModuleName,
Expand Down
2 changes: 1 addition & 1 deletion x/epochs/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@

// GetQueryCmd returns the capability module's root query command.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd(types.StoreKey)
return cli.GetQueryCmd()

Check warning on line 81 in x/epochs/module.go

View check run for this annotation

Codecov / codecov/patch

x/epochs/module.go#L81

Added line #L81 was not covered by tests
}

// ----------------------------------------------------------------------------
Expand Down
67 changes: 67 additions & 0 deletions x/genmsg/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package genmsg

import (
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"

v1 "github.com/NibiruChain/nibiru/x/genmsg/v1"
)

func anyToMsg(ir types.InterfaceRegistry, anyMsg *types.Any) (sdk.Msg, error) {
var sdkMsg sdk.Msg
err := ir.UnpackAny(anyMsg, &sdkMsg)
if err != nil {
return nil, err
}

Check warning on line 18 in x/genmsg/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/genmsg/genesis.go#L17-L18

Added lines #L17 - L18 were not covered by tests
if err = sdkMsg.ValidateBasic(); err != nil {
return nil, err
}
return sdkMsg, nil
}

func validateGenesis(cdc codec.JSONCodec, genesis *v1.GenesisState) error {
interfaceRegistryProvider, ok := cdc.(interface {
InterfaceRegistry() types.InterfaceRegistry
})
if !ok {
return fmt.Errorf("codec does not implement InterfaceRegistry")
}

Check warning on line 31 in x/genmsg/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/genmsg/genesis.go#L30-L31

Added lines #L30 - L31 were not covered by tests
interfaceRegistry := interfaceRegistryProvider.InterfaceRegistry()
// check if all messages are known by the codec
for i, anyMsg := range genesis.Messages {
if _, err := anyToMsg(interfaceRegistry, anyMsg); err != nil {
return fmt.Errorf("at index %d: %w", i, err)
}
}
return nil
}

func initGenesis(context sdk.Context, cdc codec.JSONCodec, router MessageRouter, genesis *v1.GenesisState) error {
interfaceRegistryProvider, ok := cdc.(interface {
InterfaceRegistry() types.InterfaceRegistry
})
if !ok {
return fmt.Errorf("codec does not implement InterfaceRegistry")
}

Check warning on line 48 in x/genmsg/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/genmsg/genesis.go#L47-L48

Added lines #L47 - L48 were not covered by tests
interfaceRegistry := interfaceRegistryProvider.InterfaceRegistry()

// execute all messages in order
for i, anyMsg := range genesis.Messages {
msg, err := anyToMsg(interfaceRegistry, anyMsg)
if err != nil {
return fmt.Errorf("at index %d: message decoding: %w", i, err)
}

Check warning on line 56 in x/genmsg/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/genmsg/genesis.go#L55-L56

Added lines #L55 - L56 were not covered by tests
handler := router.Handler(msg)
if handler == nil {
return fmt.Errorf("at index %d: no handler for message %T %s", i, msg, msg)
}
_, err = handler(context, msg)
if err != nil {
return fmt.Errorf("at index %d: message processing: %w", i, err)
}

Check warning on line 64 in x/genmsg/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/genmsg/genesis.go#L63-L64

Added lines #L63 - L64 were not covered by tests
}
return nil
}
111 changes: 111 additions & 0 deletions x/genmsg/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package genmsg

import (
"testing"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/require"

v1 "github.com/NibiruChain/nibiru/x/genmsg/v1"
)

type mockRouter struct {
handler func(msg sdk.Msg) baseapp.MsgServiceHandler
}

func (m mockRouter) Handler(msg sdk.Msg) baseapp.MsgServiceHandler { return m.handler(msg) }

func makeCodec(_ *testing.T) codec.JSONCodec {
ir := types.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(ir)
ir.RegisterInterface(sdk.MsgInterfaceProtoName, (*sdk.Msg)(nil), &banktypes.MsgSend{})
return cdc
}

func newGenesisFromMsgs(t *testing.T, cdc codec.JSONCodec, msgs ...proto.Message) *v1.GenesisState {
genesis := new(v1.GenesisState)
for _, msg := range msgs {
anyProto, err := types.NewAnyWithValue(msg)
require.NoError(t, err)
genesis.Messages = append(genesis.Messages, anyProto)
}
genesisJSON, err := cdc.MarshalJSON(genesis)
require.NoError(t, err)
genesis = new(v1.GenesisState)
require.NoError(t, cdc.UnmarshalJSON(genesisJSON, genesis))
return genesis
}

func Test_initGenesis(t *testing.T) {
cdc := makeCodec(t)
ctx := sdk.Context{}

t.Run("works - no msgs", func(t *testing.T) {
r := mockRouter{func(msg sdk.Msg) baseapp.MsgServiceHandler {
return func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error) {
return &sdk.Result{}, nil
}
}}

err := initGenesis(ctx, cdc, r, newGenesisFromMsgs(t, cdc))
require.NoError(t, err)
})

t.Run("works - with message", func(t *testing.T) {
called := false
r := mockRouter{func(msg sdk.Msg) baseapp.MsgServiceHandler {
return func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error) {
called = true
return &sdk.Result{}, nil
}
}}

err := initGenesis(ctx, cdc, r, newGenesisFromMsgs(t, cdc, &banktypes.MsgSend{
FromAddress: sdk.AccAddress("a").String(),
ToAddress: sdk.AccAddress("b").String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 1000)),
}))
require.NoError(t, err)
require.True(t, called)
})

t.Run("fails - handler is nil", func(t *testing.T) {
r := mockRouter{func(msg sdk.Msg) baseapp.MsgServiceHandler {
return nil
}}

err := initGenesis(ctx, cdc, r, newGenesisFromMsgs(t, cdc, &banktypes.MsgSend{
FromAddress: sdk.AccAddress("a").String(),
ToAddress: sdk.AccAddress("b").String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 1000)),
}))
require.Error(t, err)
})
}

func Test_validateGenesis(t *testing.T) {
cdc := makeCodec(t)
t.Run("works - empty", func(t *testing.T) {
err := validateGenesis(cdc, &v1.GenesisState{})
require.NoError(t, err)
})
t.Run("works - with messages", func(t *testing.T) {
genesis := newGenesisFromMsgs(t, cdc, &banktypes.MsgSend{
FromAddress: sdk.AccAddress("sender").String(),
ToAddress: sdk.AccAddress("receiver").String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 1000)),
})
err := validateGenesis(cdc, genesis)
require.NoError(t, err)
})
t.Run("fails - validate basic", func(t *testing.T) {
genesis := newGenesisFromMsgs(t, cdc, &banktypes.MsgSend{})
err := validateGenesis(cdc, genesis)
require.Error(t, err)
})
}
60 changes: 60 additions & 0 deletions x/genmsg/integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package genmsg_test

import (
"testing"

tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/require"

"github.com/NibiruChain/nibiru/app"
"github.com/NibiruChain/nibiru/x/common/testutil/testapp"
"github.com/NibiruChain/nibiru/x/genmsg"
v1 "github.com/NibiruChain/nibiru/x/genmsg/v1"
)

func TestIntegration(t *testing.T) {
senderAddr := sdk.AccAddress("sender")
recvAddr := sdk.AccAddress("recv")

encoding := app.MakeEncodingConfig()
appGenesis := app.NewDefaultGenesisState(encoding.Marshaler)

appGenesis[banktypes.ModuleName] = encoding.Marshaler.MustMarshalJSON(&banktypes.GenesisState{
Balances: []banktypes.Balance{
{
Address: senderAddr.String(),
Coins: sdk.NewCoins(sdk.NewInt64Coin("unibi", 100000)),
},
},
})

testMsg := &banktypes.MsgSend{
FromAddress: senderAddr.String(),
ToAddress: recvAddr.String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("unibi", 1000)),
}

anyMsg, err := codectypes.NewAnyWithValue(testMsg)
require.NoError(t, err)

appGenesis[genmsg.ModuleName] = encoding.Marshaler.MustMarshalJSON(
&v1.GenesisState{
Messages: []*codectypes.Any{anyMsg},
},
)

app := testapp.NewNibiruTestApp(appGenesis)
ctx := app.NewContext(false, tmproto.Header{
Height: 1,
})

balance, err := app.BankKeeper.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: recvAddr.String(),
Denom: "unibi",
})
require.NoError(t, err)
require.True(t, balance.Balance.Equal(sdk.NewInt64Coin("unibi", 1000)))
}
Loading
Loading