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

chore: re-add argentum upgrade handler #476

Draft
wants to merge 3 commits into
base: v9
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ func (app *App) RegisterUpgradeHandler() error {
upgrade.CreateUpgradeHandler(
app.ModuleManager,
app.Configurator(),
app.Logger(),
app.CapabilityKeeper,
app.DollarKeeper,
app.WormholeKeeper,
),
)

Expand Down
93 changes: 90 additions & 3 deletions e2e/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,111 @@
package e2e_test

import (
"context"
"testing"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/noble-assets/noble/e2e"
"github.com/strangelove-ventures/interchaintest/v8"
"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"github.com/stretchr/testify/require"
)

func TestChainUpgrade(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}

genesisVersion := "v9.0.0-rc.0"
genesisVersion := "v7.0.0"

upgrades := []e2e.ChainUpgrade{
{
Image: e2e.GhcrImage("v8.0.5"),
UpgradeName: "helium",
PreUpgrade: func(t *testing.T, ctx context.Context, noble *cosmos.CosmosChain, authority ibc.Wallet, icaTs *e2e.ICATestSuite) {
icaAddr, err := e2e.RegisterICAAccount(ctx, icaTs)
require.NoError(t, err, "failed to setup ICA account")
require.NotEmpty(t, icaAddr, "ICA address should not be empty")

// After successfully creating and querying the ICA account we need to update the test suite value for later usage.
icaTs.IcaAddress = icaAddr

// Assert initial balance of the ICA is correct.
initBal, err := noble.BankQueryBalance(ctx, icaAddr, noble.Config().Denom)
require.NoError(t, err, "failed to query bank balance")
require.True(t, initBal.Equal(icaTs.InitBal), "invalid balance expected(%s), got(%s)", icaTs.InitBal, initBal)

// Create and fund a user on Noble for use as the dst address in the bank transfer that we
// compose below.
users := interchaintest.GetAndFundTestUsers(t, ctx, "user", icaTs.InitBal, icaTs.Host)
dstAddress := users[0].FormattedAddress()

transferAmount := math.NewInt(1_000_000)

fromAddress := sdk.MustAccAddressFromBech32(icaAddr)
toAddress := sdk.MustAccAddressFromBech32(dstAddress)
coin := sdk.NewCoin(icaTs.Host.Config().Denom, transferAmount)
msgs := []sdk.Msg{banktypes.NewMsgSend(fromAddress, toAddress, sdk.NewCoins(coin))}

icaTs.Msgs = msgs

err = e2e.SendICATx(ctx, icaTs)
require.NoError(t, err, "failed to send ICA tx")

// Assert that the updated balance of the dst address is correct.
expectedBal := icaTs.InitBal.Add(transferAmount)
updatedBal, err := noble.BankQueryBalance(ctx, dstAddress, noble.Config().Denom)
require.NoError(t, err, "failed to query bank balance")
require.True(t, updatedBal.Equal(expectedBal), "invalid balance expected(%s), got(%s)", expectedBal, updatedBal)
},
PostUpgrade: func(t *testing.T, ctx context.Context, noble *cosmos.CosmosChain, authority ibc.Wallet, icaTs *e2e.ICATestSuite) {
msgSend, ok := icaTs.Msgs[0].(*banktypes.MsgSend)
require.True(t, ok, "expected MsgSend, got %T", icaTs.Msgs[0])

coin := msgSend.Amount[0]

// Verify that the previously created ICA no longer works.
err := e2e.SendICATx(ctx, icaTs)
require.Error(t, err, "should have failed to send ICA tx after v8.0.0 upgrade")

// Assert that the balance of the dst address has not updated.
expectedBal := icaTs.InitBal.Add(coin.Amount)
bal, err := noble.BankQueryBalance(ctx, msgSend.ToAddress, noble.Config().Denom)
require.NoError(t, err, "failed to query bank balance")
require.True(t, bal.Equal(expectedBal), "invalid balance expected(%s), got(%s)", expectedBal, bal)
},
},
{
Image: e2e.LocalImages[0],
UpgradeName: "v9.0.0-rc.1",
UpgradeName: "argentum",
PostUpgrade: func(t *testing.T, ctx context.Context, noble *cosmos.CosmosChain, authority ibc.Wallet, icaTs *e2e.ICATestSuite) {
msgSend, ok := icaTs.Msgs[0].(*banktypes.MsgSend)
require.True(t, ok, "expected MsgSend, got %T", icaTs.Msgs[0])

coin := msgSend.Amount[0]

// The ICA tx we sent in the previous PostUpgrade handler will be relayed once the chain restarts with
// the changes in v8.1 so we need to account for that when asserting the dst address bal is correct.
expectedBal := icaTs.InitBal.Add(coin.Amount).Add(coin.Amount)
bal, err := noble.BankQueryBalance(ctx, msgSend.ToAddress, noble.Config().Denom)
require.NoError(t, err, "failed to query bank balance")
require.True(t, bal.Equal(expectedBal), "invalid balance expected(%s), got(%s)", expectedBal, bal)

// Verify that the previously created ICA works again with new txs as well.
err = e2e.SendICATx(ctx, icaTs)
require.NoError(t, err, "failed to send ICA tx")

// Assert that the balance of the dst address is correct.
expectedBal = bal.Add(coin.Amount)
updatedBal, err := noble.BankQueryBalance(ctx, msgSend.ToAddress, noble.Config().Denom)
require.NoError(t, err, "failed to query bank balance")
require.True(t, updatedBal.Equal(expectedBal), "invalid balance expected(%s), got(%s)", expectedBal, updatedBal)
},
},
}

