From f10363cc86151fc16b340254846996fe3149d7e6 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Sun, 6 Oct 2024 01:34:13 +0800 Subject: [PATCH] Problem: app hash mismatch occurs when upgrade to iavl v1.2.0 (#1618) * Problem: app hash mismatch occurs when upgrade to iavl v1.2.0 * try to reproduce in unit test * reproduced * make initial version compatible with iavl 1.2 * changelog * remove debug log * align submodule * fix unit test * fix lint * better make test * fix initial version * cleanup * cleanup * cleanup * lint --------- Co-authored-by: huangyi --- .github/workflows/build.yml | 5 +--- CHANGELOG.md | 5 ++++ Makefile | 2 +- go.mod | 2 -- go.sum | 4 +-- gomod2nix.toml | 5 ++-- integration_tests/utils.py | 3 +- memiavl/db.go | 2 +- memiavl/db_test.go | 55 ++++++++++++++++--------------------- memiavl/go.mod | 2 +- memiavl/go.sum | 4 +-- memiavl/import.go | 4 +-- memiavl/multitree.go | 33 ++++++++++++---------- memiavl/tree.go | 48 +++++++++++++++++--------------- memiavl/tree_test.go | 40 +++++++++++++++++++++++++++ store/go.mod | 2 +- store/go.sum | 4 +-- versiondb/go.mod | 2 +- versiondb/go.sum | 4 +-- 19 files changed, 131 insertions(+), 95 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8ac7083d79..e309e8e155 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -74,10 +74,7 @@ jobs: signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}" - name: test & coverage report creation run: | - nix develop -c make test - nix develop -c make test-memiavl - nix develop -c make test-store - nix develop .#rocksdb -c make test-versiondb + nix develop .#rocksdb -c make test test-versiondb if: steps.changed-files.outputs.any_changed == 'true' - name: filter out proto files run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c8b732ffa..a000159192 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## UNRELEASED +### State Machine Breaking + +* (memiavl)[#1618](https://github.com/crypto-org-chain/cronos/pull/1618) memiavl change initial version logic to be + compatible with iavl 1.2.0. + ### Improvements * [#1592](https://github.com/crypto-org-chain/cronos/pull/1592) Change the default parallelism of the block-stm to minimum between GOMAXPROCS and NumCPU diff --git a/Makefile b/Makefile index 0336cf1f48..33cbf460b5 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ build: check-network print-ledger go.sum install: check-network print-ledger go.sum @go install -mod=readonly $(BUILD_FLAGS) ./cmd/cronosd -test: +test: test-memiavl test-store @go test -tags=objstore -v -mod=readonly $(PACKAGES) -coverprofile=$(COVERAGE) -covermode=atomic test-memiavl: diff --git a/go.mod b/go.mod index 6d0f9ff42a..ae09b3cd20 100644 --- a/go.mod +++ b/go.mod @@ -268,8 +268,6 @@ replace ( replace ( // Use cosmos keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 - // FIXME: address the replacement when bump v1.2.0 to that triggers app hash mismatch in upgrade test - github.com/cosmos/iavl => github.com/cosmos/iavl v1.1.2 // dgrijalva/jwt-go is deprecated and doesn't receive security updates. // TODO: remove it: https://github.com/cosmos/cosmos-sdk/issues/13134 github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2 diff --git a/go.sum b/go.sum index 5d4d6bb8fb..0b2a9a9b12 100644 --- a/go.sum +++ b/go.sum @@ -393,8 +393,8 @@ github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= -github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= -github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= +github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= +github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= github.com/cosmos/ibc-go/modules/apps/callbacks v0.0.0-20240913130017-6b2554360c0e h1:jMqihcJRBdpRrKGOMS1bDyyoo2JoQxv4QmMCwK3HSvI= github.com/cosmos/ibc-go/modules/apps/callbacks v0.0.0-20240913130017-6b2554360c0e/go.mod h1:akR14gsU5YD5S1G5I6lOI7z51OjR1vJko06Rs/3/Ym0= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= diff --git a/gomod2nix.toml b/gomod2nix.toml index d4784cd231..7ddc52c9ac 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -186,9 +186,8 @@ schema = 3 version = "v1.7.0" hash = "sha256-ZkEUImxBBo8Q/6c7tVR0rybpLbtlplzvgfLl5xvtV00=" [mod."github.com/cosmos/iavl"] - version = "v1.1.2" - hash = "sha256-fhh5fN1BMDxbF4PobERMQdIb9vIrxaSl0tRXas0WKmc=" - replaced = "github.com/cosmos/iavl" + version = "v1.2.0" + hash = "sha256-NYSt6LOGyspP6eZXo9e5+2MFwyrWxD/rp2dRTtlWg2E=" [mod."github.com/cosmos/ibc-go/modules/apps/callbacks"] version = "v0.0.0-20240913130017-6b2554360c0e" hash = "sha256-mL+g8WB+fLUlTKMnrdn8rTgw2gqXsHlky3/BTsyfek0=" diff --git a/integration_tests/utils.py b/integration_tests/utils.py index 65b0812cbb..eda86d61d6 100644 --- a/integration_tests/utils.py +++ b/integration_tests/utils.py @@ -113,10 +113,9 @@ def wait_for_block(cli, height, timeout=240): print(f"get sync status failed: {e}", file=sys.stderr) else: current_height = int(get_sync_info(status)["latest_block_height"]) - print("debug current height", current_height) + print("current block height", current_height) if current_height >= height: break - print("current block height", current_height) time.sleep(0.5) else: raise TimeoutError(f"wait for block {height} timeout") diff --git a/memiavl/db.go b/memiavl/db.go index 3f12ca5ecc..02566c8a52 100644 --- a/memiavl/db.go +++ b/memiavl/db.go @@ -699,7 +699,7 @@ func (db *DB) reloadMultiTree(mtree *MultiTree) error { db.MultiTree = *mtree // catch-up the pending changes - return db.MultiTree.applyWALEntry(db.pendingLog) + return db.applyWALEntry(db.pendingLog) } // rewriteIfApplicable execute the snapshot rewrite strategy according to current height diff --git a/memiavl/db_test.go b/memiavl/db_test.go index f249d59013..a59f8c3886 100644 --- a/memiavl/db_test.go +++ b/memiavl/db_test.go @@ -180,6 +180,7 @@ func TestInitialVersion(t *testing.T) { name2 := "new2" key := "hello" value := "world" + value1 := "world1" for _, initialVersion := range []int64{0, 1, 100} { dir := t.TempDir() db, err := Load(dir, Options{CreateIfMissing: true, InitialStores: []string{name}}) @@ -188,66 +189,56 @@ func TestInitialVersion(t *testing.T) { require.NoError(t, db.ApplyChangeSets(mockNameChangeSet(name, key, value))) v, err := db.Commit() require.NoError(t, err) - if initialVersion <= 1 { - require.Equal(t, int64(1), v) - } else { - require.Equal(t, initialVersion, v) - } - hash := db.LastCommitInfo().StoreInfos[0].CommitId.Hash - require.Equal(t, "6032661ab0d201132db7a8fa1da6a0afe427e6278bd122c301197680ab79ca02", hex.EncodeToString(hash)) - require.NoError(t, db.ApplyChangeSets(mockNameChangeSet(name, key, "world1"))) + + realInitialVersion := max(initialVersion, 1) + require.Equal(t, realInitialVersion, v) + + // the nodes are created with initial version to be compatible with iavl v1 behavior. + // with iavl v0, the nodes are created with version 1. + commitId := db.LastCommitInfo().StoreInfos[0].CommitId + require.Equal(t, commitId.Hash, HashNode(newLeafNode([]byte(key), []byte(value), uint32(commitId.Version)))) + + require.NoError(t, db.ApplyChangeSets(mockNameChangeSet(name, key, value1))) v, err = db.Commit() require.NoError(t, err) - hash = db.LastCommitInfo().StoreInfos[0].CommitId.Hash - if initialVersion <= 1 { - require.Equal(t, int64(2), v) - require.Equal(t, "ef0530f9bf1af56c19a3bac32a3ec4f76a6fefaacb2efd4027a2cf37240f60bb", hex.EncodeToString(hash)) - } else { - require.Equal(t, initialVersion+1, v) - require.Equal(t, "a719e7d699d42ea8e5637ec84675a2c28f14a00a71fb518f20aa2c395673a3b8", hex.EncodeToString(hash)) - } + commitId = db.LastCommitInfo().StoreInfos[0].CommitId + require.Equal(t, realInitialVersion+1, v) + require.Equal(t, commitId.Hash, HashNode(newLeafNode([]byte(key), []byte(value1), uint32(commitId.Version)))) require.NoError(t, db.Close()) + // reload the db, check the contents are the same db, err = Load(dir, Options{}) require.NoError(t, err) require.Equal(t, uint32(initialVersion), db.initialVersion) require.Equal(t, v, db.Version()) - require.Equal(t, hex.EncodeToString(hash), hex.EncodeToString(db.LastCommitInfo().StoreInfos[0].CommitId.Hash)) + require.Equal(t, hex.EncodeToString(commitId.Hash), hex.EncodeToString(db.LastCommitInfo().StoreInfos[0].CommitId.Hash)) + // add a new store to a reloaded db db.ApplyUpgrades([]*TreeNameUpgrade{{Name: name1}}) require.NoError(t, db.ApplyChangeSets(mockNameChangeSet(name1, key, value))) v, err = db.Commit() require.NoError(t, err) - if initialVersion <= 1 { - require.Equal(t, int64(3), v) - } else { - require.Equal(t, initialVersion+2, v) - } + require.Equal(t, realInitialVersion+2, v) require.Equal(t, 2, len(db.lastCommitInfo.StoreInfos)) info := db.lastCommitInfo.StoreInfos[0] require.Equal(t, name1, info.Name) require.Equal(t, v, info.CommitId.Version) - require.Equal(t, "6032661ab0d201132db7a8fa1da6a0afe427e6278bd122c301197680ab79ca02", hex.EncodeToString(info.CommitId.Hash)) - // the nodes are created with version 1, which is compatible with iavl behavior: https://github.com/cosmos/iavl/pull/660 - require.Equal(t, info.CommitId.Hash, HashNode(newLeafNode([]byte(key), []byte(value), 1))) + require.Equal(t, info.CommitId.Hash, HashNode(newLeafNode([]byte(key), []byte(value), uint32(info.CommitId.Version)))) + // test snapshot rewriting and reload require.NoError(t, db.RewriteSnapshot()) require.NoError(t, db.Reload()) - + // add new store after snapshot rewriting db.ApplyUpgrades([]*TreeNameUpgrade{{Name: name2}}) require.NoError(t, db.ApplyChangeSets(mockNameChangeSet(name2, key, value))) v, err = db.Commit() require.NoError(t, err) - if initialVersion <= 1 { - require.Equal(t, int64(4), v) - } else { - require.Equal(t, initialVersion+3, v) - } + require.Equal(t, realInitialVersion+3, v) require.Equal(t, 3, len(db.lastCommitInfo.StoreInfos)) info2 := db.lastCommitInfo.StoreInfos[1] require.Equal(t, name2, info2.Name) require.Equal(t, v, info2.CommitId.Version) - require.Equal(t, hex.EncodeToString(info.CommitId.Hash), hex.EncodeToString(info2.CommitId.Hash)) + require.Equal(t, info2.CommitId.Hash, HashNode(newLeafNode([]byte(key), []byte(value), uint32(info2.CommitId.Version)))) } } diff --git a/memiavl/go.mod b/memiavl/go.mod index 432fafb6e5..fb19c3adcb 100644 --- a/memiavl/go.mod +++ b/memiavl/go.mod @@ -10,7 +10,7 @@ require ( github.com/alitto/pond v1.8.3 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/gogoproto v1.4.11 - github.com/cosmos/iavl v1.1.2 + github.com/cosmos/iavl v1.2.0 github.com/cosmos/ics23/go v0.10.0 github.com/ledgerwatch/erigon-lib v0.0.0-20230210071639-db0e7ed11263 github.com/stretchr/testify v1.8.4 diff --git a/memiavl/go.sum b/memiavl/go.sum index a11ec86934..815f13790e 100644 --- a/memiavl/go.sum +++ b/memiavl/go.sum @@ -30,8 +30,8 @@ github.com/cosmos/cosmos-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAK github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= -github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= -github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= +github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= +github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/memiavl/import.go b/memiavl/import.go index 9bab85a44c..3e9bc48ce0 100644 --- a/memiavl/import.go +++ b/memiavl/import.go @@ -131,7 +131,7 @@ func (ai *TreeImporter) Close() error { // doImport a stream of `ExportNode`s into a new snapshot. func doImport(dir string, version int64, nodes <-chan *ExportNode) (returnErr error) { if version > int64(math.MaxUint32) { - return errors.New("version overflows uint32") + return fmt.Errorf("version overflows uint32: %d", version) } return writeSnapshot(context.Background(), dir, uint32(version), func(w *snapshotWriter) (uint32, error) { @@ -167,7 +167,7 @@ type importer struct { func (i *importer) Add(n *ExportNode) error { if n.Version > int64(math.MaxUint32) { - return errors.New("version overflows uint32") + return fmt.Errorf("version overflows uint32: %d", n.Version) } if n.Height == 0 { diff --git a/memiavl/multitree.go b/memiavl/multitree.go index 866123b597..d2702708bd 100644 --- a/memiavl/multitree.go +++ b/memiavl/multitree.go @@ -105,8 +105,9 @@ func LoadMultiTree(dir string, zeroCopy bool, cacheSize int) (*MultiTree, error) zeroCopy: zeroCopy, cacheSize: cacheSize, } - // initial version is nesserary for wal index conversion - mtree.setInitialVersion(metadata.InitialVersion) + // initial version is nesserary for wal index conversion, + // overflow checked in `readMetadata`. + mtree.setInitialVersion(uint32(metadata.InitialVersion)) return mtree, nil } @@ -133,26 +134,28 @@ func (t *MultiTree) SetInitialVersion(initialVersion int64) error { } for _, entry := range t.trees { - if !entry.Tree.IsEmpty() { + if !entry.IsEmpty() { return fmt.Errorf("tree is not empty: %s", entry.Name) } } - t.setInitialVersion(initialVersion) + t.setInitialVersion(uint32(initialVersion)) return nil } -func (t *MultiTree) setInitialVersion(initialVersion int64) { - t.initialVersion = uint32(initialVersion) - for _, entry := range t.trees { - entry.Tree.initialVersion = t.initialVersion +func (t *MultiTree) setInitialVersion(initialVersion uint32) { + t.initialVersion = initialVersion + if t.initialVersion > 1 { + for _, entry := range t.trees { + entry.setInitialVersion(t.initialVersion) + } } } func (t *MultiTree) SetZeroCopy(zeroCopy bool) { t.zeroCopy = zeroCopy for _, entry := range t.trees { - entry.Tree.SetZeroCopy(zeroCopy) + entry.SetZeroCopy(zeroCopy) } } @@ -161,7 +164,7 @@ func (t *MultiTree) Copy(cacheSize int) *MultiTree { trees := make([]NamedTree, len(t.trees)) treesByName := make(map[string]int, len(t.trees)) for i, entry := range t.trees { - tree := entry.Tree.Copy(cacheSize) + tree := entry.Copy(cacheSize) trees[i] = NamedTree{Tree: tree, Name: entry.Name} treesByName[entry.Name] = i } @@ -247,7 +250,7 @@ func (t *MultiTree) ApplyChangeSet(name string, changeSet ChangeSet) error { if !found { return fmt.Errorf("unknown tree name %s", name) } - t.trees[i].Tree.ApplyChangeSet(changeSet) + t.trees[i].ApplyChangeSet(changeSet) return nil } @@ -271,7 +274,7 @@ func (t *MultiTree) WorkingCommitInfo() *CommitInfo { func (t *MultiTree) SaveVersion(updateCommitInfo bool) (int64, error) { t.lastCommitInfo.Version = nextVersion(t.lastCommitInfo.Version, t.initialVersion) for _, entry := range t.trees { - if _, _, err := entry.Tree.SaveVersion(updateCommitInfo); err != nil { + if _, _, err := entry.SaveVersion(updateCommitInfo); err != nil { return 0, err } } @@ -292,8 +295,8 @@ func (t *MultiTree) buildCommitInfo(version int64) *CommitInfo { infos = append(infos, StoreInfo{ Name: entry.Name, CommitId: CommitID{ - Version: entry.Tree.Version(), - Hash: entry.Tree.RootHash(), + Version: entry.Version(), + Hash: entry.RootHash(), }, }) } @@ -410,7 +413,7 @@ func WriteFileSync(name string, data []byte) error { func (t *MultiTree) Close() error { errs := make([]error, 0, len(t.trees)) for _, entry := range t.trees { - errs = append(errs, entry.Tree.Close()) + errs = append(errs, entry.Close()) } t.trees = nil t.treesByName = nil diff --git a/memiavl/tree.go b/memiavl/tree.go index 0b26290822..4e3fbadb1c 100644 --- a/memiavl/tree.go +++ b/memiavl/tree.go @@ -3,7 +3,6 @@ package memiavl import ( "bytes" "crypto/sha256" - "errors" "fmt" "math" @@ -21,7 +20,7 @@ func NewCache(cacheSize int) cache.Cache { // verify change sets by replay them to rebuild iavl tree and verify the root hashes type Tree struct { - version uint32 + version, cowVersion uint32 // root node of empty tree is represented as `nil` root Node snapshot *Snapshot @@ -29,8 +28,6 @@ type Tree struct { // simple lru cache provided by iavl library cache cache.Cache - initialVersion, cowVersion uint32 - // when true, the get and iterator methods could return a slice pointing to mmaped blob files. zeroCopy bool } @@ -44,14 +41,13 @@ func (n *cacheNode) GetKey() []byte { } // NewEmptyTree creates an empty tree at an arbitrary version. -func NewEmptyTree(version uint64, initialVersion uint32, cacheSize int) *Tree { +func NewEmptyTree(version uint64, cacheSize int) *Tree { if version >= math.MaxUint32 { panic("version overflows uint32") } return &Tree{ - version: uint32(version), - initialVersion: initialVersion, + version: uint32(version), // no need to copy if the tree is not backed by snapshot zeroCopy: true, cache: NewCache(cacheSize), @@ -60,13 +56,16 @@ func NewEmptyTree(version uint64, initialVersion uint32, cacheSize int) *Tree { // New creates an empty tree at genesis version func New(cacheSize int) *Tree { - return NewEmptyTree(0, 0, cacheSize) + return NewEmptyTree(0, cacheSize) } // New creates a empty tree with initial-version, // it happens when a new store created at the middle of the chain. func NewWithInitialVersion(initialVersion uint32, cacheSize int) *Tree { - return NewEmptyTree(0, initialVersion, cacheSize) + if initialVersion <= 1 { + return New(cacheSize) + } + return NewEmptyTree(uint64(initialVersion-1), cacheSize) } // NewFromSnapshot mmap the blob files and create the root node. @@ -97,10 +96,24 @@ func (t *Tree) SetInitialVersion(initialVersion int64) error { if initialVersion >= math.MaxUint32 { return fmt.Errorf("version overflows uint32: %d", initialVersion) } - t.initialVersion = uint32(initialVersion) + + t.setInitialVersion(uint32(initialVersion)) return nil } +func (t *Tree) setInitialVersion(initialVersion uint32) { + if t.version > 0 { + // initial version has no effect if the tree is already initialized + return + } + + if initialVersion < 1 { + t.version = 0 + } else { + t.version = initialVersion - 1 + } +} + // Copy returns a snapshot of the tree which won't be modified by further modifications on the main tree, // the returned new tree can be accessed concurrently with the main tree. func (t *Tree) Copy(cacheSize int) *Tree { @@ -145,8 +158,8 @@ func (t *Tree) remove(key []byte) { // SaveVersion increases the version number and optionally updates the hashes func (t *Tree) SaveVersion(updateHash bool) ([]byte, int64, error) { - if t.version >= uint32(math.MaxUint32) { - return nil, 0, errors.New("version overflows uint32") + if t.version == uint32(math.MaxUint32) { + return nil, 0, fmt.Errorf("version overflows uint32: %d", t.version) } var hash []byte @@ -154,7 +167,7 @@ func (t *Tree) SaveVersion(updateHash bool) ([]byte, int64, error) { hash = t.RootHash() } - t.version = nextVersionU32(t.version, t.initialVersion) + t.version++ return hash, int64(t.version), nil } @@ -284,12 +297,3 @@ func (t *Tree) Close() error { t.root = nil return err } - -// nextVersionU32 is compatible with existing golang iavl implementation. -// see: https://github.com/cosmos/iavl/pull/660 -func nextVersionU32(v uint32, initialVersion uint32) uint32 { - if v == 0 && initialVersion > 1 { - return initialVersion - } - return v + 1 -} diff --git a/memiavl/tree_test.go b/memiavl/tree_test.go index 6a013415bb..a05aa207a7 100644 --- a/memiavl/tree_test.go +++ b/memiavl/tree_test.go @@ -1,6 +1,7 @@ package memiavl import ( + "bytes" "fmt" "strconv" "testing" @@ -16,6 +17,9 @@ var ( ChangeSets []ChangeSet RefHashes [][]byte ExpectItems [][]pair + + IAVLInitialVersion = 100 + RefHashesInitialVersion [][]byte ) func mockKVPairs(kvPairs ...string) []*KVPair { @@ -62,14 +66,34 @@ func init() { // generate ref hashes with ref impl d := wrapper.NewDBWrapper(db.NewMemDB()) refTree := iavl.NewMutableTree(d, 0, true, log.NewNopLogger()) + refTreeInitialVersion := iavl.NewMutableTree(d, 0, true, log.NewNopLogger(), iavl.InitialVersionOption(uint64(IAVLInitialVersion))) for _, changes := range ChangeSets { + { + if err := applyChangeSetRef(refTreeInitialVersion, changes); err != nil { + panic(err) + } + workingHash := refTreeInitialVersion.WorkingHash() + refHash, _, err := refTreeInitialVersion.SaveVersion() + if err != nil { + panic(err) + } + if !bytes.Equal(workingHash, refHash) { + panic(fmt.Sprintf("working hash %X != ref hash %X", workingHash, refHash)) + } + RefHashesInitialVersion = append(RefHashesInitialVersion, refHash) + } + if err := applyChangeSetRef(refTree, changes); err != nil { panic(err) } + workingHash := refTree.WorkingHash() refHash, _, err := refTree.SaveVersion() if err != nil { panic(err) } + if !bytes.Equal(workingHash, refHash) { + panic(fmt.Sprintf("working hash %X != ref hash %X", workingHash, refHash)) + } RefHashes = append(RefHashes, refHash) } @@ -154,10 +178,26 @@ func TestRootHashes(t *testing.T) { for i, changes := range ChangeSets { tree.ApplyChangeSet(changes) + workingHash := tree.RootHash() hash, v, err := tree.SaveVersion(true) require.NoError(t, err) require.Equal(t, i+1, int(v)) require.Equal(t, RefHashes[i], hash) + require.Equal(t, hash, workingHash) + } +} + +func TestRootHashesInitialVersion(t *testing.T) { + tree := NewWithInitialVersion(uint32(IAVLInitialVersion), 0) + + for i, changes := range ChangeSets { + tree.ApplyChangeSet(changes) + workingHash := tree.RootHash() + hash, v, err := tree.SaveVersion(true) + require.NoError(t, err) + require.Equal(t, IAVLInitialVersion+i, int(v)) + require.Equal(t, RefHashesInitialVersion[i], hash) + require.Equal(t, hash, workingHash) } } diff --git a/store/go.mod b/store/go.mod index b769133448..c832e6cd14 100644 --- a/store/go.mod +++ b/store/go.mod @@ -48,7 +48,7 @@ require ( github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect - github.com/cosmos/iavl v1.1.2 // indirect + github.com/cosmos/iavl v1.2.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect diff --git a/store/go.sum b/store/go.sum index 1a825a070c..045ca0fb1c 100644 --- a/store/go.sum +++ b/store/go.sum @@ -135,8 +135,8 @@ github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= -github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= -github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= +github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= +github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= diff --git a/versiondb/go.mod b/versiondb/go.mod index d8e347a08d..a1dfb84a67 100644 --- a/versiondb/go.mod +++ b/versiondb/go.mod @@ -13,7 +13,7 @@ require ( github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-sdk v0.50.4 github.com/cosmos/gogoproto v1.7.0 - github.com/cosmos/iavl v1.1.2 + github.com/cosmos/iavl v1.2.0 github.com/cosmos/ibc-go/modules/capability v1.0.0 github.com/crypto-org-chain/cronos/memiavl v0.0.3 github.com/golang/snappy v0.0.4 diff --git a/versiondb/go.sum b/versiondb/go.sum index ca050a3dc3..55288ac140 100644 --- a/versiondb/go.sum +++ b/versiondb/go.sum @@ -152,8 +152,8 @@ github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= -github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= -github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= +github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= +github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM=