Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ibc-hooks transfer stack order and add tests #270

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ bin
*/.DS_Store


scripts/tests/ibc-hooks/counter/target
data
24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,27 @@ install: go.sum

build:
go build $(BUILD_FLAGS) -o bin/migalood ./cmd/migalood

integration-test-all: init-test-framework \
test-relayer \
test-ibc-hooks

init-test-framework: clean-testing-data install
@echo "Initializing both blockchains..."
./scripts/tests/init-test-framework.sh

test-relayer:
@echo "Testing relayer..."
./scripts/tests/relayer/interchain-acc-config/rly-init.sh

test-ibc-hooks:
@echo "Testing ibc hooks..."
./scripts/tests/ibc-hooks/increment.sh

clean-testing-data:
@echo "Killing migalood and removing previous data"
-@pkill migalood 2>/dev/null
-@pkill rly 2>/dev/null
-@rm -rf ./data

.PHONY: all install build integration-test-all init-test-framework test-relayer test-ibc-hooks clean-testing-data
123 changes: 56 additions & 67 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@

// IBC hooks
IBCHooksKeeper *ibchookskeeper.Keeper
TransferStack *ibchooks.IBCMiddleware
TransferStack porttypes.Middleware
Ics20WasmHooks *ibchooks.WasmHooks
HooksICS4Wrapper ibchooks.ICS4Middleware

Expand Down Expand Up @@ -518,18 +518,6 @@
AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)).
AddRoute(alliancemoduletypes.RouterKey, alliancemodule.NewAllianceProposalHandler(app.AllianceKeeper))

// RouterKeeper must be created before TransferKeeper
app.RouterKeeper = *routerkeeper.NewKeeper(
appCodec,
app.keys[routertypes.StoreKey],
app.GetSubspace(routertypes.ModuleName),
app.TransferKeeper,
app.IBCKeeper.ChannelKeeper,
app.DistrKeeper,
app.BankKeeper,
app.IBCKeeper.ChannelKeeper,
)

// Configure the hooks keeper
hooksKeeper := ibchookskeeper.NewKeeper(
keys[ibchookstypes.StoreKey],
Expand All @@ -543,38 +531,47 @@
app.Ics20WasmHooks,
)

// IBC Fee Module keeper
app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(
appCodec, keys[ibcfeetypes.StoreKey],
app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware
app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper,
)

// Create Transfer Keepers
app.TransferKeeper = ibctransferkeeper.NewKeeper(
appCodec,
keys[ibctransfertypes.StoreKey],
app.GetSubspace(ibctransfertypes.ModuleName),
app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware
app.HooksICS4Wrapper,
app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper,
app.AccountKeeper,
app.BankKeeper,
scopedTransferKeeper,
)
transferIBCModule := transfer.NewIBCModule(app.TransferKeeper)

app.RouterKeeper.SetTransferKeeper(app.TransferKeeper)
// Hooks Middleware
hooksTransferStack := ibchooks.NewIBCMiddleware(&transferIBCModule, &app.HooksICS4Wrapper)

// ICA Host keeper
app.ICAHostKeeper = icahostkeeper.NewKeeper(
appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName),
app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack
app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(),
app.RouterKeeper = *routerkeeper.NewKeeper(
appCodec,
app.keys[routertypes.StoreKey],
app.GetSubspace(routertypes.ModuleName),
app.TransferKeeper,
app.IBCKeeper.ChannelKeeper,
app.DistrKeeper,
app.BankKeeper,
app.IBCKeeper.ChannelKeeper,
)
icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper)
pmfTransferStack := router.NewIBCMiddleware(hooksTransferStack,
&app.RouterKeeper,
5,
routerkeeper.DefaultForwardTransferPacketTimeoutTimestamp,
routerkeeper.DefaultRefundTransferPacketTimeoutTimestamp,
)
app.TransferStack = &pmfTransferStack
expertdicer marked this conversation as resolved.
Show resolved Hide resolved

app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(
appCodec, keys[ibcfeetypes.StoreKey],
app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware
app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper,
)
app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper(
appCodec,
keys[icacontrollertypes.StoreKey],
Expand All @@ -585,9 +582,34 @@
scopedICAControllerKeeper,
app.MsgServiceRouter(),
)
app.ICAHostKeeper = icahostkeeper.NewKeeper(
appCodec,
keys[icahosttypes.StoreKey],
app.GetSubspace(icahosttypes.SubModuleName),
app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack
app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper,
app.AccountKeeper,
scopedICAHostKeeper,
app.MsgServiceRouter(),
)
icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper)

// For wasmd we use the demo controller from https://github.com/cosmos/interchain-accounts but see notes below
app.InterTxKeeper = intertxkeeper.NewKeeper(appCodec, keys[intertxtypes.StoreKey], app.ICAControllerKeeper, scopedInterTxKeeper)
app.InterTxKeeper = intertxkeeper.NewKeeper(
appCodec,
keys[intertxtypes.StoreKey],
app.ICAControllerKeeper,
scopedInterTxKeeper,
)

var icaControllerStack porttypes.IBCModule
icaControllerStack = intertx.NewIBCModule(app.InterTxKeeper)
icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper)
icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper)

icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper)
icaHostStack := ibcfee.NewIBCMiddleware(icaHostIBCModule, app.IBCFeeKeeper)

// create evidence keeper with router
evidenceKeeper := evidencekeeper.NewKeeper(
Expand Down Expand Up @@ -635,51 +657,18 @@
govRouter.AddRoute(wasm.RouterKey, wasm.NewWasmProposalHandler(app.WasmKeeper, enabledProposals))
}

