Skip to content

Commit

Permalink
chore(08-wasm): Pin code during app initialisation (#5161)
Browse files Browse the repository at this point in the history
* init InitializePinnedCodes

* testing

* call Pin during app inisitalization

* linting

* update docs

* spacing

* update docs

* add extra line

* chore: update tmproto, tmos aliases to cmtproto, cmtos

* chore: use suite.Require().NoError(), rename gotErr to err

* testing: nits

* Use table driven tests for TestInitializedPinnedCodes

---------

Co-authored-by: Carlos Rodriguez <carlos@interchain.io>
Co-authored-by: Damian Nolan <damiannolan@gmail.com>
Co-authored-by: DimitrisJim <d.f.hilliard@gmail.com>
(cherry picked from commit 2c9017f)
  • Loading branch information
vuong177 authored and mergify[bot] committed Nov 29, 2023
1 parent 8ce1911 commit e2ba288
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 8 deletions.
34 changes: 26 additions & 8 deletions docs/docs/03-light-clients/04-wasm/03-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ The sample code below shows the relevant integration points in `app.go` required
import (
...
"github.com/cosmos/cosmos-sdk/runtime"

cmtos "github.com/cometbft/cometbft/libs/os"

wasm "github.com/cosmos/ibc-go/modules/light-clients/08-wasm"
wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper"
Expand Down Expand Up @@ -54,13 +56,14 @@ func NewSimApp(
...
wasmtypes.StoreKey,
)
// Instantiate 08-wasm's keeper
// This sample code uses a constructor function that
// accepts a pointer to an existing instance of Wasm VM.
// This is the recommended approach when the chain
// also uses `x/wasm`, and then the Wasm VM instance
// can be shared.
// See the section below for more information.

// Instantiate 08-wasm's keeper
// This sample code uses a constructor function that
// accepts a pointer to an existing instance of Wasm VM.
// This is the recommended approach when the chain
// also uses `x/wasm`, and then the Wasm VM instance
// can be shared.
// See the section below for more information.
app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM(
appCodec,
runtime.NewKVStoreService(keys[wasmtypes.StoreKey]),
Expand Down Expand Up @@ -106,6 +109,17 @@ func NewSimApp(
}
}
...

if loadLatest {
...

ctx := app.BaseApp.NewUncachedContext(true, cmtproto.Header{})

// Initialize pinned codes in wasmvm as they are not persisted there
if err := wasmkeeper.InitializePinnedCodes(ctx); err != nil {
cmtos.Exit(fmt.Sprintf("failed initialize pinned codes %s", err))
}
}
}
```

Expand Down Expand Up @@ -245,4 +259,8 @@ Or alternatively the parameter can be updated via a governance proposal (see at

## Adding snapshot support

In order to use the `08-wasm` module chains are required to register the `WasmSnapshotter` extension in the snapshot manager. This snapshotter takes care of persisting the external state, in the form of contract code, of the Wasm VM instance to disk when the chain is snapshotted.
In order to use the `08-wasm` module chains are required to register the `WasmSnapshotter` extension in the snapshot manager. This snapshotter takes care of persisting the external state, in the form of contract code, of the Wasm VM instance to disk when the chain is snapshotted. [This code](https://github.com/cosmos/ibc-go/blob/2bd29c08fd1fe50b461fc33a25735aa792dc896e/modules/light-clients/08-wasm/testing/simapp/app.go#L768-L776) should be placed in `NewSimApp` function in `app.go`:

## Pin byte codes at start

Wasm byte codes should be pinned to the WasmVM cache on every application start, therefore [this code](https://github.com/cosmos/ibc-go/blob/0ed221f687ffce75984bc57402fd678e07aa6cc5/modules/light-clients/08-wasm/testing/simapp/app.go#L821-L826) should be placed in `NewSimApp` function in `app.go`.
15 changes: 15 additions & 0 deletions modules/light-clients/08-wasm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,18 @@ func (k Keeper) GetWasmClientState(ctx sdk.Context, clientID string) (*types.Cli

return wasmClientState, nil
}

// InitializePinnedCodes updates wasmvm to pin to cache all contracts marked as pinned
func InitializePinnedCodes(ctx sdk.Context) error {
checksums, err := types.GetAllChecksums(ctx)
if err != nil {
return err
}

for _, checksum := range checksums {
if err := ibcwasm.GetVM().Pin(checksum); err != nil {
return err
}
}
return nil
}
68 changes: 68 additions & 0 deletions modules/light-clients/08-wasm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,71 @@ func (suite *KeeperTestSuite) TestNewKeeper() {
})
}
}

func (suite *KeeperTestSuite) TestInitializedPinnedCodes() {
var capturedChecksums []wasmvm.Checksum

testCases := []struct {
name string
malleate func()
expError error
}{
{
"success",
func() {
suite.mockVM.PinFn = func(checksum wasmvm.Checksum) error {
capturedChecksums = append(capturedChecksums, checksum)
return nil
}
},
nil,
},
{
"failure: pin error",
func() {
suite.mockVM.PinFn = func(checksum wasmvm.Checksum) error {
return wasmtesting.ErrMockVM
}
},
wasmtesting.ErrMockVM,
},
}

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

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

ctx := suite.chainA.GetContext()
wasmClientKeeper := GetSimApp(suite.chainA).WasmClientKeeper

contracts := [][]byte{wasmtesting.Code, wasmtesting.CreateMockContract([]byte("gzipped-contract"))}

Check failure on line 273 in modules/light-clients/08-wasm/keeper/keeper_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: wasmtesting.CreateMockContract (typecheck)
checksumIDs := make([]types.Checksum, len(contracts))
signer := authtypes.NewModuleAddress(govtypes.ModuleName).String()

// store contract on chain
for i, contract := range contracts {
msg := types.NewMsgStoreCode(signer, contract)

res, err := wasmClientKeeper.StoreCode(ctx, msg)
suite.Require().NoError(err)

checksumIDs[i] = res.Checksum
}

// malleate after storing contracts
tc.malleate()

err := keeper.InitializePinnedCodes(ctx)

expPass := tc.expError == nil
if expPass {
suite.Require().NoError(err)
suite.ElementsMatch(checksumIDs, capturedChecksums)
} else {
suite.Require().ErrorIs(err, tc.expError)
}
})
}
}
9 changes: 9 additions & 0 deletions modules/light-clients/08-wasm/testing/simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ import (
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

abci "github.com/cometbft/cometbft/abci/types"
cmtos "github.com/cometbft/cometbft/libs/os"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"

"github.com/cosmos/ibc-go/modules/capability"
capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper"
Expand Down Expand Up @@ -815,6 +817,13 @@ func NewSimApp(
if err := app.LoadLatestVersion(); err != nil {
panic(fmt.Errorf("error loading last version: %w", err))
}

ctx := app.BaseApp.NewUncachedContext(true, cmtproto.Header{})

// Initialize pinned codes in wasmvm as they are not persisted there
if err := wasmkeeper.InitializePinnedCodes(ctx); err != nil {
cmtos.Exit(fmt.Sprintf("failed initialize pinned codes %s", err))
}
}

app.ScopedIBCKeeper = scopedIBCKeeper
Expand Down

0 comments on commit e2ba288

Please sign in to comment.