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

v5.0.2 upgrade handler #770

Merged
merged 7 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"
"time"

v502 "github.com/neutron-org/neutron/v5/app/upgrades/v5.0.2"
dynamicfeestypes "github.com/neutron-org/neutron/v5/x/dynamicfees/types"

"github.com/skip-mev/feemarket/x/feemarket"
Expand Down Expand Up @@ -228,6 +229,7 @@ const (
var (
Upgrades = []upgrades.Upgrade{
v500.Upgrade,
v502.Upgrade,
}

// DefaultNodeHome default home directories for the application daemon
Expand Down
18 changes: 18 additions & 0 deletions app/upgrades/v5.0.2/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package v502

import (
storetypes "cosmossdk.io/store/types"

"github.com/neutron-org/neutron/v5/app/upgrades"
)

const (
// UpgradeName defines the on-chain upgrade name.
UpgradeName = "v5.0.2"
)

var Upgrade = upgrades.Upgrade{
UpgradeName: UpgradeName,
CreateUpgradeHandler: CreateUpgradeHandler,
StoreUpgrades: storetypes.StoreUpgrades{},
}
30 changes: 30 additions & 0 deletions app/upgrades/v5.0.2/upgrades.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package v502

import (
"context"
"fmt"

upgradetypes "cosmossdk.io/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"

"github.com/neutron-org/neutron/v5/app/upgrades"
)

func CreateUpgradeHandler(
_ *module.Manager,
_ module.Configurator,
_ *upgrades.UpgradeKeepers,
_ upgrades.StoreKeys,
_ codec.Codec,
) upgradetypes.UpgradeHandler {
return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
ctx := sdk.UnwrapSDKContext(c)

ctx.Logger().Info("Starting module migrations...")

ctx.Logger().Info(fmt.Sprintf("Migration {%s} applied", UpgradeName))
return vm, nil
}
}
37 changes: 37 additions & 0 deletions app/upgrades/v5.0.2/upgrades_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package v502_test

import (
"testing"

upgradetypes "cosmossdk.io/x/upgrade/types"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

v502 "github.com/neutron-org/neutron/v5/app/upgrades/v5.0.2"
"github.com/neutron-org/neutron/v5/testutil"
)

type UpgradeTestSuite struct {
testutil.IBCConnectionTestSuite
}

func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(UpgradeTestSuite))
}

func (suite *UpgradeTestSuite) SetupTest() {
suite.IBCConnectionTestSuite.SetupTest()
}

