forked from cosmos/ibc-go
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: denom traces migration handler (cosmos#1680)
* update code & test * register migrator service
- Loading branch information
1 parent
5f5a287
commit be5ccf3
Showing
8 changed files
with
265 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package keeper | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
"github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" | ||
) | ||
|
||
// Migrator is a struct for handling in-place store migrations. | ||
type Migrator struct { | ||
keeper Keeper | ||
} | ||
|
||
// NewMigrator returns a new Migrator. | ||
func NewMigrator(keeper Keeper) Migrator { | ||
return Migrator{keeper: keeper} | ||
} | ||
|
||
// MigrateTraces migrates the DenomTraces to the correct format, accounting for slashes in the BaseDenom. | ||
func (m Migrator) MigrateTraces(ctx sdk.Context) error { | ||
|
||
// list of traces that must replace the old traces in store | ||
var newTraces []types.DenomTrace | ||
m.keeper.IterateDenomTraces(ctx, | ||
func(dt types.DenomTrace) (stop bool) { | ||
// check if the new way of splitting FullDenom | ||
// is the same as the current DenomTrace. | ||
// If it isn't then store the new DenomTrace in the list of new traces. | ||
newTrace := types.ParseDenomTrace(dt.GetFullDenomPath()) | ||
err := newTrace.Validate() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
if dt.IBCDenom() != newTrace.IBCDenom() { | ||
// The new form of parsing will result in a token denomination change. | ||
// A bank migration is required. A panic should occur to prevent the | ||
// chain from using corrupted state. | ||
panic(fmt.Sprintf("migration will result in corrupted state. Previous IBC token (%s) requires a bank migration. Expected denom trace (%s)", dt, newTrace)) | ||
} | ||
|
||
if !equalTraces(newTrace, dt) { | ||
newTraces = append(newTraces, newTrace) | ||
} | ||
return false | ||
}) | ||
|
||
// replace the outdated traces with the new trace information | ||
for _, nt := range newTraces { | ||
m.keeper.SetDenomTrace(ctx, nt) | ||
} | ||
return nil | ||
} | ||
|
||
func equalTraces(dtA, dtB types.DenomTrace) bool { | ||
return dtA.BaseDenom == dtB.BaseDenom && dtA.Path == dtB.Path | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package keeper_test | ||
|
||
import ( | ||
"fmt" | ||
|
||
transferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" | ||
transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" | ||
) | ||
|
||
func (suite *KeeperTestSuite) TestMigratorMigrateTraces() { | ||
|
||
testCases := []struct { | ||
msg string | ||
malleate func() | ||
expectedTraces transfertypes.Traces | ||
}{ | ||
|
||
{ | ||
"success: two slashes in base denom", | ||
func() { | ||
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( | ||
suite.chainA.GetContext(), | ||
transfertypes.DenomTrace{ | ||
BaseDenom: "pool/1", Path: "transfer/channel-0/gamm", | ||
}) | ||
}, | ||
transfertypes.Traces{ | ||
{ | ||
BaseDenom: "gamm/pool/1", Path: "transfer/channel-0", | ||
}, | ||
}, | ||
}, | ||
{ | ||
"success: one slash in base denom", | ||
func() { | ||
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( | ||
suite.chainA.GetContext(), | ||
transfertypes.DenomTrace{ | ||
BaseDenom: "0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", Path: "transfer/channel-149/erc", | ||
}) | ||
}, | ||
transfertypes.Traces{ | ||
{ | ||
BaseDenom: "erc/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", Path: "transfer/channel-149", | ||
}, | ||
}, | ||
}, | ||
{ | ||
"success: multiple slashes in a row in base denom", | ||
func() { | ||
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( | ||
suite.chainA.GetContext(), | ||
transfertypes.DenomTrace{ | ||
BaseDenom: "1", Path: "transfer/channel-5/gamm//pool", | ||
}) | ||
}, | ||
transfertypes.Traces{ | ||
{ | ||
BaseDenom: "gamm//pool/1", Path: "transfer/channel-5", | ||
}, | ||
}, | ||
}, | ||
{ | ||
"success: multihop base denom", | ||
func() { | ||
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( | ||
suite.chainA.GetContext(), | ||
transfertypes.DenomTrace{ | ||
BaseDenom: "transfer/channel-1/uatom", Path: "transfer/channel-0", | ||
}) | ||
}, | ||
transfertypes.Traces{ | ||
{ | ||
BaseDenom: "uatom", Path: "transfer/channel-0/transfer/channel-1", | ||
}, | ||
}, | ||
}, | ||
{ | ||
"success: non-standard port", | ||
func() { | ||
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( | ||
suite.chainA.GetContext(), | ||
transfertypes.DenomTrace{ | ||
BaseDenom: "customport/channel-7/uatom", Path: "transfer/channel-0/transfer/channel-1", | ||
}) | ||
}, | ||
transfertypes.Traces{ | ||
{ | ||
BaseDenom: "uatom", Path: "transfer/channel-0/transfer/channel-1/customport/channel-7", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
suite.Run(fmt.Sprintf("case %s", tc.msg), func() { | ||
suite.SetupTest() // reset | ||
|
||
tc.malleate() // explicitly set up denom traces | ||
|
||
migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper) | ||
err := migrator.MigrateTraces(suite.chainA.GetContext()) | ||
suite.Require().NoError(err) | ||
|
||
traces := suite.chainA.GetSimApp().TransferKeeper.GetAllDenomTraces(suite.chainA.GetContext()) | ||
suite.Require().Equal(tc.expectedTraces, traces) | ||
}) | ||
} | ||
} | ||
|
||
func (suite *KeeperTestSuite) TestMigratorMigrateTracesCorruptionDetection() { | ||
// IBCDenom() previously would return "customport/channel-0/uatom", but now should return ibc/{hash} | ||
corruptedDenomTrace := transfertypes.DenomTrace{ | ||
BaseDenom: "customport/channel-0/uatom", | ||
Path: "", | ||
} | ||
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), corruptedDenomTrace) | ||
|
||
migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper) | ||
suite.Panics(func() { | ||
migrator.MigrateTraces(suite.chainA.GetContext()) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.