-
Notifications
You must be signed in to change notification settings - Fork 585
/
store.go
180 lines (147 loc) · 6.07 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package v100
import (
"fmt"
"strings"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/ibc-go/v2/modules/core/02-client/types"
clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types"
host "github.com/cosmos/ibc-go/v2/modules/core/24-host"
"github.com/cosmos/ibc-go/v2/modules/core/exported"
smtypes "github.com/cosmos/ibc-go/v2/modules/light-clients/06-solomachine/types"
ibctmtypes "github.com/cosmos/ibc-go/v2/modules/light-clients/07-tendermint/types"
)
// MigrateStore performs in-place store migrations from SDK v0.40 of the IBC module to v1.0.0 of ibc-go.
// The migration includes:
//
// - Migrating solo machine client states from v1 to v2 protobuf definition
// - Pruning all solo machine consensus states
// - Pruning expired tendermint consensus states
// - Adds ProcessedHeight and Iteration keys for unexpired tendermint consensus states
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) (err error) {
store := ctx.KVStore(storeKey)
iterator := sdk.KVStorePrefixIterator(store, host.KeyClientStorePrefix)
var clients []string
// collect all clients
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")
if keySplit[len(keySplit)-1] != host.KeyClientState {
continue
}
// key is clients/{clientid}/clientState
// Thus, keySplit[1] is clientID
clients = append(clients, keySplit[1])
}
for _, clientID := range clients {
clientType, _, err := types.ParseClientIdentifier(clientID)
if err != nil {
return err
}
clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID))
clientStore := prefix.NewStore(ctx.KVStore(storeKey), clientPrefix)
bz := clientStore.Get(host.ClientStateKey())
if bz == nil {
return clienttypes.ErrClientNotFound
}
switch clientType {
case exported.Solomachine:
any := &codectypes.Any{}
if err := cdc.Unmarshal(bz, any); err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal client state bytes into solo machine client state")
}
clientState := &ClientState{}
if err := cdc.Unmarshal(any.Value, clientState); err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal client state bytes into solo machine client state")
}
updatedClientState := migrateSolomachine(clientState)
bz, err := clienttypes.MarshalClientState(cdc, updatedClientState)
if err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal client state bytes into solo machine client state")
}
// update solomachine in store
clientStore.Set(host.ClientStateKey(), bz)
pruneSolomachineConsensusStates(clientStore)
case exported.Tendermint:
var clientState exported.ClientState
if err := cdc.UnmarshalInterface(bz, &clientState); err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal client state bytes into tendermint client state")
}
tmClientState, ok := clientState.(*ibctmtypes.ClientState)
if !ok {
return sdkerrors.Wrap(types.ErrInvalidClient, "client state is not tendermint even though client id contains 07-tendermint")
}
// add iteration keys so pruning will be successful
if err = addConsensusMetadata(ctx, clientStore, cdc, tmClientState); err != nil {
return err
}
if err = ibctmtypes.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, tmClientState); err != nil {
return err
}
default:
continue
}
}
return nil
}
// migrateSolomachine migrates the solomachine from v1 to v2 solo machine protobuf defintion.
func migrateSolomachine(clientState *ClientState) *smtypes.ClientState {
isFrozen := clientState.FrozenSequence != 0
consensusState := &smtypes.ConsensusState{
PublicKey: clientState.ConsensusState.PublicKey,
Diversifier: clientState.ConsensusState.Diversifier,
Timestamp: clientState.ConsensusState.Timestamp,
}
return &smtypes.ClientState{
Sequence: clientState.Sequence,
IsFrozen: isFrozen,
ConsensusState: consensusState,
AllowUpdateAfterProposal: clientState.AllowUpdateAfterProposal,
}
}
// pruneSolomachineConsensusStates removes all solomachine consensus states from the
// client store.
func pruneSolomachineConsensusStates(clientStore sdk.KVStore) {
iterator := sdk.KVStorePrefixIterator(clientStore, []byte(host.KeyConsensusStatePrefix))
var heights []exported.Height
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")
// key is in the format "consensusStates/<height>"
if len(keySplit) != 2 || keySplit[0] != string(host.KeyConsensusStatePrefix) {
continue
}
// collect consensus states to be pruned
heights = append(heights, types.MustParseHeight(keySplit[1]))
}
// delete all consensus states
for _, height := range heights {
clientStore.Delete(host.ConsensusStateKey(height))
}
}
// addConsensusMetadata adds the iteration key and processed height for all tendermint consensus states
// These keys were not included in the previous release of the IBC module. Adding the iteration keys allows
// for pruning iteration.
func addConsensusMetadata(ctx sdk.Context, clientStore sdk.KVStore, cdc codec.BinaryCodec, clientState *ibctmtypes.ClientState) error {
var heights []exported.Height
iterator := sdk.KVStorePrefixIterator(clientStore, []byte(host.KeyConsensusStatePrefix))
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")
// consensus key is in the format "consensusStates/<height>"
if len(keySplit) != 2 {
continue
}
heights = append(heights, types.MustParseHeight(keySplit[1]))
}
for _, height := range heights {
// set the iteration key and processed height
// these keys were not included in the SDK v0.42.0 release
ibctmtypes.SetProcessedHeight(clientStore, height, clienttypes.GetSelfHeight(ctx))
ibctmtypes.SetIterationKey(clientStore, height)
}
return nil
}