-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: x/bank/044 migrateDenomMetadata (#10239)
* fix: x/bank/044 migrateDenomMetadata * adding changelog entry * comment update * fix tests (cherry picked from commit 16a953c) # Conflicts: # CHANGELOG.md # x/bank/migrations/v044/keys.go # x/bank/migrations/v044/store.go # x/bank/migrations/v044/store_test.go # x/bank/types/key.go
- Loading branch information
1 parent
37f5069
commit 299ab46
Showing
6 changed files
with
336 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package v044 | ||
|
||
var ( | ||
DenomAddressPrefix = []byte{0x03} | ||
) | ||
|
||
// CreateDenomAddressPrefix creates a prefix for a reverse index of denomination | ||
// to account balance for that denomination. | ||
func CreateDenomAddressPrefix(denom string) []byte { | ||
// we add a "zero" byte at the end - null byte terminator, to allow prefix denom prefix | ||
// scan. Setting it is not needed (key[last] = 0) - because this is the default. | ||
key := make([]byte, len(DenomAddressPrefix)+len(denom)+1) | ||
copy(key, DenomAddressPrefix) | ||
copy(key[len(DenomAddressPrefix):], denom) | ||
return key | ||
} |
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,93 @@ | ||
package v044 | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
"github.com/cosmos/cosmos-sdk/store/prefix" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/types/address" | ||
v043 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v043" | ||
"github.com/cosmos/cosmos-sdk/x/bank/types" | ||
) | ||
|
||
// MigrateStore performs in-place store migrations from v0.43 to v0.44. The | ||
// migration includes: | ||
// | ||
// - Migrate coin storage to save only amount. | ||
// - Add an additional reverse index from denomination to address. | ||
// - Remove duplicate denom from denom metadata store key. | ||
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) error { | ||
store := ctx.KVStore(storeKey) | ||
err := addDenomReverseIndex(store, cdc) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return migrateDenomMetadata(store) | ||
} | ||
|
||
func addDenomReverseIndex(store sdk.KVStore, cdc codec.BinaryCodec) error { | ||
oldBalancesStore := prefix.NewStore(store, v043.BalancesPrefix) | ||
|
||
oldBalancesIter := oldBalancesStore.Iterator(nil, nil) | ||
defer oldBalancesIter.Close() | ||
|
||
denomPrefixStores := make(map[string]prefix.Store) // memoize prefix stores | ||
|
||
for ; oldBalancesIter.Valid(); oldBalancesIter.Next() { | ||
var balance sdk.Coin | ||
if err := cdc.Unmarshal(oldBalancesIter.Value(), &balance); err != nil { | ||
return err | ||
} | ||
|
||
addr, err := v043.AddressFromBalancesStore(oldBalancesIter.Key()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var coin sdk.DecCoin | ||
if err := cdc.Unmarshal(oldBalancesIter.Value(), &coin); err != nil { | ||
return err | ||
} | ||
|
||
bz, err := coin.Amount.Marshal() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
newStore := prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) | ||
newStore.Set([]byte(coin.Denom), bz) | ||
|
||
denomPrefixStore, ok := denomPrefixStores[balance.Denom] | ||
if !ok { | ||
denomPrefixStore = prefix.NewStore(store, CreateDenomAddressPrefix(balance.Denom)) | ||
denomPrefixStores[balance.Denom] = denomPrefixStore | ||
} | ||
|
||
// Store a reverse index from denomination to account address with a | ||
// sentinel value. | ||
denomPrefixStore.Set(address.MustLengthPrefix(addr), []byte{0}) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func migrateDenomMetadata(store sdk.KVStore) error { | ||
oldDenomMetaDataStore := prefix.NewStore(store, v043.DenomMetadataPrefix) | ||
|
||
oldDenomMetaDataIter := oldDenomMetaDataStore.Iterator(nil, nil) | ||
defer oldDenomMetaDataIter.Close() | ||
|
||
for ; oldDenomMetaDataIter.Valid(); oldDenomMetaDataIter.Next() { | ||
oldKey := oldDenomMetaDataIter.Key() | ||
l := len(oldKey)/2 + 1 | ||
|
||
var newKey = make([]byte, len(types.DenomMetadataPrefix)+l) | ||
// old key: prefix_bytes | denom_bytes | denom_bytes | ||
copy(newKey, types.DenomMetadataPrefix) | ||
copy(newKey[len(types.DenomMetadataPrefix):], oldKey[:l]) | ||
store.Set(newKey, oldDenomMetaDataIter.Value()) | ||
oldDenomMetaDataStore.Delete(oldKey) | ||
} | ||
|
||
return nil | ||
} |
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,129 @@ | ||
package v044_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/cosmos/cosmos-sdk/simapp" | ||
"github.com/cosmos/cosmos-sdk/store/prefix" | ||
"github.com/cosmos/cosmos-sdk/testutil" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/types/address" | ||
v043 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v043" | ||
v044 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v044" | ||
"github.com/cosmos/cosmos-sdk/x/bank/types" | ||
) | ||
|
||
func TestMigrateStore(t *testing.T) { | ||
encCfg := simapp.MakeTestEncodingConfig() | ||
bankKey := sdk.NewKVStoreKey("bank") | ||
ctx := testutil.DefaultContext(bankKey, sdk.NewTransientStoreKey("transient_test")) | ||
store := ctx.KVStore(bankKey) | ||
|
||
addr := sdk.AccAddress([]byte("addr________________")) | ||
prefixAccStore := prefix.NewStore(store, v043.CreateAccountBalancesPrefix(addr)) | ||
|
||
balances := sdk.NewCoins( | ||
sdk.NewCoin("foo", sdk.NewInt(10000)), | ||
sdk.NewCoin("bar", sdk.NewInt(20000)), | ||
) | ||
|
||
for _, b := range balances { | ||
bz, err := encCfg.Codec.Marshal(&b) | ||
require.NoError(t, err) | ||
|
||
prefixAccStore.Set([]byte(b.Denom), bz) | ||
} | ||
|
||
require.NoError(t, v044.MigrateStore(ctx, bankKey, encCfg.Codec)) | ||
|
||
for _, b := range balances { | ||
addrPrefixStore := prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) | ||
bz := addrPrefixStore.Get([]byte(b.Denom)) | ||
var expected sdk.Int | ||
require.NoError(t, expected.Unmarshal(bz)) | ||
require.Equal(t, expected, b.Amount) | ||
} | ||
|
||
for _, b := range balances { | ||
denomPrefixStore := prefix.NewStore(store, v044.CreateDenomAddressPrefix(b.Denom)) | ||
bz := denomPrefixStore.Get(address.MustLengthPrefix(addr)) | ||
require.NotNil(t, bz) | ||
} | ||
} | ||
|
||
func TestMigrateDenomMetaData(t *testing.T) { | ||
encCfg := simapp.MakeTestEncodingConfig() | ||
bankKey := sdk.NewKVStoreKey("bank") | ||
ctx := testutil.DefaultContext(bankKey, sdk.NewTransientStoreKey("transient_test")) | ||
store := ctx.KVStore(bankKey) | ||
metaData := []types.Metadata{ | ||
{ | ||
Name: "Cosmos Hub Atom", | ||
Symbol: "ATOM", | ||
Description: "The native staking token of the Cosmos Hub.", | ||
DenomUnits: []*types.DenomUnit{ | ||
{"uatom", uint32(0), []string{"microatom"}}, | ||
{"matom", uint32(3), []string{"milliatom"}}, | ||
{"atom", uint32(6), nil}, | ||
}, | ||
Base: "uatom", | ||
Display: "atom", | ||
}, | ||
{ | ||
Name: "Token", | ||
Symbol: "TOKEN", | ||
Description: "The native staking token of the Token Hub.", | ||
DenomUnits: []*types.DenomUnit{ | ||
{"1token", uint32(5), []string{"decitoken"}}, | ||
{"2token", uint32(4), []string{"centitoken"}}, | ||
{"3token", uint32(7), []string{"dekatoken"}}, | ||
}, | ||
Base: "utoken", | ||
Display: "token", | ||
}, | ||
} | ||
denomMetadataStore := prefix.NewStore(store, v043.DenomMetadataPrefix) | ||
|
||
for i := range []int{0, 1} { | ||
key := append(v043.DenomMetadataPrefix, []byte(metaData[i].Base)...) | ||
// keys before 0.44 had denom two times in the key | ||
key = append(key, []byte(metaData[i].Base)...) | ||
bz, err := encCfg.Codec.Marshal(&metaData[i]) | ||
require.NoError(t, err) | ||
denomMetadataStore.Set(key, bz) | ||
} | ||
|
||
require.NoError(t, v044.MigrateStore(ctx, bankKey, encCfg.Codec)) | ||
|
||
denomMetadataStore = prefix.NewStore(store, v043.DenomMetadataPrefix) | ||
denomMetadataIter := denomMetadataStore.Iterator(nil, nil) | ||
defer denomMetadataIter.Close() | ||
for i := 0; denomMetadataIter.Valid(); denomMetadataIter.Next() { | ||
var result types.Metadata | ||
newKey := denomMetadataIter.Key() | ||
|
||
// make sure old entry is deleted | ||
oldKey := append(newKey, newKey[1:]...) | ||
bz := denomMetadataStore.Get(oldKey) | ||
require.Nil(t, bz) | ||
|
||
require.Equal(t, string(newKey)[1:], metaData[i].Base, "idx: %d", i) | ||
bz = denomMetadataStore.Get(denomMetadataIter.Key()) | ||
require.NotNil(t, bz) | ||
err := encCfg.Codec.Unmarshal(bz, &result) | ||
require.NoError(t, err) | ||
assertMetaDataEqual(t, metaData[i], result) | ||
i++ | ||
} | ||
} | ||
|
||
func assertMetaDataEqual(t *testing.T, expected, actual types.Metadata) { | ||
require.Equal(t, expected.GetBase(), actual.GetBase()) | ||
require.Equal(t, expected.GetDisplay(), actual.GetDisplay()) | ||
require.Equal(t, expected.GetDescription(), actual.GetDescription()) | ||
require.Equal(t, expected.GetDenomUnits()[1].GetDenom(), actual.GetDenomUnits()[1].GetDenom()) | ||
require.Equal(t, expected.GetDenomUnits()[1].GetExponent(), actual.GetDenomUnits()[1].GetExponent()) | ||
require.Equal(t, expected.GetDenomUnits()[1].GetAliases(), actual.GetDenomUnits()[1].GetAliases()) | ||
} |
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