-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
feat: state migration from IAVL to SMT (ADR-040) #10962
Changes from 35 commits
4cc992f
df0dc4f
fca170d
79583ec
bcfeff1
d511fa3
00b99a7
0eaec31
9f496e9
39b303b
8b16dad
b305280
ebc1d3b
64e1cb4
39d51cf
242939e
a9fa647
ada2859
38527f7
1e884cf
1b79269
00b6360
dc57212
4695365
3a5bdf0
c103f16
4a9feb5
677639e
074da95
a05f72e
6eb51d1
c16dc89
119b77a
a97ed5a
179743c
bb61b5d
f381e09
7eec931
1af9b3b
ec331a0
e21a6f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package multi | ||
|
||
import ( | ||
dbm "github.com/cosmos/cosmos-sdk/db" | ||
"github.com/cosmos/cosmos-sdk/store/iavl" | ||
"github.com/cosmos/cosmos-sdk/store/mem" | ||
v1Store "github.com/cosmos/cosmos-sdk/store/rootmulti" | ||
"github.com/cosmos/cosmos-sdk/store/transient" | ||
"github.com/cosmos/cosmos-sdk/store/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
// MigrateFromV1 will migrate the state from iavl to smt | ||
func MigrateFromV1(rootMultiStore *v1Store.Store, store2db dbm.DBConnection, storeConfig StoreConfig) (*Store, error) { | ||
type namedStore struct { | ||
*iavl.Store | ||
name string | ||
} | ||
var stores []namedStore | ||
for _, storeKey := range rootMultiStore.StoreKeysByName() { | ||
keyName := storeKey.Name() | ||
switch store := rootMultiStore.GetStoreByName(keyName).(type) { | ||
case *iavl.Store: | ||
err := storeConfig.RegisterSubstore(keyName, types.StoreTypePersistent) | ||
if err != nil { | ||
return nil, err | ||
} | ||
stores = append(stores, namedStore{name: keyName, Store: store}) | ||
case *transient.Store, *mem.Store: | ||
continue | ||
default: | ||
return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "don't know how to migrate store %q of type %T", keyName, store) | ||
} | ||
} | ||
|
||
// creating the new store of smt tree | ||
rootStore, err := NewStore(store2db, storeConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// if version is 0 there is no state data to commit | ||
if rootMultiStore.LastCommitID().Version == 0 { | ||
return rootStore, nil | ||
} | ||
|
||
// iterate through the rootmulti stores and save the key/values into smt tree | ||
for _, store := range stores { | ||
subStore, err := rootStore.getSubstore(store.name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we make sure that we use the same store key when doing migration? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we are registering the |
||
if err != nil { | ||
return nil, err | ||
} | ||
// iterate all iavl tree node key/values | ||
iterator := store.Iterator(nil, nil) | ||
for ; iterator.Valid(); iterator.Next() { | ||
// set the iavl key,values into smt node | ||
subStore.Set(iterator.Key(), iterator.Value()) | ||
} | ||
} | ||
|
||
// commit the all key/values from iavl to smt tree (SMT Store) | ||
_, err = rootStore.commit(uint64(rootMultiStore.LastCommitID().Version)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return rootStore, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package multi | ||
|
||
import ( | ||
"encoding/binary" | ||
"fmt" | ||
"math/rand" | ||
"testing" | ||
|
||
"github.com/cosmos/cosmos-sdk/db/memdb" | ||
"github.com/cosmos/cosmos-sdk/store/iavl" | ||
"github.com/cosmos/cosmos-sdk/store/rootmulti" | ||
"github.com/cosmos/cosmos-sdk/store/types" | ||
"github.com/stretchr/testify/require" | ||
dbm "github.com/tendermint/tm-db" | ||
) | ||
|
||
func TestMigrationV2(t *testing.T) { | ||
r := rand.New(rand.NewSource(49872768940)) | ||
|
||
// setup a rootmulti store | ||
db := dbm.NewMemDB() | ||
v1Store := rootmulti.NewStore(db) | ||
|
||
// mount the kvStores | ||
var keys []*types.KVStoreKey | ||
for i := uint8(0); i < 10; i++ { | ||
key := types.NewKVStoreKey(fmt.Sprintf("store%v", i)) | ||
v1Store.MountStoreWithDB(key, types.StoreTypeIAVL, nil) | ||
keys = append(keys, key) | ||
} | ||
|
||
err := v1Store.LoadLatestVersion() | ||
require.Nil(t, err) | ||
|
||
// setup a random test data | ||
for _, key := range keys { | ||
store := v1Store.GetStore(key).(*iavl.Store) | ||
store.Set([]byte("temp_data"), []byte("one")) | ||
|
||
for i := 0; i < len(keys); i++ { | ||
k := make([]byte, 8) | ||
v := make([]byte, 1024) | ||
binary.BigEndian.PutUint64(k, uint64(i)) | ||
_, err := r.Read(v) | ||
if err != nil { | ||
panic(err) | ||
} | ||
store.Set(k, v) | ||
} | ||
} | ||
|
||
testCases := []struct { | ||
testName string | ||
emptyStore bool | ||
}{ | ||
{ | ||
"Migration With Empty Store", | ||
true, | ||
}, | ||
{ | ||
"Migration From Root Multi Store (IAVL) to SMT ", | ||
false, | ||
}, | ||
} | ||
|
||
for _, testCase := range testCases { | ||
if !testCase.emptyStore { | ||
v1Store.Commit() | ||
} | ||
|
||
// setup a new root store of smt | ||
db2 := memdb.NewDB() | ||
storeConfig := DefaultStoreConfig() | ||
// migrating the iavl store (v1) to smt store (v2) | ||
v2Store, err := MigrateFromV1(v1Store, db2, storeConfig) | ||
require.NoError(t, err) | ||
|
||
for _, key := range keys { | ||
v2StoreKVStore := v2Store.GetKVStore(key) | ||
if testCase.emptyStore { | ||
// check the empty store | ||
require.Nil(t, v2StoreKVStore.Get([]byte("temp_data"))) | ||
} else { | ||
require.Equal(t, v2StoreKVStore.Get([]byte("temp_data")), []byte("one")) | ||
} | ||
require.Equal(t, v2Store.LastCommitID().Version, v1Store.LastCommitID().Version) | ||
} | ||
err = v2Store.Close() | ||
require.NoError(t, err) | ||
} | ||
} | ||
|
||
// TestMigrateV2ForEmptyStore checking empty store migration | ||
func TestMigrateV2ForEmptyStore(t *testing.T) { | ||
// setup a rootmulti store | ||
db := dbm.NewMemDB() | ||
v1Store := rootmulti.NewStore(db) | ||
err := v1Store.LoadLatestVersion() | ||
require.Nil(t, err) | ||
db2 := memdb.NewDB() | ||
storeConfig := DefaultStoreConfig() | ||
// migrating the iavl store (v1) to smt store (v2) | ||
v2Store, err := MigrateFromV1(v1Store, db2, storeConfig) | ||
require.NoError(t, err) | ||
require.Equal(t, v2Store.LastCommitID(), v1Store.LastCommitID()) | ||
} | ||
robert-zaremba marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to finish the renames in this file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok