diff --git a/x/wasm/internal/keeper/keeper.go b/x/wasm/internal/keeper/keeper.go index 774f483925..ce3f1bb4c3 100644 --- a/x/wasm/internal/keeper/keeper.go +++ b/x/wasm/internal/keeper/keeper.go @@ -3,8 +3,11 @@ package keeper import ( "bytes" "encoding/binary" + "fmt" "path/filepath" + xdebug "runtime/debug" + "github.com/cosmos/cosmos-sdk/x/staking" "github.com/pkg/errors" @@ -336,7 +339,13 @@ func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []b if err != nil { return nil, err } + // prepare querier + if nil == k.queryPlugins.Wasm { + fmt.Println("k.queryPlugins.Wasm is nil: \n" + string(xdebug.Stack())) + } + + fmt.Printf("keeper.go/QuerySmart/k.queryPlugins: %v\n", k.queryPlugins) querier := QueryHandler{ Ctx: ctx, Plugins: k.queryPlugins, diff --git a/x/wasm/internal/keeper/keeper_test.go b/x/wasm/internal/keeper/keeper_test.go index d75d0007c4..d85bd2efcd 100644 --- a/x/wasm/internal/keeper/keeper_test.go +++ b/x/wasm/internal/keeper/keeper_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "encoding/json" + "fmt" "io/ioutil" "os" "testing" @@ -869,3 +870,30 @@ func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) { addr := sdk.AccAddress(pub.Address()) return key, pub, addr } + +func TestOOMKillsInfiniteQueryLoopEithan(t *testing.T) { + tempDir, err := ioutil.TempDir("", "wasm") + require.NoError(t, err) + ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil) + accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + walletA := createFakeFundedAccount(ctx, accKeeper, deposit.Add(deposit...)) + + wasmCode, err := ioutil.ReadFile("./testdata/test-contract/contract.wasm.gz") + require.NoError(t, err) + + codeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") + require.NoError(t, err) + defer os.RemoveAll(tempDir) + + // init + + contractAddress, _ := keeper.Instantiate(ctx, codeID, walletA, nil, []byte(`{"nop":{}}`), "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) + + // infinite external query loop + + _, err = keeper.QuerySmart(ctx, contractAddress, []byte(fmt.Sprintf(`{"send_external_query_infinite_loop":{"to":"%s"}}`, contractAddress.String()))) + + require.Error(t, err) +} diff --git a/x/wasm/internal/keeper/testdata/test-contract/.gitignore b/x/wasm/internal/keeper/testdata/test-contract/.gitignore new file mode 100644 index 0000000000..10fe5d6150 --- /dev/null +++ b/x/wasm/internal/keeper/testdata/test-contract/.gitignore @@ -0,0 +1,12 @@ +# Build results +/target + +# Text file backups +**/*.rs.bk + +# macOS +.DS_Store + +# IDEs +*.iml +.idea diff --git a/x/wasm/internal/keeper/testdata/test-contract/Cargo.lock b/x/wasm/internal/keeper/testdata/test-contract/Cargo.lock new file mode 100644 index 0000000000..b96f27b590 --- /dev/null +++ b/x/wasm/internal/keeper/testdata/test-contract/Cargo.lock @@ -0,0 +1,245 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "backtrace" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cosmwasm-std" +version = "0.9.1" +source = "git+https://github.com/CosmWasm/cosmwasm?tag=v0.9.1#a18591c0ae3a069f7d6246f2cab0cbfdfda7053b" +dependencies = [ + "base64", + "schemars", + "serde", + "serde-json-wasm", + "snafu", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "gimli" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + +[[package]] +name = "libc" +version = "0.2.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" + +[[package]] +name = "miniz_oxide" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" + +[[package]] +name = "proc-macro2" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "schemars" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be77ed66abed6954aabf6a3e31a84706bedbf93750d267e92ef4a6d90bbd6a61" +dependencies = [ + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11af7a475c9ee266cfaa9e303a47c830ebe072bf3101ab907a7b7b9d816fa01d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "serde" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7294d94d390f1d2334697c065ea591d7074c676e2d20aa6f1df752fced29823f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "snafu" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5aed652511f5c9123cf2afbe9c244c29db6effa2abb05c866e965c82405ce" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebf8f7d5720104a9df0f7076a8682024e958bba0fe9848767bb44f251f3648e9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "test-contract" +version = "0.0.1" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/x/wasm/internal/keeper/testdata/test-contract/Cargo.toml b/x/wasm/internal/keeper/testdata/test-contract/Cargo.toml new file mode 100644 index 0000000000..95e41b5e0e --- /dev/null +++ b/x/wasm/internal/keeper/testdata/test-contract/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "test-contract" +version = "0.0.1" +authors = ["Enigma "] +edition = "2018" +description = "A Test contract intended to use in system tests for the Secret Netowrk" +license = "MIT" +exclude = [ + # Those files are cosmwasm-opt 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"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +default = ["backtraces"] +backtraces = ["cosmwasm-std/backtraces"] + +[dependencies] +cosmwasm-std = { git = "https://github.com/CosmWasm/cosmwasm", tag = "v0.9.1" } +schemars = "0.7" +serde = { version = "1.0.114", default-features = false, features = [ + "derive", + "alloc" +] } +# serde-json-wasm = "0.2.1" diff --git a/x/wasm/internal/keeper/testdata/test-contract/Makefile b/x/wasm/internal/keeper/testdata/test-contract/Makefile new file mode 100644 index 0000000000..d1928422af --- /dev/null +++ b/x/wasm/internal/keeper/testdata/test-contract/Makefile @@ -0,0 +1,8 @@ +all: + RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown --locked + wasm-opt -Os ./target/wasm32-unknown-unknown/release/test_contract.wasm -o ./contract.wasm + cat contract.wasm | gzip -9 > ./contract.wasm.gz + +clean: + cargo clean + -rm -f ./contract.wasm ./contract.wasm.gz \ No newline at end of file diff --git a/x/wasm/internal/keeper/testdata/test-contract/README.md b/x/wasm/internal/keeper/testdata/test-contract/README.md new file mode 100644 index 0000000000..6f604781c3 --- /dev/null +++ b/x/wasm/internal/keeper/testdata/test-contract/README.md @@ -0,0 +1 @@ +Just `make`. :rainbow: diff --git a/x/wasm/internal/keeper/testdata/test-contract/contract.wasm b/x/wasm/internal/keeper/testdata/test-contract/contract.wasm new file mode 100644 index 0000000000..11f6d30d30 Binary files /dev/null and b/x/wasm/internal/keeper/testdata/test-contract/contract.wasm differ diff --git a/x/wasm/internal/keeper/testdata/test-contract/contract.wasm.gz b/x/wasm/internal/keeper/testdata/test-contract/contract.wasm.gz new file mode 100644 index 0000000000..54643bb10c Binary files /dev/null and b/x/wasm/internal/keeper/testdata/test-contract/contract.wasm.gz differ diff --git a/x/wasm/internal/keeper/testdata/test-contract/src/contract.rs b/x/wasm/internal/keeper/testdata/test-contract/src/contract.rs new file mode 100644 index 0000000000..f378c8458b --- /dev/null +++ b/x/wasm/internal/keeper/testdata/test-contract/src/contract.rs @@ -0,0 +1,101 @@ +use cosmwasm_std::{ + Api, Binary, Env, Extern, HandleResponse, HandleResult, HumanAddr, InitResponse, InitResult, + MigrateResponse, Querier, QueryRequest, QueryResult, StdResult, Storage, WasmQuery, +}; + +/////////////////////////////// Messages /////////////////////////////// + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum InitMsg { + Nop {}, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum HandleMsg {} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum QueryMsg { + SendExternalQueryInfiniteLoop { to: HumanAddr }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum MigrateMsg {} + +/////////////////////////////// Init /////////////////////////////// + +pub fn init( + _deps: &mut Extern, + _env: Env, + msg: InitMsg, +) -> InitResult { + match msg { + InitMsg::Nop {} => Ok(InitResponse { + messages: vec![], + log: vec![], + }), + } +} + +/////////////////////////////// Handle /////////////////////////////// + +pub fn handle( + _deps: &mut Extern, + _env: Env, + _msg: HandleMsg, +) -> HandleResult { + Ok(HandleResponse { + messages: vec![], + log: vec![], + data: None, + }) +} + +/////////////////////////////// Query /////////////////////////////// + +pub fn query(deps: &Extern, msg: QueryMsg) -> QueryResult { + match msg { + QueryMsg::SendExternalQueryInfiniteLoop { to } => { + send_external_query_infinite_loop(deps, to) + } + } +} + +fn send_external_query_infinite_loop( + deps: &Extern, + contract_addr: HumanAddr, +) -> QueryResult { + let answer = deps + .querier + .query::(&QueryRequest::Wasm(WasmQuery::Smart { + contract_addr: contract_addr.clone(), + msg: Binary( + format!( + r#"{{"send_external_query_infinite_loop":{{"to":"{}"}}}}"#, + contract_addr.clone().to_string() + ) + .into(), + ), + })); + + match answer { + Ok(wtf) => Ok(Binary(wtf.into())), + Err(e) => Err(e), + } +} + +/////////////////////////////// Migrate /////////////////////////////// + +pub fn migrate( + _deps: &mut Extern, + _env: Env, + _msg: MigrateMsg, +) -> StdResult { + Ok(MigrateResponse::default()) +} diff --git a/x/wasm/internal/keeper/testdata/test-contract/src/lib.rs b/x/wasm/internal/keeper/testdata/test-contract/src/lib.rs new file mode 100644 index 0000000000..a31cbfcbef --- /dev/null +++ b/x/wasm/internal/keeper/testdata/test-contract/src/lib.rs @@ -0,0 +1,47 @@ +pub mod contract; + +#[cfg(target_arch = "wasm32")] +mod wasm { + use super::contract; + use cosmwasm_std::{ + do_handle, do_init, do_migrate, do_query, ExternalApi, ExternalQuerier, ExternalStorage, + }; + + #[no_mangle] + extern "C" fn init(env_ptr: u32, msg_ptr: u32) -> u32 { + do_init( + &contract::init::, + env_ptr, + msg_ptr, + ) + } + + #[no_mangle] + extern "C" fn handle(env_ptr: u32, msg_ptr: u32) -> u32 { + do_handle( + &contract::handle::, + env_ptr, + msg_ptr, + ) + } + + #[no_mangle] + extern "C" fn migrate(env_ptr: u32, msg_ptr: u32) -> u32 { + do_migrate( + &contract::migrate::, + env_ptr, + msg_ptr, + ) + } + + #[no_mangle] + extern "C" fn query(msg_ptr: u32) -> u32 { + do_query( + &contract::query::, + msg_ptr, + ) + } + + // Other C externs like cosmwasm_vm_version_1, allocate, deallocate are available + // automatically because we `use cosmwasm_std`. +}