func (suite *UpgradeTestSuite) TestOracleUpgrade() {
app := suite.GetNeutronZoneApp(suite.ChainA)
ctx := suite.ChainA.GetContext().WithChainID("neutron-1")
t := suite.T()

upgrade := upgradetypes.Plan{
Name: v502.UpgradeName,
Info: "some text here",
Height: 100,
}
require.NoError(t, app.UpgradeKeeper.ApplyUpgrade(ctx, upgrade))
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ require (
)

replace (
cosmossdk.io/math => cosmossdk.io/math v1.4.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already 1.4.0, if you don't want to prevent future updates, i think it's not necessarily to set a replacement

Copy link
Collaborator Author

@pr0n00gler pr0n00gler Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this replace force for v1.4.0 to be used in all dependencies?

github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
github.com/CosmWasm/wasmd => github.com/neutron-org/wasmd v0.53.0-neutron
github.com/cometbft/cometbft => github.com/neutron-org/cometbft v0.0.0-20241111105801-a7fe160b0b62
Expand Down
10 changes: 10 additions & 0 deletions testutil/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,16 @@ func (suite *IBCConnectionTestSuite) FundAcc(acc sdk.AccAddress, amounts sdk.Coi
suite.Require().NoError(err)
}

// FundModuleAcc funds target modules with specified amount.
func (suite *IBCConnectionTestSuite) FundModuleAcc(moduleName string, amounts sdk.Coins) {
bankKeeper := suite.GetNeutronZoneApp(suite.ChainA).BankKeeper
err := bankKeeper.MintCoins(suite.ChainA.GetContext(), tokenfactorytypes.ModuleName, amounts)
suite.Require().NoError(err)

err = bankKeeper.SendCoinsFromModuleToModule(suite.ChainA.GetContext(), tokenfactorytypes.ModuleName, moduleName, amounts)
suite.Require().NoError(err)
}

// update CCV path with correct info
func SetupCCVPath(path *ibctesting.Path, suite *IBCConnectionTestSuite) {
// - set provider endpoint's clientID
Expand Down
222 changes: 222 additions & 0 deletions x/tokenfactory/keeper/before_send_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package keeper_test

import (
"encoding/json"
"fmt"
"os"

"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

dextypes "github.com/neutron-org/neutron/v5/x/dex/types"
icqtypes "github.com/neutron-org/neutron/v5/x/interchainqueries/types"
"github.com/neutron-org/neutron/v5/x/tokenfactory/types"
)

Expand Down Expand Up @@ -46,6 +51,127 @@ func (suite *KeeperTestSuite) initBalanceTrackContract(denom string) (sdk.AccAdd
return cosmwasmAddress, codeID, factoryDenom
}

type SendMsgTestCase struct {
desc string
msg func(denom string) *banktypes.MsgSend
expectPass bool
}

func (suite *KeeperTestSuite) TestBeforeSendHook() {
for _, tc := range []struct {
desc string
wasmFile string
sendMsgs []SendMsgTestCase
}{
{
desc: "should not allow sending 100 amount of *any* denom",
wasmFile: "./testdata/no100.wasm",
sendMsgs: []SendMsgTestCase{
{
desc: "sending 1 of factorydenom should not error",
msg: func(factorydenom string) *banktypes.MsgSend {
return banktypes.NewMsgSend(
suite.TestAccs[0],
suite.TestAccs[1],
sdk.NewCoins(sdk.NewInt64Coin(factorydenom, 1)),
)
},
expectPass: true,
},
{
desc: "sending 1 of non-factorydenom should not error",
msg: func(factorydenom string) *banktypes.MsgSend {
return banktypes.NewMsgSend(
suite.TestAccs[0],
suite.TestAccs[1],
sdk.NewCoins(sdk.NewInt64Coin("foo", 1)),
)
},
expectPass: true,
},
{
desc: "sending 100 of factorydenom should error",
msg: func(factorydenom string) *banktypes.MsgSend {
return banktypes.NewMsgSend(
suite.TestAccs[0],
suite.TestAccs[1],
sdk.NewCoins(sdk.NewInt64Coin(factorydenom, 100)),
)
},
expectPass: false,
},
{
desc: "sending 100 of non-factorydenom should work",
msg: func(factorydenom string) *banktypes.MsgSend {
return banktypes.NewMsgSend(
suite.TestAccs[0],
suite.TestAccs[1],
sdk.NewCoins(sdk.NewInt64Coin("foo", 100)),
)
},
expectPass: true,
},
{
desc: "having 100 coin within coins should not work",
msg: func(factorydenom string) *banktypes.MsgSend {
return banktypes.NewMsgSend(
suite.TestAccs[0],
suite.TestAccs[1],
sdk.NewCoins(sdk.NewInt64Coin(factorydenom, 100), sdk.NewInt64Coin("foo", 1)),
)
},
expectPass: false,
},
},
},
} {
suite.Run(fmt.Sprintf("Case %suite", tc.desc), func() {
// setup test
suite.Setup()

senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress()
suite.TopUpWallet(suite.ChainA.GetContext(), senderAddress, suite.TestAccs[0])

// upload and instantiate wasm code
wasmCode, err := os.ReadFile(tc.wasmFile)
suite.Require().NoError(err, "test: %v", tc.desc)
codeID, _, err := suite.contractKeeper.Create(suite.ChainA.GetContext(), suite.TestAccs[0], wasmCode, nil)
suite.Require().NoError(err, "test: %v", tc.desc)
cosmwasmAddress, _, err := suite.contractKeeper.Instantiate(suite.ChainA.GetContext(), codeID, suite.TestAccs[0], suite.TestAccs[0], []byte("{}"), "", sdk.NewCoins())
suite.Require().NoError(err, "test: %v", tc.desc)

// create new denom
res, err := suite.msgServer.CreateDenom(suite.ChainA.GetContext(), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin"))
suite.Require().NoError(err, "test: %v", tc.desc)
denom := res.GetNewTokenDenom()

// mint enough coins to the creator
_, err = suite.msgServer.Mint(suite.ChainA.GetContext(), types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(denom, 1000000000)))
suite.Require().NoError(err)
// mint some non token factory denom coins for testing
suite.FundAcc(sdk.MustAccAddressFromBech32(suite.TestAccs[0].String()), sdk.Coins{sdk.NewInt64Coin("foo", 100000000000)})

params := types.DefaultParams()
params.WhitelistedHooks = []*types.WhitelistedHook{{DenomCreator: suite.TestAccs[0].String(), CodeID: 1}}
err = suite.GetNeutronZoneApp(suite.ChainA).TokenFactoryKeeper.SetParams(suite.ChainA.GetContext(), params)
suite.Require().NoError(err)

// set beforesend hook to the new denom
_, err = suite.msgServer.SetBeforeSendHook(suite.ChainA.GetContext(), types.NewMsgSetBeforeSendHook(suite.TestAccs[0].String(), denom, cosmwasmAddress.String()))
suite.Require().NoError(err, "test: %v", tc.desc)

for _, sendTc := range tc.sendMsgs {
_, err := suite.bankMsgServer.Send(suite.ChainA.GetContext(), sendTc.msg(denom))
if sendTc.expectPass {
suite.Require().NoError(err, "test: %v", sendTc.desc)
} else {
suite.Require().Error(err, "test: %v", sendTc.desc)
}
}
})
}
}

func (suite *KeeperTestSuite) TestTrackBeforeSendWasm() {
suite.Setup()

Expand Down Expand Up @@ -115,3 +241,99 @@ func (suite *KeeperTestSuite) TestNonWhitelistedHooksNotCalled() {
// Whitelisted contract is not called
suite.Require().Equal("\"0\"", string(queryResp))
}

// TestInfiniteTrackBeforeSend tests gas metering with infinite loop contract
// to properly test if we are gas metering trackBeforeSend properly.
func (suite *KeeperTestSuite) TestInfiniteTrackBeforeSend() {
for _, tc := range []struct {
name string
wasmFile string
tokenToSend sdk.Coins
useFactoryDenom bool
blockBeforeSend bool
expectedError bool
}{
{
name: "sending tokenfactory denom from module to module with infinite contract should panic",
wasmFile: "./testdata/infinite_track_beforesend.wasm",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Links to contracts source code would be helpful.

useFactoryDenom: true,
},
{
name: "sending tokenfactory denom from account to account with infinite contract should panic",
wasmFile: "./testdata/infinite_track_beforesend.wasm",
useFactoryDenom: true,
blockBeforeSend: true,
},
{
name: "sending non-tokenfactory denom from module to module with infinite contract should not panic",
wasmFile: "./testdata/infinite_track_beforesend.wasm",
tokenToSend: sdk.NewCoins(sdk.NewInt64Coin("foo", 1000000)),
useFactoryDenom: false,
},
{
name: "Try using no 100",
wasmFile: "./testdata/no100.wasm",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure i understand, what the contract does, could you give a brief description?

useFactoryDenom: true,
},
} {
suite.Run(fmt.Sprintf("Case %suite", tc.name), func() {
// setup test
suite.Setup()

// load wasm file
wasmCode, err := os.ReadFile(tc.wasmFile)
suite.Require().NoError(err)

// instantiate wasm code
codeID, _, err := suite.contractKeeper.Create(suite.ChainA.GetContext(), suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), wasmCode, nil)
suite.Require().NoError(err, "test: %v", tc.name)
cosmwasmAddress, _, err := suite.contractKeeper.Instantiate(suite.ChainA.GetContext(), codeID, suite.TestAccs[0], suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), []byte("{}"), "", sdk.NewCoins())
suite.Require().NoError(err, "test: %v", tc.name)

params := types.DefaultParams()
params.WhitelistedHooks = []*types.WhitelistedHook{{DenomCreator: suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress().String(), CodeID: 1}}
err = suite.GetNeutronZoneApp(suite.ChainA).TokenFactoryKeeper.SetParams(suite.ChainA.GetContext(), params)
suite.Require().NoError(err)

// create new denom
res, err := suite.msgServer.CreateDenom(suite.ChainA.GetContext(), types.NewMsgCreateDenom(suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "bitcoin"))
suite.Require().NoError(err, "test: %v", tc.name)
factoryDenom := res.GetNewTokenDenom()

var tokenToSend sdk.Coins
if tc.useFactoryDenom {
tokenToSend = sdk.NewCoins(sdk.NewInt64Coin(factoryDenom, 100))
} else {
tokenToSend = tc.tokenToSend
}

// send the mint module tokenToSend
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mint?

if tc.blockBeforeSend {
suite.FundAcc(suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), tokenToSend)
} else {
suite.FundModuleAcc(icqtypes.ModuleName, tokenToSend)
}

// set beforesend hook to the new denom
// we register infinite loop contract here to test if we are gas metering properly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as i can see, no100 in the list of testcases and it's not infinite loop. Comment misleading?

_, err = suite.msgServer.SetBeforeSendHook(suite.ChainA.GetContext(), types.NewMsgSetBeforeSendHook(suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress().String(), factoryDenom, cosmwasmAddress.String()))
suite.Require().NoError(err, "test: %v", tc.name)

ctx := suite.ChainA.GetContext().WithGasMeter(storetypes.NewGasMeter(30_000_000))

if tc.blockBeforeSend {
err = suite.GetNeutronZoneApp(suite.ChainA).BankKeeper.SendCoins(ctx, suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), suite.ChainA.SenderAccounts[1].SenderAccount.GetAddress(), tokenToSend)
suite.Require().Error(err)
} else {
// track before send suppresses in any case, thus we expect no error
err = suite.GetNeutronZoneApp(suite.ChainA).BankKeeper.SendCoinsFromModuleToModule(ctx, icqtypes.ModuleName, dextypes.ModuleName, tokenToSend)
suite.Require().NoError(err)

// send should happen regardless of trackBeforeSend results
distributionModuleAddress := suite.GetNeutronZoneApp(suite.ChainA).AccountKeeper.GetModuleAddress("dex")
pr0n00gler marked this conversation as resolved.
Show resolved Hide resolved
distributionModuleBalances := suite.GetNeutronZoneApp(suite.ChainA).BankKeeper.GetAllBalances(suite.ChainA.GetContext(), distributionModuleAddress)
suite.Require().True(distributionModuleBalances.Equal(tokenToSend))
}
})
}
}
Loading
Loading