// Create Transfer Stack
var transferStack porttypes.IBCModule
transferStack = transfer.NewIBCModule(app.TransferKeeper)
transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper)
transferStack = router.NewIBCMiddleware(
transferStack,
&app.RouterKeeper,
0,
routerkeeper.DefaultForwardTransferPacketTimeoutTimestamp,
routerkeeper.DefaultRefundTransferPacketTimeoutTimestamp,
)
// Hooks Middleware
hooksTransferStack := ibchooks.NewIBCMiddleware(transferStack, &app.HooksICS4Wrapper)
app.TransferStack = &hooksTransferStack

// Create Interchain Accounts Stack
// SendPacket, since it is originating from the application to core IBC:
// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket

// Note: please do your research before using this in production app, this is a demo and not an officially
// supported IBC team implementation. Do your own research before using it.
var icaControllerStack porttypes.IBCModule
// You will likely want to use your own reviewed and maintained ica auth module
icaControllerStack = intertx.NewIBCModule(app.InterTxKeeper)
icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper)
icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper)

// RecvPacket, message that originates from core IBC and goes down to app, the flow is:
// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket
var icaHostStack porttypes.IBCModule
icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper)
icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper)

// Create fee enabled wasm ibc Stack
var wasmStack porttypes.IBCModule
wasmStack = wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper, app.IBCFeeKeeper)
wasmStack = ibcfee.NewIBCMiddleware(wasmStack, app.IBCFeeKeeper)

// Create static IBC router, add app routes, then set and seal it
ibcRouter := porttypes.NewRouter().
expertdicer marked this conversation as resolved.
Show resolved Hide resolved
AddRoute(ibctransfertypes.ModuleName, transferStack).
AddRoute(wasm.ModuleName, wasmStack).
AddRoute(intertxtypes.ModuleName, icaControllerStack).
AddRoute(icacontrollertypes.SubModuleName, icaControllerStack).
AddRoute(icahosttypes.SubModuleName, icaHostStack)
AddRoute(icahosttypes.SubModuleName, icaHostStack).
AddRoute(ibctransfertypes.ModuleName, pmfTransferStack).
AddRoute(wasm.ModuleName, wasmStack)
app.IBCKeeper.SetRouter(ibcRouter)

govConfig := govtypes.DefaultConfig()
Expand Down Expand Up @@ -1100,7 +1089,7 @@

for _, upgrade := range Upgrades {
if upgradeInfo.Name == upgrade.UpgradeName {
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &upgrade.StoreUpgrades))

Check failure on line 1092 in app/app.go

View workflow job for this annotation

GitHub Actions / lint

G601: Implicit memory aliasing in for loop. (gosec)
}
app.UpgradeKeeper.SetUpgradeHandler(
upgrade.UpgradeName,
Expand Down
15 changes: 15 additions & 0 deletions scripts/tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Tests

This folder contains the integration tests that should run successfully each time a new core release is created.

At the moment, there are four tests defined that can be run with `make integration-test-all`. The breakdown of each test is as follows:

- [init-test-framework](./start.sh): build the core and spin up two nodes with their own genesis event and some accounts preloaded with funds.
- [test-relayer](./relayer/): connect the two blockchains with a relayer opening a channel between both of them.
- [test-ica](./ica/delegate.sh): using the relayer, this test creates an interchain account and delegates funds using an interchain message.
- [test-ibc-hooks](./ibc-hooks/increment.sh): deploys a slightly modified [counter contract](./ibc-hooks/counter/) to chain test-2 and submits two requests from chain test-1 to validate that the contract received the funds and executed the wasm code correctly.
- remove-ica-data: removes the data and kills the process when the integration tests are completed.

## Development process

This set of tests must run out of the box in Linux-based systems installing [GoLang 1.20](https://go.dev/), [jq](https://stedolan.github.io/jq/), [screen](https://www.geeksforgeeks.org/screen-command-in-linux-with-examples/) and [rly](https://github.com/cosmos/relayer).
43 changes: 43 additions & 0 deletions scripts/tests/ibc-hooks/counter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
name = "counter"
description = "Cosmwasm counter dapp, with permissions for testing Osmosis wasmhooks"
version = "0.1.0"
authors = ["osmosis contributors"]
edition = "2021"

exclude = [
# Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication.
"contract.wasm",
"hash.txt",
]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib", "rlib"]

[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []

[package.metadata.scripts]
optimize = """docker run --rm -v "$(pwd)":/code \
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/rust-optimizer:0.12.6
"""

[dependencies]
cosmwasm-schema = "1.1.3"
cosmwasm-std = "1.1.3"
cosmwasm-storage = "1.1.3"
cw-storage-plus = "0.16.0"
cw2 = "0.16.0"
schemars = "0.8.10"
serde = { version = "1.0.145", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.31" }

[dev-dependencies]
cw-multi-test = "0.16.0"
11 changes: 11 additions & 0 deletions scripts/tests/ibc-hooks/counter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Counter contract from [Osmosis Labs](https://github.com/osmosis-labs/osmosis/commit/64393a14e18b2562d72a3892eec716197a3716c7)

This contract is a modification of the standard cosmwasm `counter` contract.
Namely, it tracks a counter, _by sender_.
This is a better way to test wasmhooks.

This contract tracks any funds sent to it by adding it to the state under the `sender` key.

This way we can verify that, independently of the sender, the funds will end up under the
`WasmHooksModuleAccount` address when the contract is executed via an IBC send that goes
through the wasmhooks module.
1 change: 1 addition & 0 deletions scripts/tests/ibc-hooks/counter/artifacts/checksums.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c0e7a3b40d9710f6f72322293ba5cd871714008d9accd9a91c0fb08272609054 counter.wasm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bffb3256d4fd5668e497ae5671844ef3dcdf1a5f2594747b894dfc02e243ab0e ./target/wasm32-unknown-unknown/release/counter.wasm
Binary file not shown.
Loading
Loading