e2e.TestChainUpgrade(t, genesisVersion, upgrades, false)
e2e.TestChainUpgrade(t, genesisVersion, upgrades, true)
}
4 changes: 2 additions & 2 deletions e2e/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ func NobleSpinUp(t *testing.T, ctx context.Context, version []ibc.DockerImage, s
numFullNodes := 0

cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{
NobleChainSpec(ctx, &nw, "grand-1", version, numValidators, numFullNodes, setupAllCircleRoles),
NobleChainSpec(ctx, &nw, "noble-1", version, numValidators, numFullNodes, setupAllCircleRoles),
})

chains, err := cf.Chains(t.Name())
Expand Down Expand Up @@ -485,7 +485,7 @@ func NobleSpinUpIBC(t *testing.T, ctx context.Context, version []ibc.DockerImage
numFullNodes := 0

cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{
NobleChainSpec(ctx, &nw, "grand-1", version, numValidators, numFullNodes, setupAllCircleRoles),
NobleChainSpec(ctx, &nw, "noble-1", version, numValidators, numFullNodes, setupAllCircleRoles),
{
Name: "ibc-go-simd",
Version: "v8.5.1",
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ require (
github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2
github.com/cosmos/ibc-go/modules/capability v1.0.1
github.com/cosmos/ibc-go/v8 v8.5.2
github.com/ethereum/go-ethereum v1.14.13
github.com/golangci/golangci-lint v1.61.0
github.com/monerium/module-noble/v2 v2.0.0
github.com/noble-assets/authority v1.0.1
Expand Down Expand Up @@ -129,7 +130,6 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/ethereum/go-ethereum v1.14.13 // indirect
github.com/ettle/strcase v0.2.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
Expand Down
17 changes: 16 additions & 1 deletion upgrade/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,22 @@
package upgrade

// UpgradeName is the name of this specific software upgrade used on-chain.
const UpgradeName = "v9.0.0-rc.1"
const UpgradeName = "argentum"

// UpgradeASCII is the ASCII art shown to node operators upon successful upgrade.
const UpgradeASCII = `

█████╗ ██████╗ ██████╗ ███████╗███╗ ██╗████████╗██╗ ██╗███╗ ███╗
██╔══██╗██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██║ ██║████╗ ████║
███████║██████╔╝██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██║ ██║██╔████╔██║
██╔══██║██╔══██╗██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║ ██║██║╚██╔╝██║
██║ ██║██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ╚██████╔╝██║ ╚═╝ ██║
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝

`

// TestnetChainID is the Chain ID of the Noble testnet.
const TestnetChainID = "grand-1"

// MainnetChainID is the Chain ID of the Noble mainnet.
const MainnetChainID = "noble-1"
13 changes: 12 additions & 1 deletion upgrade/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@ import (
storetypes "cosmossdk.io/store/types"
upgradetypes "cosmossdk.io/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/baseapp"

dollartypes "dollar.noble.xyz/types"
wormholetypes "github.com/noble-assets/wormhole/types"
swaptypes "swap.noble.xyz/types"
)

func CreateStoreLoader(upgradeHeight int64) baseapp.StoreLoader {
storeUpgrades := storetypes.StoreUpgrades{}
storeUpgrades := storetypes.StoreUpgrades{
Added: []string{
// Noble Modules
dollartypes.ModuleName,
swaptypes.ModuleName,
wormholetypes.ModuleName,
},
}

return upgradetypes.UpgradeStoreLoader(upgradeHeight, &storeUpgrades)
}
130 changes: 126 additions & 4 deletions upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,143 @@ import (
"context"
"fmt"

"cosmossdk.io/errors"
"cosmossdk.io/log"
upgradetypes "cosmossdk.io/x/upgrade/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/ethereum/go-ethereum/common"

capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper"
capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types"
icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"
icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"

wormholekeeper "github.com/noble-assets/wormhole/keeper"
wormholetypes "github.com/noble-assets/wormhole/types"

dollarkeeper "dollar.noble.xyz/keeper"
portaltypes "dollar.noble.xyz/types/portal"
)

func CreateUpgradeHandler(
mm *module.Manager,
cfg module.Configurator,
logger log.Logger,
capabilityKeeper *capabilitykeeper.Keeper,
dollarKeeper *dollarkeeper.Keeper,
wormholeKeeper *wormholekeeper.Keeper,
) upgradetypes.UpgradeHandler {
return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
chainID := sdk.UnwrapSDKContext(ctx).ChainID()
if chainID != TestnetChainID {
return vm, fmt.Errorf("%s upgrade not allowed to execute on %s chain", UpgradeName, chainID)
vm, err := mm.RunMigrations(ctx, cfg, vm)
if err != nil {
return vm, err
}

sdkCtx := sdk.UnwrapSDKContext(ctx)

FixICS27ChannelCapabilities(sdkCtx, capabilityKeeper)

if err := ConfigureWormholeModule(sdkCtx, wormholeKeeper); err != nil {
return vm, err
}

if err := ConfigureDollarModule(sdkCtx, dollarKeeper); err != nil {
return vm, err
}

logger.Info("Welcome to a new generation of Noble!" + UpgradeASCII)

return vm, nil
}
}

// FixICS27ChannelCapabilities finds all capabilities wrongfully owned by the
// ICA Controller module and replaces them with the ICA Host module. This was
// introduced in the v8 Helium upgrade after we executed the recommended ICS27
// migration logic for chains that utilize the ICA Controller module.
func FixICS27ChannelCapabilities(ctx sdk.Context, capabilityKeeper *capabilitykeeper.Keeper) {
index := capabilityKeeper.GetLatestIndex(ctx)

for i := uint64(1); i < index; i++ {
wrapper, ok := capabilityKeeper.GetOwners(ctx, i)
if !ok {
continue
}

for _, owner := range wrapper.GetOwners() {
if owner.Module == icacontrollertypes.SubModuleName {
wrapper.Remove(owner)
wrapper.Set(capabilitytypes.Owner{
Module: icahosttypes.SubModuleName,
Name: owner.Name,
})
}
}

capabilityKeeper.SetOwners(ctx, i, wrapper)
}

capabilityKeeper.InitMemStore(ctx)
}

// ConfigureWormholeModule sets both the Wormhole module configuration and an initial guardian set.
func ConfigureWormholeModule(ctx sdk.Context, wormholeKeeper *wormholekeeper.Keeper) (err error) {
switch ctx.ChainID() {
case TestnetChainID:
err = wormholeKeeper.Config.Set(ctx, wormholetypes.Config{
ChainId: 4009,
GuardianSetIndex: 0,
GuardianSetExpiry: 0,
GovChain: 1,
GovAddress: common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000004"),
})
if err != nil {
return errors.Wrap(err, "unable to set wormhole config in state")
}

err = wormholeKeeper.GuardianSets.Set(ctx, 0, wormholetypes.GuardianSet{
// https://github.com/wormhole-foundation/wormhole/blob/3797ed082150e6d66c0dce3fea7f2848364af7d5/ethereum/env/.env.sepolia.testnet#L7
Addresses: [][]byte{common.FromHex("0x13947Bd48b18E53fdAeEe77F3473391aC727C638")},
ExpirationTime: 0,
})
if err != nil {
return errors.Wrap(err, "unable to set wormhole guardian set in state")
}

return nil
case MainnetChainID:
// TODO: Add the necessary configurations for mainnet here!
return nil
default:
return fmt.Errorf("cannot configure the wormhole module on %s chain", ctx.ChainID())
}
}

// ConfigureDollarModule sets both the Dollar Portal submodule owner and an initial peer.
func ConfigureDollarModule(ctx sdk.Context, dollarKeeper *dollarkeeper.Keeper) (err error) {
switch ctx.ChainID() {
case TestnetChainID:
err = dollarKeeper.Owner.Set(ctx, "noble1mx48c5tv6ss9k7793n3a7sv48nfjllhxkd6tq3")
if err != nil {
return errors.Wrap(err, "unable to set dollar portal owner in state")
}

err = dollarKeeper.Peers.Set(ctx, 10002, portaltypes.Peer{
// https://sepolia.etherscan.io/address/0x29CbF1e07166D31446307aE07999fa6d16223990
Transceiver: common.FromHex("0x00000000000000000000000029cbf1e07166d31446307ae07999fa6d16223990"),
// https://sepolia.etherscan.io/address/0x1B7aE194B20C555B9d999c835F74cDCE36A67a74
Manager: common.FromHex("0x0000000000000000000000001b7ae194b20c555b9d999c835f74cdce36a67a74"),
})
if err != nil {
return errors.Wrap(err, "unable to set dollar portal peer in state")
}

return mm.RunMigrations(ctx, cfg, vm)
return nil
case MainnetChainID:
// TODO: Add the necessary configurations for mainnet here!
return nil
default:
return fmt.Errorf("cannot configure the dollar module on %s chain", ctx.ChainID())
}
}