cosmos / ibc-go

Inter-Blockchain Communication Protocol (IBC) implementation in Golang.
https://ibc.cosmos.network/
MIT License
549 stars 580 forks source link

Refactor 08-wasm snapshotter tests to use existing simapp setup #5003

Open damiannolan opened 11 months ago

damiannolan commented 11 months ago

Currently the snapshotter tests in 08-wasm rely on additional test helpers for bootstrapping a custom simapp with extra app options.

Refactor the snapshotter tests to setup simapp using the standard test setup pattern.

are we happy to keep this test helpers simapp setup? Or do we want to try to make this work with the existing pattern of simapp setup? cc. @colin-axner @DimitrisJim

_Originally posted by @damiannolan in https://github.com/cosmos/ibc-go/pull/4723#discussion_r1378560926_

ThanhNhann commented 10 months ago

Hi @damiannolan, can I do this?

DimitrisJim commented 10 months ago

you most definitely can @ThanhNhann, thanks so much for offering! :1st_place_medal:

damiannolan commented 10 months ago

Hi, I realise that it wasn't clear from the issue the intended direction for addressing this task.

The main points to consider were:

What I had in mind was something like the following. I did not get to spend much time on this but I think this code is running into an iavl importer error further down the stack (I don't think app state is being reset entirely).

// SetupWasmWithSnapshotter entrypoint for snaphotter tests - override the default testing app init func
// use setupTestingAppWithSnapshotter to configure the snapshot db and store
func (suite *KeeperTestSuite) SetupWasmWithSnapshotter() {
        ibctesting.DefaultTestingAppInit = suite.setupTestingAppWithSnapshotter

    suite.coordinator = ibctesting.NewCoordinator(suite.T(), 1)
    suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
}

func (suite *KeeperTestSuite) setupTestingAppWithSnapshotter() {
        db := dbm.NewMemDB()

    nodeHome := simapp.DefaultNodeHome
    snapshotDir := filepath.Join(nodeHome, "data", "snapshots")
    snapshotDB, err := dbm.NewDB("snapshots", dbm.MemDBBackend, snapshotDir)
    if err != nil {
        panic(err)
    }

    suite.T().Cleanup(func() {
        if err := snapshotDB.Close(); err != nil {
            panic(err)
        }
    })

    snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir)
    if err != nil {
        panic(err)
    }

    app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, simtestutil.EmptyAppOptions{}, wasmtesting.NewMockWasmEngine(), baseapp.SetSnapshot(snapshotStore, snapshottypes.SnapshotOptions{KeepRecent: 2}))
    return app, app.DefaultGenesis()
}

func (suite *KeeperTestSuite) TestSnapshotter() {
    gzippedContract, err := types.GzipIt(wasmtesting.CreateMockContract([]byte("gzipped-contract")))
    suite.Require().NoError(err)

    testCases := []struct {
        name      string
        contracts [][]byte
    }{
        {
            name:      "single contract",
            contracts: [][]byte{wasmtesting.Code},
        },
        {
            name:      "multiple contracts",
            contracts: [][]byte{wasmtesting.Code, gzippedContract},
        },
    }

    for _, tc := range testCases {
        tc := tc

        suite.Run(tc.name, func() {
            suite.SetupWasmWithSnapshotter()

            var checksums [][]byte
            var expChecksums []byte

            // store contract on chain
            for _, contract := range tc.contracts {
                signer := authtypes.NewModuleAddress(govtypes.ModuleName).String()
                msg := types.NewMsgStoreCode(signer, contract)

                res, err := GetSimApp(suite.chainA).WasmClientKeeper.StoreCode(suite.chainA.GetContext(), msg)
                suite.Require().NoError(err)

                checksums = append(checksums, res.Checksum)
                expChecksums = append(expChecksums, res.Checksum...)
            }

            // ABCI commit block and create snapshot
            suite.coordinator.CommitBlock(suite.chainA)

            snapshotHeight := uint64(GetSimApp(suite.chainA).LastBlockHeight())
            snapshot, err := GetSimApp(suite.chainA).SnapshotManager().Create(snapshotHeight)
            suite.Require().NoError(err)
            suite.Require().NotNil(snapshot)

            suite.SetupWasmWithSnapshotter() // reset app state

            resp, err := GetSimApp(suite.chainA).WasmClientKeeper.Checksums(suite.chainA.GetContext(), &types.QueryChecksumsRequest{})
            suite.Require().NoError(err)
            suite.Require().Empty(resp.Checksums)

            err = GetSimApp(suite.chainA).SnapshotManager().Restore(*snapshot)
            suite.Require().NoError(err)

            for i := uint32(0); i < snapshot.Chunks; i++ {
                chunkBz, err := GetSimApp(suite.chainA).SnapshotManager().LoadChunk(snapshot.Height, snapshot.Format, i)
                suite.Require().NoError(err)

                end, err := GetSimApp(suite.chainA).SnapshotManager().RestoreChunk(chunkBz)
                suite.Require().NoError(err)

                if end {
                    break
                }
            }

            var restoredChecksums []byte
            for _, checksum := range checksums {
                resp, err := GetSimApp(suite.chainA).WasmClientKeeper.Code(suite.chainA.GetContext(), &types.QueryCodeRequest{Checksum: hex.EncodeToString(checksum)})
                suite.Require().NoError(err)

                checksum, err := types.CreateChecksum(resp.Data)
                suite.Require().NoError(err)

                restoredChecksums = append(restoredChecksums, checksum...)
            }

            suite.Require().Equal(expChecksums, restoredChecksums)
        })
    }
}