-
Notifications
You must be signed in to change notification settings - Fork 106
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
Changes from 1 commit
7753d04
810f87f
50c5cee
0f9cb22
fa76dff
d5e86d2
cca46e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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{}, | ||
} |
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 | ||
} | ||
} |
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)) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
) | ||
|
||
|
@@ -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() | ||
|
||
|
@@ -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", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
_, 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)) | ||
} | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?