From 085ab67ad739e696aef50445e05af9fca7949c26 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Wed, 27 May 2020 10:47:33 +0200 Subject: [PATCH 01/19] Registered upgrade module tx commands --- x/upgrade/module.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x/upgrade/module.go b/x/upgrade/module.go index d0a8ee51975c..7edb4a610db2 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -65,12 +65,15 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { } // GetTxCmd returns the transaction commands for this module -func (AppModuleBasic) GetTxCmd(_ context.CLIContext) *cobra.Command { +func (AppModuleBasic) GetTxCmd(ctx context.CLIContext) *cobra.Command { txCmd := &cobra.Command{ Use: "upgrade", Short: "Upgrade transaction subcommands", } - txCmd.AddCommand(flags.PostCommands()...) + txCmd.AddCommand(flags.PostCommands( + cli.NewCmdSubmitUpgradeProposal(ctx), + cli.NewCmdSubmitCancelUpgradeProposal(ctx), + )...) return txCmd } From 30193c80b9ffe195b5406890c1e97e3fd0d912ae Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Wed, 30 Sep 2020 09:35:53 +0200 Subject: [PATCH 02/19] Return empty store tree on non-existing version --- store/iavl/store.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 3d6bedabdbbb..51378096b7d7 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -80,9 +80,10 @@ func UnsafeNewStore(tree *iavl.MutableTree) *Store { // be used for querying and iteration only. If the version does not exist or has // been pruned, an error will be returned. Any mutable operations executed will // result in a panic. +// TODO: CHANGE THIS DOCUMENTATION func (st *Store) GetImmutable(version int64) (*Store, error) { if !st.VersionExists(version) { - return nil, iavl.ErrVersionDoesNotExist + return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, nil } iTree, err := st.tree.GetImmutable(version) From 8d510549943029959c1c37600ac928132c7f7e4f Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Wed, 30 Sep 2020 09:35:53 +0200 Subject: [PATCH 03/19] Return empty store tree on non-existing version --- store/iavl/store.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 3d6bedabdbbb..51378096b7d7 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -80,9 +80,10 @@ func UnsafeNewStore(tree *iavl.MutableTree) *Store { // be used for querying and iteration only. If the version does not exist or has // been pruned, an error will be returned. Any mutable operations executed will // result in a panic. +// TODO: CHANGE THIS DOCUMENTATION func (st *Store) GetImmutable(version int64) (*Store, error) { if !st.VersionExists(version) { - return nil, iavl.ErrVersionDoesNotExist + return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, nil } iTree, err := st.tree.GetImmutable(version) From de349adbb2095a79aeb65fab93b618d671e4c724 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Thu, 1 Oct 2020 08:08:25 +0200 Subject: [PATCH 04/19] Improving the loading of new stores --- go.mod | 7 +++++ go.sum | 14 ++++++++++ store/iavl/store.go | 11 ++++++++ store/iavl/store_test.go | 56 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/go.mod b/go.mod index 7272880066b6..b2e8eb023402 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ module github.com/cosmos/cosmos-sdk require ( github.com/99designs/keyring v1.1.6 + github.com/DataDog/zstd v1.4.5 // indirect github.com/armon/go-metrics v0.3.4 github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.21.0-beta @@ -12,11 +13,15 @@ require ( github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/iavl v0.15.0-rc3 github.com/cosmos/ledger-cosmos-go v0.11.1 + github.com/dgraph-io/badger/v2 v2.2007.2 // indirect + github.com/dgraph-io/ristretto v0.0.3 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 github.com/gogo/gateway v1.1.0 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.2 + github.com/golang/snappy v0.0.2 // indirect github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.15.0 @@ -43,6 +48,8 @@ require ( github.com/tendermint/tendermint v0.34.0-rc4 github.com/tendermint/tm-db v0.6.2 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a + golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 google.golang.org/grpc v1.32.0 google.golang.org/protobuf v1.25.0 diff --git a/go.sum b/go.sum index fa49f96b6aba..a2f4b170da7d 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1: github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -139,13 +141,19 @@ github.com/dgraph-io/badger/v2 v2.0.3 h1:inzdf6VF/NZ+tJ8RwwYMjJMvsOALTHYdozn0qSl github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= github.com/dgraph-io/badger/v2 v2.2007.1 h1:t36VcBCpo4SsmAD5M8wVv1ieVzcALyGfaJ92z4ccULM= github.com/dgraph-io/badger/v2 v2.2007.1/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3 h1:MQLRM35Pp0yAyBYksjbj1nZI/w6eyRY/mWoM1sFf4kU= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= @@ -228,6 +236,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -681,6 +691,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 h1:YfxMZzv3PjGonQYNUaeU2+DhAdqOxerQ30JFB6WgAXo= +golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -729,6 +741,8 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/store/iavl/store.go b/store/iavl/store.go index 51378096b7d7..62ea172642a7 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -42,16 +42,27 @@ type Store struct { // LoadStore returns an IAVL Store as a CommitKVStore. Internally, it will load the // store's version (id) from the provided DB. An error is returned if the version // fails to load. +// TODO: CHANGE THIS DOCUMENTATION func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVStore, error) { tree, err := iavl.NewMutableTree(db, defaultIAVLCacheSize) if err != nil { return nil, err } + // Set initial versions for new stores + hasBeenAddedNow := false + if tree.Version() == 0 { + tree.SetInitialVersion(uint64(id.Version)) + hasBeenAddedNow = true + } + if lazyLoading { _, err = tree.LazyLoadVersion(id.Version) } else { _, err = tree.LoadVersion(id.Version) + if hasBeenAddedNow && err != nil { + err = nil + } } if err != nil { diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 052021310f99..2bf7c9398186 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -50,6 +50,62 @@ func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { return tree, types.CommitID{Version: ver, Hash: hash} } +func TestLoadStore(t *testing.T) { + db := dbm.NewMemDB() + tree, _ := newAlohaTree(t, db) + store := UnsafeNewStore(tree) + + // Create non-pruned height H + require.True(t, tree.Set([]byte("hello"), []byte("hallo"))) + hash, verH, err := tree.SaveVersion() + cIDH := types.CommitID{Version: verH, Hash: hash} + require.Nil(t, err) + + // Create pruned height Hp + require.True(t, tree.Set([]byte("hello"), []byte("hola"))) + hash, verHp, err := tree.SaveVersion() + cIDHp := types.CommitID{Version: verHp, Hash: hash} + require.Nil(t, err) + + // TODO: Prune this height + + // Create current height Hc + require.True(t, tree.Set([]byte("hello"), []byte("ciao"))) + hash, verHc, err := tree.SaveVersion() + cIDHc := types.CommitID{Version: verHc, Hash: hash} + require.Nil(t, err) + + // Querying an existing store at some previous non-pruned height H + hStore, err := store.GetImmutable(verH) + require.NoError(t, err) + require.Equal(t, hStore.Get([]byte("hello")), []byte("hallo")) + + // Querying an existing store at some previous pruned height Hp + hpStore, err := store.GetImmutable(verHp) + require.NoError(t, err) + require.Equal(t, hpStore.Get([]byte("hello")), []byte("hola")) + + // Querying an existing store at current height Hc + hcStore, err := store.GetImmutable(verHc) + require.NoError(t, err) + require.Equal(t, hcStore.Get([]byte("hello")), []byte("ciao")) + + // Querying a new store at some previous non-pruned height H + newHStore, err := LoadStore(db, cIDH, false) + require.NoError(t, err) + require.Nil(t, newHStore.Get([]byte("aloha"))) + + // Querying a new store at some previous pruned height Hp + newHpStore, err := LoadStore(db, cIDHp, false) + require.NoError(t, err) + require.Nil(t, newHpStore.Get([]byte("aloha"))) + + // Querying a new store at current height H + newHcStore, err := LoadStore(db, cIDHc, false) + require.NoError(t, err) + require.Nil(t, newHcStore.Get([]byte("aloha"))) +} + func TestGetImmutable(t *testing.T) { db := dbm.NewMemDB() tree, cID := newAlohaTree(t, db) From 8c0bc0bb3368522aa295e56d9fb0bd7ab0e7eced Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Thu, 1 Oct 2020 12:35:50 +0200 Subject: [PATCH 05/19] Moved the SetInitialVersion after the load --- store/iavl/store.go | 14 ++++---------- store/iavl/store_test.go | 12 ++++++------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 62ea172642a7..591e42c64cd8 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -49,26 +49,20 @@ func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVSt return nil, err } - // Set initial versions for new stores - hasBeenAddedNow := false - if tree.Version() == 0 { - tree.SetInitialVersion(uint64(id.Version)) - hasBeenAddedNow = true - } - if lazyLoading { _, err = tree.LazyLoadVersion(id.Version) } else { _, err = tree.LoadVersion(id.Version) - if hasBeenAddedNow && err != nil { - err = nil - } } if err != nil { return nil, err } + if tree.Version() == 0 { + tree.SetInitialVersion(uint64(id.Version)) + } + return &Store{ tree: tree, }, nil diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 2bf7c9398186..a4e7281b3514 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -78,32 +78,32 @@ func TestLoadStore(t *testing.T) { // Querying an existing store at some previous non-pruned height H hStore, err := store.GetImmutable(verH) require.NoError(t, err) - require.Equal(t, hStore.Get([]byte("hello")), []byte("hallo")) + require.Equal(t, string(hStore.Get([]byte("hello"))), "hallo") // Querying an existing store at some previous pruned height Hp hpStore, err := store.GetImmutable(verHp) require.NoError(t, err) - require.Equal(t, hpStore.Get([]byte("hello")), []byte("hola")) + require.Equal(t, string(hpStore.Get([]byte("hello"))), "hola") // Querying an existing store at current height Hc hcStore, err := store.GetImmutable(verHc) require.NoError(t, err) - require.Equal(t, hcStore.Get([]byte("hello")), []byte("ciao")) + require.Equal(t, string(hcStore.Get([]byte("hello"))), "ciao") // Querying a new store at some previous non-pruned height H newHStore, err := LoadStore(db, cIDH, false) require.NoError(t, err) - require.Nil(t, newHStore.Get([]byte("aloha"))) + require.Nil(t, string(newHStore.Get([]byte("aloha")))) // Querying a new store at some previous pruned height Hp newHpStore, err := LoadStore(db, cIDHp, false) require.NoError(t, err) - require.Nil(t, newHpStore.Get([]byte("aloha"))) + require.Nil(t, string(newHpStore.Get([]byte("aloha")))) // Querying a new store at current height H newHcStore, err := LoadStore(db, cIDHc, false) require.NoError(t, err) - require.Nil(t, newHcStore.Get([]byte("aloha"))) + require.Nil(t, string(newHcStore.Get([]byte("aloha")))) } func TestGetImmutable(t *testing.T) { From 508457f5a035399bc43814f3fa22ef05c1297b2f Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Fri, 2 Oct 2020 08:17:08 +0200 Subject: [PATCH 06/19] Improved the StoreUpgrades object adding the Added modules --- store/iavl/store.go | 14 ++++++++------ store/iavl/store_test.go | 6 +++--- store/rootmulti/store.go | 26 +++++++++++++++++++++----- store/rootmulti/store_test.go | 13 +++++++++++-- store/types/store.go | 14 ++++++++++++++ 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 591e42c64cd8..1ea86bfe7cf3 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -42,9 +42,15 @@ type Store struct { // LoadStore returns an IAVL Store as a CommitKVStore. Internally, it will load the // store's version (id) from the provided DB. An error is returned if the version // fails to load. -// TODO: CHANGE THIS DOCUMENTATION func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVStore, error) { - tree, err := iavl.NewMutableTree(db, defaultIAVLCacheSize) + return LoadStoreWithInitialVersion(db, id, lazyLoading, 0) +} + +// LoadStore returns an IAVL Store as a CommitKVStore setting its initialVersion +// to the one given. Internally, it will load the store's version (id) from the +// provided DB. An error is returned if the version fails to load. +func LoadStoreWithInitialVersion(db dbm.DB, id types.CommitID, lazyLoading bool, initialVersion int64) (types.CommitKVStore, error) { + tree, err := iavl.NewMutableTreeWithOpts(db, defaultIAVLCacheSize, &iavl.Options{InitialVersion: uint64(initialVersion)}) if err != nil { return nil, err } @@ -59,10 +65,6 @@ func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVSt return nil, err } - if tree.Version() == 0 { - tree.SetInitialVersion(uint64(id.Version)) - } - return &Store{ tree: tree, }, nil diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index a4e7281b3514..d433cfc87cd7 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -93,17 +93,17 @@ func TestLoadStore(t *testing.T) { // Querying a new store at some previous non-pruned height H newHStore, err := LoadStore(db, cIDH, false) require.NoError(t, err) - require.Nil(t, string(newHStore.Get([]byte("aloha")))) + require.Equal(t, string(newHStore.Get([]byte("hello"))), "hallo") // Querying a new store at some previous pruned height Hp newHpStore, err := LoadStore(db, cIDHp, false) require.NoError(t, err) - require.Nil(t, string(newHpStore.Get([]byte("aloha")))) + require.Equal(t, string(newHpStore.Get([]byte("hello"))), "hola") // Querying a new store at current height H newHcStore, err := LoadStore(db, cIDHc, false) require.NoError(t, err) - require.Nil(t, string(newHcStore.Get([]byte("aloha")))) + require.Equal(t, string(newHcStore.Get([]byte("hello"))), "ciao") } func TestGetImmutable(t *testing.T) { diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index bf8a473b8d0b..f34fe5972087 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -187,7 +187,14 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { var newStores = make(map[types.StoreKey]types.CommitKVStore) for key, storeParams := range rs.storesParams { - store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams) + commitID := rs.getCommitID(infos, key.Name()) + + // If it has been added, set the initial version + if upgrades.IsAdded(key.Name()) { + storeParams.initialVersion = ver + } + + store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams) if err != nil { return errors.Wrap(err, "failed to load store") } @@ -813,7 +820,15 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID panic("recursive MultiStores not yet supported") case types.StoreTypeIAVL: - store, err := iavl.LoadStore(db, id, rs.lazyLoading) + var store types.CommitKVStore + var err error + + if params.initialVersion == 0 { + store, err = iavl.LoadStore(db, id, rs.lazyLoading) + } else { + store, err = iavl.LoadStoreWithInitialVersion(db, id, rs.lazyLoading, params.initialVersion) + } + if err != nil { return nil, err } @@ -868,9 +883,10 @@ func (rs *Store) buildCommitInfo(version int64) *types.CommitInfo { } type storeParams struct { - key types.StoreKey - db dbm.DB - typ types.StoreType + key types.StoreKey + db dbm.DB + typ types.StoreType + initialVersion int64 } func getLatestVersion(db dbm.DB) int64 { diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 7341154f2edd..b185e50ee4cd 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -192,6 +192,9 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, s3) s3.Set(k3, v3) + s4, _ := store.getStoreByName("store4").(types.KVStore) + require.Nil(t, s4) + // do one commit commitID := store.Commit() expectedCommitID := getExpectedCommitID(store, 1) @@ -231,6 +234,10 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, s3) require.Nil(t, s3.Get(k3)) // data was deleted + // store4 is mounted, with empty data + s4, _ = restore.getStoreByName("store4").(types.KVStore) + require.NotNil(t, s4) + // store2 is no longer mounted st2 := restore.getStoreByName("store2") require.Nil(t, st2) @@ -262,8 +269,8 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { ci, err = getCommitInfo(db, 2) require.NoError(t, err) require.Equal(t, int64(2), ci.Version) - require.Equal(t, 3, len(ci.StoreInfos), ci.StoreInfos) - checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3"}) + require.Equal(t, 4, len(ci.StoreInfos), ci.StoreInfos) + checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3", "store4"}) } func TestParsePath(t *testing.T) { @@ -796,8 +803,10 @@ func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(types.NewKVStoreKey("store4"), types.StoreTypeIAVL, nil) upgrades := &types.StoreUpgrades{ + Added: []string{"store4"}, Renamed: []types.StoreRename{{ OldKey: "store2", NewKey: "restore2", diff --git a/store/types/store.go b/store/types/store.go index 989ae94e8c42..289a5623f04d 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -44,6 +44,7 @@ type Queryable interface { // StoreUpgrades defines a series of transformations to apply the multistore db upon load type StoreUpgrades struct { + Added []string `json:"added"` Renamed []StoreRename `json:"renamed"` Deleted []string `json:"deleted"` } @@ -63,6 +64,19 @@ type StoreRename struct { NewKey string `json:"new_key"` } +// IsDeleted returns true if the given key should be added +func (s *StoreUpgrades) IsAdded(key string) bool { + if s == nil { + return false + } + for _, d := range s.Added { + if d == key { + return true + } + } + return false +} + // IsDeleted returns true if the given key should be deleted func (s *StoreUpgrades) IsDeleted(key string) bool { if s == nil { From 40b2caf5f809099f32e03643c469bc7e115f3c2d Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Mon, 5 Oct 2020 08:27:24 +0200 Subject: [PATCH 07/19] Rolled back version error and moved int64 to uint64 conversion --- store/iavl/store.go | 7 +++---- store/rootmulti/store.go | 4 ++-- store/rootmulti/store_test.go | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 1ea86bfe7cf3..61b4b2a444ba 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -49,8 +49,8 @@ func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVSt // LoadStore returns an IAVL Store as a CommitKVStore setting its initialVersion // to the one given. Internally, it will load the store's version (id) from the // provided DB. An error is returned if the version fails to load. -func LoadStoreWithInitialVersion(db dbm.DB, id types.CommitID, lazyLoading bool, initialVersion int64) (types.CommitKVStore, error) { - tree, err := iavl.NewMutableTreeWithOpts(db, defaultIAVLCacheSize, &iavl.Options{InitialVersion: uint64(initialVersion)}) +func LoadStoreWithInitialVersion(db dbm.DB, id types.CommitID, lazyLoading bool, initialVersion uint64) (types.CommitKVStore, error) { + tree, err := iavl.NewMutableTreeWithOpts(db, defaultIAVLCacheSize, &iavl.Options{InitialVersion: initialVersion}) if err != nil { return nil, err } @@ -87,10 +87,9 @@ func UnsafeNewStore(tree *iavl.MutableTree) *Store { // be used for querying and iteration only. If the version does not exist or has // been pruned, an error will be returned. Any mutable operations executed will // result in a panic. -// TODO: CHANGE THIS DOCUMENTATION func (st *Store) GetImmutable(version int64) (*Store, error) { if !st.VersionExists(version) { - return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, nil + return nil, iavl.ErrVersionDoesNotExist } iTree, err := st.tree.GetImmutable(version) diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index f34fe5972087..03fca8105d34 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -191,7 +191,7 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { // If it has been added, set the initial version if upgrades.IsAdded(key.Name()) { - storeParams.initialVersion = ver + storeParams.initialVersion = uint64(ver) } store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams) @@ -886,7 +886,7 @@ type storeParams struct { key types.StoreKey db dbm.DB typ types.StoreType - initialVersion int64 + initialVersion uint64 } func getLatestVersion(db dbm.DB) int64 { diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index b185e50ee4cd..1ef8f04636d4 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -238,6 +238,20 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { s4, _ = restore.getStoreByName("store4").(types.KVStore) require.NotNil(t, s4) + iterator := s4.Iterator(nil, nil) + + values := 0 + for ; iterator.Valid(); iterator.Next() { + values += 1 + } + require.Zero(t, values) + + require.NoError(t, iterator.Close()) + + // write something inside store4 + k4, v4 := []byte("fourth"), []byte("created") + s4.Set(k4, v4) + // store2 is no longer mounted st2 := restore.getStoreByName("store2") require.Nil(t, st2) @@ -265,6 +279,10 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, rl2) require.Equal(t, v2, rl2.Get(k2)) + rl4, _ := reload.getStoreByName("store4").(types.KVStore) + require.NotNil(t, rl4) + require.Equal(t, v4, rl4.Get(k4)) + // check commitInfo in storage ci, err = getCommitInfo(db, 2) require.NoError(t, err) From 28d866aef07762a412662ec0d0db21177f22d176 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Wed, 30 Sep 2020 09:35:53 +0200 Subject: [PATCH 08/19] Fixed the loading of stores after an on-chain upgrade --- go.mod | 7 +++++ go.sum | 14 +++++++++ store/iavl/store.go | 9 +++++- store/iavl/store_test.go | 56 +++++++++++++++++++++++++++++++++++ store/rootmulti/store.go | 26 ++++++++++++---- store/rootmulti/store_test.go | 31 +++++++++++++++++-- store/types/store.go | 14 +++++++++ 7 files changed, 149 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 7272880066b6..b2e8eb023402 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ module github.com/cosmos/cosmos-sdk require ( github.com/99designs/keyring v1.1.6 + github.com/DataDog/zstd v1.4.5 // indirect github.com/armon/go-metrics v0.3.4 github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.21.0-beta @@ -12,11 +13,15 @@ require ( github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/iavl v0.15.0-rc3 github.com/cosmos/ledger-cosmos-go v0.11.1 + github.com/dgraph-io/badger/v2 v2.2007.2 // indirect + github.com/dgraph-io/ristretto v0.0.3 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 github.com/gogo/gateway v1.1.0 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.2 + github.com/golang/snappy v0.0.2 // indirect github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.15.0 @@ -43,6 +48,8 @@ require ( github.com/tendermint/tendermint v0.34.0-rc4 github.com/tendermint/tm-db v0.6.2 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a + golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 google.golang.org/grpc v1.32.0 google.golang.org/protobuf v1.25.0 diff --git a/go.sum b/go.sum index fa49f96b6aba..a2f4b170da7d 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1: github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -139,13 +141,19 @@ github.com/dgraph-io/badger/v2 v2.0.3 h1:inzdf6VF/NZ+tJ8RwwYMjJMvsOALTHYdozn0qSl github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= github.com/dgraph-io/badger/v2 v2.2007.1 h1:t36VcBCpo4SsmAD5M8wVv1ieVzcALyGfaJ92z4ccULM= github.com/dgraph-io/badger/v2 v2.2007.1/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3 h1:MQLRM35Pp0yAyBYksjbj1nZI/w6eyRY/mWoM1sFf4kU= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= @@ -228,6 +236,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -681,6 +691,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 h1:YfxMZzv3PjGonQYNUaeU2+DhAdqOxerQ30JFB6WgAXo= +golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -729,6 +741,8 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/store/iavl/store.go b/store/iavl/store.go index 3d6bedabdbbb..61b4b2a444ba 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -43,7 +43,14 @@ type Store struct { // store's version (id) from the provided DB. An error is returned if the version // fails to load. func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVStore, error) { - tree, err := iavl.NewMutableTree(db, defaultIAVLCacheSize) + return LoadStoreWithInitialVersion(db, id, lazyLoading, 0) +} + +// LoadStore returns an IAVL Store as a CommitKVStore setting its initialVersion +// to the one given. Internally, it will load the store's version (id) from the +// provided DB. An error is returned if the version fails to load. +func LoadStoreWithInitialVersion(db dbm.DB, id types.CommitID, lazyLoading bool, initialVersion uint64) (types.CommitKVStore, error) { + tree, err := iavl.NewMutableTreeWithOpts(db, defaultIAVLCacheSize, &iavl.Options{InitialVersion: initialVersion}) if err != nil { return nil, err } diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 052021310f99..d433cfc87cd7 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -50,6 +50,62 @@ func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { return tree, types.CommitID{Version: ver, Hash: hash} } +func TestLoadStore(t *testing.T) { + db := dbm.NewMemDB() + tree, _ := newAlohaTree(t, db) + store := UnsafeNewStore(tree) + + // Create non-pruned height H + require.True(t, tree.Set([]byte("hello"), []byte("hallo"))) + hash, verH, err := tree.SaveVersion() + cIDH := types.CommitID{Version: verH, Hash: hash} + require.Nil(t, err) + + // Create pruned height Hp + require.True(t, tree.Set([]byte("hello"), []byte("hola"))) + hash, verHp, err := tree.SaveVersion() + cIDHp := types.CommitID{Version: verHp, Hash: hash} + require.Nil(t, err) + + // TODO: Prune this height + + // Create current height Hc + require.True(t, tree.Set([]byte("hello"), []byte("ciao"))) + hash, verHc, err := tree.SaveVersion() + cIDHc := types.CommitID{Version: verHc, Hash: hash} + require.Nil(t, err) + + // Querying an existing store at some previous non-pruned height H + hStore, err := store.GetImmutable(verH) + require.NoError(t, err) + require.Equal(t, string(hStore.Get([]byte("hello"))), "hallo") + + // Querying an existing store at some previous pruned height Hp + hpStore, err := store.GetImmutable(verHp) + require.NoError(t, err) + require.Equal(t, string(hpStore.Get([]byte("hello"))), "hola") + + // Querying an existing store at current height Hc + hcStore, err := store.GetImmutable(verHc) + require.NoError(t, err) + require.Equal(t, string(hcStore.Get([]byte("hello"))), "ciao") + + // Querying a new store at some previous non-pruned height H + newHStore, err := LoadStore(db, cIDH, false) + require.NoError(t, err) + require.Equal(t, string(newHStore.Get([]byte("hello"))), "hallo") + + // Querying a new store at some previous pruned height Hp + newHpStore, err := LoadStore(db, cIDHp, false) + require.NoError(t, err) + require.Equal(t, string(newHpStore.Get([]byte("hello"))), "hola") + + // Querying a new store at current height H + newHcStore, err := LoadStore(db, cIDHc, false) + require.NoError(t, err) + require.Equal(t, string(newHcStore.Get([]byte("hello"))), "ciao") +} + func TestGetImmutable(t *testing.T) { db := dbm.NewMemDB() tree, cID := newAlohaTree(t, db) diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index bf8a473b8d0b..03fca8105d34 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -187,7 +187,14 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { var newStores = make(map[types.StoreKey]types.CommitKVStore) for key, storeParams := range rs.storesParams { - store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams) + commitID := rs.getCommitID(infos, key.Name()) + + // If it has been added, set the initial version + if upgrades.IsAdded(key.Name()) { + storeParams.initialVersion = uint64(ver) + } + + store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams) if err != nil { return errors.Wrap(err, "failed to load store") } @@ -813,7 +820,15 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID panic("recursive MultiStores not yet supported") case types.StoreTypeIAVL: - store, err := iavl.LoadStore(db, id, rs.lazyLoading) + var store types.CommitKVStore + var err error + + if params.initialVersion == 0 { + store, err = iavl.LoadStore(db, id, rs.lazyLoading) + } else { + store, err = iavl.LoadStoreWithInitialVersion(db, id, rs.lazyLoading, params.initialVersion) + } + if err != nil { return nil, err } @@ -868,9 +883,10 @@ func (rs *Store) buildCommitInfo(version int64) *types.CommitInfo { } type storeParams struct { - key types.StoreKey - db dbm.DB - typ types.StoreType + key types.StoreKey + db dbm.DB + typ types.StoreType + initialVersion uint64 } func getLatestVersion(db dbm.DB) int64 { diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 7341154f2edd..1ef8f04636d4 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -192,6 +192,9 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, s3) s3.Set(k3, v3) + s4, _ := store.getStoreByName("store4").(types.KVStore) + require.Nil(t, s4) + // do one commit commitID := store.Commit() expectedCommitID := getExpectedCommitID(store, 1) @@ -231,6 +234,24 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, s3) require.Nil(t, s3.Get(k3)) // data was deleted + // store4 is mounted, with empty data + s4, _ = restore.getStoreByName("store4").(types.KVStore) + require.NotNil(t, s4) + + iterator := s4.Iterator(nil, nil) + + values := 0 + for ; iterator.Valid(); iterator.Next() { + values += 1 + } + require.Zero(t, values) + + require.NoError(t, iterator.Close()) + + // write something inside store4 + k4, v4 := []byte("fourth"), []byte("created") + s4.Set(k4, v4) + // store2 is no longer mounted st2 := restore.getStoreByName("store2") require.Nil(t, st2) @@ -258,12 +279,16 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, rl2) require.Equal(t, v2, rl2.Get(k2)) + rl4, _ := reload.getStoreByName("store4").(types.KVStore) + require.NotNil(t, rl4) + require.Equal(t, v4, rl4.Get(k4)) + // check commitInfo in storage ci, err = getCommitInfo(db, 2) require.NoError(t, err) require.Equal(t, int64(2), ci.Version) - require.Equal(t, 3, len(ci.StoreInfos), ci.StoreInfos) - checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3"}) + require.Equal(t, 4, len(ci.StoreInfos), ci.StoreInfos) + checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3", "store4"}) } func TestParsePath(t *testing.T) { @@ -796,8 +821,10 @@ func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(types.NewKVStoreKey("store4"), types.StoreTypeIAVL, nil) upgrades := &types.StoreUpgrades{ + Added: []string{"store4"}, Renamed: []types.StoreRename{{ OldKey: "store2", NewKey: "restore2", diff --git a/store/types/store.go b/store/types/store.go index 989ae94e8c42..289a5623f04d 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -44,6 +44,7 @@ type Queryable interface { // StoreUpgrades defines a series of transformations to apply the multistore db upon load type StoreUpgrades struct { + Added []string `json:"added"` Renamed []StoreRename `json:"renamed"` Deleted []string `json:"deleted"` } @@ -63,6 +64,19 @@ type StoreRename struct { NewKey string `json:"new_key"` } +// IsDeleted returns true if the given key should be added +func (s *StoreUpgrades) IsAdded(key string) bool { + if s == nil { + return false + } + for _, d := range s.Added { + if d == key { + return true + } + } + return false +} + // IsDeleted returns true if the given key should be deleted func (s *StoreUpgrades) IsDeleted(key string) bool { if s == nil { From e8654888d030994282983ad4bfa793b12afb59ce Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Thu, 8 Oct 2020 13:20:20 +0200 Subject: [PATCH 09/19] Added back empty tree return on missing version --- store/iavl/store.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 61b4b2a444ba..20fd972fee90 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -85,11 +85,11 @@ func UnsafeNewStore(tree *iavl.MutableTree) *Store { // GetImmutable returns a reference to a new store backed by an immutable IAVL // tree at a specific version (height) without any pruning options. This should // be used for querying and iteration only. If the version does not exist or has -// been pruned, an error will be returned. Any mutable operations executed will -// result in a panic. +// been pruned, an empty immutable IAVL tree will be used. +// Any mutable operations executed will result in a panic. func (st *Store) GetImmutable(version int64) (*Store, error) { if !st.VersionExists(version) { - return nil, iavl.ErrVersionDoesNotExist + return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, nil } iTree, err := st.tree.GetImmutable(version) From 95b036162292b43c8cb6540ab28c65ab9d528bf8 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Thu, 8 Oct 2020 13:17:38 +0200 Subject: [PATCH 10/19] Added back empty tree return on missing version and fixed some bugs --- store/iavl/store.go | 2 -- store/rootmulti/store.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 20fd972fee90..deadb3424415 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -160,8 +160,6 @@ func (st *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Ca // Implements types.KVStore. func (st *Store) Set(key, value []byte) { - defer telemetry.MeasureSince(time.Now(), "store", "iavl", "set") - types.AssertValidKey(key) types.AssertValidValue(value) st.tree.Set(key, value) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 03fca8105d34..90633a922078 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -191,7 +191,7 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { // If it has been added, set the initial version if upgrades.IsAdded(key.Name()) { - storeParams.initialVersion = uint64(ver) + storeParams.initialVersion = uint64(ver) + 1 } store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams) From 691aeaf0ec2e7a9a642f6a9156740ced3e78d758 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Wed, 30 Sep 2020 09:35:53 +0200 Subject: [PATCH 11/19] Fixed the loading of stores after an on-chain upgrade --- go.mod | 7 +++++ go.sum | 14 +++++++++ store/iavl/store.go | 9 +++++- store/iavl/store_test.go | 56 +++++++++++++++++++++++++++++++++++ store/rootmulti/store.go | 26 ++++++++++++---- store/rootmulti/store_test.go | 31 +++++++++++++++++-- store/types/store.go | 14 +++++++++ 7 files changed, 149 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 7504e763d16d..36edfebd7807 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ module github.com/cosmos/cosmos-sdk require ( github.com/99designs/keyring v1.1.6 + github.com/DataDog/zstd v1.4.5 // indirect github.com/armon/go-metrics v0.3.4 github.com/bgentry/speakeasy v0.1.0 github.com/btcsuite/btcd v0.21.0-beta @@ -12,11 +13,15 @@ require ( github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d github.com/cosmos/iavl v0.15.0-rc3 github.com/cosmos/ledger-cosmos-go v0.11.1 + github.com/dgraph-io/badger/v2 v2.2007.2 // indirect + github.com/dgraph-io/ristretto v0.0.3 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 github.com/gogo/gateway v1.1.0 github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.2 + github.com/golang/snappy v0.0.2 // indirect github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.15.0 @@ -43,6 +48,8 @@ require ( github.com/tendermint/tendermint v0.34.0-rc4.0.20201005135527-d7d0ffea13c6 github.com/tendermint/tm-db v0.6.2 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a + golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 google.golang.org/grpc v1.32.0 google.golang.org/protobuf v1.25.0 diff --git a/go.sum b/go.sum index b395dd5f6653..bac3efdb1804 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1: github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -139,13 +141,19 @@ github.com/dgraph-io/badger/v2 v2.0.3 h1:inzdf6VF/NZ+tJ8RwwYMjJMvsOALTHYdozn0qSl github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= github.com/dgraph-io/badger/v2 v2.2007.1 h1:t36VcBCpo4SsmAD5M8wVv1ieVzcALyGfaJ92z4ccULM= github.com/dgraph-io/badger/v2 v2.2007.1/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3 h1:MQLRM35Pp0yAyBYksjbj1nZI/w6eyRY/mWoM1sFf4kU= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= @@ -228,6 +236,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -681,6 +691,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 h1:YfxMZzv3PjGonQYNUaeU2+DhAdqOxerQ30JFB6WgAXo= +golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -729,6 +741,8 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/store/iavl/store.go b/store/iavl/store.go index 3d6bedabdbbb..61b4b2a444ba 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -43,7 +43,14 @@ type Store struct { // store's version (id) from the provided DB. An error is returned if the version // fails to load. func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVStore, error) { - tree, err := iavl.NewMutableTree(db, defaultIAVLCacheSize) + return LoadStoreWithInitialVersion(db, id, lazyLoading, 0) +} + +// LoadStore returns an IAVL Store as a CommitKVStore setting its initialVersion +// to the one given. Internally, it will load the store's version (id) from the +// provided DB. An error is returned if the version fails to load. +func LoadStoreWithInitialVersion(db dbm.DB, id types.CommitID, lazyLoading bool, initialVersion uint64) (types.CommitKVStore, error) { + tree, err := iavl.NewMutableTreeWithOpts(db, defaultIAVLCacheSize, &iavl.Options{InitialVersion: initialVersion}) if err != nil { return nil, err } diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 052021310f99..d433cfc87cd7 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -50,6 +50,62 @@ func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { return tree, types.CommitID{Version: ver, Hash: hash} } +func TestLoadStore(t *testing.T) { + db := dbm.NewMemDB() + tree, _ := newAlohaTree(t, db) + store := UnsafeNewStore(tree) + + // Create non-pruned height H + require.True(t, tree.Set([]byte("hello"), []byte("hallo"))) + hash, verH, err := tree.SaveVersion() + cIDH := types.CommitID{Version: verH, Hash: hash} + require.Nil(t, err) + + // Create pruned height Hp + require.True(t, tree.Set([]byte("hello"), []byte("hola"))) + hash, verHp, err := tree.SaveVersion() + cIDHp := types.CommitID{Version: verHp, Hash: hash} + require.Nil(t, err) + + // TODO: Prune this height + + // Create current height Hc + require.True(t, tree.Set([]byte("hello"), []byte("ciao"))) + hash, verHc, err := tree.SaveVersion() + cIDHc := types.CommitID{Version: verHc, Hash: hash} + require.Nil(t, err) + + // Querying an existing store at some previous non-pruned height H + hStore, err := store.GetImmutable(verH) + require.NoError(t, err) + require.Equal(t, string(hStore.Get([]byte("hello"))), "hallo") + + // Querying an existing store at some previous pruned height Hp + hpStore, err := store.GetImmutable(verHp) + require.NoError(t, err) + require.Equal(t, string(hpStore.Get([]byte("hello"))), "hola") + + // Querying an existing store at current height Hc + hcStore, err := store.GetImmutable(verHc) + require.NoError(t, err) + require.Equal(t, string(hcStore.Get([]byte("hello"))), "ciao") + + // Querying a new store at some previous non-pruned height H + newHStore, err := LoadStore(db, cIDH, false) + require.NoError(t, err) + require.Equal(t, string(newHStore.Get([]byte("hello"))), "hallo") + + // Querying a new store at some previous pruned height Hp + newHpStore, err := LoadStore(db, cIDHp, false) + require.NoError(t, err) + require.Equal(t, string(newHpStore.Get([]byte("hello"))), "hola") + + // Querying a new store at current height H + newHcStore, err := LoadStore(db, cIDHc, false) + require.NoError(t, err) + require.Equal(t, string(newHcStore.Get([]byte("hello"))), "ciao") +} + func TestGetImmutable(t *testing.T) { db := dbm.NewMemDB() tree, cID := newAlohaTree(t, db) diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index bf8a473b8d0b..03fca8105d34 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -187,7 +187,14 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { var newStores = make(map[types.StoreKey]types.CommitKVStore) for key, storeParams := range rs.storesParams { - store, err := rs.loadCommitStoreFromParams(key, rs.getCommitID(infos, key.Name()), storeParams) + commitID := rs.getCommitID(infos, key.Name()) + + // If it has been added, set the initial version + if upgrades.IsAdded(key.Name()) { + storeParams.initialVersion = uint64(ver) + } + + store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams) if err != nil { return errors.Wrap(err, "failed to load store") } @@ -813,7 +820,15 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID panic("recursive MultiStores not yet supported") case types.StoreTypeIAVL: - store, err := iavl.LoadStore(db, id, rs.lazyLoading) + var store types.CommitKVStore + var err error + + if params.initialVersion == 0 { + store, err = iavl.LoadStore(db, id, rs.lazyLoading) + } else { + store, err = iavl.LoadStoreWithInitialVersion(db, id, rs.lazyLoading, params.initialVersion) + } + if err != nil { return nil, err } @@ -868,9 +883,10 @@ func (rs *Store) buildCommitInfo(version int64) *types.CommitInfo { } type storeParams struct { - key types.StoreKey - db dbm.DB - typ types.StoreType + key types.StoreKey + db dbm.DB + typ types.StoreType + initialVersion uint64 } func getLatestVersion(db dbm.DB) int64 { diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 7341154f2edd..1ef8f04636d4 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -192,6 +192,9 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, s3) s3.Set(k3, v3) + s4, _ := store.getStoreByName("store4").(types.KVStore) + require.Nil(t, s4) + // do one commit commitID := store.Commit() expectedCommitID := getExpectedCommitID(store, 1) @@ -231,6 +234,24 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, s3) require.Nil(t, s3.Get(k3)) // data was deleted + // store4 is mounted, with empty data + s4, _ = restore.getStoreByName("store4").(types.KVStore) + require.NotNil(t, s4) + + iterator := s4.Iterator(nil, nil) + + values := 0 + for ; iterator.Valid(); iterator.Next() { + values += 1 + } + require.Zero(t, values) + + require.NoError(t, iterator.Close()) + + // write something inside store4 + k4, v4 := []byte("fourth"), []byte("created") + s4.Set(k4, v4) + // store2 is no longer mounted st2 := restore.getStoreByName("store2") require.Nil(t, st2) @@ -258,12 +279,16 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.NotNil(t, rl2) require.Equal(t, v2, rl2.Get(k2)) + rl4, _ := reload.getStoreByName("store4").(types.KVStore) + require.NotNil(t, rl4) + require.Equal(t, v4, rl4.Get(k4)) + // check commitInfo in storage ci, err = getCommitInfo(db, 2) require.NoError(t, err) require.Equal(t, int64(2), ci.Version) - require.Equal(t, 3, len(ci.StoreInfos), ci.StoreInfos) - checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3"}) + require.Equal(t, 4, len(ci.StoreInfos), ci.StoreInfos) + checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3", "store4"}) } func TestParsePath(t *testing.T) { @@ -796,8 +821,10 @@ func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) + store.MountStoreWithDB(types.NewKVStoreKey("store4"), types.StoreTypeIAVL, nil) upgrades := &types.StoreUpgrades{ + Added: []string{"store4"}, Renamed: []types.StoreRename{{ OldKey: "store2", NewKey: "restore2", diff --git a/store/types/store.go b/store/types/store.go index 989ae94e8c42..289a5623f04d 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -44,6 +44,7 @@ type Queryable interface { // StoreUpgrades defines a series of transformations to apply the multistore db upon load type StoreUpgrades struct { + Added []string `json:"added"` Renamed []StoreRename `json:"renamed"` Deleted []string `json:"deleted"` } @@ -63,6 +64,19 @@ type StoreRename struct { NewKey string `json:"new_key"` } +// IsDeleted returns true if the given key should be added +func (s *StoreUpgrades) IsAdded(key string) bool { + if s == nil { + return false + } + for _, d := range s.Added { + if d == key { + return true + } + } + return false +} + // IsDeleted returns true if the given key should be deleted func (s *StoreUpgrades) IsDeleted(key string) bool { if s == nil { From 230839c07ec48dd034b072d919d3dec1abd08026 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Thu, 8 Oct 2020 13:20:20 +0200 Subject: [PATCH 12/19] Added back empty tree return on missing version --- store/iavl/store.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 61b4b2a444ba..20fd972fee90 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -85,11 +85,11 @@ func UnsafeNewStore(tree *iavl.MutableTree) *Store { // GetImmutable returns a reference to a new store backed by an immutable IAVL // tree at a specific version (height) without any pruning options. This should // be used for querying and iteration only. If the version does not exist or has -// been pruned, an error will be returned. Any mutable operations executed will -// result in a panic. +// been pruned, an empty immutable IAVL tree will be used. +// Any mutable operations executed will result in a panic. func (st *Store) GetImmutable(version int64) (*Store, error) { if !st.VersionExists(version) { - return nil, iavl.ErrVersionDoesNotExist + return &Store{tree: &immutableTree{&iavl.ImmutableTree{}}}, nil } iTree, err := st.tree.GetImmutable(version) From 0deaf8ae9ede1bb65a69499949781e3571afa8f9 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Thu, 8 Oct 2020 13:17:38 +0200 Subject: [PATCH 13/19] Added back empty tree return on missing version and fixed some bugs --- store/iavl/store.go | 2 -- store/rootmulti/store.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index 20fd972fee90..deadb3424415 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -160,8 +160,6 @@ func (st *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Ca // Implements types.KVStore. func (st *Store) Set(key, value []byte) { - defer telemetry.MeasureSince(time.Now(), "store", "iavl", "set") - types.AssertValidKey(key) types.AssertValidValue(value) st.tree.Set(key, value) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 03fca8105d34..90633a922078 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -191,7 +191,7 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { // If it has been added, set the initial version if upgrades.IsAdded(key.Name()) { - storeParams.initialVersion = uint64(ver) + storeParams.initialVersion = uint64(ver) + 1 } store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams) From 308b7f01b4243c218e0febd871d69e2c6aa0885f Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Fri, 9 Oct 2020 14:33:36 +0200 Subject: [PATCH 14/19] Added CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 094ffc042e8e..f233b3ccd48f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -216,6 +216,7 @@ invalid or incomplete requests. * (x/genutil) [\#5938](https://github.com/cosmos/cosmos-sdk/pull/5938) Fix `InitializeNodeValidatorFiles` error handling. * (x/staking) [\#5949](https://github.com/cosmos/cosmos-sdk/pull/5949) Skip staking `HistoricalInfoKey` in simulations as headers are not exported. * (client) [\#5964](https://github.com/cosmos/cosmos-sdk/issues/5964) `--trust-node` is now false by default - for real. Users must ensure it is set to true if they don't want to enable the verifier. +* (kvstore) [\#7415](https://github.com/cosmos/cosmos-sdk/pull/7415) Allow new stores to be registered during on-chain upgrades. ### State Machine Breaking From fe796344e02568de5906bef93dc4cbea0619db7e Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Fri, 9 Oct 2020 14:40:54 +0200 Subject: [PATCH 15/19] Fixed rootmulti tests to not fail when an invalid height is queried. Now empty stores are returned instead --- store/rootmulti/store_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 1ef8f04636d4..efe2618779a4 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -79,9 +79,9 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { cID := ms.Commit() require.Equal(t, int64(1), cID.Version) - // require failure when given an invalid or pruned version + // require no failure when given an invalid or pruned version _, err = ms.CacheMultiStoreWithVersion(cID.Version + 1) - require.Error(t, err) + require.NoError(t, err) // require a valid version can be cache-loaded cms, err := ms.CacheMultiStoreWithVersion(cID.Version) @@ -499,7 +499,7 @@ func TestMultiStore_Pruning(t *testing.T) { for _, v := range tc.deleted { _, err := ms.CacheMultiStoreWithVersion(v) - require.Error(t, err, "expected error when loading height: %d", v) + require.NoError(t, err, "expected error when loading height: %d", v) } }) } @@ -535,7 +535,7 @@ func TestMultiStore_PruningRestart(t *testing.T) { for _, v := range pruneHeights { _, err := ms.CacheMultiStoreWithVersion(v) - require.Error(t, err, "expected error when loading height: %d", v) + require.NoError(t, err, "expected error when loading height: %d", v) } } From 4fc58f4aa96219bc216fd444b2f6b60c8d7a59ee Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Fri, 9 Oct 2020 14:51:25 +0200 Subject: [PATCH 16/19] Fixed store tests --- store/iavl/store.go | 1 + store/iavl/store_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/store/iavl/store.go b/store/iavl/store.go index deadb3424415..cf7737d5d814 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -160,6 +160,7 @@ func (st *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.Ca // Implements types.KVStore. func (st *Store) Set(key, value []byte) { + types.AssertValidKey(key) types.AssertValidValue(value) st.tree.Set(key, value) } diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index d433cfc87cd7..790830038ba9 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -117,7 +117,7 @@ func TestGetImmutable(t *testing.T) { require.Nil(t, err) _, err = store.GetImmutable(cID.Version + 1) - require.Error(t, err) + require.NoError(t, err) newStore, err := store.GetImmutable(cID.Version - 1) require.NoError(t, err) From 9cbb46ce7cdb276f4e47466d3f32c5eb1252d4b2 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Mon, 12 Oct 2020 07:20:18 +0200 Subject: [PATCH 17/19] Fixed failing test --- baseapp/baseapp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 760e624eb99f..233fbabc4212 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -422,7 +422,7 @@ func TestLoadVersionPruning(t *testing.T) { for _, v := range []int64{1, 2, 4} { _, err = app.cms.CacheMultiStoreWithVersion(v) - require.Error(t, err) + require.NoError(t, err) } for _, v := range []int64{3, 5, 6, 7} { From 4467d502ea4669e0b6094517cdb5f4722f0ccc21 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 12 Oct 2020 15:47:25 +0200 Subject: [PATCH 18/19] Update store/types/store.go Co-authored-by: Aleksandr Bezobchuk --- store/types/store.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/store/types/store.go b/store/types/store.go index 289a5623f04d..a2d6ab6f59cd 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -69,12 +69,7 @@ func (s *StoreUpgrades) IsAdded(key string) bool { if s == nil { return false } - for _, d := range s.Added { - if d == key { - return true - } - } - return false + return tmstrings.StringInSlice(s.Added, key) } // IsDeleted returns true if the given key should be deleted From 3d0612a2c618251f2061ea8e4627460e1a3ea0c3 Mon Sep 17 00:00:00 2001 From: "riccardo.montagnin" Date: Tue, 13 Oct 2020 07:16:30 +0200 Subject: [PATCH 19/19] Fixed build error --- store/types/store.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/store/types/store.go b/store/types/store.go index a2d6ab6f59cd..f78fcad3f402 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -9,6 +9,7 @@ import ( snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/types/kv" + tmstrings "github.com/tendermint/tendermint/libs/strings" ) type Store interface { @@ -69,7 +70,7 @@ func (s *StoreUpgrades) IsAdded(key string) bool { if s == nil { return false } - return tmstrings.StringInSlice(s.Added, key) + return tmstrings.StringInSlice(key, s.Added) } // IsDeleted returns true if the given key should be deleted