Skip to content

Commit 5cc62d2

Browse files
committed
Denom traces migration
1 parent c40ddd9 commit 5cc62d2

File tree

4 files changed

+994
-14
lines changed

4 files changed

+994
-14
lines changed

app/traces/traces.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package traces
2+
3+
import (
4+
"fmt"
5+
6+
storetypes "cosmossdk.io/store/types"
7+
"github.com/cosmos/cosmos-sdk/codec"
8+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
9+
sdk "github.com/cosmos/cosmos-sdk/types"
10+
ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types"
11+
)
12+
13+
func NewDenomTracesMigrator(ibcStore storetypes.KVStore) DenomTracesMigrator {
14+
return DenomTracesMigrator{ibcStore: ibcStore}
15+
}
16+
17+
// DenomTraces is a struct for handling in-place store migrations.
18+
type DenomTracesMigrator struct {
19+
ibcStore storetypes.KVStore
20+
}
21+
22+
func equalTraces(dtA, dtB DenomTrace) bool {
23+
return dtA.BaseDenom == dtB.BaseDenom && dtA.Path == dtB.Path
24+
}
25+
26+
// IterateDenomTraces iterates over the denomination traces in the store
27+
// and performs a callback function.
28+
func (m DenomTracesMigrator) IterateDenomTraces(ctx sdk.Context, cdc codec.Codec, cb func(denomTrace DenomTrace) bool) {
29+
30+
iterator := storetypes.KVStorePrefixIterator(m.ibcStore, ibctransfertypes.DenomTraceKey)
31+
32+
defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() })
33+
for ; iterator.Valid(); iterator.Next() {
34+
denomTrace := MustUnmarshalDenomTrace(iterator.Value(), cdc)
35+
if cb(denomTrace) {
36+
break
37+
}
38+
}
39+
}
40+
41+
// MustUnmarshalDenomTrace attempts to decode and return an DenomTrace object from
42+
// raw encoded bytes. It panics on error.
43+
func MustUnmarshalDenomTrace(bz []byte, cdc codec.Codec) DenomTrace {
44+
var denomTrace DenomTrace
45+
46+
cdc.MustUnmarshal(bz, &denomTrace)
47+
return denomTrace
48+
}
49+
50+
// MustMarshalDenomTrace attempts to encode an DenomTrace object and returns the
51+
// raw encoded bytes. It panics on error.
52+
func MustMarshalDenomTrace(denomTrace DenomTrace, cdc codec.Codec) []byte {
53+
return cdc.MustMarshal(&denomTrace)
54+
}
55+
56+
// SetDenomTrace sets a new {trace hash -> denom trace} pair to the store.
57+
func (m DenomTracesMigrator) SetDenomTrace(ctx sdk.Context, cdc codec.Codec, denomTrace DenomTrace) {
58+
bz := MustMarshalDenomTrace(denomTrace, cdc)
59+
m.ibcStore.Set(denomTrace.Hash(), bz)
60+
}
61+
62+
// MigrateTraces migrates the DenomTraces to the correct format, accounting for slashes in the BaseDenom.
63+
func (m DenomTracesMigrator) MigrateTraces(ctx sdk.Context) error {
64+
ir := codectypes.NewInterfaceRegistry()
65+
cdc := codec.NewProtoCodec(ir)
66+
67+
// list of traces that must replace the old traces in store
68+
var newTraces []DenomTrace
69+
m.IterateDenomTraces(ctx, cdc,
70+
func(dt DenomTrace) (stop bool) {
71+
// check if the new way of splitting FullDenom
72+
// is the same as the current DenomTrace.
73+
// If it isn't then store the new DenomTrace in the list of new traces.
74+
newTrace := ParseDenomTrace(dt.GetFullDenomPath())
75+
err := newTrace.Validate()
76+
if err != nil {
77+
panic(err)
78+
}
79+
80+
if dt.IBCDenom() != newTrace.IBCDenom() {
81+
// The new form of parsing will result in a token denomination change.
82+
// A bank migration is required. A panic should occur to prevent the
83+
// chain from using corrupted state.
84+
panic(fmt.Errorf("migration will result in corrupted state. Previous IBC token (%s) requires a bank migration. Expected denom trace (%s)", dt, newTrace))
85+
}
86+
87+
if !equalTraces(newTrace, dt) {
88+
newTraces = append(newTraces, newTrace)
89+
}
90+
91+
return false
92+
})
93+
94+
// replace the outdated traces with the new trace information
95+
for _, nt := range newTraces {
96+
m.SetDenomTrace(ctx, cdc, nt)
97+
}
98+
return nil
99+
}

0 commit comments

Comments
 (0)