diff --git a/Makefile b/Makefile index 9bba5d15e..5e88cfd43 100644 --- a/Makefile +++ b/Makefile @@ -468,7 +468,7 @@ update-swagger-openapi-docs: statik proto-swagger-openapi-gen # proto-check-breaking: # @buf check breaking --against-input '.git#branch=master' -protoVer=v0.7 +protoVer=v0.2 proto-all: proto-format proto-lint proto-gen proto-swagger-openapi-gen diff --git a/app/app.go b/app/app.go index e2c7eff33..fea7de6f1 100644 --- a/app/app.go +++ b/app/app.go @@ -432,6 +432,10 @@ func NewSecretNetworkApp( app.distrKeeper, app.mintKeeper, app.stakingKeeper, + app.capabilityKeeper.ScopeToModule(compute.ModuleName), + app.ibcKeeper.PortKeeper, + app.transferKeeper, + app.ibcKeeper.ChannelKeeper, computeRouter, computeDir, computeConfig, diff --git a/cosmwasm/Cargo.lock b/cosmwasm/Cargo.lock index 6b43f5541..59454256d 100644 --- a/cosmwasm/Cargo.lock +++ b/cosmwasm/Cargo.lock @@ -1077,6 +1077,7 @@ dependencies = [ "schemars 0.8.8", "serde", "serde-json-wasm 0.3.2", + "snafu", "thiserror", "uint", ] diff --git a/cosmwasm/contracts/burner/Cargo.toml b/cosmwasm/contracts/burner/Cargo.toml index 39141d838..70449d164 100644 --- a/cosmwasm/contracts/burner/Cargo.toml +++ b/cosmwasm/contracts/burner/Cargo.toml @@ -31,7 +31,7 @@ cranelift = ["cosmwasm-vm/cranelift"] backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std", features = ["iterator"] } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1", features = ["iterator"] } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/cosmwasm/contracts/debug-print/Cargo.toml b/cosmwasm/contracts/debug-print/Cargo.toml index f99f64bb8..c449abdc1 100644 --- a/cosmwasm/contracts/debug-print/Cargo.toml +++ b/cosmwasm/contracts/debug-print/Cargo.toml @@ -32,7 +32,7 @@ default = [] backtraces = ["cosmwasm-std/backtraces"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std", features = ["iterator", "debug-print"] } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1", features = ["iterator", "debug-print"] } schemars = "0.7" serde = { version = "1.0.103", default-features = false, features = ["derive"] } #snafu = { version = "0.6.3" } diff --git a/cosmwasm/contracts/dist/Cargo.toml b/cosmwasm/contracts/dist/Cargo.toml index 9d3d87211..a076501e8 100644 --- a/cosmwasm/contracts/dist/Cargo.toml +++ b/cosmwasm/contracts/dist/Cargo.toml @@ -31,8 +31,8 @@ overflow-checks = true default = [] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std" } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.7" serde = { version = "=1.0.103", default-features = false, features = [ "derive" diff --git a/cosmwasm/contracts/erc20/Cargo.toml b/cosmwasm/contracts/erc20/Cargo.toml index e57f5fad7..91be1f16f 100644 --- a/cosmwasm/contracts/erc20/Cargo.toml +++ b/cosmwasm/contracts/erc20/Cargo.toml @@ -36,8 +36,8 @@ cranelift = ["cosmwasm-vm/default-cranelift"] singlepass = ["cosmwasm-vm/default-singlepass"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std" } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.7" serde = { version = "1.0.103", default-features = false, features = ["derive"] } hex = "0.4" diff --git a/cosmwasm/contracts/escrow/Cargo.toml b/cosmwasm/contracts/escrow/Cargo.toml index 1960ad68c..ce3b88b1d 100644 --- a/cosmwasm/contracts/escrow/Cargo.toml +++ b/cosmwasm/contracts/escrow/Cargo.toml @@ -36,8 +36,8 @@ cranelift = ["cosmwasm-vm/default-cranelift"] singlepass = ["cosmwasm-vm/default-singlepass"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std" } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.7" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/cosmwasm/contracts/gov/Cargo.toml b/cosmwasm/contracts/gov/Cargo.toml index 1257e1d8e..9e4fd261f 100644 --- a/cosmwasm/contracts/gov/Cargo.toml +++ b/cosmwasm/contracts/gov/Cargo.toml @@ -31,8 +31,8 @@ overflow-checks = true default = [] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std" } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.7" serde = { version = "1", default-features = false, features = [ "derive" diff --git a/cosmwasm/contracts/hackatom/Cargo.toml b/cosmwasm/contracts/hackatom/Cargo.toml index fe80d4cc6..0472ac0d8 100644 --- a/cosmwasm/contracts/hackatom/Cargo.toml +++ b/cosmwasm/contracts/hackatom/Cargo.toml @@ -30,7 +30,7 @@ cranelift = ["cosmwasm-vm/cranelift"] backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std", default-features = false } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1", default-features = false } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } sha2 = "0.9.1" @@ -38,5 +38,5 @@ thiserror = "1.0" [dev-dependencies] cosmwasm-schema = { path = "../../packages/schema" } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } cosmwasm-vm = { path = "../../packages/sgx-vm", package = "cosmwasm-sgx-vm", default-features = false } diff --git a/cosmwasm/contracts/mint/Cargo.toml b/cosmwasm/contracts/mint/Cargo.toml index 98ccf517e..f0ed7feeb 100644 --- a/cosmwasm/contracts/mint/Cargo.toml +++ b/cosmwasm/contracts/mint/Cargo.toml @@ -31,8 +31,8 @@ overflow-checks = true default = [] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std" } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1"} +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.7" serde = { version = "=1.0.103", default-features = false, features = [ "derive" diff --git a/cosmwasm/contracts/plaintext-logs/Cargo.toml b/cosmwasm/contracts/plaintext-logs/Cargo.toml index 5da3772ca..c653fab65 100644 --- a/cosmwasm/contracts/plaintext-logs/Cargo.toml +++ b/cosmwasm/contracts/plaintext-logs/Cargo.toml @@ -32,7 +32,7 @@ default = [] backtraces = ["cosmwasm-std/backtraces"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std", features = ["iterator"] } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1", features = ["iterator"] } schemars = "0.7" serde = { version = "1.0.103", default-features = false, features = ["derive"] } #snafu = { version = "0.6.3" } diff --git a/cosmwasm/contracts/queue/Cargo.toml b/cosmwasm/contracts/queue/Cargo.toml index 03a3c4d0b..eed841075 100644 --- a/cosmwasm/contracts/queue/Cargo.toml +++ b/cosmwasm/contracts/queue/Cargo.toml @@ -32,7 +32,7 @@ backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] library = [] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std", features = ["iterator"] } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1", features = ["iterator"] } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/cosmwasm/contracts/reflect/Cargo.toml b/cosmwasm/contracts/reflect/Cargo.toml index 50cb1208c..0e7f1af9f 100644 --- a/cosmwasm/contracts/reflect/Cargo.toml +++ b/cosmwasm/contracts/reflect/Cargo.toml @@ -33,8 +33,8 @@ cranelift = ["cosmwasm-vm/cranelift"] backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std", features = ["staking"] } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1", features = ["staking"] } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.8.1" serde = { version = "^1.0.117", default-features = false, features = [ "derive" diff --git a/cosmwasm/contracts/staking/Cargo.toml b/cosmwasm/contracts/staking/Cargo.toml index ae8f6d10d..9b01dd070 100644 --- a/cosmwasm/contracts/staking/Cargo.toml +++ b/cosmwasm/contracts/staking/Cargo.toml @@ -31,8 +31,8 @@ cranelift = ["cosmwasm-vm/cranelift"] backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] [dependencies] -cosmwasm-std = { path = "../../packages/std", package = "secret-cosmwasm-std",features = ["staking"] } -cosmwasm-storage = { path = "../../packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1", features = ["staking"] } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } snafu = "0.6" diff --git a/cosmwasm/enclaves/Cargo.lock b/cosmwasm/enclaves/Cargo.lock index 3a7582683..487a9abcb 100644 --- a/cosmwasm/enclaves/Cargo.lock +++ b/cosmwasm/enclaves/Cargo.lock @@ -452,6 +452,7 @@ dependencies = [ "enclave_cosmwasm_types", "enclave_crypto", "log", + "num_enum", "prost", "protobuf", "serde 1.0.118", @@ -501,7 +502,7 @@ dependencies = [ "log", "ring", "ripemd160", - "secp256k1 0.19.0", + "secp256k1", "sgx_trts 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", "sgx_tstd 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", "sgx_types 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", @@ -739,6 +740,27 @@ dependencies = [ "autocfg 1.1.0", ] +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "opaque-debug" version = "0.2.3" @@ -763,6 +785,16 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + [[package]] name = "proc-macro2" version = "1.0.36" @@ -962,25 +994,7 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c42e6f1735c5f00f51e43e28d6634141f2bcad10931b2609ddd74a86d751260" dependencies = [ - "secp256k1-sys 0.3.0", -] - -[[package]] -name = "secp256k1" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" -dependencies = [ - "secp256k1-sys 0.4.2", -] - -[[package]] -name = "secp256k1-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" -dependencies = [ - "cc", + "secp256k1-sys", ] [[package]] diff --git a/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs b/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs index d963c12b3..0ae80be4d 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs @@ -8,11 +8,12 @@ use cosmwasm_v010_types::encoding::Binary; use cosmwasm_v010_types::types::CanonicalAddr; use cosmwasm_v016_types::addresses::Addr; use cosmwasm_v016_types::timestamp::Timestamp; -use enclave_cosmos_types::types::{ContractCode, SigInfo}; +use enclave_cosmos_types::types::{ContractCode, SigInfo, HandleType}; use enclave_cosmwasm_types as cosmwasm_v010_types; use enclave_cosmwasm_v016_types as cosmwasm_v016_types; use enclave_crypto::Ed25519PublicKey; use enclave_utils::coalesce; +use cosmos_proto::tx::signing::SignMode; use super::contract_validation::{ extract_contract_key, generate_encryption_key, validate_contract_key, validate_msg, @@ -21,7 +22,7 @@ use super::contract_validation::{ use super::gas::WasmCosts; use super::io::encrypt_output; use super::module_cache::create_module_instance; -use super::types::{IoNonce, SecretMessage}; +use super::types::{IoNonce, SecretMessage, Reply, SubMsgResult, SubMsgResponse}; use super::wasm::{ContractInstance, ContractOperation, Engine}; /* @@ -148,6 +149,86 @@ pub fn init( }) } +// Parse the message that was passed to handle (Based on the assumption that it might be a reply or IBC as well) +pub fn parse_message( + message: &[u8], + sig_info: &SigInfo, + handle_type: &HandleType, +) -> Result<(SecretMessage, Vec), EnclaveError> { + let orig_secret_msg = SecretMessage::from_slice(message)?; + + return match handle_type { + HandleType::HANDLE_TYPE_EXECUTE => { + trace!("handle input before decryption: {:?}", base64::encode(&message)); + let decrypted_msg = orig_secret_msg.decrypt()?; + Ok((orig_secret_msg, decrypted_msg)) + }, + HandleType::HANDLE_TYPE_REPLY => { + if sig_info.sign_mode == SignMode::SIGN_MODE_UNSPECIFIED { + trace!("reply input is not encrypted"); + let decrypted_msg = orig_secret_msg.msg.clone(); + + return Ok((orig_secret_msg, decrypted_msg)); + } + + // Here we are sure the reply is OK because only OK is encrypted + trace!("reply input before decryption: {:?}", base64::encode(&message)); + let parsed_encrypted_reply: Reply = serde_json::from_slice(&orig_secret_msg.msg).map_err(|err| { + warn!( + "reply got an error while trying to deserialize msg input bytes into json {:?}: {}", + String::from_utf8_lossy(&orig_secret_msg.msg), + err + ); + EnclaveError::FailedToDeserialize + })?; + match parsed_encrypted_reply.result { + SubMsgResult::Ok(response) => { + let data = response.data.unwrap(); + + // First decrypt the message and then create new decrypted reply + let tmp_secret_msg = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: data.as_slice().to_vec() + }; + + let tmp_decrypted_msg = tmp_secret_msg.decrypt()?; + + // Now we need to create synthetic SecretMessage to fit the API in "handle" + let result = SubMsgResult::Ok(SubMsgResponse { + events: response.events, + data: Some(Binary(tmp_decrypted_msg)), + }); + let decrypted_reply = Reply { + id: parsed_encrypted_reply.id, + result + }; + + let decrypted_reply_as_vec = serde_json::to_vec(&decrypted_reply).map_err(|err| { + warn!( + "got an error while trying to serialize reply into bytes {:?}: {}", + decrypted_reply, err + ); + EnclaveError::FailedToSerialize + })?; + + let secret_msg = SecretMessage { + nonce: tmp_secret_msg.nonce, + user_public_key: tmp_secret_msg.user_public_key, + msg: decrypted_reply_as_vec.clone() + }; + + Ok((secret_msg, decrypted_reply_as_vec)) + }, + SubMsgResult::Err(_) => { + warn!("got an error while trying to deserialize reply, error should not be encrypted"); + Err(EnclaveError::FailedToDeserialize) + } + } + }, + } +} + pub fn handle( context: Ctx, gas_limit: u64, @@ -156,6 +237,7 @@ pub fn handle( env: &[u8], msg: &[u8], sig_info: &[u8], + handle_type: u8 ) -> Result { let contract_code = ContractCode::new(contract); @@ -197,15 +279,15 @@ pub fn handle( EnclaveError::FailedToDeserialize })?; - trace!("handle input before decryption: {:?}", base64::encode(&msg)); - let secret_msg = SecretMessage::from_slice(msg)?; + // The flow of handle is now used for multiple messages (such ash Handle, Reply) + // When the message is handle, we expect it always to be encrypted while in Reply for example it might be plaintext + let parsed_handle_type : HandleType = handle_type.try_into(); + + let (secret_msg, decrypted_msg) = parse_message(msg, &parsed_sig_info, &parsed_handle_type)?; // Verify env parameters against the signed tx verify_params(&parsed_sig_info, &env_v010, &secret_msg)?; - let secret_msg = SecretMessage::from_slice(msg)?; - let decrypted_msg = secret_msg.decrypt()?; - let validated_msg = validate_msg(&decrypted_msg, contract_code.hash())?; trace!( @@ -217,6 +299,9 @@ pub fn handle( trace!("Handle: Contract Key: {:?}", hex::encode(contract_key)); + // Although the operation here is not always handle it is irrelevant in this case + // because it only helps to decide whether to check floating points or not + // In this case we want to do the same as in Handle both for Reply and for others so we can always pass "Handle". let mut engine = start_engine( context, gas_limit, @@ -237,7 +322,7 @@ pub fn handle( // This wrapper is used to coalesce all errors in this block to one object // so we can `.map_err()` in one place for all of them let output = coalesce!(EnclaveError, { - let vec_ptr = engine.handle(env_ptr, msg_info_ptr, msg_ptr)?; + let vec_ptr = engine.handle(env_ptr, msg_info_ptr, msg_ptr, parsed_handle_type)?; let output = engine.extract_vector(vec_ptr)?; diff --git a/cosmwasm/enclaves/shared/contract-engine/src/external/ecalls.rs b/cosmwasm/enclaves/shared/contract-engine/src/external/ecalls.rs index 66319a022..8b94d4684 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/external/ecalls.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/external/ecalls.rs @@ -244,6 +244,7 @@ pub unsafe extern "C" fn ecall_handle( msg_len: usize, sig_info: *const u8, sig_info_len: usize, + handle_type: u8, ) -> HandleResult { let _recursion_guard = match recursion_depth::guard() { Ok(rg) => rg, @@ -285,6 +286,7 @@ pub unsafe extern "C" fn ecall_handle( env, msg, sig_info, + handle_type, ); *used_gas = local_used_gas; result_handle_success_to_handleresult(result) diff --git a/cosmwasm/enclaves/shared/contract-engine/src/types.rs b/cosmwasm/enclaves/shared/contract-engine/src/types.rs index 69307d575..c934ee851 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/types.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/types.rs @@ -5,9 +5,39 @@ use enclave_crypto::{AESKey, Ed25519PublicKey, SIVEncryptable}; use enclave_ffi_types::EnclaveError; use super::io::calc_encryption_key; +use enclave_cosmwasm_v016_types::results::Event; +use enclave_cosmwasm_types::encoding::Binary; pub type IoNonce = [u8; 32]; +/// The information we get back from a successful sub message execution, +/// with full Cosmos SDK events. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct SubMsgResponse { + pub events: Vec, + pub data: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum SubMsgResult { + Ok(SubMsgResponse), + /// An error type that every custom error created by contract developers can be converted to. + /// This could potentially have more structure, but String is the easiest. + #[serde(rename = "error")] + Err(String), +} + +/// The result object returned to `reply`. We always get the ID from the submessage +/// back and then must handle success and error cases ourselves. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct Reply { + /// The ID that the contract set when emitting the `SubMsg`. + /// Use this to identify which submessage triggered the `reply`. + pub id: u64, + pub result: SubMsgResult, +} + #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct SecretMessage { pub nonce: IoNonce, diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs index 5637c1dd3..95d5e1b7a 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use bech32::{FromBase32, ToBase32}; use log::*; use rand_chacha::ChaChaRng; @@ -23,7 +21,6 @@ use crate::gas::WasmCosts; use crate::query_chain::encrypt_and_query_chain; use crate::types::IoNonce; use crate::wasm::traits::WasmiApi; -use secp256k1::Secp256k1; /// api_marker is based on this compatibility chart: /// https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/vm/README.md#compatibility @@ -864,169 +861,6 @@ impl WasmiApi for ContractInstance { self.humanize_address(canonical_ptr, human_ptr) } - // This was added in v1 (v0.14?) but we're also backporting it to v0.10 - // to support easy migration from a crate to this API for existing v0.10 - // contracts. - fn secp256k1_verify( - &mut self, - message_hash_ptr: i32, - signature_ptr: i32, - public_key_ptr: i32, - ) -> Result, Trap> { - self.use_gas_externally(self.gas_costs.external_secp256k1_verify as u64)?; - - let message_hash_data = self - .extract_vector(message_hash_ptr as u32) - .map_err(|err| { - debug!( - "secp256k1_verify() error while trying to read message_hash from wasm memory" - ); - err - })?; - let signature_data = self.extract_vector(signature_ptr as u32).map_err(|err| { - debug!("secp256k1_verify() error while trying to read signature from wasm memory"); - err - })?; - let public_key = self.extract_vector(public_key_ptr as u32).map_err(|err| { - debug!("secp256k1_verify() error while trying to read public_key from wasm memory"); - err - })?; - - trace!( - "secp256k1_verify() was called from WASM code with message_hash {:x?} (len {:?} should be 32)", - &message_hash_data, - message_hash_data.len() - ); - trace!( - "secp256k1_verify() was called from WASM code with signature {:x?} (len {:?} should be 64)", - &signature_data, - signature_data.len() - ); - trace!( - "secp256k1_verify() was called from WASM code with public_key {:x?} (len {:?} should be 33 or 65)", - &public_key, - public_key.len() - ); - - // check message_hash input - if message_hash_data.len() != 32 { - // return 3 == InvalidHashFormat - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/crypto/src/errors.rs#L93 - Ok(Some(RuntimeValue::I32(3))) - } - - // check signature input - if !signature_data.len() != 64 { - // return 4 == InvalidSignatureFormat - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/crypto/src/errors.rs#L94 - Ok(Some(RuntimeValue::I32(4))) - } - - // check pubkey input - if !match public_key.first() { - // compressed - Some(0x02) | Some(0x03) => data.len() == 33, - // uncompressed - Some(0x04) => data.len() == 65, - // hybrid - // see https://docs.rs/secp256k1-abc-sys/0.1.2/secp256k1_abc_sys/fn.secp256k1_ec_pubkey_parse.html - Some(0x06) | Some(0x07) => data.len() == 65, - _ => false, - } { - // return 5 == InvalidPubkeyFormat - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/crypto/src/errors.rs#L95 - Ok(Some(RuntimeValue::I32(5))) - } - - let secp256k1_msg = match secp256k1::Message::from_slice(&message_hash_data) { - Err(err) => { - debug!("secp256k1_verify() failed to create a secp256k1 message from message_hash: {:?}", err); - - // return 10 == GenericErr - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/crypto/src/errors.rs#L98 - return Ok(Some(RuntimeValue::I32(10))); - } - Ok(x) => x, - }; - - let secp256k1_sig = match secp256k1::Signature::from_compact(&signature_data) { - Err(err) => { - debug!("secp256k1_verify() malformed signature: {:?}", err); - - // return 10 == GenericErr - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/crypto/src/errors.rs#L98 - return Ok(Some(RuntimeValue::I32(10))); - } - Ok(x) => x, - }; - - let secp256k1_pk = match secp256k1::PublicKey::from_slice(public_key.as_slice()) { - Err(err) => { - debug!("secp256k1_verify() malformed pubkey: {:?}", err); - - // return 10 == GenericErr - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/crypto/src/errors.rs#L98 - return Ok(Some(RuntimeValue::I32(10))); - } - Ok(x) => x, - }; - - match Secp256k1::verification_only().verify(&secp256k1_msg, &secp256k1_sig, &secp256k1_pk) { - Err(err) => { - debug!("secp256k1_verify() failed to verify signatures: {:?}", err); - - // return 1 == failed, invalid signature - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/vm/src/imports.rs#L220 - return Ok(Some(RuntimeValue::I32(1))); - } - Ok(()) => { - // return 0 == success, valid signature - // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta5/packages/vm/src/imports.rs#L220 - return Ok(Some(RuntimeValue::I32(0))); - } - } - } - - fn secp256k1_recover_pubkey( - &mut self, - message_hash_ptr: i32, - signature_ptr: i32, - recovery_param: i32, - ) -> Result, Trap> { - // self.use_gas_externally(self.gas_costs.external_secp256k1_recover_pubkey as u64)?; - - // todo!() - Ok(None) - } - - fn ed25519_verify( - &mut self, - message_ptr: i32, - signature_ptr: i32, - public_key_ptr: i32, - ) -> Result, Trap> { - // self.use_gas_externally(self.gas_costs.external_ed25519_verify as u64)?; - - // todo!() - Ok(None) - } - - fn ed25519_batch_verify( - &mut self, - messages_ptr: i32, - signatures_ptr: i32, - public_keys_ptr: i32, - ) -> Result, Trap> { - // let signatures_count = todo!(); - - // self.use_gas_externally( - // signatures_count * self.gas_costs.external_ed25519_batch_verify_per_one as u64, - // )?; - - // todo!(); - Ok(None) - } - /// Debug prints from the contract while in testnet fn debug(&mut self, message_ptr: i32) -> Result, Trap> { let message_bytes = self.extract_vector(message_ptr as u32).map_err(|err| { diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs index e05cbb449..057ce993d 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs @@ -6,6 +6,7 @@ use enclave_ffi_types::EnclaveError; use super::contract::{ContractInstance, CosmWasmApiVersion}; use crate::errors::{wasmi_error_to_enclave_error, WasmEngineError}; +use enclave_cosmos_types::types::HandleType; pub struct Engine { pub contract_instance: ContractInstance, @@ -93,6 +94,7 @@ impl Engine { env_ptr: u32, msg_info_ptr: u32, msg_ptr: u32, + handle_type: HandleType ) -> Result { info!("Invoking handle() in wasm"); @@ -130,14 +132,25 @@ impl Engine { RuntimeValue::I32(msg_ptr as i32), ], ), - CosmWasmApiVersion::V1 => ( - "execute", - vec![ - RuntimeValue::I32(env_ptr as i32), - RuntimeValue::I32(msg_info_ptr as i32), - RuntimeValue::I32(msg_ptr as i32), - ], - ), + CosmWasmApiVersion::V1 => { + match handle_type { + HandleType::HANDLE_TYPE_EXECUTE => ( + "execute", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_info_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), + HandleType::HANDLE_TYPE_REPLY => ( + "reply", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), + } + }, }; match self @@ -147,7 +160,7 @@ impl Engine { { Some(RuntimeValue::I32(offset)) => Ok(offset as u32), other => { - warn!("handle method returned value which wasn't u32: {:?}", other); + warn!("{} method returned value which wasn't u32: {:?}",func_name, other); Err(EnclaveError::FailedFunctionCall) } } diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/externals.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/externals.rs index d84c0bc18..8092d4b39 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/externals.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/externals.rs @@ -93,7 +93,7 @@ impl Externals for ContractInstance { warn!("read_db() error reading argument, stopping wasm: {:?}", err); err })?; - self.db_read(key) + self.read_db(key) } HostFunctions::DbRemoveIndex => { let key: i32 = args.nth_checked(0).map_err(|err| { @@ -226,22 +226,6 @@ impl Externals for ContractInstance { self.addr_humanize(canonical, human) } - HostFunctions::Secp256k1Verify => { - let message_hash = args.nth_checked(0).map_err(|err| { - warn!( - "secp256k1_verify() error reading 1st argument, stopping wasm: {:?}", - err - ); - err - })?; - let signature = args.nth_checked(1).map_err(|err| { - warn!( - "secp256k1_verify() error reading 2nd argument, stopping wasm: {:?}", - err - ); - err - })?; - } HostFunctions::Secp256k1VerifyIndex => { let message_hash = args.nth_checked(0).map_err(|err| { warn!( diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/import_resolver.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/import_resolver.rs index ed82786cf..c83181631 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/import_resolver.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/import_resolver.rs @@ -83,47 +83,12 @@ impl ModuleImportResolver for WasmiImportResolver { Signature::new(&[ValueType::I32][..], Some(ValueType::I32)), HostFunctions::AddrValidateIndex.into(), ), - // fn secp256k1_verify(message_hash_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32; - // v0.16 - "secp256k1_verify" => FuncInstance::alloc_host( - Signature::new( - &[ValueType::I32, ValueType::I32, ValueType::I32][..], - Some(ValueType::I32), - ), - HostFunctions::Secp256k1Verify.into(), - ), - // fn secp256k1_recover_pubkey(message_hash_ptr: u32, signature_ptr: u32, recovery_param: u32) -> u64; - // v0.16 - "secp256k1_recover_pubkey" => FuncInstance::alloc_host( - Signature::new( - &[ValueType::I32, ValueType::I32, ValueType::I32][..], - Some(ValueType::I64), - ), - HostFunctions::Secp256k1RecoverPubkey.into(), - ), - // fn ed25519_verify(message_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32; - // v0.16 - "ed25519_verify" => FuncInstance::alloc_host( - Signature::new( - &[ValueType::I32, ValueType::I32, ValueType::I32][..], - Some(ValueType::I32), - ), - HostFunctions::Ed25519Verify.into(), - ), - // fn ed25519_batch_verify(messages_ptr: u32, signatures_ptr: u32, public_keys_ptr: u32) -> u32; - // v0.16 - "ed25519_batch_verify" => FuncInstance::alloc_host( - Signature::new( - &[ValueType::I32, ValueType::I32, ValueType::I32][..], - Some(ValueType::I32), - ), - HostFunctions::Ed25519BatchVerify.into(), - ), // fn debug(source_ptr: u32); // v0.16 + #[cfg(feature = "debug-print")] "debug" => FuncInstance::alloc_host( Signature::new(&[ValueType::I32][..], None), - HostFunctions::Debug.into(), + HostFunctions::DebugPrintIndex.into(), ), #[cfg(feature = "debug-print")] "debug_print" => FuncInstance::alloc_host( diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/traits.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/traits.rs index cc320bcd3..f8cd39c49 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/traits.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/traits.rs @@ -90,38 +90,6 @@ pub trait WasmiApi { #[cfg(feature = "debug-print")] fn debug_print_index(&self, message: i32) -> Result, Trap>; - /// CosmWasm v0.10 + v1 - fn secp256k1_verify( - &mut self, - message_hash_ptr: i32, - signature_ptr: i32, - public_key_ptr: i32, - ) -> Result, Trap>; - - /// CosmWasm v0.10 + v1 - fn secp256k1_recover_pubkey( - &mut self, - message_hash_ptr: i32, - signature_ptr: i32, - recovery_param: i32, - ) -> Result, Trap>; - - /// CosmWasm v0.10 + v1 - fn ed25519_verify( - &mut self, - message_ptr: i32, - signature_ptr: i32, - public_key_ptr: i32, - ) -> Result, Trap>; - - /// CosmWasm v0.10 + v1 - fn ed25519_batch_verify( - &mut self, - messages_ptr: i32, - signatures_ptr: i32, - public_keys_ptr: i32, - ) -> Result, Trap>; - /// CosmWasm v0.10 + v1 fn secp256k1_sign( &mut self, diff --git a/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml b/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml index 59d69e658..52aaca70b 100644 --- a/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml +++ b/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml @@ -27,5 +27,6 @@ derive_more = "0.99" protobuf = "2.25.2" sha2 = "0.8.1" +num_enum = "0.5.7" prost = { git = "https://github.com/mesalock-linux/prost-sgx", rev = "cd3103a6d45cf7a43b6c1c5e4223428097d1c547", default-features = false, features = ["prost-derive"] } diff --git a/cosmwasm/enclaves/shared/cosmos-types/src/types.rs b/cosmwasm/enclaves/shared/cosmos-types/src/types.rs index d8ee39ac9..7e43d06b8 100644 --- a/cosmwasm/enclaves/shared/cosmos-types/src/types.rs +++ b/cosmwasm/enclaves/shared/cosmos-types/src/types.rs @@ -141,6 +141,32 @@ pub enum SignModeDef { SIGN_MODE_LEGACY_AMINO_JSON = 127, } +#[allow(non_camel_case_types)] +#[derive(Deserialize, Clone, Debug, PartialEq)] +pub enum HandleType { + HANDLE_TYPE_EXECUTE = 0, + HANDLE_TYPE_REPLY = 1, + +} + +impl TryFrom for HandleType { + type Error = EnclaveError; + + fn try_from(value: u8) -> Result { + match t { + 0 => Ok(HandleType::HANDLE_TYPE_EXECUTE), + 1 => Ok(HandleType::HANDLE_TYPE_REPLY), + _ => { + error!( + "Handle function received wrong handle type: {}", + value + ); + Err(EnclaveError::FailedToDeserialize); + } + } + } +} + // This is called `VerificationInfo` on the Go side #[derive(Deserialize, Clone, Debug, PartialEq)] pub struct SigInfo { diff --git a/cosmwasm/packages/sgx-vm/src/cache.rs b/cosmwasm/packages/sgx-vm/src/cache.rs index cf5bba487..a68adff8f 100644 --- a/cosmwasm/packages/sgx-vm/src/cache.rs +++ b/cosmwasm/packages/sgx-vm/src/cache.rs @@ -4,12 +4,14 @@ use std::io::{Read, Write}; use std::marker::PhantomData; use std::path::PathBuf; use std::sync::Mutex; +use parity_wasm::elements::{deserialize_buffer}; /* use crate::backends::{backend, compile}; */ use crate::checksum::Checksum; -use crate::compatability::check_wasm; +use crate::compatability::{check_wasm, check_wasm_exports, REQUIRED_IBC_EXPORTS}; +use crate::features::required_features_from_module; use crate::errors::{VmError, VmResult}; use crate::instance::Instance; /* @@ -121,25 +123,6 @@ where } } - pub fn deserialize_wasm(wasm_code: &[u8]) -> VmResult { - deserialize_buffer(wasm_code).map_err(|err| { - VmError::static_validation_err(format!( - "Wasm bytecode could not be deserialized. Deserialization error: \"{}\"", - err - )) - }) - } - - /// Returns true if and only if all IBC entry points ([`REQUIRED_IBC_EXPORTS`]) - /// exist as exported functions. This does not guarantee the entry points - /// are functional and for simplicity does not even check their signatures. - pub fn has_ibc_entry_points(module: &impl ExportInfo) -> bool { - let available_exports = module.exported_function_names(None); - REQUIRED_IBC_EXPORTS - .iter() - .all(|required| available_exports.contains(*required)) - } - /// Performs static anlyzation on this Wasm without compiling or instantiating it. /// /// Once the contract was stored via [`save_wasm`], this can be called at any point in time. @@ -147,9 +130,24 @@ where pub fn analyze(&self, checksum: &Checksum) -> VmResult { // Here we could use a streaming deserializer to slightly improve performance. However, this way it is DRYer. let wasm = self.load_wasm(checksum)?; - let module = deserialize_wasm(&wasm)?; + + let module = match deserialize_buffer(&wasm) { + Ok(deserialized) => deserialized, + Err(err) => { + return Err(VmError::static_validation_err(format!( + "Wasm bytecode could not be deserialized. Deserialization error: \"{}\"", + err + ))); + } + }; + + let has_ibc_entry_points = match check_wasm_exports(&module, REQUIRED_IBC_EXPORTS) { + Ok(_) => true, + Err(_) => false + }; + Ok(AnalysisReport { - has_ibc_entry_points: has_ibc_entry_points(&module), + has_ibc_entry_points, required_features: required_features_from_module(&module), }) } diff --git a/cosmwasm/packages/sgx-vm/src/calls.rs b/cosmwasm/packages/sgx-vm/src/calls.rs index 49a6513c6..c32393827 100644 --- a/cosmwasm/packages/sgx-vm/src/calls.rs +++ b/cosmwasm/packages/sgx-vm/src/calls.rs @@ -94,12 +94,13 @@ pub fn call_handle_raw VmResult> { instance.set_storage_readonly(false); /* call_raw(instance, "handle", &[env, msg], MAX_LENGTH_HANDLE) */ - instance.call_handle(env, msg, sig_info) + instance.call_handle(env, msg, sig_info, handle_type) } /// Calls Wasm export "query" and returns raw data from the contract. diff --git a/cosmwasm/packages/sgx-vm/src/compatability.rs b/cosmwasm/packages/sgx-vm/src/compatability.rs index 7e080cbf0..8c6bc8385 100644 --- a/cosmwasm/packages/sgx-vm/src/compatability.rs +++ b/cosmwasm/packages/sgx-vm/src/compatability.rs @@ -75,6 +75,15 @@ const REQUIRED_EXPORTS_V1: &[&str] = &[ "instantiate", ]; +pub const REQUIRED_IBC_EXPORTS: &[&str] = &[ + "ibc_channel_open", + "ibc_channel_connect", + "ibc_channel_close", + "ibc_packet_receive", + "ibc_packet_ack", + "ibc_packet_timeout", +]; + const MEMORY_LIMIT: u32 = 512; // in pages /// Checks if the data is valid wasm and compatibility with the CosmWasm API (imports and exports) @@ -149,7 +158,7 @@ fn check_wasm_memories(module: &Module) -> VmResult<()> { Ok(()) } -fn check_wasm_exports(module: &Module, required_exports: &[&str]) -> VmResult<()> { +pub fn check_wasm_exports(module: &Module, required_exports: &[&str]) -> VmResult<()> { let available_exports: Vec = module.export_section().map_or(vec![], |export_section| { export_section .entries() diff --git a/cosmwasm/packages/sgx-vm/src/instance.rs b/cosmwasm/packages/sgx-vm/src/instance.rs index 3b5c5687f..798d7475a 100644 --- a/cosmwasm/packages/sgx-vm/src/instance.rs +++ b/cosmwasm/packages/sgx-vm/src/instance.rs @@ -327,18 +327,18 @@ where } pub fn call_init(&mut self, env: &[u8], msg: &[u8], sig_info: &[u8]) -> VmResult> { - let init_result = self.inner.init(env, msg, sig_info)?; - Ok(init_result.into_output()) + let result = self.inner.init(env, msg, sig_info)?; + Ok(result.into_output()) } - pub fn call_handle(&mut self, env: &[u8], msg: &[u8], sig_info: &[u8]) -> VmResult> { - let init_result = self.inner.handle(env, msg, sig_info)?; - Ok(init_result.into_output()) + pub fn call_handle(&mut self, env: &[u8], msg: &[u8], sig_info: &[u8], handle_type: u8) -> VmResult> { + let result = self.inner.handle(env, msg, sig_info, handle_type)?; + Ok(result.into_output()) } pub fn call_query(&mut self, env: &[u8], msg: &[u8]) -> VmResult> { - let init_result = self.inner.query(env, msg)?; - Ok(init_result.into_output()) + let result = self.inner.query(env, msg)?; + Ok(result.into_output()) } } diff --git a/cosmwasm/packages/sgx-vm/src/wasmi/imports.rs b/cosmwasm/packages/sgx-vm/src/wasmi/imports.rs index 59dfa31ea..fc213d813 100644 --- a/cosmwasm/packages/sgx-vm/src/wasmi/imports.rs +++ b/cosmwasm/packages/sgx-vm/src/wasmi/imports.rs @@ -49,6 +49,7 @@ extern "C" { msg_len: usize, sig_info: *const u8, sig_info_len: usize, + handle_type: u8, ) -> sgx_status_t; } diff --git a/cosmwasm/packages/sgx-vm/src/wasmi/wrapper.rs b/cosmwasm/packages/sgx-vm/src/wasmi/wrapper.rs index f08a4f9c4..5559b491f 100644 --- a/cosmwasm/packages/sgx-vm/src/wasmi/wrapper.rs +++ b/cosmwasm/packages/sgx-vm/src/wasmi/wrapper.rs @@ -144,7 +144,7 @@ where } } - pub fn handle(&mut self, env: &[u8], msg: &[u8], sig_info: &[u8]) -> VmResult { + pub fn handle(&mut self, env: &[u8], msg: &[u8], sig_info: &[u8], handle_type: u8) -> VmResult { trace!( "handle() called with env: {:?} msg: {:?} gas_left: {}", String::from_utf8_lossy(env), @@ -177,6 +177,7 @@ where msg.len(), sig_info.as_ptr(), sig_info.len(), + handle_type ) }; diff --git a/cosmwasm/packages/std/Cargo.toml b/cosmwasm/packages/std/Cargo.toml index 869ef4210..20a6ad2cf 100644 --- a/cosmwasm/packages/std/Cargo.toml +++ b/cosmwasm/packages/std/Cargo.toml @@ -53,6 +53,7 @@ serde = { version = "1.0.117", default-features = false, features = [ "alloc" ] } thiserror = "1.0" +snafu = { version = "0.6.6" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] cosmwasm-crypto = { path = "../crypto", version = "0.16.0" } diff --git a/cosmwasm/packages/std/src/addresses.rs b/cosmwasm/packages/std/src/addresses.rs index 7f431089c..0f8901365 100644 --- a/cosmwasm/packages/std/src/addresses.rs +++ b/cosmwasm/packages/std/src/addresses.rs @@ -136,10 +136,6 @@ impl From<&Addr> for HumanAddr { } } -#[deprecated( - since = "0.14.0", - note = "HumanAddr is not much more than an alias to String and it does not provide significant safety advantages. With CosmWasm 0.14, we now use String when there was HumanAddr before. There is also the new Addr, which holds a validated immutable human readable address." -)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema, Default)] pub struct HumanAddr(pub String); diff --git a/cosmwasm/packages/std/src/imports.rs b/cosmwasm/packages/std/src/imports.rs index cf4698023..ff162fdca 100644 --- a/cosmwasm/packages/std/src/imports.rs +++ b/cosmwasm/packages/std/src/imports.rs @@ -1,18 +1,19 @@ use std::vec::Vec; -use crate::addresses::{CanonicalAddr, HumanAddr}; -use crate::encoding::Binary; -use crate::errors::{RecoverPubkeyError, SigningError, StdError, StdResult, VerificationError}; +use crate::addresses::{Addr, CanonicalAddr}; +use crate::binary::Binary; +use crate::errors::{ + RecoverPubkeyError, SigningError, StdError, StdResult, SystemError, VerificationError, +}; #[cfg(feature = "iterator")] -use crate::iterator::{Order, KV}; -use crate::memory::{alloc, build_region, consume_region, encode_sections, Region}; +use crate::iterator::{Order, Pair}; +use crate::memory::{ + alloc, build_region, consume_region, encode_sections, get_optional_region_address, Region, +}; +use crate::results::SystemResult; +use crate::sections::decode_sections2; use crate::serde::from_slice; use crate::traits::{Api, Querier, QuerierResult, Storage}; -#[cfg(feature = "iterator")] -use crate::{ - iterator::{Order, Pair}, - memory::get_optional_region_address, -}; /// An upper bound for typical canonical address lengths (e.g. 20 in Cosmos SDK/Ethereum or 32 in Nano/Substrate) const CANONICAL_ADDRESS_BUFFER_LENGTH: usize = 64; @@ -37,15 +38,6 @@ extern "C" { fn addr_canonicalize(source_ptr: u32, destination_ptr: u32) -> u32; fn addr_humanize(source_ptr: u32, destination_ptr: u32) -> u32; - fn secp256k1_verify(message_hash_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32; - fn secp256k1_recover_pubkey( - message_hash_ptr: u32, - signature_ptr: u32, - recovery_param: u32, - ) -> u64; - fn ed25519_verify(message_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32; - fn ed25519_batch_verify(messages_ptr: u32, signatures_ptr: u32, public_keys_ptr: u32) -> u32; - fn debug(source_ptr: u32); /// Executes a query on the chain (import). Not to be confused with the @@ -233,118 +225,6 @@ impl Api for ExternalApi { Ok(Addr::unchecked(address)) } - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - let hash_send = build_region(message_hash); - let hash_send_ptr = &*hash_send as *const Region as u32; - let sig_send = build_region(signature); - let sig_send_ptr = &*sig_send as *const Region as u32; - let pubkey_send = build_region(public_key); - let pubkey_send_ptr = &*pubkey_send as *const Region as u32; - - let result = unsafe { secp256k1_verify(hash_send_ptr, sig_send_ptr, pubkey_send_ptr) }; - match result { - 0 => Ok(true), - 1 => Ok(false), - 2 => panic!("MessageTooLong must not happen. This is a bug in the VM."), - 3 => Err(VerificationError::InvalidHashFormat), - 4 => Err(VerificationError::InvalidSignatureFormat), - 5 => Err(VerificationError::InvalidPubkeyFormat), - 10 => Err(VerificationError::GenericErr), - error_code => Err(VerificationError::unknown_err(error_code)), - } - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recover_param: u8, - ) -> Result, RecoverPubkeyError> { - let hash_send = build_region(message_hash); - let hash_send_ptr = &*hash_send as *const Region as u32; - let sig_send = build_region(signature); - let sig_send_ptr = &*sig_send as *const Region as u32; - - let result = - unsafe { secp256k1_recover_pubkey(hash_send_ptr, sig_send_ptr, recover_param.into()) }; - let error_code = from_high_half(result); - let pubkey_ptr = from_low_half(result); - match error_code { - 0 => { - let pubkey = unsafe { consume_region(pubkey_ptr as *mut Region) }; - Ok(pubkey) - } - 2 => panic!("MessageTooLong must not happen. This is a bug in the VM."), - 3 => Err(RecoverPubkeyError::InvalidHashFormat), - 4 => Err(RecoverPubkeyError::InvalidSignatureFormat), - 6 => Err(RecoverPubkeyError::InvalidRecoveryParam), - error_code => Err(RecoverPubkeyError::unknown_err(error_code)), - } - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - let msg_send = build_region(message); - let msg_send_ptr = &*msg_send as *const Region as u32; - let sig_send = build_region(signature); - let sig_send_ptr = &*sig_send as *const Region as u32; - let pubkey_send = build_region(public_key); - let pubkey_send_ptr = &*pubkey_send as *const Region as u32; - - let result = unsafe { ed25519_verify(msg_send_ptr, sig_send_ptr, pubkey_send_ptr) }; - match result { - 0 => Ok(true), - 1 => Ok(false), - 2 => panic!("Error code 2 unused since CosmWasm 0.15. This is a bug in the VM."), - 3 => panic!("InvalidHashFormat must not happen. This is a bug in the VM."), - 4 => Err(VerificationError::InvalidSignatureFormat), - 5 => Err(VerificationError::InvalidPubkeyFormat), - 10 => Err(VerificationError::GenericErr), - error_code => Err(VerificationError::unknown_err(error_code)), - } - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - let msgs_encoded = encode_sections(messages); - let msgs_send = build_region(&msgs_encoded); - let msgs_send_ptr = &*msgs_send as *const Region as u32; - - let sigs_encoded = encode_sections(signatures); - let sig_sends = build_region(&sigs_encoded); - let sigs_send_ptr = &*sig_sends as *const Region as u32; - - let pubkeys_encoded = encode_sections(public_keys); - let pubkeys_send = build_region(&pubkeys_encoded); - let pubkeys_send_ptr = &*pubkeys_send as *const Region as u32; - - let result = - unsafe { ed25519_batch_verify(msgs_send_ptr, sigs_send_ptr, pubkeys_send_ptr) }; - match result { - 0 => Ok(true), - 1 => Ok(false), - 2 => panic!("Error code 2 unused since CosmWasm 0.15. This is a bug in the VM."), - 3 => panic!("InvalidHashFormat must not happen. This is a bug in the VM."), - 4 => Err(VerificationError::InvalidSignatureFormat), - 5 => Err(VerificationError::InvalidPubkeyFormat), - 10 => Err(VerificationError::GenericErr), - error_code => Err(VerificationError::unknown_err(error_code)), - } - } - fn debug(&self, message: &str) { // keep the boxes in scope, so we free it at the end (don't cast to pointers same line as build_region) let region = build_region(message.as_bytes()); diff --git a/cosmwasm/packages/std/src/mock.rs b/cosmwasm/packages/std/src/mock.rs index 43c7f9485..3a158dd63 100644 --- a/cosmwasm/packages/std/src/mock.rs +++ b/cosmwasm/packages/std/src/mock.rs @@ -7,7 +7,9 @@ use crate::addresses::{Addr, CanonicalAddr}; use crate::binary::Binary; use crate::coins::Coin; use crate::deps::OwnedDeps; -use crate::errors::{RecoverPubkeyError, StdError, StdResult, SystemError, VerificationError}; +use crate::errors::{ + RecoverPubkeyError, SigningError, StdError, StdResult, SystemError, VerificationError, +}; #[cfg(feature = "stargate")] use crate::ibc::{ IbcAcknowledgement, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, @@ -193,42 +195,6 @@ impl Api for MockApi { println!("{}", message); } - fn secp256k1_verify( - &self, - _message_hash: &[u8], - _signature: &[u8], - _public_key: &[u8], - ) -> Result { - Ok(true) - } - - fn secp256k1_recover_pubkey( - &self, - _message_hash: &[u8], - _signature: &[u8], - _recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - Ok(vec![]) - } - - fn ed25519_verify( - &self, - _message: &[u8], - _signature: &[u8], - _public_key: &[u8], - ) -> Result { - Ok(true) - } - - fn ed25519_batch_verify( - &self, - _messages: &[&[u8]], - _signatures: &[&[u8]], - _public_keys: &[&[u8]], - ) -> Result { - Ok(true) - } - fn secp256k1_sign( &self, _message: &[u8], diff --git a/cosmwasm/packages/std/src/traits.rs b/cosmwasm/packages/std/src/traits.rs index f21643292..30d9b1017 100644 --- a/cosmwasm/packages/std/src/traits.rs +++ b/cosmwasm/packages/std/src/traits.rs @@ -1,13 +1,10 @@ use serde::{de::DeserializeOwned, Serialize}; use std::ops::Deref; -use crate::addresses::{Addr, CanonicalAddr}; +use crate::addresses::{Addr, CanonicalAddr, HumanAddr}; use crate::binary::Binary; use crate::coins::Coin; -use crate::encoding::Binary; -use crate::errors::{ - RecoverPubkeyError, SigningError, StdError, StdResult, SystemResult, VerificationError, -}; +use crate::errors::{RecoverPubkeyError, SigningError, StdError, StdResult, VerificationError}; #[cfg(feature = "iterator")] use crate::iterator::{Order, Pair}; use crate::query::{ diff --git a/go-cosmwasm/Cargo.lock b/go-cosmwasm/Cargo.lock index 08ca647c1..a08498261 100644 --- a/go-cosmwasm/Cargo.lock +++ b/go-cosmwasm/Cargo.lock @@ -69,12 +69,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" version = "1.2.1" @@ -90,12 +84,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "cbindgen" version = "0.13.2" @@ -180,30 +168,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "const-oid" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" - -[[package]] -name = "cosmwasm-crypto" -version = "0.16.0" -dependencies = [ - "digest", - "ed25519-zebra", - "k256", - "rand_core 0.5.1", - "thiserror", -] - -[[package]] -name = "cosmwasm-derive" -version = "0.16.0" -dependencies = [ - "syn", -] - [[package]] name = "cosmwasm-sgx-vm" version = "0.10.0" @@ -217,8 +181,8 @@ dependencies = [ "num_cpus", "parity-wasm", "parking_lot", - "schemars 0.7.6", - "secret-cosmwasm-std 0.10.1", + "schemars", + "secret-cosmwasm-std", "serde", "serde_json", "sgx_types", @@ -233,34 +197,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" -dependencies = [ - "generic-array", - "rand_core 0.6.3", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "ctor" version = "0.1.15" @@ -271,28 +207,6 @@ dependencies = [ "syn", ] -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - -[[package]] -name = "der" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" -dependencies = [ - "const-oid", -] - [[package]] name = "derive_more" version = "0.99.9" @@ -319,54 +233,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "dyn-clone" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" - -[[package]] -name = "ecdsa" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" -dependencies = [ - "der", - "elliptic-curve", - "hmac", - "signature", -] - -[[package]] -name = "ed25519-zebra" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409" -dependencies = [ - "curve25519-dalek", - "hex", - "rand_core 0.5.1", - "serde", - "sha2", - "thiserror", -] - -[[package]] -name = "elliptic-curve" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" -dependencies = [ - "crypto-bigint", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.3", - "subtle", - "zeroize", -] - [[package]] name = "enclave-ffi-types" version = "0.1.0" @@ -397,16 +263,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ff" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" -dependencies = [ - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "gcc" version = "0.3.55" @@ -431,18 +287,7 @@ checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ "cfg-if 0.1.10", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -460,7 +305,7 @@ dependencies = [ "ctor", "errno", "log", - "secret-cosmwasm-std 0.16.0", + "secret-cosmwasm-std", "serde", "serde_json", "sgx_edl", @@ -469,17 +314,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "group" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" -dependencies = [ - "ff", - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "heck" version = "0.3.1" @@ -504,16 +338,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest", -] - [[package]] name = "instant" version = "0.1.12" @@ -529,18 +353,6 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -[[package]] -name = "k256" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sha2", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -662,16 +474,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "pkcs8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" -dependencies = [ - "der", - "spki", -] - [[package]] name = "ppv-lite86" version = "0.2.8" @@ -702,10 +504,10 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14", + "getrandom", "libc", "rand_chacha", - "rand_core 0.5.1", + "rand_core", "rand_hc", ] @@ -716,7 +518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core 0.5.1", + "rand_core", ] [[package]] @@ -725,16 +527,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom 0.2.5", + "getrandom", ] [[package]] @@ -743,7 +536,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1", + "rand_core", ] [[package]] @@ -788,19 +581,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be77ed66abed6954aabf6a3e31a84706bedbf93750d267e92ef4a6d90bbd6a61" dependencies = [ - "schemars_derive 0.7.6", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3" -dependencies = [ - "dyn-clone", - "schemars_derive 0.8.8", + "schemars_derive", "serde", "serde_json", ] @@ -817,18 +598,6 @@ dependencies = [ "syn", ] -[[package]] -name = "schemars_derive" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ae4dce13e8614c46ac3c38ef1c0d668b101df6ac39817aebdaa26642ddae9b" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn", -] - [[package]] name = "scopeguard" version = "1.1.0" @@ -842,26 +611,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5d4b8fed972d924458d9c3c0e6c9fbf6c4c5e30655571e3d2b78be056d316e9" dependencies = [ "base64 0.11.0", - "schemars 0.7.6", + "schemars", "serde", - "serde-json-wasm 0.2.1", + "serde-json-wasm", "snafu", ] -[[package]] -name = "secret-cosmwasm-std" -version = "0.16.0" -dependencies = [ - "base64 0.13.0", - "cosmwasm-crypto", - "cosmwasm-derive", - "schemars 0.8.8", - "serde", - "serde-json-wasm 0.3.2", - "thiserror", - "uint", -] - [[package]] name = "serde" version = "1.0.117" @@ -880,15 +635,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde-json-wasm" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "042ac496d97e5885149d34139bad1d617192770d7eb8f1866da2317ff4501853" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" version = "1.0.117" @@ -954,16 +700,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "signature" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" -dependencies = [ - "digest", - "rand_core 0.6.3", -] - [[package]] name = "simple_logger" version = "1.6.0" @@ -1005,33 +741,12 @@ dependencies = [ "syn", ] -[[package]] -name = "spki" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" -dependencies = [ - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - [[package]] name = "syn" version = "1.0.38" @@ -1111,18 +826,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" -[[package]] -name = "uint" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - [[package]] name = "unicode-segmentation" version = "1.6.0" @@ -1159,12 +862,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - [[package]] name = "winapi" version = "0.3.9" @@ -1186,9 +883,3 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zeroize" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" diff --git a/go-cosmwasm/Cargo.toml b/go-cosmwasm/Cargo.toml index 2affff648..662be0557 100644 --- a/go-cosmwasm/Cargo.toml +++ b/go-cosmwasm/Cargo.toml @@ -36,7 +36,7 @@ debug-print = ["cosmwasm-sgx-vm/debug-print"] query-node = ["cosmwasm-sgx-vm/query-node"] [dependencies] -cosmwasm-std = { path = "../cosmwasm/packages/std", package = "secret-cosmwasm-std", features = ["iterator"] } +cosmwasm-std = { package = "secret-cosmwasm-std", features = ["iterator"], version = "0.10.1"} cosmwasm-sgx-vm = { path = "../cosmwasm/packages/sgx-vm", features = [ "iterator" ] } diff --git a/go-cosmwasm/api/bindings.h b/go-cosmwasm/api/bindings.h index d8bc73509..fee312d71 100644 --- a/go-cosmwasm/api/bindings.h +++ b/go-cosmwasm/api/bindings.h @@ -63,20 +63,20 @@ typedef struct Buffer { typedef struct AnalysisReport { bool has_ibc_entry_points; /** - * An UTF-8 encoded comma separated list of reqired features. + * An UTF-8 encoded comma separated list of required features. * This is never None/nil. */ Buffer required_features; } AnalysisReport; -typedef struct EnclaveRuntimeConfig { - uint8_t module_cache_size; -} EnclaveRuntimeConfig; - typedef struct cache_t { } cache_t; +typedef struct EnclaveRuntimeConfig { + uint8_t module_cache_size; +} EnclaveRuntimeConfig; + /** * An opaque type. `*gas_meter_t` represents a pointer to Go memory holding the gas meter. */ @@ -145,6 +145,8 @@ typedef struct GoQuerier { Buffer allocate_rust(const uint8_t *ptr, uintptr_t length); +AnalysisReport analyze_code(cache_t *cache, Buffer checksum, Buffer *error_msg); + void configure_enclave_runtime(EnclaveRuntimeConfig config, Buffer *err); Buffer create(cache_t *cache, Buffer wasm, Buffer *err); @@ -169,7 +171,8 @@ Buffer handle(cache_t *cache, uint64_t gas_limit, uint64_t *gas_used, Buffer *err, - Buffer sig_info); + Buffer sig_info, + uint8_t handle_type); Buffer init_bootstrap(Buffer spid, Buffer api_key, Buffer *err); @@ -202,10 +205,6 @@ Buffer query(cache_t *cache, uint64_t *gas_used, Buffer *err); -AnalysisReport analyze_code(cache_t *cache, - ByteSliceView checksum, - Buffer *error_msg); - /** * frees a cache reference * diff --git a/go-cosmwasm/api/iterator.go b/go-cosmwasm/api/iterator.go new file mode 100644 index 000000000..0d2fe8e68 --- /dev/null +++ b/go-cosmwasm/api/iterator.go @@ -0,0 +1,68 @@ +package api + +import ( + dbm "github.com/tendermint/tm-db" + "sync" +) + +// frame stores all Iterators for one contract +type frame []dbm.Iterator + +// iteratorStack contains one frame for each contract, indexed by a counter +// 10 is a rather arbitrary guess on how many frames might be needed simultaneously +var iteratorStack = make(map[uint64]frame, 10) +var iteratorStackMutex sync.Mutex + +// this is a global counter when we create DBs +var dbCounter uint64 +var dbCounterMutex sync.Mutex + +// startContract is called at the beginning of a contract runtime to create a new frame on the iteratorStack +// updates dbCounter for an index +func startContract() uint64 { + dbCounterMutex.Lock() + defer dbCounterMutex.Unlock() + dbCounter += 1 + return dbCounter +} + +func popFrame(counter uint64) frame { + iteratorStackMutex.Lock() + defer iteratorStackMutex.Unlock() + // get the item from the stack + + remove := iteratorStack[counter] + delete(iteratorStack, counter) + return remove +} + +// endContract is called at the end of a contract runtime to remove one item from the IteratorStack +func endContract(counter uint64) { + // we pull popFrame in another function so we don't hold the mutex while cleaning up the popped frame + remove := popFrame(counter) + // free all iterators in the frame when we release it + for _, iter := range remove { + iter.Close() + } +} + +// storeIterator will add this to the end of the latest stack and return a reference to it. +// We start counting with 1, so the 0 value is flagged as an error. This means we must +// remember to do idx-1 when retrieving +func storeIterator(dbCounter uint64, it dbm.Iterator) uint64 { + iteratorStackMutex.Lock() + defer iteratorStackMutex.Unlock() + + frame := append(iteratorStack[dbCounter], it) + iteratorStack[dbCounter] = frame + return uint64(len(frame)) +} + +// retrieveIterator will recover an iterator based on index. This ensures it will not be garbage collected. +// We start counting with 1, in storeIterator so the 0 value is flagged as an error. This means we must +// remember to do idx-1 when retrieving +func retrieveIterator(dbCounter uint64, index uint64) dbm.Iterator { + iteratorStackMutex.Lock() + defer iteratorStackMutex.Unlock() + return iteratorStack[dbCounter][index-1] +} diff --git a/go-cosmwasm/api/lib.go b/go-cosmwasm/api/lib.go index c8524fdc0..41006acad 100644 --- a/go-cosmwasm/api/lib.go +++ b/go-cosmwasm/api/lib.go @@ -182,6 +182,7 @@ func Handle( querier *Querier, gasLimit uint64, sigInfo []byte, + handleType types.HandleType, ) ([]byte, uint64, error) { id := sendSlice(code_id) defer freeAfterSend(id) @@ -208,7 +209,7 @@ func Handle( runtime.LockOSThread() defer runtime.UnlockOSThread() - res, err := C.handle(cache.ptr, id, p, m, db, a, q, u64(gasLimit), &gasUsed, &errmsg, s) + res, err := C.handle(cache.ptr, id, p, m, db, a, q, u64(gasLimit), &gasUsed, &errmsg, s, u8(handleType)) if err != nil && err.(syscall.Errno) != C.ErrnoValue_Success { // Depending on the nature of the error, `gasUsed` will either have a meaningful value, or just 0. return nil, uint64(gasUsed), errorWithMessage(err, errmsg) diff --git a/go-cosmwasm/api/lib_mock.go b/go-cosmwasm/api/lib_mock.go index e6d0caf16..94d304040 100644 --- a/go-cosmwasm/api/lib_mock.go +++ b/go-cosmwasm/api/lib_mock.go @@ -1,3 +1,4 @@ +//go:build secretcli // +build secretcli package api @@ -11,6 +12,7 @@ package api import ( //"fmt" "github.com/enigmampc/SecretNetwork/go-cosmwasm/types" + v1types "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" ) // nice aliases to the rust names @@ -149,6 +151,7 @@ func Handle( querier *Querier, gasLimit uint64, sigInfo []byte, + handleType types.HandleType, ) ([]byte, uint64, error) { //id := sendSlice(code_id) //defer freeAfterSend(id) @@ -230,6 +233,26 @@ func Query( return nil, 0, nil } +func AnalyzeCode( + cache Cache, + codeHash []byte, +) (*v1types.AnalysisReport, error) { + //cs := sendSlice(codeHash) + //defer runtime.KeepAlive(codeHash) + //errMsg := C.Buffer{} + //report, err := C.analyze_code(cache.ptr, cs, &errMsg) + // + //if err != nil { + // return nil, errorWithMessage(err, errMsg) + //} + //res := v1types.AnalysisReport{ + // HasIBCEntryPoints: bool(report.has_ibc_entry_points), + // RequiredFeatures: string(receiveVector(report.required_features)), + //} + //return &res, nil + return nil, nil +} + // KeyGen Send KeyGen request to enclave func KeyGen() ([]byte, error) { //errmsg := C.Buffer{} diff --git a/go-cosmwasm/lib.go b/go-cosmwasm/lib.go index 0a94288f7..2f5e5524f 100644 --- a/go-cosmwasm/lib.go +++ b/go-cosmwasm/lib.go @@ -162,6 +162,7 @@ func (w *Wasmer) Execute( gasMeter GasMeter, gasLimit uint64, sigInfo types.VerificationInfo, + handleType types.HandleType, ) (interface{}, uint64, error) { paramBin, err := json.Marshal(env) if err != nil { @@ -172,7 +173,7 @@ func (w *Wasmer) Execute( return nil, 0, err } - data, gasUsed, err := api.Handle(w.cache, code, paramBin, executeMsg, &gasMeter, store, &goapi, &querier, gasLimit, sigInfoBin) + data, gasUsed, err := api.Handle(w.cache, code, paramBin, executeMsg, &gasMeter, store, &goapi, &querier, gasLimit, sigInfoBin, handleType) if err != nil { return nil, gasUsed, err } @@ -239,7 +240,6 @@ func (w *Wasmer) Query( // AnalyzeCode returns a report of static analysis of the wasm contract (uncompiled). // This contract must have been stored in the cache previously (via Create). // Only info currently returned is if it exposes all ibc entry points, but this may grow later -// Currently just reports if it exposes all IBC entry points. func (w *Wasmer) AnalyzeCode( codeHash []byte, ) (*v1types.AnalysisReport, error) { diff --git a/go-cosmwasm/src/error/mod.rs b/go-cosmwasm/src/error/mod.rs index 2afda3aa3..35deac91e 100644 --- a/go-cosmwasm/src/error/mod.rs +++ b/go-cosmwasm/src/error/mod.rs @@ -2,4 +2,4 @@ mod go; mod rust; pub use go::GoResult; -pub use rust::{clear_error, handle_c_error, set_error, Error}; +pub use rust::{clear_error, handle_c_error, handle_c_error_default, set_error, Error}; diff --git a/go-cosmwasm/src/error/rust.rs b/go-cosmwasm/src/error/rust.rs index 067ee3ed8..ea832ba04 100644 --- a/go-cosmwasm/src/error/rust.rs +++ b/go-cosmwasm/src/error/rust.rs @@ -141,6 +141,25 @@ where } } +pub fn handle_c_error_default( + result: Result, + errout: Option<&mut Buffer>, +) -> T + where + T: Default, +{ + match result { + Ok(value) => { + clear_error(); + value + } + Err(error) => { + set_error(error, errout); + Default::default() + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/go-cosmwasm/src/lib.rs b/go-cosmwasm/src/lib.rs index f14980cf1..a2fdbc469 100644 --- a/go-cosmwasm/src/lib.rs +++ b/go-cosmwasm/src/lib.rs @@ -15,7 +15,7 @@ use std::convert::TryInto; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::str::from_utf8; -use crate::error::{clear_error, handle_c_error, set_error, Error}; +use crate::error::{clear_error, handle_c_error, handle_c_error_default, set_error, Error}; use cosmwasm_sgx_vm::untrusted_init_bootstrap; use cosmwasm_sgx_vm::{ @@ -23,7 +23,7 @@ use cosmwasm_sgx_vm::{ }; use cosmwasm_sgx_vm::{ create_attestation_report_u, untrusted_get_encrypted_seed, untrusted_health_check, - untrusted_init_node, untrusted_key_gen, + untrusted_init_node, untrusted_key_gen }; use ctor::ctor; @@ -402,11 +402,12 @@ pub extern "C" fn handle( gas_used: Option<&mut u64>, err: Option<&mut Buffer>, sig_info: Buffer, + handle_type: u8, ) -> Buffer { let r = match to_cache(cache) { Some(c) => catch_unwind(AssertUnwindSafe(move || { do_handle( - c, code_id, params, msg, db, api, querier, gas_limit, gas_used, sig_info, + c, code_id, params, msg, db, api, querier, gas_limit, gas_used, sig_info, handle_type ) })) .unwrap_or_else(|_| Err(Error::panic())), @@ -428,6 +429,7 @@ fn do_handle( gas_limit: u64, gas_used: Option<&mut u64>, sig_info: Buffer, + handle_type: u8 ) -> Result, Error> { let gas_used = gas_used.ok_or_else(|| Error::empty_arg(GAS_USED_ARG))?; let code_id: Checksum = unsafe { code_id.read() } @@ -440,7 +442,7 @@ fn do_handle( let deps = to_extern(db, api, querier); let mut instance = cache.get_instance(&code_id, deps, gas_limit)?; // We only check this result after reporting gas usage and returning the instance into the cache. - let res = call_handle_raw(&mut instance, params, msg, sig_info); + let res = call_handle_raw(&mut instance, params, msg, sig_info, handle_type); *gas_used = instance.create_gas_report().used_internally; instance.recycle(); Ok(res?) @@ -505,10 +507,10 @@ fn do_query( /// has to be destroyed exactly once. When calling `analyze_code` /// from Go this is done via `C.destroy_unmanaged_vector`. #[repr(C)] -#[derive(Copy, Clone, Default, Debug, PartialEq)] +#[derive(Clone, Default, Debug, PartialEq)] pub struct AnalysisReport { pub has_ibc_entry_points: bool, - /// An UTF-8 encoded comma separated list of reqired features. + /// An UTF-8 encoded comma separated list of required features. /// This is never None/nil. pub required_features: Buffer, } @@ -516,27 +518,41 @@ pub struct AnalysisReport { #[no_mangle] pub extern "C" fn analyze_code( cache: *mut cache_t, - checksum: ByteSliceView, + checksum: Buffer, error_msg: Option<&mut Buffer>, ) -> AnalysisReport { let r = match to_cache(cache) { - Some(c) => catch_unwind(AssertUnwindSafe(move || do_analyze_code(c, checksum))) + Some(c) => catch_unwind(AssertUnwindSafe(move || { + do_analyze_code(c, checksum) + })) .unwrap_or_else(|_| Err(Error::panic())), - None => Err(Error::unset_arg(CACHE_ARG)), + None => Err(Error::empty_arg(CACHE_ARG)), }; + handle_c_error_default(r, error_msg) } fn do_analyze_code( - cache: &mut Cache, - checksum: ByteSliceView, + cache: &mut CosmCache, + checksum: Buffer, ) -> Result { - let checksum: Checksum = checksum - .read() - .ok_or_else(|| Error::unset_arg(CHECKSUM_ARG))? + let checksum: Checksum = unsafe { checksum.read() } + .ok_or_else(|| Error::empty_arg(CODE_ID_ARG))? .try_into()?; let report = cache.analyze(&checksum)?; - Ok(report.into()) + let mut features_vec : Vec = vec!(); + for feature in &report.required_features { + if features_vec.len() > 0 { + features_vec.append(&mut (",".as_bytes().to_vec())) + } + + features_vec.append(&mut feature.as_bytes().to_vec()) + } + + Ok(AnalysisReport{ + has_ibc_entry_points: report.has_ibc_entry_points, + required_features: Buffer::from_vec(features_vec), + }) } #[no_mangle] diff --git a/go-cosmwasm/src/memory.rs b/go-cosmwasm/src/memory.rs index cb56f713b..58095a0bd 100644 --- a/go-cosmwasm/src/memory.rs +++ b/go-cosmwasm/src/memory.rs @@ -21,7 +21,7 @@ pub extern "C" fn free_rust(buf: Buffer) { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub struct Buffer { pub ptr: *mut u8, diff --git a/go-cosmwasm/types/types.go b/go-cosmwasm/types/types.go index 5b7b232ee..5718ea5f1 100644 --- a/go-cosmwasm/types/types.go +++ b/go-cosmwasm/types/types.go @@ -59,10 +59,17 @@ func (o OutOfGasError) Error() string { } type VerificationInfo struct { - Bytes []byte `json:"sign_bytes"` - SignMode string `json:"sign_mode"` - ModeInfo []byte `json:"mode_info"` - PublicKey []byte `json:"public_key"` - Signature []byte `json:"signature"` - CallbackSignature []byte `json:"callback_sig"` // Optional + Bytes []byte `json:"sign_bytes"` + SignMode string `json:"sign_mode"` + ModeInfo []byte `json:"mode_info"` + PublicKey []byte `json:"public_key"` + Signature []byte `json:"signature"` + CallbackSignature []byte `json:"callback_sig"` // Optional } + +type HandleType int + +const ( + HandleTypeExecute HandleType = iota + HandleTypeReply +) diff --git a/go-cosmwasm/types/v1/ibc.go b/go-cosmwasm/types/v1/ibc.go index 208511214..87b60a361 100644 --- a/go-cosmwasm/types/v1/ibc.go +++ b/go-cosmwasm/types/v1/ibc.go @@ -1,5 +1,9 @@ package v1types +import ( + abci "github.com/tendermint/tendermint/abci/types" +) + type IBCEndpoint struct { PortID string `json:"port_id"` ChannelID string `json:"channel_id"` @@ -219,7 +223,7 @@ type IBCBasicResponse struct { // "fire and forget". Messages []SubMsg `json:"messages"` // attributes for a log event to return over abci interface - Attributes []EventAttribute `json:"attributes"` + Attributes []abci.EventAttribute `json:"attributes"` // custom events (separate from the main one that contains the attributes // above) Events []Event `json:"events"` @@ -250,8 +254,8 @@ type IBCReceiveResponse struct { // If the ReplyOn value matches the result, the runtime will invoke this // contract's `reply` entry point after execution. Otherwise, this is all // "fire and forget". - Messages []SubMsg `json:"messages"` - Attributes []EventAttribute `json:"attributes"` + Messages []SubMsg `json:"messages"` + Attributes []abci.EventAttribute `json:"attributes"` // custom events (separate from the main one that contains the attributes // above) Events []Event `json:"events"` diff --git a/go-cosmwasm/types/v1/msg_v1.go b/go-cosmwasm/types/v1/msg_v1.go index 69c713b4f..aea2bb809 100644 --- a/go-cosmwasm/types/v1/msg_v1.go +++ b/go-cosmwasm/types/v1/msg_v1.go @@ -5,6 +5,7 @@ import ( "fmt" types "github.com/enigmampc/SecretNetwork/go-cosmwasm/types" + v010msgtypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v010" ) //------- Results / Msgs ------------- @@ -27,31 +28,31 @@ type Response struct { // base64-encoded bytes to return as ABCI.Data field Data []byte `json:"data"` // attributes for a log event to return over abci interface - Attributes []EventAttribute `json:"attributes"` + Attributes []v010msgtypes.LogAttribute `json:"attributes"` // custom events (separate from the main one that contains the attributes // above) Events []Event `json:"events"` } -// EventAttributes must encode empty array as [] -type EventAttributes []EventAttribute +// LogAttributes must encode empty array as [] +type LogAttributes []v010msgtypes.LogAttribute // MarshalJSON ensures that we get [] for empty arrays -func (a EventAttributes) MarshalJSON() ([]byte, error) { +func (a LogAttributes) MarshalJSON() ([]byte, error) { if len(a) == 0 { return []byte("[]"), nil } - var raw []EventAttribute = a + var raw []v010msgtypes.LogAttribute = a return json.Marshal(raw) } // UnmarshalJSON ensures that we get [] for empty arrays -func (a *EventAttributes) UnmarshalJSON(data []byte) error { +func (a *LogAttributes) UnmarshalJSON(data []byte) error { // make sure we deserialize [] back to null if string(data) == "[]" || string(data) == "null" { return nil } - var raw []EventAttribute + var raw []v010msgtypes.LogAttribute if err := json.Unmarshal(data, &raw); err != nil { return err } @@ -59,12 +60,6 @@ func (a *EventAttributes) UnmarshalJSON(data []byte) error { return nil } -// EventAttribute -type EventAttribute struct { - Key string `json:"key"` - Value string `json:"value"` -} - // CosmosMsg is an rust enum and only (exactly) one of the fields should be set // Should we do a cleaner approach in Go? (type/data?) type CosmosMsg struct { @@ -108,50 +103,50 @@ type GovMsg struct { Vote *VoteMsg `json:"vote,omitempty"` } -type voteOption int +type VoteOption int type VoteMsg struct { ProposalId uint64 `json:"proposal_id"` - Vote voteOption `json:"vote"` + Vote VoteOption `json:"vote"` } const ( - Yes voteOption = iota + Yes VoteOption = iota No Abstain NoWithVeto ) -var fromVoteOption = map[voteOption]string{ +var fromVoteOption = map[VoteOption]string{ Yes: "yes", No: "no", Abstain: "abstain", NoWithVeto: "no_with_veto", } -var toVoteOption = map[string]voteOption{ +var ToVoteOption = map[string]VoteOption{ "yes": Yes, "no": No, "abstain": Abstain, "no_with_veto": NoWithVeto, } -func (v voteOption) String() string { +func (v VoteOption) String() string { return fromVoteOption[v] } -func (v voteOption) MarshalJSON() ([]byte, error) { +func (v VoteOption) MarshalJSON() ([]byte, error) { return json.Marshal(v.String()) } -func (s *voteOption) UnmarshalJSON(b []byte) error { +func (s *VoteOption) UnmarshalJSON(b []byte) error { var j string err := json.Unmarshal(b, &j) if err != nil { return err } - voteOption, ok := toVoteOption[j] + voteOption, ok := ToVoteOption[j] if !ok { return fmt.Errorf("invalid vote option '%v'", j) } @@ -177,25 +172,10 @@ type CloseChannelMsg struct { } type StakingMsg struct { - Delegate *DelegateMsg `json:"delegate,omitempty"` - Undelegate *UndelegateMsg `json:"undelegate,omitempty"` - Redelegate *RedelegateMsg `json:"redelegate,omitempty"` -} - -type DelegateMsg struct { - Validator string `json:"validator"` - Amount types.Coin `json:"amount"` -} - -type UndelegateMsg struct { - Validator string `json:"validator"` - Amount types.Coin `json:"amount"` -} - -type RedelegateMsg struct { - SrcValidator string `json:"src_validator"` - DstValidator string `json:"dst_validator"` - Amount types.Coin `json:"amount"` + Delegate *v010msgtypes.DelegateMsg `json:"delegate,omitempty"` + Undelegate *v010msgtypes.UndelegateMsg `json:"undelegate,omitempty"` + Redelegate *v010msgtypes.RedelegateMsg `json:"redelegate,omitempty"` + Withdraw *v010msgtypes.WithdrawMsg `json:"withdraw,omitempty"` } type DistributionMsg struct { @@ -225,44 +205,6 @@ type StargateMsg struct { } type WasmMsg struct { - Execute *ExecuteMsg `json:"execute,omitempty"` - Instantiate *InstantiateMsg `json:"instantiate,omitempty"` -} - -// ExecuteMsg is used to call another defined contract on this chain. -// The calling contract requires the callee to be defined beforehand, -// and the address should have been defined in initialization. -// And we assume the developer tested the ABIs and coded them together. -// -// Since a contract is immutable once it is deployed, we don't need to transform this. -// If it was properly coded and worked once, it will continue to work throughout upgrades. -type ExecuteMsg struct { - // ContractAddr is the sdk.AccAddress of the contract, which uniquely defines - // the contract ID and instance ID. The sdk module should maintain a reverse lookup table. - ContractAddr string `json:"contract_addr"` - // Custom addition to support binding a message to specific code to harden against offline & replay attacks - // This is only needed when creating a callback message - CallbackCodeHash string `json:"callback_code_hash"` - // Msg is assumed to be a json-encoded message, which will be passed directly - // as `userMsg` when calling `Handle` on the above-defined contract - Msg []byte `json:"msg"` - // Send is an optional amount of coins this contract sends to the called contract - Funds types.Coins `json:"funds"` -} - -// InstantiateMsg will create a new contract instance from a previously uploaded CodeID. -// This allows one contract to spawn "sub-contracts". -type InstantiateMsg struct { - // CodeID is the reference to the wasm byte code as used by the Cosmos-SDK - CodeID uint64 `json:"code_id"` - // Custom addition to support binding a message to specific code to harden against offline & replay attacks - // This is only needed when creating a callback message - CallbackCodeHash string `json:"callback_code_hash"` - // Msg is assumed to be a json-encoded message, which will be passed directly - // as `userMsg` when calling `Init` on a new contract with the above-defined CodeID - Msg []byte `json:"msg"` - // Send is an optional amount of coins this contract sends to the called contract - Funds types.Coins `json:"funds"` - // Label is optional metadata to be stored with a contract instance. - Label string `json:"label"` + Execute *v010msgtypes.ExecuteMsg `json:"execute,omitempty"` + Instantiate *v010msgtypes.InstantiateMsg `json:"instantiate,omitempty"` } diff --git a/go-cosmwasm/types/v1/subcall.go b/go-cosmwasm/types/v1/subcall.go index 8617fe9f9..f1f71b365 100644 --- a/go-cosmwasm/types/v1/subcall.go +++ b/go-cosmwasm/types/v1/subcall.go @@ -51,6 +51,18 @@ func (s *replyOn) UnmarshalJSON(b []byte) error { return nil } +type SubMsgResponse struct { + Events Events `json:"events"` + Data []byte `json:"data,omitempty"` +} + +// SubMsgResult is the raw response we return from wasmd after executing a SubMsg. +// This mirrors Rust's SubMsgResult. +type SubMsgResult struct { + Ok *SubMsgResponse `json:"ok,omitempty"` + Err string `json:"error,omitempty"` +} + // SubMsg wraps a CosmosMsg with some metadata for handling replies (ID) and optionally // limiting the gas usage (GasLimit) type SubMsg struct { @@ -61,8 +73,8 @@ type SubMsg struct { } type Reply struct { - ID uint64 `json:"id"` - Result SubcallResult `json:"result"` + ID uint64 `json:"id"` + Result SubMsgResult `json:"result"` } // SubcallResult is the raw response we return from the sdk -> reply after executing a SubMsg. @@ -104,6 +116,6 @@ func (e *Events) UnmarshalJSON(data []byte) error { } type Event struct { - Type string `json:"type"` - Attributes EventAttributes `json:"attributes"` + Type string `json:"type"` + Attributes LogAttributes `json:"attributes"` } diff --git a/proto/secret/compute/v1beta1/types.proto b/proto/secret/compute/v1beta1/types.proto index a6c39bb4f..ab87ad726 100644 --- a/proto/secret/compute/v1beta1/types.proto +++ b/proto/secret/compute/v1beta1/types.proto @@ -56,15 +56,10 @@ message ContractCustomInfo { message ContractInfo { uint64 code_id = 1 [(gogoproto.customname) = "CodeID"]; bytes creator = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; -// bytes admin = 3 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; string label = 4; // never show this in query results, just use for sorting // (Note: when using json tag "-" amino refused to serialize it...) AbsoluteTxPosition created = 5; - // bytes init_msg = 5 [(gogoproto.casttype) = "encoding/json.RawMessage"]; - // - // AbsoluteTxPosition last_updated = 7; - // uint64 previous_code_id = 8 [(gogoproto.customname) = "PreviousCodeID"]; string ibc_port_id = 6 [ (gogoproto.customname) = "IBCPortID" ]; } diff --git a/x/compute/alias.go b/x/compute/alias.go index 2ba531868..47f42e992 100644 --- a/x/compute/alias.go +++ b/x/compute/alias.go @@ -54,7 +54,6 @@ var ( NewContractInfo = types.NewContractInfo NewEnv = types.NewEnv NewWasmCoins = types.NewWasmCoins - ParseEvents = types.ParseEvents DefaultWasmConfig = types.DefaultWasmConfig IsEncryptedError = types.IsEncryptedErrorCode ErrContainsQueryError = types.ErrContainsQueryError diff --git a/x/compute/handler.go b/x/compute/handler.go index b3484d2f9..b37a20696 100644 --- a/x/compute/handler.go +++ b/x/compute/handler.go @@ -77,7 +77,7 @@ func handleStoreCode(ctx sdk.Context, k Keeper, msg *MsgStoreCode) (*sdk.Result, } func handleInstantiate(ctx sdk.Context, k Keeper, msg *MsgInstantiateContract) (*sdk.Result, error) { - contractAddr, err := k.Instantiate(ctx, msg.CodeID, msg.Sender, msg.InitMsg, msg.Label, msg.InitFunds, msg.CallbackSig) + contractAddr, _, err := k.Instantiate(ctx, msg.CodeID, msg.Sender, msg.InitMsg, msg.Label, msg.InitFunds, msg.CallbackSig) if err != nil { return nil, err } @@ -88,7 +88,7 @@ func handleInstantiate(ctx sdk.Context, k Keeper, msg *MsgInstantiateContract) ( sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(types.AttributeKeySigner, msg.Sender.String()), sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", msg.CodeID)), - sdk.NewAttribute(types.AttributeKeyContract, contractAddr.String()), + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String()), )} events = append(events, custom.ToABCIEvents()...) @@ -120,7 +120,7 @@ func handleExecute(ctx sdk.Context, k Keeper, msg *MsgExecuteContract) (*sdk.Res sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(types.AttributeKeySigner, msg.Sender.String()), - sdk.NewAttribute(types.AttributeKeyContract, msg.Contract.String()), + sdk.NewAttribute(types.AttributeKeyContractAddr, msg.Contract.String()), )} events = append(events, custom.ToABCIEvents()...) diff --git a/x/compute/internal/keeper/distribution_test.go b/x/compute/internal/keeper/distribution_test.go index b0e47632b..f75fce854 100644 --- a/x/compute/internal/keeper/distribution_test.go +++ b/x/compute/internal/keeper/distribution_test.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" "encoding/json" + "github.com/enigmampc/SecretNetwork/x/compute/internal/types" "io/ioutil" "testing" @@ -27,7 +28,12 @@ type Delegator struct { // TestDistributionRewards tests querying staking rewards from inside a contract - first testing no rewards, then advancing // 1 block and checking the rewards again func TestDistributionRewards(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, stakingKeeper, keeper, distKeeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper, keepers.DistKeeper @@ -73,7 +79,7 @@ func TestDistributionRewards(t *testing.T) { require.NoError(t, err) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initBz, govId, nil) - govAddr, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", nil, nil) + govAddr, _, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", nil, nil) require.NoError(t, err) require.NotEmpty(t, govAddr) diff --git a/x/compute/internal/keeper/gov_test.go b/x/compute/internal/keeper/gov_test.go index fa4f17f7c..1b2df8730 100644 --- a/x/compute/internal/keeper/gov_test.go +++ b/x/compute/internal/keeper/gov_test.go @@ -4,14 +4,14 @@ import ( "bytes" "encoding/binary" "encoding/json" + wasmTypes "github.com/enigmampc/SecretNetwork/x/compute/internal/types" "io/ioutil" "testing" - "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" ) var ( @@ -37,7 +37,12 @@ func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool { // TestGovQueryProposals tests reading how many proposals are active - first testing 0 proposals, then adding // an active proposal and checking that there is 1 active func TestGovQueryProposals(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource wasmTypes.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, _, keeper, govKeeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper, keepers.GovKeeper @@ -65,7 +70,7 @@ func TestGovQueryProposals(t *testing.T) { require.NoError(t, err) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initBz, govId, nil) - govAddr, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", nil, nil) + govAddr, _, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", nil, nil) require.NoError(t, err) require.NotEmpty(t, govAddr) @@ -99,7 +104,12 @@ func TestGovQueryProposals(t *testing.T) { // TestGovQueryProposals tests reading how many proposals are active - first testing 0 proposals, then adding // an active proposal and checking that there is 1 active func TestGovVote(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource wasmTypes.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, _, keeper, govKeeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper, keepers.GovKeeper @@ -129,7 +139,7 @@ func TestGovVote(t *testing.T) { require.NoError(t, err) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initBz, govId, deposit2) - govAddr, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", deposit2, nil) + govAddr, _, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", deposit2, nil) require.NoError(t, err) require.NotEmpty(t, govAddr) @@ -159,5 +169,5 @@ func TestGovVote(t *testing.T) { votes := govKeeper.GetAllVotes(ctx) require.Equal(t, uint64(0x1), votes[0].ProposalId) require.Equal(t, govAddr.String(), votes[0].Voter) - require.Equal(t, govtypes.OptionYes, votes[0].Option) + require.Equal(t, types.OptionYes, votes[0].Option) } diff --git a/x/compute/internal/keeper/handler_plugin.go b/x/compute/internal/keeper/handler_plugin.go index 30749973d..289152165 100644 --- a/x/compute/internal/keeper/handler_plugin.go +++ b/x/compute/internal/keeper/handler_plugin.go @@ -2,6 +2,16 @@ package keeper import ( "encoding/json" + "errors" + "fmt" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + channelkeeper "github.com/cosmos/ibc-go/v3/modules/core/04-channel/keeper" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + v1wasmTypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -18,40 +28,147 @@ import ( "github.com/enigmampc/SecretNetwork/x/compute/internal/types" ) +// MessageHandlerChain defines a chain of handlers that are called one by one until it can be handled. +type MessageHandlerChain struct { + handlers []Messenger +} + type MessageHandler struct { router sdk.Router encoders MessageEncoders } -func NewMessageHandler(router sdk.Router, customEncoders *MessageEncoders) MessageHandler { - encoders := DefaultEncoders().Merge(customEncoders) +func NewSDKMessageHandler(router sdk.Router, encoders MessageEncoders) MessageHandler { return MessageHandler{ router: router, encoders: encoders, } } -type BankEncoder func(sender sdk.AccAddress, msg *v010wasmTypes.BankMsg) ([]sdk.Msg, error) +// IBCRawPacketHandler handels IBC.SendPacket messages which are published to an IBC channel. +type IBCRawPacketHandler struct { + channelKeeper channelkeeper.Keeper + capabilityKeeper capabilitykeeper.ScopedKeeper +} + +func NewIBCRawPacketHandler(chk channelkeeper.Keeper, cak capabilitykeeper.ScopedKeeper) IBCRawPacketHandler { + return IBCRawPacketHandler{channelKeeper: chk, capabilityKeeper: cak} +} + +func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandlerChain { + r := &MessageHandlerChain{handlers: append([]Messenger{first}, others...)} + for i := range r.handlers { + if r.handlers[i] == nil { + panic(fmt.Sprintf("handler must not be nil at position : %d", i)) + } + } + return r +} + +func NewMessageHandler( + router sdk.Router, + customEncoders *MessageEncoders, + channelKeeper channelkeeper.Keeper, + capabilityKeeper capabilitykeeper.ScopedKeeper, + portSource types.ICS20TransferPortSource, + unpacker codectypes.AnyUnpacker) Messenger { + encoders := DefaultEncoders(portSource, unpacker).Merge(customEncoders) + return NewMessageHandlerChain( + NewSDKMessageHandler(router, encoders), + NewIBCRawPacketHandler(channelKeeper, capabilityKeeper), + ) +} + +// DispatchMsg dispatch message and calls chained handlers one after another in +// order to find the right one to process given message. If a handler cannot +// process given message (returns ErrUnknownMsg), its result is ignored and the +// next handler is executed. +func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg v1wasmTypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { + for _, h := range m.handlers { + events, data, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + switch { + case err == nil: + return events, data, nil + case errors.Is(err, types.ErrUnknownMsg): + continue + default: + return events, data, err + } + } + return nil, nil, sdkerrors.Wrap(types.ErrUnknownMsg, "no handler found") +} + +// DispatchMsg publishes a raw IBC packet onto the channel. +func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg v1wasmTypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + if msg.IBC == nil || msg.IBC.SendPacket == nil { + return nil, nil, types.ErrUnknownMsg + } + if contractIBCPortID == "" { + return nil, nil, sdkerrors.Wrapf(types.ErrUnsupportedForContract, "ibc not supported") + } + contractIBCChannelID := msg.IBC.SendPacket.ChannelID + if contractIBCChannelID == "" { + return nil, nil, sdkerrors.Wrapf(types.ErrEmpty, "ibc channel") + } + + sequence, found := h.channelKeeper.GetNextSequenceSend(ctx, contractIBCPortID, contractIBCChannelID) + if !found { + return nil, nil, sdkerrors.Wrapf(channeltypes.ErrSequenceSendNotFound, + "source port: %s, source channel: %s", contractIBCPortID, contractIBCChannelID, + ) + } + + channelInfo, ok := h.channelKeeper.GetChannel(ctx, contractIBCPortID, contractIBCChannelID) + if !ok { + return nil, nil, sdkerrors.Wrap(channeltypes.ErrInvalidChannel, "not found") + } + channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID)) + if !ok { + return nil, nil, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + packet := channeltypes.NewPacket( + msg.IBC.SendPacket.Data, + sequence, + contractIBCPortID, + contractIBCChannelID, + channelInfo.Counterparty.PortId, + channelInfo.Counterparty.ChannelId, + convertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block), + msg.IBC.SendPacket.Timeout.Timestamp, + ) + return nil, nil, h.channelKeeper.SendPacket(ctx, channelCap, packet) +} + +type BankEncoder func(sender sdk.AccAddress, msg *v1wasmTypes.BankMsg) ([]sdk.Msg, error) type CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) -type StakingEncoder func(sender sdk.AccAddress, msg *v010wasmTypes.StakingMsg) ([]sdk.Msg, error) -type WasmEncoder func(sender sdk.AccAddress, msg *v010wasmTypes.WasmMsg) ([]sdk.Msg, error) -type GovEncoder func(sender sdk.AccAddress, msg *v010wasmTypes.GovMsg) ([]sdk.Msg, error) +type DistributionEncoder func(sender sdk.AccAddress, msg *v1wasmTypes.DistributionMsg) ([]sdk.Msg, error) +type GovEncoder func(sender sdk.AccAddress, msg *v1wasmTypes.GovMsg) ([]sdk.Msg, error) +type IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *v1wasmTypes.IBCMsg) ([]sdk.Msg, error) +type StakingEncoder func(sender sdk.AccAddress, msg *v1wasmTypes.StakingMsg) ([]sdk.Msg, error) +type StargateEncoder func(sender sdk.AccAddress, msg *v1wasmTypes.StargateMsg) ([]sdk.Msg, error) +type WasmEncoder func(sender sdk.AccAddress, msg *v1wasmTypes.WasmMsg) ([]sdk.Msg, error) type MessageEncoders struct { - Bank BankEncoder - Custom CustomEncoder - Staking StakingEncoder - Wasm WasmEncoder - Gov GovEncoder + Bank BankEncoder + Custom CustomEncoder + Distribution DistributionEncoder + Gov GovEncoder + IBC IBCEncoder + Staking StakingEncoder + Stargate StargateEncoder + Wasm WasmEncoder } -func DefaultEncoders() MessageEncoders { +func DefaultEncoders(portSource types.ICS20TransferPortSource, unpacker codectypes.AnyUnpacker) MessageEncoders { return MessageEncoders{ - Bank: EncodeBankMsg, - Custom: NoCustomMsg, - Staking: EncodeStakingMsg, - Wasm: EncodeWasmMsg, - Gov: EncodeGovMsg, + Bank: EncodeBankMsg, + Custom: NoCustomMsg, + Distribution: EncodeDistributionMsg, + Gov: EncodeGovMsg, + IBC: EncodeIBCMsg(portSource), + Staking: EncodeStakingMsg, + Stargate: EncodeStargateMsg(unpacker), + Wasm: EncodeWasmMsg, } } @@ -77,39 +194,86 @@ func (e MessageEncoders) Merge(o *MessageEncoders) MessageEncoders { return e } -func (e MessageEncoders) Encode(contractAddr sdk.AccAddress, msg v010wasmTypes.CosmosMsg) ([]sdk.Msg, error) { +func isValidV010Msg(msg v010wasmTypes.CosmosMsg) bool { + count := 0 + if msg.Bank != nil { + if msg.Bank.Send != nil { + count++ + } + } + if msg.Custom != nil { + count++ + } + if msg.Staking != nil { + if msg.Staking.Delegate != nil { + count++ + } + if msg.Staking.Undelegate != nil { + count++ + } + if msg.Staking.Redelegate != nil { + count++ + } + if msg.Staking.Withdraw != nil { + count++ + } + } + if msg.Wasm != nil { + if msg.Wasm.Execute != nil { + count++ + } + if msg.Wasm.Instantiate != nil { + count++ + } + } + if msg.Gov != nil { + if msg.Gov.Vote != nil { + count++ + } + } + + return count == 1 +} + +func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg v1wasmTypes.CosmosMsg) ([]sdk.Msg, error) { switch { case msg.Bank != nil: return e.Bank(contractAddr, msg.Bank) case msg.Custom != nil: return e.Custom(contractAddr, msg.Custom) + case msg.Distribution != nil: + return e.Distribution(contractAddr, msg.Distribution) + case msg.Gov != nil: + return e.Gov(contractAddr, msg.Gov) + case msg.IBC != nil: + return e.IBC(ctx, contractAddr, contractIBCPortID, msg.IBC) case msg.Staking != nil: return e.Staking(contractAddr, msg.Staking) + case msg.Stargate != nil: + return e.Stargate(contractAddr, msg.Stargate) case msg.Wasm != nil: return e.Wasm(contractAddr, msg.Wasm) - case msg.Gov != nil: - return e.Gov(contractAddr, msg.Gov) } return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Wasm") } -var VoteOptionMap = map[string]string{ - "Yes": "VOTE_OPTION_YES", - "Abstain": "VOTE_OPTION_ABSTAIN", - "No": "VOTE_OPTION_NO", - "NoWithVeto": "VOTE_OPTION_NO_WITH_VETO", +var VoteOptionMap = map[v1wasmTypes.VoteOption]string{ + v1wasmTypes.Yes: "VOTE_OPTION_YES", + v1wasmTypes.Abstain: "VOTE_OPTION_ABSTAIN", + v1wasmTypes.No: "VOTE_OPTION_NO", + v1wasmTypes.NoWithVeto: "VOTE_OPTION_NO_WITH_VETO", } -func EncodeGovMsg(sender sdk.AccAddress, msg *v010wasmTypes.GovMsg) ([]sdk.Msg, error) { +func EncodeGovMsg(sender sdk.AccAddress, msg *v1wasmTypes.GovMsg) ([]sdk.Msg, error) { if msg.Vote == nil { return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Gov") } - opt, exists := VoteOptionMap[msg.Vote.VoteOption] + opt, exists := VoteOptionMap[msg.Vote.Vote] if !exists { // if it's not found, let the `VoteOptionFromString` below fail - opt = msg.Vote.VoteOption + opt = "" } option, err := govtypes.VoteOptionFromString(opt) @@ -117,11 +281,41 @@ func EncodeGovMsg(sender sdk.AccAddress, msg *v010wasmTypes.GovMsg) ([]sdk.Msg, return nil, err } - sdkMsg := govtypes.NewMsgVote(sender, msg.Vote.Proposal, option) + sdkMsg := govtypes.NewMsgVote(sender, msg.Vote.ProposalId, option) return []sdk.Msg{sdkMsg}, nil } -func EncodeBankMsg(sender sdk.AccAddress, msg *v010wasmTypes.BankMsg) ([]sdk.Msg, error) { +func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *v1wasmTypes.IBCMsg) ([]sdk.Msg, error) { + return func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *v1wasmTypes.IBCMsg) ([]sdk.Msg, error) { + switch { + case msg.CloseChannel != nil: + return []sdk.Msg{&channeltypes.MsgChannelCloseInit{ + PortId: PortIDForContract(sender), + ChannelId: msg.CloseChannel.ChannelID, + Signer: sender.String(), + }}, nil + case msg.Transfer != nil: + amount, err := convertWasmCoinToSdkCoin(msg.Transfer.Amount) + if err != nil { + return nil, sdkerrors.Wrap(err, "amount") + } + msg := &ibctransfertypes.MsgTransfer{ + SourcePort: portSource.GetPort(ctx), + SourceChannel: msg.Transfer.ChannelID, + Token: amount, + Sender: sender.String(), + Receiver: msg.Transfer.ToAddress, + TimeoutHeight: convertWasmIBCTimeoutHeightToCosmosHeight(msg.Transfer.Timeout.Block), + TimeoutTimestamp: msg.Transfer.Timeout.Timestamp, + } + return []sdk.Msg{msg}, nil + default: + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "Unknown variant of IBC") + } + } +} + +func EncodeBankMsg(sender sdk.AccAddress, msg *v1wasmTypes.BankMsg) ([]sdk.Msg, error) { if msg.Send == nil { return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Bank") } @@ -129,11 +323,7 @@ func EncodeBankMsg(sender sdk.AccAddress, msg *v010wasmTypes.BankMsg) ([]sdk.Msg return nil, nil } // validate that the addresses are valid - _, stderr := sdk.AccAddressFromBech32(msg.Send.FromAddress) - if stderr != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Send.FromAddress) - } - _, stderr = sdk.AccAddressFromBech32(msg.Send.ToAddress) + _, stderr := sdk.AccAddressFromBech32(msg.Send.ToAddress) if stderr != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Send.ToAddress) } @@ -143,7 +333,7 @@ func EncodeBankMsg(sender sdk.AccAddress, msg *v010wasmTypes.BankMsg) ([]sdk.Msg return nil, err } sdkMsg := banktypes.MsgSend{ - FromAddress: msg.Send.FromAddress, + FromAddress: sender.String(), ToAddress: msg.Send.ToAddress, Amount: toSend, } @@ -154,7 +344,26 @@ func NoCustomMsg(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Custom variant not supported") } -func EncodeStakingMsg(sender sdk.AccAddress, msg *v010wasmTypes.StakingMsg) ([]sdk.Msg, error) { +func EncodeDistributionMsg(sender sdk.AccAddress, msg *v1wasmTypes.DistributionMsg) ([]sdk.Msg, error) { + switch { + case msg.SetWithdrawAddress != nil: + setMsg := distrtypes.MsgSetWithdrawAddress{ + DelegatorAddress: sender.String(), + WithdrawAddress: msg.SetWithdrawAddress.Address, + } + return []sdk.Msg{&setMsg}, nil + case msg.WithdrawDelegatorReward != nil: + withdrawMsg := distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: sender.String(), + ValidatorAddress: msg.WithdrawDelegatorReward.Validator, + } + return []sdk.Msg{&withdrawMsg}, nil + default: + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Distribution") + } +} + +func EncodeStakingMsg(sender sdk.AccAddress, msg *v1wasmTypes.StakingMsg) ([]sdk.Msg, error) { var err error switch { case msg.Delegate != nil: @@ -242,7 +451,24 @@ func EncodeStakingMsg(sender sdk.AccAddress, msg *v010wasmTypes.StakingMsg) ([]s } } -func EncodeWasmMsg(sender sdk.AccAddress, msg *v010wasmTypes.WasmMsg) ([]sdk.Msg, error) { +func EncodeStargateMsg(unpacker codectypes.AnyUnpacker) StargateEncoder { + return func(sender sdk.AccAddress, msg *v1wasmTypes.StargateMsg) ([]sdk.Msg, error) { + any := codectypes.Any{ + TypeUrl: msg.TypeURL, + Value: msg.Value, + } + var sdkMsg sdk.Msg + if err := unpacker.UnpackAny(&any, &sdkMsg); err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("Cannot unpack proto message with type URL: %s", msg.TypeURL)) + } + if err := codectypes.UnpackInterfaces(sdkMsg, unpacker); err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("UnpackInterfaces inside msg: %s", err)) + } + return []sdk.Msg{sdkMsg}, nil + } +} + +func EncodeWasmMsg(sender sdk.AccAddress, msg *v1wasmTypes.WasmMsg) ([]sdk.Msg, error) { switch { case msg.Execute != nil: contractAddr, err := sdk.AccAddressFromBech32(msg.Execute.ContractAddr) @@ -285,14 +511,13 @@ func EncodeWasmMsg(sender sdk.AccAddress, msg *v010wasmTypes.WasmMsg) ([]sdk.Msg } } -func (k Keeper) Dispatch(ctx sdk.Context, contractAddr sdk.AccAddress, msg v010wasmTypes.CosmosMsg) (events sdk.Events, data []byte, err error) { - - sdkMsgs, err := k.messenger.encoders.Encode(contractAddr, msg) +func (h MessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg v1wasmTypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { + sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg) if err != nil { return nil, nil, err } for _, sdkMsg := range sdkMsgs { - _, _, err := k.handleSdkMessage(ctx, contractAddr, sdkMsg) + _, _, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) if err != nil { return nil, nil, err } @@ -301,7 +526,7 @@ func (k Keeper) Dispatch(ctx sdk.Context, contractAddr sdk.AccAddress, msg v010w return nil, nil, nil } -func (k Keeper) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) (sdk.Events, []byte, error) { +func (h MessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) (sdk.Events, []byte, error) { if err := msg.ValidateBasic(); err != nil { return nil, nil, err } @@ -317,7 +542,7 @@ func (k Keeper) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg var err error if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok { msgRoute := legacyMsg.Route() - handler := k.messenger.router.Route(ctx, msgRoute) + handler := h.router.Route(ctx, msgRoute) if handler == nil { return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s", msgRoute) } @@ -365,6 +590,14 @@ func (k Keeper) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg return nil, nil, nil } +// convertWasmIBCTimeoutHeightToCosmosHeight converts a wasm type ibc timeout height to ibc module type height +func convertWasmIBCTimeoutHeightToCosmosHeight(ibcTimeoutBlock *v1wasmTypes.IBCTimeoutBlock) ibcclienttypes.Height { + if ibcTimeoutBlock == nil { + return ibcclienttypes.NewHeight(0, 0) + } + return ibcclienttypes.NewHeight(ibcTimeoutBlock.Revision, ibcTimeoutBlock.Height) +} + func convertWasmCoinsToSdkCoins(coins []wasmTypes.Coin) (sdk.Coins, error) { var toSend sdk.Coins for _, coin := range coins { diff --git a/x/compute/internal/keeper/handler_plugin_test.go b/x/compute/internal/keeper/handler_plugin_test.go index 39fd7a133..e5c586042 100644 --- a/x/compute/internal/keeper/handler_plugin_test.go +++ b/x/compute/internal/keeper/handler_plugin_test.go @@ -30,8 +30,10 @@ func TestEncoding(t *testing.T) { jsonMsg := json.RawMessage(`{"foo": 123}`) cases := map[string]struct { - sender sdk.AccAddress - input v010wasmTypes.CosmosMsg + sender sdk.AccAddress + input v010wasmTypes.CosmosMsg + srcContractIBCPort string + transferPortSource types.ICS20TransferPortSource // set if valid output []sdk.Msg // set if invalid @@ -263,11 +265,15 @@ func TestEncoding(t *testing.T) { }, } - encoder := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + for name, tc := range cases { tc := tc t.Run(name, func(t *testing.T) { - res, err := encoder.Encode(tc.sender, tc.input) + var ctx sdk.Context + encoder := DefaultEncoders(tc.transferPortSource, encodingConfig.Marshaler) + v1input, _ := V010MsgToV1SubMsg(tc.input) + res, err := encoder.Encode(ctx, tc.sender, tc.srcContractIBCPort, v1input.Msg) if tc.isError { require.Error(t, err) } else { diff --git a/x/compute/internal/keeper/keeper.go b/x/compute/internal/keeper/keeper.go index 3121adcf4..47df389ea 100644 --- a/x/compute/internal/keeper/keeper.go +++ b/x/compute/internal/keeper/keeper.go @@ -3,7 +3,12 @@ package keeper import ( "bytes" "encoding/binary" + "encoding/json" "fmt" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + channelkeeper "github.com/cosmos/ibc-go/v3/modules/core/04-channel/keeper" + portkeeper "github.com/cosmos/ibc-go/v3/modules/core/05-port/keeper" + wasmTypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types" "path/filepath" "strconv" "time" @@ -20,6 +25,7 @@ import ( govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/crypto" @@ -38,6 +44,19 @@ import ( "github.com/enigmampc/SecretNetwork/x/compute/internal/types" ) +type ResponseHandler interface { + // Handle processes the data returned by a contract invocation. + Handle( + ctx sdk.Context, + contractAddr sdk.AccAddress, + ibcPort string, + messages []v1wasmTypes.SubMsg, + origRspData []byte, + ogTx []byte, + sigInfo wasmTypes.VerificationInfo, + ) ([]byte, error) +} + // Keeper will have a reference to Wasmer with it's own data directory. type Keeper struct { storeKey sdk.StoreKey @@ -45,11 +64,12 @@ type Keeper struct { legacyAmino codec.LegacyAmino accountKeeper authkeeper.AccountKeeper bankKeeper bankkeeper.Keeper - portKeeper types.PortKeeper - capabilityKeeper types.CapabilityKeeper + portKeeper portkeeper.Keeper + capabilityKeeper capabilitykeeper.ScopedKeeper wasmer wasm.Wasmer queryPlugins QueryPlugins - messenger MessageHandler + messenger Messenger + responseHandler ResponseHandler // queryGasLimit is the max wasm gas that can be spent on executing a query with a contract queryGasLimit uint64 serviceRouter MsgServiceRouter @@ -62,8 +82,10 @@ type MsgServiceRouter interface { Handler(msg sdk.Msg) baseapp.MsgServiceHandler } -// NewKeeper creates a new contract Keeper instance -// If customEncoders is non-nil, we can use this to override some of the message handler, especially custom +func moduleLogger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + func NewKeeper( cdc codec.Codec, legacyAmino codec.LegacyAmino, @@ -74,7 +96,10 @@ func NewKeeper( distKeeper distrkeeper.Keeper, mintKeeper mintkeeper.Keeper, stakingKeeper stakingkeeper.Keeper, -//serviceRouter MsgServiceRouter, + capabilityKeeper capabilitykeeper.ScopedKeeper, + portKeeper portkeeper.Keeper, + portSource types.ICS20TransferPortSource, + channelKeeper channelkeeper.Keeper, router sdk.Router, homeDir string, wasmConfig *types.WasmConfig, @@ -95,19 +120,19 @@ func NewKeeper( */ keeper := Keeper{ - storeKey: storeKey, - cdc: cdc, - legacyAmino: legacyAmino, - wasmer: *wasmer, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, - messenger: NewMessageHandler(router, customEncoders), - queryGasLimit: wasmConfig.SmartQueryGasLimit, - //serviceRouter: serviceRouter, - // authZPolicy: DefaultAuthorizationPolicy{}, - //paramSpace: paramSpace, + storeKey: storeKey, + cdc: cdc, + legacyAmino: legacyAmino, + wasmer: *wasmer, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + portKeeper: portKeeper, + capabilityKeeper: capabilityKeeper, + messenger: NewMessageHandler(router, customEncoders, channelKeeper, capabilityKeeper, portSource, cdc), + queryGasLimit: wasmConfig.SmartQueryGasLimit, } keeper.queryPlugins = DefaultQueryPlugins(govKeeper, distKeeper, mintKeeper, bankKeeper, stakingKeeper, &keeper).Merge(customPlugins) + keeper.responseHandler = NewContractResponseHandler(NewMessageDispatcher(keeper.messenger, keeper)) return keeper } @@ -269,6 +294,66 @@ func (k Keeper) GetSignerInfo(ctx sdk.Context, signer sdk.AccAddress) ([]byte, s return signBytes, signMode, modeInfoBytes, pkBytes, tx.Signatures[pkIndex], nil } +func V010MsgToV1SubMsg(msg v010wasmTypes.CosmosMsg) (v1wasmTypes.SubMsg, error) { + if !isValidV010Msg(msg) { + return v1wasmTypes.SubMsg{}, fmt.Errorf("exactly one message type is supported: %v", msg) + } + + subMsg := v1wasmTypes.SubMsg{ + ID: 0, // https://github.com/CosmWasm/cosmwasm/blob/v1.0.0/packages/std/src/results/submessages.rs#L40-L41 + GasLimit: nil, // New v1 submessages module handles nil as unlimited, in v010 the gas was not limited for messages + ReplyOn: v1wasmTypes.ReplyNever, + } + + if msg.Bank != nil { + subMsg.Msg = v1wasmTypes.CosmosMsg{ + Bank: &v1wasmTypes.BankMsg{ + Send: &v1wasmTypes.SendMsg{ToAddress: msg.Bank.Send.ToAddress, Amount: msg.Bank.Send.Amount}, + }, + } + } else if msg.Custom != nil { + subMsg.Msg.Custom = msg.Custom + } else if msg.Staking != nil { + subMsg.Msg = v1wasmTypes.CosmosMsg{ + Staking: &v1wasmTypes.StakingMsg{ + Delegate: msg.Staking.Delegate, + Undelegate: msg.Staking.Undelegate, + Redelegate: msg.Staking.Redelegate, + Withdraw: msg.Staking.Withdraw, + }, + } + } else if msg.Wasm != nil { + subMsg.Msg = v1wasmTypes.CosmosMsg{ + Wasm: &v1wasmTypes.WasmMsg{ + Execute: msg.Wasm.Execute, + Instantiate: msg.Wasm.Instantiate, + }, + } + + } else if msg.Gov != nil { + subMsg.Msg = v1wasmTypes.CosmosMsg{ + Gov: &v1wasmTypes.GovMsg{ + Vote: &v1wasmTypes.VoteMsg{ProposalId: msg.Gov.Vote.Proposal, Vote: v1wasmTypes.ToVoteOption[msg.Gov.Vote.VoteOption]}, + }, + } + } + + return subMsg, nil +} + +func V010MsgsToV1SubMsgs(msgs []v010wasmTypes.CosmosMsg) ([]v1wasmTypes.SubMsg, error) { + subMsgs := []v1wasmTypes.SubMsg{} + for _, msg := range msgs { + v1SubMsg, err := V010MsgToV1SubMsg(msg) + if err != nil { + return nil, err + } + subMsgs = append(subMsgs, v1SubMsg) + } + + return subMsgs, nil +} + // Instantiate creates an instance of a WASM contract func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, callbackSig []byte) (sdk.AccAddress, []byte, error) { defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "instantiate") @@ -360,26 +445,28 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddre switch res := response.(type) { case v010wasmTypes.InitResponse: // emit all events from this contract itself - events := types.ParseEvents(res.Log, contractAddress) - ctx.EventManager().EmitEvents(events) // persist instance createdAt := types.NewAbsoluteTxPosition(ctx) - instance := types.NewContractInfo(codeID, creator, label, createdAt) - store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshal(&instance)) + contractInfo := types.NewContractInfo(codeID, creator, label, createdAt) + store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshal(&contractInfo)) // fmt.Printf("Storing key: %v for account %s\n", key, contractAddress) store.Set(types.GetContractEnclaveKey(contractAddress), key) - store.Set(types.GetContractLabelPrefix(label), contractAddress) - err = k.dispatchMessages(ctx, contractAddress, res.Messages) + subMessages, err := V010MsgsToV1SubMsgs(res.Messages) if err != nil { - return nil, nil, err + return nil, nil, sdkerrors.Wrap(err, "couldn't convert v010 messages to v1 messages") } - return contractAddress, nil, nil + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, subMessages, res.Log, []byte{}, initMsg, verificationInfo) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "dispatch") + } + + return contractAddress, data, nil case v1wasmTypes.Response: // persist instance first createdAt := types.NewAbsoluteTxPosition(ctx) @@ -405,14 +492,20 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddre sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), )) - data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + // persist instance + store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshal(&contractInfo)) + store.Set(types.GetContractEnclaveKey(contractAddress), key) + + store.Set(types.GetContractLabelPrefix(label), contractAddress) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, initMsg, verificationInfo) if err != nil { return nil, nil, sdkerrors.Wrap(err, "dispatch") } return contractAddress, data, nil default: - return nil, sdkerrors.Wrap(types.ErrInstantiateFailed, fmt.Sprintf("cannot detect response type: %v", res)) + return nil, nil, sdkerrors.Wrap(types.ErrInstantiateFailed, fmt.Sprintf("cannot detect response type: %v", res)) } } @@ -439,7 +532,7 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller verificationInfo := types.NewVerificationInfo(signBytes, signMode, modeInfoBytes, pkBytes, signerSig, callbackSig) - codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) if err != nil { return nil, err } @@ -468,7 +561,7 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller } gas := gasForContract(ctx) - response, gasUsed, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas, verificationInfo) + response, gasUsed, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas, verificationInfo, wasmTypes.HandleTypeExecute) consumeGas(ctx, gasUsed) if execErr != nil { @@ -477,21 +570,33 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller switch res := response.(type) { case v010wasmTypes.HandleResponse: - // emit all events from this contract itself - events := types.ParseEvents(res.Log, contractAddress) - ctx.EventManager().EmitEvents(events) + subMessages, err := V010MsgsToV1SubMsgs(res.Messages) + if err != nil { + return nil, sdkerrors.Wrap(err, "couldn't convert v010 messages to v1 messages") + } - err = k.dispatchMessages(ctx, contractAddress, res.Messages) + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, subMessages, res.Log, res.Data, msg, verificationInfo) if err != nil { - return nil, err + return nil, sdkerrors.Wrap(err, "dispatch") } return &sdk.Result{ - Data: res.Data, + Data: data, }, nil case v1wasmTypes.Response: - // TODO - return nil, sdkerrors.Wrap(types.ErrInstantiateFailed, fmt.Sprintf("cannot detect response type: %v", res)) + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeExecute, + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + )) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, msg, verificationInfo) + if err != nil { + return nil, sdkerrors.Wrap(err, "dispatch") + } + + return &sdk.Result{ + Data: data, + }, nil default: return nil, sdkerrors.Wrap(types.ErrInstantiateFailed, fmt.Sprintf("cannot detect response type: %v", res)) } @@ -516,7 +621,7 @@ func (k Keeper) querySmartImpl(ctx sdk.Context, contractAddr sdk.AccAddress, req ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading CosmWasm module: query") - codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) if err != nil { return nil, err } @@ -569,25 +674,25 @@ func (k Keeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key [] return result } -func (k Keeper) contractInstance(ctx sdk.Context, contractAddress sdk.AccAddress) (types.CodeInfo, prefix.Store, error) { +func (k Keeper) contractInstance(ctx sdk.Context, contractAddress sdk.AccAddress) (types.ContractInfo, types.CodeInfo, prefix.Store, error) { store := ctx.KVStore(k.storeKey) contractBz := store.Get(types.GetContractAddressKey(contractAddress)) if contractBz == nil { - return types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "contract") + return types.ContractInfo{}, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "contract") } var contract types.ContractInfo k.cdc.MustUnmarshal(contractBz, &contract) contractInfoBz := store.Get(types.GetCodeKey(contract.CodeID)) if contractInfoBz == nil { - return types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "contract info") + return types.ContractInfo{}, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "contract info") } var codeInfo types.CodeInfo k.cdc.MustUnmarshal(contractInfoBz, &codeInfo) prefixStoreKey := types.GetContractStorePrefixKey(contractAddress) prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) - return codeInfo, prefixStore, nil + return contract, codeInfo, prefixStore, nil } func (k Keeper) GetContractKey(ctx sdk.Context, contractAddress sdk.AccAddress) []byte { @@ -755,18 +860,24 @@ func (k Keeper) GetByteCode(ctx sdk.Context, codeID uint64) ([]byte, error) { return k.wasmer.GetCode(codeInfo.CodeHash) } -func (k Keeper) dispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, msgs []v010wasmTypes.CosmosMsg) error { - for _, msg := range msgs { - - //var events sdk.Events - //var data []byte - var err error - - if _, _, err = k.Dispatch(ctx, contractAddr, msg); err != nil { - return err - } - } - return nil +// handleContractResponse processes the contract response data by emitting events and sending sub-/messages. +func (k *Keeper) handleContractResponse( + ctx sdk.Context, + contractAddr sdk.AccAddress, + ibcPort string, + msgs []v1wasmTypes.SubMsg, + logs []v010wasmTypes.LogAttribute, + data []byte, + // original TX in order to extract the first 64bytes of signing info + ogTx []byte, + // sigInfo of the initial message that triggered the original contract call + // This is used mainly in replies in order to decrypt their data. + ogSigInfo wasmTypes.VerificationInfo, +) ([]byte, error) { + events := types.ContractLogsToSdkEvents(logs, contractAddr) + ctx.EventManager().EmitEvents(events) + + return k.responseHandler.Handle(ctx, contractAddr, ibcPort, msgs, data, ogTx, ogSigInfo) } func gasForContract(ctx sdk.Context) uint64 { @@ -882,3 +993,89 @@ func gasMeter(ctx sdk.Context) MultipiedGasMeter { originalMeter: ctx.GasMeter(), } } + +type MsgDispatcher interface { + DispatchSubmessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []v1wasmTypes.SubMsg, ogTx []byte, ogSigInfo wasmTypes.VerificationInfo) ([]byte, error) +} + +// ContractResponseHandler default implementation that first dispatches submessage then normal messages. +// The Submessage execution may include an success/failure response handling by the contract that can overwrite the +// original +type ContractResponseHandler struct { + md MsgDispatcher +} + +func NewContractResponseHandler(md MsgDispatcher) *ContractResponseHandler { + return &ContractResponseHandler{md: md} +} + +// Handle processes the data returned by a contract invocation. +func (h ContractResponseHandler) Handle(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, messages []v1wasmTypes.SubMsg, origRspData []byte, ogTx []byte, ogSigInfo wasmTypes.VerificationInfo) ([]byte, error) { + result := origRspData + switch rsp, err := h.md.DispatchSubmessages(ctx, contractAddr, ibcPort, messages, ogTx, ogSigInfo); { + case err != nil: + return nil, sdkerrors.Wrap(err, "submessages") + case rsp != nil: + result = rsp + } + return result, nil +} + +// reply is only called from keeper internal functions (dispatchSubmessages) after processing the submessage +func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply v1wasmTypes.Reply, ogTx []byte, ogSigInfo wasmTypes.VerificationInfo) ([]byte, error) { + + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) + if err != nil { + return nil, err + } + + // always consider this pinned + ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading Compute module: reply") + + store := ctx.KVStore(k.storeKey) + contractKey := store.Get(types.GetContractEnclaveKey(contractAddress)) + + env := types.NewEnv(ctx, contractAddress, sdk.Coins{}, contractAddress, contractKey) + + // prepare querier + querier := QueryHandler{ + Ctx: ctx, + Plugins: k.queryPlugins, + } + + // instantiate wasm contract + gas := gasForContract(ctx) + marshaledReply, error := json.Marshal(reply) + marshaledReply = append(ogTx[0:64], marshaledReply...) + + if error != nil { + return nil, error + } + + response, gasUsed, execErr := k.wasmer.Execute(codeInfo.CodeHash, env, marshaledReply, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, ogSigInfo, wasmTypes.HandleTypeReply) + + switch res := response.(type) { + case v010wasmTypes.HandleResponse: + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, fmt.Sprintf("response of reply should always be cosmwasm v1 response: %v", res)) + case v1wasmTypes.Response: + consumeGas(ctx, gasUsed) + if execErr != nil { + return nil, sdkerrors.Wrap(types.ErrReplyFailed, execErr.Error()) + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeReply, + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + )) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, ogTx, ogSigInfo) + if err != nil { + return nil, sdkerrors.Wrap(err, "dispatch") + } + + return data, nil + default: + return nil, sdkerrors.Wrap(types.ErrReplyFailed, fmt.Sprintf("cannot detect response type: %v", res)) + } + +} diff --git a/x/compute/internal/keeper/keeper_test.go b/x/compute/internal/keeper/keeper_test.go index f1e094ad5..4a88f6391 100644 --- a/x/compute/internal/keeper/keeper_test.go +++ b/x/compute/internal/keeper/keeper_test.go @@ -54,13 +54,23 @@ func init() { } func TestNewKeeper(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) _, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) require.NotNil(t, keepers.WasmKeeper) } func TestCreate(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -178,7 +188,12 @@ func TestCreateWithParamPermissions(t *testing.T) { */ func TestCreateDuplicate(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -208,7 +223,12 @@ func TestCreateDuplicate(t *testing.T) { } func TestCreateWithSimulation(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -265,7 +285,12 @@ func TestIsSimulationMode(t *testing.T) { } func TestCreateWithGzippedPayload(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -287,7 +312,12 @@ func TestCreateWithGzippedPayload(t *testing.T) { } func TestInstantiate(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -341,7 +371,7 @@ func TestInstantiate(t *testing.T) { ctx = ctx.WithTxBytes(txBytes) // create with no balance is also legal - contractAddr, err := keeper.Instantiate(ctx, contractID, creator /* , nil */, initMsgBz, "demo contract 1", nil, nil) + contractAddr, _, err := keeper.Instantiate(ctx, contractID, creator /* , nil */, initMsgBz, "demo contract 1", nil, nil) require.NoError(t, err) require.Equal(t, "secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg", contractAddr.String()) @@ -357,7 +387,7 @@ func TestInstantiate(t *testing.T) { require.Equal(t, info.Label, "demo contract 1") // test that creating again with the same label will fail - _, err = keeper.Instantiate(ctx, contractID, creator /* , nil */, initMsgBz, "demo contract 1", nil, nil) + _, _, err = keeper.Instantiate(ctx, contractID, creator /* , nil */, initMsgBz, "demo contract 1", nil, nil) require.Error(t, err) /* @@ -486,14 +516,19 @@ func TestInstantiateWithPermissions(t *testing.T) { contractID, err := keeper.Create(ctx, myAddr, wasmCode, "https://github.com/CosmWasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm", "") require.NoError(t, err) - _, err = keeper.Instantiate(ctx, contractID, spec.srcActor, nil, initMsgBz, "demo contract 1", nil) + _,_, err = keeper.Instantiate(ctx, contractID, spec.srcActor, nil, initMsgBz, "demo contract 1", nil) assert.True(t, spec.expError.Is(err), "got %+v", err) }) } } */ func TestInstantiateWithNonExistingCodeID(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -527,13 +562,18 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) { ctx = ctx.WithTxBytes(txBytes) - addr, err := keeper.Instantiate(ctx, nonExistingCodeID, creator /* , nil */, initMsgBz, "demo contract 2", nil, nil) + addr, _, err := keeper.Instantiate(ctx, nonExistingCodeID, creator /* , nil */, initMsgBz, "demo contract 2", nil, nil) require.True(t, types.ErrNotFound.Is(err), err) require.Nil(t, addr) } func TestExecute(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -570,7 +610,7 @@ func TestExecute(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initMsgBz, contractID, deposit) // create with no balance is also legal - addr, err := keeper.Instantiate(ctx, contractID, creator /* , nil */, initMsgBz, "demo contract 1", deposit, nil) + addr, _, err := keeper.Instantiate(ctx, contractID, creator /* , nil */, initMsgBz, "demo contract 1", deposit, nil) require.NoError(t, err) @@ -719,7 +759,12 @@ func TestExecuteWithDeposit(t *testing.T) { } func TestExecuteWithNonExistingAddress(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -752,7 +797,12 @@ func TestExecuteWithNonExistingAddress(t *testing.T) { } func TestExecuteWithPanic(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -802,7 +852,12 @@ func TestExecuteWithPanic(t *testing.T) { } func TestExecuteWithCpuLoop(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -853,7 +908,7 @@ func TestExecuteWithCpuLoop(t *testing.T) { ctx = ctx.WithTxBytes(txBytes) - addr, err := keeper.Instantiate(ctx, contractID, creator /* , nil */, msgBz, "demo contract 5", deposit, nil) + addr, _, err := keeper.Instantiate(ctx, contractID, creator /* , nil */, msgBz, "demo contract 5", deposit, nil) require.NoError(t, err) // make sure we set a limit before calling @@ -905,7 +960,12 @@ func TestExecuteWithCpuLoop(t *testing.T) { } func TestExecuteWithStorageLoop(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper diff --git a/x/compute/internal/keeper/mint_test.go b/x/compute/internal/keeper/mint_test.go index 28b6daaf2..39f0b6004 100644 --- a/x/compute/internal/keeper/mint_test.go +++ b/x/compute/internal/keeper/mint_test.go @@ -2,6 +2,7 @@ package keeper import ( "encoding/json" + "github.com/enigmampc/SecretNetwork/x/compute/internal/types" "io/ioutil" "testing" @@ -25,7 +26,12 @@ type MintExecMsgBondedRatio struct { // TestMintQuerier func TestMintQuerier(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, stakingKeeper, keeper, distKeeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper, keepers.DistKeeper @@ -69,7 +75,7 @@ func TestMintQuerier(t *testing.T) { require.NoError(t, err) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initBz, govId, nil) - govAddr, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", nil, nil) + govAddr, _, err := keeper.Instantiate(ctx, govId, creator, initBz, "gidi gov", nil, nil) require.NoError(t, err) require.NotEmpty(t, govAddr) diff --git a/x/compute/internal/keeper/msg_dispatcher.go b/x/compute/internal/keeper/msg_dispatcher.go new file mode 100644 index 000000000..8cc809e78 --- /dev/null +++ b/x/compute/internal/keeper/msg_dispatcher.go @@ -0,0 +1,352 @@ +package keeper + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + wasmTypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types" + v010wasmTypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v010" + v1wasmTypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" + "github.com/enigmampc/SecretNetwork/x/compute/internal/types" + abci "github.com/tendermint/tendermint/abci/types" + "reflect" +) + +// Messenger is an extension point for custom wasmd message handling +type Messenger interface { + // DispatchMsg encodes the wasmVM message and dispatches it. + DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg v1wasmTypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) +} + +// Replyer is a subset of keeper that can handle replies to submessages +type Replyer interface { + reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply v1wasmTypes.Reply, ogTx []byte, ogSigInfo wasmTypes.VerificationInfo) ([]byte, error) +} + +// MessageDispatcher coordinates message sending and submessage reply/ state commits +type MessageDispatcher struct { + messenger Messenger + keeper Replyer +} + +// NewMessageDispatcher constructor +func NewMessageDispatcher(messenger Messenger, keeper Replyer) *MessageDispatcher { + return &MessageDispatcher{messenger: messenger, keeper: keeper} +} + +func filterEvents(events []sdk.Event) []sdk.Event { + // pre-allocate space for efficiency + res := make([]sdk.Event, 0, len(events)) + for _, ev := range events { + if ev.Type != "message" { + res = append(res, ev) + } + } + return res +} + +func sdkAttributesToWasmVMAttributes(attrs []abci.EventAttribute) []v010wasmTypes.LogAttribute { + res := make([]v010wasmTypes.LogAttribute, len(attrs)) + for i, attr := range attrs { + res[i] = v010wasmTypes.LogAttribute{ + Key: string(attr.Key), + Value: string(attr.Value), + } + } + return res +} + +func sdkEventsToWasmVMEvents(events []sdk.Event) []v1wasmTypes.Event { + res := make([]v1wasmTypes.Event, len(events)) + for i, ev := range events { + res[i] = v1wasmTypes.Event{ + Type: ev.Type, + Attributes: sdkAttributesToWasmVMAttributes(ev.Attributes), + } + } + return res +} + +// dispatchMsgWithGasLimit sends a message with gas limit applied +func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg v1wasmTypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, err error) { + limitedMeter := sdk.NewGasMeter(gasLimit) + subCtx := ctx.WithGasMeter(limitedMeter) + + // catch out of gas panic and just charge the entire gas limit + defer func() { + if r := recover(); r != nil { + // if it's not an OutOfGas error, raise it again + if _, ok := r.(sdk.ErrorOutOfGas); !ok { + // log it to get the original stack trace somewhere (as panic(r) keeps message but stacktrace to here + moduleLogger(ctx).Info("SubMsg rethrowing panic: %#v", r) + panic(r) + } + ctx.GasMeter().ConsumeGas(gasLimit, "Sub-Message OutOfGas panic") + err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "SubMsg hit gas limit") + } + }() + events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg) + + // make sure we charge the parent what was spent + spent := subCtx.GasMeter().GasConsumed() + ctx.GasMeter().ConsumeGas(spent, "From limited Sub-Message") + + return events, data, err +} + +// SystemError captures all errors returned from the Rust code as SystemError. +// Exactly one of the fields should be set. +type SystemError struct { + InvalidRequest *InvalidRequest `json:"invalid_request,omitempty"` + InvalidResponse *InvalidResponse `json:"invalid_response,omitempty"` + NoSuchContract *NoSuchContract `json:"no_such_contract,omitempty"` + Unknown *Unknown `json:"unknown,omitempty"` + UnsupportedRequest *UnsupportedRequest `json:"unsupported_request,omitempty"` +} + +var ( + _ error = SystemError{} + _ error = InvalidRequest{} + _ error = InvalidResponse{} + _ error = NoSuchContract{} + _ error = Unknown{} + _ error = UnsupportedRequest{} +) + +func (a SystemError) Error() string { + switch { + case a.InvalidRequest != nil: + return a.InvalidRequest.Error() + case a.InvalidResponse != nil: + return a.InvalidResponse.Error() + case a.NoSuchContract != nil: + return a.NoSuchContract.Error() + case a.Unknown != nil: + return a.Unknown.Error() + case a.UnsupportedRequest != nil: + return a.UnsupportedRequest.Error() + default: + panic("unknown error variant") + } +} + +type InvalidRequest struct { + Err string `json:"error"` + Request []byte `json:"request"` +} + +func (e InvalidRequest) Error() string { + return fmt.Sprintf("invalid request: %s - original request: %s", e.Err, string(e.Request)) +} + +type InvalidResponse struct { + Err string `json:"error"` + Response []byte `json:"response"` +} + +func (e InvalidResponse) Error() string { + return fmt.Sprintf("invalid response: %s - original response: %s", e.Err, string(e.Response)) +} + +type NoSuchContract struct { + Addr string `json:"addr,omitempty"` +} + +func (e NoSuchContract) Error() string { + return fmt.Sprintf("no such contract: %s", e.Addr) +} + +type Unknown struct{} + +func (e Unknown) Error() string { + return "unknown system error" +} + +type UnsupportedRequest struct { + Kind string `json:"kind,omitempty"` +} + +func (e UnsupportedRequest) Error() string { + return fmt.Sprintf("unsupported request: %s", e.Kind) +} + +// check if an interface is nil (even if it has type info) +func isNil(i interface{}) bool { + if i == nil { + return true + } + if reflect.TypeOf(i).Kind() == reflect.Ptr { + // IsNil panics if you try it on a struct (not a pointer) + return reflect.ValueOf(i).IsNil() + } + // if we aren't a pointer, can't be nil, can we? + return false +} + +// ToSystemError will try to convert the given error to an SystemError. +// This is important to returning any Go error back to Rust. +// +// If it is already StdError, return self. +// If it is an error, which could be a sub-field of StdError, embed it. +// If it is anything else, **return nil** +// +// This may return nil on an unknown error, whereas ToStdError will always create +// a valid error type. +func ToSystemError(err error) *SystemError { + if isNil(err) { + return nil + } + switch t := err.(type) { + case SystemError: + return &t + case *SystemError: + return t + case InvalidRequest: + return &SystemError{InvalidRequest: &t} + case *InvalidRequest: + return &SystemError{InvalidRequest: t} + case InvalidResponse: + return &SystemError{InvalidResponse: &t} + case *InvalidResponse: + return &SystemError{InvalidResponse: t} + case NoSuchContract: + return &SystemError{NoSuchContract: &t} + case *NoSuchContract: + return &SystemError{NoSuchContract: t} + case Unknown: + return &SystemError{Unknown: &t} + case *Unknown: + return &SystemError{Unknown: t} + case UnsupportedRequest: + return &SystemError{UnsupportedRequest: &t} + case *UnsupportedRequest: + return &SystemError{UnsupportedRequest: t} + default: + return nil + } +} + +// Reply is encrypted on when it is a contract reply and it is OK since error is always reducted to be a string. +func isReplyEncrypted(msg v1wasmTypes.CosmosMsg, reply v1wasmTypes.Reply) bool { + return (msg.Wasm != nil) && (reply.Result.Ok != nil) +} + +// Issue #759 - we don't return error string for worries of non-determinism +func redactError(err error) error { + // Do not redact system errors + // SystemErrors must be created in x/wasm and we can ensure determinism + if ToSystemError(err) != nil { + return err + } + + // FIXME: do we want to hardcode some constant string mappings here as well? + // Or better document them? (SDK error string may change on a patch release to fix wording) + // sdk/11 is out of gas + // sdk/5 is insufficient funds (on bank send) + // (we can theoretically redact less in the future, but this is a first step to safety) + codespace, code, _ := sdkerrors.ABCIInfo(err, false) + return fmt.Errorf("codespace: %s, code: %d", codespace, code) +} + +// DispatchSubmessages builds a sandbox to execute these messages and returns the execution result to the contract +// that dispatched them, both on success as well as failure +func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []v1wasmTypes.SubMsg, ogTx []byte, ogSigInfo wasmTypes.VerificationInfo) ([]byte, error) { + var rsp []byte + for _, msg := range msgs { + // Check replyOn validity + switch msg.ReplyOn { + case v1wasmTypes.ReplySuccess, v1wasmTypes.ReplyError, v1wasmTypes.ReplyAlways, v1wasmTypes.ReplyNever: + default: + return nil, sdkerrors.Wrap(types.ErrInvalid, "replyOn value") + } + + // first, we build a sub-context which we can use inside the submessages + subCtx, commit := ctx.CacheContext() + em := sdk.NewEventManager() + subCtx = subCtx.WithEventManager(em) + + // check how much gas left locally, optionally wrap the gas meter + gasRemaining := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumed() + limitGas := msg.GasLimit != nil && (*msg.GasLimit < gasRemaining) + + var err error + var events []sdk.Event + var data [][]byte + if limitGas { + events, data, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit) + } else { + events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg) + } + + // if it succeeds, commit state changes from submessage, and pass on events to Event Manager + var filteredEvents []sdk.Event + if err == nil { + commit() + filteredEvents = filterEvents(append(em.Events(), events...)) + ctx.EventManager().EmitEvents(filteredEvents) + } // on failure, revert state from sandbox, and ignore events (just skip doing the above) + + // we only callback if requested. Short-circuit here the cases we don't want to + if (msg.ReplyOn == v1wasmTypes.ReplySuccess || msg.ReplyOn == v1wasmTypes.ReplyNever) && err != nil { + // Note: this also handles the case of v010 submessage for which the execution failed + return nil, err + } + + if msg.ReplyOn == v1wasmTypes.ReplyNever || (msg.ReplyOn == v1wasmTypes.ReplyError && err == nil) { + continue + } + + // If we are here it means that ReplySuccess and success OR ReplyError and there were errors OR ReplyAlways. + // Basically, handle replying to the contract + // We need to create a SubMsgResult and pass it into the calling contract + var result v1wasmTypes.SubMsgResult + if err == nil { + // just take the first one for now if there are multiple sub-sdk messages + // and safely return nothing if no data + var responseData []byte + if len(data) > 0 { + responseData = data[0] + } + result = v1wasmTypes.SubMsgResult{ + // Copy first 64 bytes of the OG message in order to preserve the pubkey. + Ok: &v1wasmTypes.SubMsgResponse{ + Events: sdkEventsToWasmVMEvents(filteredEvents), + Data: responseData, + }, + } + } else { + // Issue #759 - we don't return error string for worries of non-determinism + moduleLogger(ctx).Info("Redacting submessage error", "cause", err) + result = v1wasmTypes.SubMsgResult{ + Err: redactError(err).Error(), + } + } + + // now handle the reply, we use the parent context, and abort on error + reply := v1wasmTypes.Reply{ + ID: msg.ID, + Result: result, + } + + // we can ignore any result returned as there is nothing to do with the data + // and the events are already in the ctx.EventManager() + + // In order to specify that the reply isn't signed by the enclave we use "SIGN_MODE_UNSPECIFIED" + // The SGX will notice that the value is SIGN_MODE_UNSPECIFIED and will treat the message as plaintext. + replySigInfo := wasmTypes.VerificationInfo{ + SignMode: "SIGN_MODE_UNSPECIFIED", + } + if isReplyEncrypted(msg.Msg, reply) { + replySigInfo = ogSigInfo + } + + rspData, err := d.keeper.reply(ctx, contractAddr, reply, ogTx, replySigInfo) + switch { + case err != nil: + return nil, sdkerrors.Wrap(err, "reply") + case rspData != nil: + rsp = rspData + } + } + return rsp, nil +} diff --git a/x/compute/internal/keeper/param_verification_test.go b/x/compute/internal/keeper/param_verification_test.go index 65aa654ad..d6b9c921b 100644 --- a/x/compute/internal/keeper/param_verification_test.go +++ b/x/compute/internal/keeper/param_verification_test.go @@ -241,7 +241,7 @@ func TestMultipleSigners(t *testing.T) { []sdk.AccAddress{walletA, walletB}, []crypto.PrivKey{privKeyA, privKeyB}, []sdk.Msg{&sdkMsgA, &sdkMsgB}, codeID, ) - contractAddressA, err := keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + contractAddressA, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) if err != nil { err = extractInnerError(t, err, nonce, true) } @@ -259,7 +259,7 @@ func TestMultipleSigners(t *testing.T) { wasmEvents, ) - contractAddressB, err := keeper.Instantiate(ctx, codeID, walletB /* nil,*/, initMsgBz, "demo contract 2", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + contractAddressB, _, err := keeper.Instantiate(ctx, codeID, walletB /* nil,*/, initMsgBz, "demo contract 2", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) if err != nil { err = extractInnerError(t, err, nonce, false) } @@ -303,7 +303,7 @@ func TestWrongSigner(t *testing.T) { ctx = prepareInitSignedTxMultipleMsgs(t, keeper, ctx, []sdk.AccAddress{walletB}, []crypto.PrivKey{privKeyB}, []sdk.Msg{&sdkMsgA}, codeID) - _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) if err != nil { err = extractInnerError(t, err, nonce, false) } @@ -334,7 +334,7 @@ func TestMultiSig(t *testing.T) { _, _, multisigAddr := multisigTxCreator(t, &ctx, keeper, i+1, j+1, i+1, &sdkMsg) - contractAddressA, err := keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil, */, initMsgBz, label, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + contractAddressA, _, err := keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil, */, initMsgBz, label, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) if err != nil { err = extractInnerError(t, err, nonce, true) } @@ -386,7 +386,7 @@ func TestMultiSigThreshold(t *testing.T) { _, _, multisigAddr := multisigTxCreator(t, &ctx, keeper, i+1, j+1, j+1, &sdkMsg) - contractAddressA, err := keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil,*/, initMsgBz, label, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + contractAddressA, _, err := keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil,*/, initMsgBz, label, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) if err != nil { err = extractInnerError(t, err, nonce, true) } @@ -435,7 +435,7 @@ func TestMultiSigThresholdNotMet(t *testing.T) { _, _, multisigAddr := multisigTxCreator(t, &ctx, keeper, 3, 2, 1, &sdkMsg) - _, err = keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err = keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) if err != nil { err = extractInnerError(t, err, nonce, false) } @@ -642,7 +642,7 @@ func TestMultiSigInMultiSig(t *testing.T) { ctx = ctx.WithTxBytes(txBytes) - contractAddressA, err := keeper.Instantiate( + contractAddressA, _, err := keeper.Instantiate( ctx, codeID, multimultisigAccount.address, @@ -747,7 +747,7 @@ func TestMultiSigInMultiSigDifferentOrder(t *testing.T) { ctx = ctx.WithTxBytes(txBytes) - contractAddressA, err := keeper.Instantiate( + contractAddressA, _, err := keeper.Instantiate( ctx, codeID, multimultisigAccount.address, @@ -816,7 +816,7 @@ func TestInvalidKeyType(t *testing.T) { ctx = prepareInitSignedTxMultipleMsgs(t, keeper, ctx, []sdk.AccAddress{edAddr}, []crypto.PrivKey{edKey}, []sdk.Msg{&sdkMsg}, codeID) - _, err = keeper.Instantiate(ctx, codeID, edAddr /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err = keeper.Instantiate(ctx, codeID, edAddr /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Contains(t, err.Error(), "failed to verify transaction signature") } @@ -896,7 +896,7 @@ func TestInvalidKeyTypeInMultisig(t *testing.T) { require.NoError(t, err) ctx = ctx.WithTxBytes(txBytes) - _, err = keeper.Instantiate( + _, _, err = keeper.Instantiate( ctx, codeID, sdk.AccAddress(multisigPubkey.address), @@ -927,7 +927,7 @@ func TestWrongFundsNoFunds(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privKeyA, initMsgBz, codeID, nil) - _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) + _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) if err != nil { err = extractInnerError(t, err, nonce, false) } @@ -952,7 +952,7 @@ func TestWrongFundsSomeFunds(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privKeyA, initMsgBz, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 200))) - _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) + _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) if err != nil { err = extractInnerError(t, err, nonce, false) } @@ -987,7 +987,7 @@ func TestWrongMessage(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privKeyA, initMsgBz, codeID, nil) - _, err = keeper.Instantiate(ctx, codeID, walletA /* nil, */, notTheRealMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) + _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil, */, notTheRealMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) if err != nil { err = extractInnerError(t, err, nonce, false) } diff --git a/x/compute/internal/keeper/querier_test.go b/x/compute/internal/keeper/querier_test.go index f880a0be7..f0f4f2c34 100644 --- a/x/compute/internal/keeper/querier_test.go +++ b/x/compute/internal/keeper/querier_test.go @@ -20,8 +20,13 @@ import ( ) func TestQueryContractLabel(t *testing.T) { - encoders := DefaultEncoders() - ctx, keepers := CreateTestInput(t, false,SupportedFeatures, &encoders, nil) + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) + ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) @@ -57,7 +62,7 @@ func TestQueryContractLabel(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, creator, privCreator, initMsgBz, contractID, deposit) - addr, err := keeper.Instantiate(ctx, contractID, creator /* nil,*/, initMsgBz, label, deposit, nil) + addr, _, err := keeper.Instantiate(ctx, contractID, creator /* nil,*/, initMsgBz, label, deposit, nil) require.NoError(t, err) // this gets us full error, not redacted sdk.Error @@ -116,7 +121,12 @@ func TestQueryContractLabel(t *testing.T) { func TestQueryContractState(t *testing.T) { t.SkipNow() // cannot interact directly with state - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -149,7 +159,7 @@ func TestQueryContractState(t *testing.T) { initMsgBz, err = wasmCtx.Encrypt(msg.Serialize()) - addr, err := keeper.Instantiate(ctx, contractID, creator /* nil,*/, initMsgBz, "demo contract to query", deposit, nil) + addr, _, err := keeper.Instantiate(ctx, contractID, creator /* nil,*/, initMsgBz, "demo contract to query", deposit, nil) require.NoError(t, err) contractModel := []types.Model{ @@ -252,7 +262,12 @@ func TestQueryContractState(t *testing.T) { } func TestListContractByCodeOrdering(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -320,7 +335,7 @@ func TestListContractByCodeOrdering(t *testing.T) { ctx = ctx.WithTxBytes(txBytes) - _, err = keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, fmt.Sprintf("contract %d", i), topUp, nil) + _, _, err = keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, fmt.Sprintf("contract %d", i), topUp, nil) require.NoError(t, err) } diff --git a/x/compute/internal/keeper/recurse_test.go b/x/compute/internal/keeper/recurse_test.go index a7214d28e..d44fdd041 100644 --- a/x/compute/internal/keeper/recurse_test.go +++ b/x/compute/internal/keeper/recurse_test.go @@ -51,7 +51,13 @@ func initRecurseContract(t *testing.T) (contract sdk.AccAddress, creator sdk.Acc return realWasmQuerier(ctx, request) }, } - encoders := DefaultEncoders() + + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, countingQuerier) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper realWasmQuerier = WasmQuerier(&keeper) diff --git a/x/compute/internal/keeper/reflect_test.go b/x/compute/internal/keeper/reflect_test.go index c8bd4e7c8..e354394e9 100644 --- a/x/compute/internal/keeper/reflect_test.go +++ b/x/compute/internal/keeper/reflect_test.go @@ -85,7 +85,7 @@ func TestMaskReflectContractSend(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, creator, privCreator, initMsgBz, maskID, maskStart) - maskAddr, err := keeper.Instantiate(ctx, maskID, creator /* nil,*/, initMsgBz, "mask contract 2", maskStart, nil) + maskAddr, _, err := keeper.Instantiate(ctx, maskID, creator /* nil,*/, initMsgBz, "mask contract 2", maskStart, nil) require.NoError(t, err) require.NotEmpty(t, maskAddr) @@ -105,7 +105,7 @@ func TestMaskReflectContractSend(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, creator, privCreator, initMsgBz, escrowID, escrowStart) - escrowAddr, err := keeper.Instantiate(ctx, escrowID, creator /* nil,*/, initMsgBz, "escrow contract 2", escrowStart, nil) + escrowAddr, _, err := keeper.Instantiate(ctx, escrowID, creator /* nil,*/, initMsgBz, "escrow contract 2", escrowStart, nil) require.NoError(t, err) require.NotEmpty(t, escrowAddr) @@ -181,7 +181,7 @@ func TestMaskReflectCustomMsg(t *testing.T) { require.NoError(t, err) contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, privCreator, initMsgBz, codeID, contractStart) - contractAddr, err := keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, "mask contract 1", contractStart, nil) + contractAddr, _, err := keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, "mask contract 1", contractStart, nil) require.NoError(t, err) require.NotEmpty(t, contractAddr) @@ -284,7 +284,7 @@ func TestMaskReflectCustomQuery(t *testing.T) { require.NoError(t, err) contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, privCreator, initMsgBz, codeID, contractStart) - contractAddr, err := keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, "mask contract 1", contractStart, nil) + contractAddr, _, err := keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, "mask contract 1", contractStart, nil) require.NoError(t, err) require.NotEmpty(t, contractAddr) diff --git a/x/compute/internal/keeper/secret_contracts_test.go b/x/compute/internal/keeper/secret_contracts_test.go index 6098835ae..8da5cfd5e 100644 --- a/x/compute/internal/keeper/secret_contracts_test.go +++ b/x/compute/internal/keeper/secret_contracts_test.go @@ -13,8 +13,6 @@ import ( stypes "github.com/cosmos/cosmos-sdk/store/types" - stypes "github.com/cosmos/cosmos-sdk/store/types" - "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" @@ -55,7 +53,12 @@ func testEncrypt(t *testing.T, keeper Keeper, ctx sdk.Context, contractAddress s } func setupTest(t *testing.T, wasmPath string) (sdk.Context, Keeper, uint64, string, sdk.AccAddress, crypto.PrivKey, sdk.AccAddress, crypto.PrivKey) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -402,7 +405,7 @@ func initHelperImpl( ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initMsgBz, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", coin))) // make the label a random base64 string, because why not? - contractAddress, err := keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, base64.RawURLEncoding.EncodeToString(nonce), sdk.NewCoins(sdk.NewInt64Coin("denom", coin)), nil) + contractAddress, _, err := keeper.Instantiate(ctx, codeID, creator /* nil,*/, initMsgBz, base64.RawURLEncoding.EncodeToString(nonce), sdk.NewCoins(sdk.NewInt64Coin("denom", coin)), nil) if wasmCallCount < 0 { // default, just check that at least 1 call happend @@ -880,7 +883,7 @@ func TestInitNotEncryptedInputError(t *testing.T) { ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privKey, initMsg, codeID, nil) // init - _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, initMsg, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, initMsg, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Error(t, err) require.Contains(t, err.Error(), "failed to decrypt data") @@ -1701,7 +1704,12 @@ func TestWasmTooHighInitialMemoryRuntimeFail(t *testing.T) { } func TestWasmTooHighInitialMemoryStaticFail(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource types.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper @@ -1730,7 +1738,7 @@ func TestCodeHashInvalid(t *testing.T) { enc, _ := wasmCtx.Encrypt(initMsg) ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privWalletA, enc, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) - _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Error(t, err) require.Contains(t, err.Error(), "failed to validate transaction") } @@ -1742,7 +1750,7 @@ func TestCodeHashEmpty(t *testing.T) { enc, _ := wasmCtx.Encrypt(initMsg) ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privWalletA, enc, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) - _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Error(t, err) require.Contains(t, err.Error(), "failed to validate transaction") } @@ -1754,7 +1762,7 @@ func TestCodeHashNotHex(t *testing.T) { enc, _ := wasmCtx.Encrypt(initMsg) ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privWalletA, enc, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) - _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Error(t, err) require.Contains(t, err.Error(), "failed to validate transaction") } @@ -1767,7 +1775,7 @@ func TestCodeHashTooSmall(t *testing.T) { enc, _ := wasmCtx.Encrypt(initMsg) ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privWalletA, enc, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) - _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Error(t, err) require.Contains(t, err.Error(), "failed to validate transaction") } @@ -1780,7 +1788,7 @@ func TestCodeHashTooBig(t *testing.T) { enc, _ := wasmCtx.Encrypt(initMsg) ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privWalletA, enc, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) - _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Error(t, err) initErr := extractInnerError(t, err, enc[0:32], true) @@ -1798,7 +1806,7 @@ func TestCodeHashWrong(t *testing.T) { enc, _ := wasmCtx.Encrypt(initMsg) ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privWalletA, enc, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) - _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) + _, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil, */, enc, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) require.Error(t, err) require.Contains(t, err.Error(), "failed to validate transaction") } diff --git a/x/compute/internal/keeper/staking_test.go b/x/compute/internal/keeper/staking_test.go index eb889c092..557753f1b 100644 --- a/x/compute/internal/keeper/staking_test.go +++ b/x/compute/internal/keeper/staking_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "github.com/cosmos/cosmos-sdk/codec/types" + wasmTypes "github.com/enigmampc/SecretNetwork/x/compute/internal/types" "io/ioutil" "testing" @@ -89,7 +90,12 @@ type InvestmentResponse struct { } func TestInitializeStaking(t *testing.T) { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource wasmTypes.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, stakingKeeper, keeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper @@ -124,7 +130,7 @@ func TestInitializeStaking(t *testing.T) { require.NoError(t, err) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initBz, stakingID, nil) - stakingAddr, err := keeper.Instantiate(ctx, stakingID, creator /* , nil */, initBz, "staking derivates - DRV", nil, nil) + stakingAddr, _, err := keeper.Instantiate(ctx, stakingID, creator /* , nil */, initBz, "staking derivates - DRV", nil, nil) require.NoError(t, err) require.NotEmpty(t, stakingAddr) @@ -170,7 +176,12 @@ type initInfo struct { } func initializeStaking(t *testing.T) initInfo { - encoders := DefaultEncoders() + encodingConfig := MakeEncodingConfig() + var transferPortSource wasmTypes.ICS20TransferPortSource + transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }} + encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) ctx, keepers := CreateTestInput(t, false, SupportedFeatures, &encoders, nil) accKeeper, stakingKeeper, keeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper @@ -213,7 +224,7 @@ func initializeStaking(t *testing.T) initInfo { require.NoError(t, err) ctx = PrepareInitSignedTx(t, keeper, ctx, creator, creatorPrivKey, initBz, stakingID, nil) - stakingAddr, err := keeper.Instantiate(ctx, stakingID, creator /* , nil */, initBz, "staking derivates - DRV", nil, nil) + stakingAddr, _, err := keeper.Instantiate(ctx, stakingID, creator /* , nil */, initBz, "staking derivates - DRV", nil, nil) require.NoError(t, err) require.NotEmpty(t, stakingAddr) diff --git a/x/compute/internal/keeper/test_common.go b/x/compute/internal/keeper/test_common.go index 7f0074ff7..c0c9443af 100644 --- a/x/compute/internal/keeper/test_common.go +++ b/x/compute/internal/keeper/test_common.go @@ -3,6 +3,17 @@ package keeper import ( "encoding/binary" "fmt" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" "io/ioutil" "os" "testing" @@ -84,6 +95,19 @@ import ( const flagLRUCacheSize = "lru_size" const flagQueryGasLimit = "query_gas_limit" +var _ wasmtypes.ICS20TransferPortSource = &MockIBCTransferKeeper{} + +type MockIBCTransferKeeper struct { + GetPortFn func(ctx sdk.Context) string +} + +func (m MockIBCTransferKeeper) GetPort(ctx sdk.Context) string { + if m.GetPortFn == nil { + panic("not expected to be called") + } + return m.GetPortFn(ctx) +} + var ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, bank.AppModuleBasic{}, @@ -197,6 +221,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc paramsKeeper.Subspace(distrtypes.ModuleName) paramsKeeper.Subspace(slashingtypes.ModuleName) paramsKeeper.Subspace(crisistypes.ModuleName) + paramsKeeper.Subspace(ibchost.ModuleName) // this is also used to initialize module accounts (so nil is meaningful here) maccPerms := map[string][]string{ @@ -331,6 +356,38 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc // Load default wasm config wasmConfig := wasmtypes.DefaultWasmConfig() + keys := sdk.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, + feegrant.StoreKey, authzkeeper.StoreKey, icahosttypes.StoreKey, + ) + + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + + upgradeKeeper := upgradekeeper.NewKeeper( + map[int64]bool{}, + keys[upgradetypes.StoreKey], + encodingConfig.Marshaler, + tempDir, + nil, + ) + + capabilityKeeper := capabilitykeeper.NewKeeper( + encodingConfig.Marshaler, + keys[capabilitytypes.StoreKey], + memKeys[capabilitytypes.MemStoreKey], + ) + + scopedIBCKeeper := capabilityKeeper.ScopeToModule(ibchost.ModuleName) + scopedWasmKeeper := capabilityKeeper.ScopeToModule("compute") + + ibchostSubSp, _ := paramsKeeper.GetSubspace(ibchost.ModuleName) + ibcKeeper := ibckeeper.NewKeeper( + encodingConfig.Marshaler, keys[ibchost.StoreKey], ibchostSubSp, stakingKeeper, upgradeKeeper, scopedIBCKeeper, + ) + // todo: new grpc routing //serviceRouter := baseapp.NewMsgServiceRouter() @@ -355,6 +412,10 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc mintKeeper, stakingKeeper, // serviceRouter, + scopedWasmKeeper, + ibcKeeper.PortKeeper, + MockIBCTransferKeeper{}, + ibcKeeper.ChannelKeeper, router, tempDir, wasmConfig, @@ -399,7 +460,7 @@ func TestHandler(k Keeper) sdk.Handler { } func handleInstantiate(ctx sdk.Context, k Keeper, msg *wasmtypes.MsgInstantiateContract) (*sdk.Result, error) { - contractAddr, err := k.Instantiate(ctx, msg.CodeID, msg.Sender /* msg.Admin, */, msg.InitMsg, msg.Label, msg.InitFunds, msg.CallbackSig) + contractAddr, _, err := k.Instantiate(ctx, msg.CodeID, msg.Sender /* msg.Admin, */, msg.InitMsg, msg.Label, msg.InitFunds, msg.CallbackSig) if err != nil { return nil, err } diff --git a/x/compute/internal/keeper/testdata/test-contract/Cargo.lock b/x/compute/internal/keeper/testdata/test-contract/Cargo.lock index 34e8064ca..b2c98b036 100644 --- a/x/compute/internal/keeper/testdata/test-contract/Cargo.lock +++ b/x/compute/internal/keeper/testdata/test-contract/Cargo.lock @@ -17,17 +17,11 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "backtrace" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" dependencies = [ "addr2line", "cc", @@ -82,25 +76,24 @@ checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ "adler", - "autocfg", ] [[package]] name = "object" -version = "0.27.1" +version = "0.28.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "memchr", ] @@ -179,6 +172,8 @@ dependencies = [ [[package]] name = "secret-cosmwasm-std" version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4b8fed972d924458d9c3c0e6c9fbf6c4c5e30655571e3d2b78be056d316e9" dependencies = [ "base64", "schemars", @@ -190,6 +185,8 @@ dependencies = [ [[package]] name = "secret-cosmwasm-storage" version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffee3243bb13c02ddcdc15458526288d36ec23422ec43681ac5d48e7325d8327" dependencies = [ "secret-cosmwasm-std", "serde", diff --git a/x/compute/internal/keeper/testdata/test-contract/Cargo.toml b/x/compute/internal/keeper/testdata/test-contract/Cargo.toml index bd4fbf9df..36251d8b3 100644 --- a/x/compute/internal/keeper/testdata/test-contract/Cargo.toml +++ b/x/compute/internal/keeper/testdata/test-contract/Cargo.toml @@ -32,8 +32,8 @@ backtraces = ["cosmwasm-std/backtraces"] with_floats = [] [dependencies] -cosmwasm-std = { path = "../../../../../../cosmwasm/packages/std", package = "secret-cosmwasm-std" } -cosmwasm-storage = { path = "../../../../../../cosmwasm/packages/storage", package = "secret-cosmwasm-storage" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } schemars = "0.7" serde = { version = "1.0.114", default-features = false, features = [ "derive", diff --git a/x/compute/internal/types/errors.go b/x/compute/internal/types/errors.go index c42beba91..cde6b93b9 100644 --- a/x/compute/internal/types/errors.go +++ b/x/compute/internal/types/errors.go @@ -57,6 +57,15 @@ var ( // ErrSigFailed error for wasm code that has already been uploaded or failed ErrSigFailed = sdkErrors.Register(DefaultCodespace, 16, "parse signature failed") + + // ErrUnsupportedForContract error when a feature is used that is not supported for/ by this contract + ErrUnsupportedForContract = sdkErrors.Register(DefaultCodespace, 17, "unsupported for this contract") + + // ErrUnknownMsg error by a message handler to show that it is not responsible for this message type + ErrUnknownMsg = sdkErrors.Register(DefaultCodespace, 18, "unknown message from the contract") + + // ErrReplyFailed error for rust execution contract failure + ErrReplyFailed = sdkErrors.Register(DefaultCodespace, 19, "reply to contract failed") ) func IsEncryptedErrorCode(code uint32) bool { diff --git a/x/compute/internal/types/events.go b/x/compute/internal/types/events.go new file mode 100644 index 000000000..17ce47c8f --- /dev/null +++ b/x/compute/internal/types/events.go @@ -0,0 +1,29 @@ +package types + +const ( + // WasmModuleEventType is stored with any contract TX that returns non empty EventAttributes + CustomEventType = "wasm" + // CustomContractEventPrefix contracts can create custom events. To not mix them with other system events they got the `wasm-` prefix. + CustomContractEventPrefix = "wasm-" + + EventTypeStoreCode = "store_code" + EventTypeInstantiate = "instantiate" + EventTypeExecute = "execute" + EventTypeMigrate = "migrate" + EventTypePinCode = "pin_code" + EventTypeUnpinCode = "unpin_code" + EventTypeSudo = "sudo" + EventTypeReply = "reply" + EventTypeGovContractResult = "gov_contract_result" +) + +// event attributes returned from contract execution +const ( + AttributeReservedPrefix = "_" + + AttributeKeyContractAddr = "contract_address" + AttributeKeyCodeID = "code_id" + AttributeKeySigner = "signer" + AttributeKeyResultDataHex = "result" + AttributeKeyFeature = "feature" +) diff --git a/x/compute/internal/types/expected_keepers.go b/x/compute/internal/types/expected_keepers.go index 86de9f689..1bef78e26 100644 --- a/x/compute/internal/types/expected_keepers.go +++ b/x/compute/internal/types/expected_keepers.go @@ -1,17 +1,8 @@ package types -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" -) +import sdk "github.com/cosmos/cosmos-sdk/types" -// PortKeeper defines the expected IBC port keeper -type PortKeeper interface { - BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability -} - -type CapabilityKeeper interface { - GetCapability(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) - ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error - AuthenticateCapability(ctx sdk.Context, capability *capabilitytypes.Capability, name string) bool +// ICS20TransferPortSource is a subset of the ibc transfer keeper. +type ICS20TransferPortSource interface { + GetPort(ctx sdk.Context) string } diff --git a/x/compute/internal/types/keys.go b/x/compute/internal/types/keys.go index 53243ba48..71fb73285 100644 --- a/x/compute/internal/types/keys.go +++ b/x/compute/internal/types/keys.go @@ -23,12 +23,6 @@ const ( RouterKey = ModuleName ) -const ( // event attributes - AttributeKeyContract = "contract_address" - AttributeKeyCodeID = "code_id" - AttributeKeySigner = "signer" -) - // nolint var ( CodeKeyPrefix = []byte{0x01} diff --git a/x/compute/internal/types/types.go b/x/compute/internal/types/types.go index 110de62e4..4cc89b488 100644 --- a/x/compute/internal/types/types.go +++ b/x/compute/internal/types/types.go @@ -2,7 +2,6 @@ package types import ( "encoding/base64" - servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -136,7 +135,7 @@ func NewEnv(ctx sdk.Context, creator sdk.AccAddress, deposit sdk.Coins, contract Contract: wasmTypes.ContractInfo{ Address: contractAddr.String(), }, - Key: wasmTypes.ContractKey(base64.StdEncoding.EncodeToString(contractKey)), + Key: wasmTypes.ContractKey(base64.StdEncoding.EncodeToString(contractKey)), Recursive: false, } return env @@ -154,11 +153,8 @@ func NewWasmCoins(cosmosCoins sdk.Coins) (wasmCoins []wasmTypes.Coin) { return wasmCoins } -const CustomEventType = "wasm" -const AttributeKeyContractAddr = "contract_address" - // ParseEvents converts wasm LogAttributes into an sdk.Events (with 0 or 1 elements) -func ParseEvents(logs []wasmTypesV010.LogAttribute, contractAddr sdk.AccAddress) sdk.Events { +func ContractLogsToSdkEvents(logs []wasmTypesV010.LogAttribute, contractAddr sdk.AccAddress) sdk.Events { // we always tag with the contract address issuing this event attrs := []sdk.Attribute{sdk.NewAttribute(AttributeKeyContractAddr, contractAddr.String())} // append attributes from wasm to the sdk.Event diff --git a/x/compute/internal/types/types.pb.go b/x/compute/internal/types/types.pb.go index e9c223e91..39cd98c51 100644 --- a/x/compute/internal/types/types.pb.go +++ b/x/compute/internal/types/types.pb.go @@ -173,11 +173,11 @@ var xxx_messageInfo_ContractCustomInfo proto.InternalMessageInfo type ContractInfo struct { CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` Creator github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=creator,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"creator,omitempty"` - // bytes admin = 3 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` + Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` // never show this in query results, just use for sorting // (Note: when using json tag "-" amino refused to serialize it...) - Created *AbsoluteTxPosition `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"` + Created *AbsoluteTxPosition `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"` + IBCPortID string `protobuf:"bytes,6,opt,name=ibc_port_id,json=ibcPortId,proto3" json:"ibc_port_id,omitempty"` } func (m *ContractInfo) Reset() { *m = ContractInfo{} } @@ -310,52 +310,54 @@ func init() { } var fileDescriptor_8ba7f40a6d1951b3 = []byte{ - // 710 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4b, 0x6b, 0xdb, 0x4a, - 0x14, 0xb6, 0xe2, 0xf7, 0xc4, 0xe4, 0x9a, 0xb9, 0xb9, 0xb9, 0x8e, 0x2f, 0xc8, 0xbe, 0x2a, 0x94, - 0x90, 0x12, 0x8b, 0xa4, 0x5d, 0x94, 0x74, 0x65, 0xc7, 0x2e, 0x71, 0xd2, 0xda, 0x41, 0x79, 0x40, - 0x5a, 0x8a, 0xd1, 0xe3, 0xc4, 0x16, 0x96, 0x34, 0x46, 0x33, 0x76, 0xad, 0x7f, 0x50, 0xb2, 0xea, - 0xb2, 0x9b, 0x40, 0xa1, 0xa5, 0xe4, 0x0f, 0xf4, 0x3f, 0x64, 0x99, 0x65, 0x17, 0xc5, 0xb4, 0xce, - 0x3f, 0xe8, 0x32, 0xab, 0xa2, 0x91, 0xfc, 0xa0, 0x8f, 0x5d, 0x57, 0x3a, 0x8f, 0x6f, 0xbe, 0x73, - 0xce, 0x77, 0x0e, 0x42, 0x12, 0x05, 0xdd, 0x05, 0x26, 0xeb, 0xc4, 0xee, 0xf5, 0x19, 0xc8, 0x83, - 0x4d, 0x0d, 0x98, 0xba, 0x29, 0x33, 0xaf, 0x07, 0xb4, 0xd4, 0x73, 0x09, 0x23, 0x78, 0x25, 0xc0, - 0x94, 0x42, 0x4c, 0x29, 0xc4, 0xe4, 0x97, 0xdb, 0xa4, 0x4d, 0x38, 0x44, 0xf6, 0xad, 0x00, 0x2d, - 0xe9, 0xe8, 0xaf, 0xb2, 0xae, 0x03, 0xa5, 0x47, 0x5e, 0x0f, 0x0e, 0x54, 0x57, 0xb5, 0xf1, 0x1e, - 0x8a, 0x0f, 0x54, 0xab, 0x0f, 0x39, 0xa1, 0x28, 0xac, 0x2d, 0x6d, 0x49, 0xa5, 0x5f, 0x13, 0x96, - 0x66, 0xef, 0x2a, 0xd9, 0x6f, 0xa3, 0x42, 0xc6, 0x53, 0x6d, 0x6b, 0x5b, 0xe2, 0x4f, 0x25, 0x25, - 0xa0, 0xd8, 0x8e, 0xbd, 0x79, 0x5b, 0x10, 0xa4, 0x0f, 0x02, 0x4a, 0xed, 0x10, 0x03, 0xea, 0xce, - 0x19, 0xc1, 0xff, 0xa1, 0xb4, 0x4e, 0x0c, 0x68, 0x75, 0x54, 0xda, 0xe1, 0x25, 0x32, 0x4a, 0xca, - 0x0f, 0xec, 0xaa, 0xb4, 0x83, 0xf7, 0x51, 0x52, 0x77, 0x41, 0x65, 0xc4, 0xcd, 0x2d, 0xf8, 0xa9, - 0xca, 0xe6, 0xed, 0xa8, 0xb0, 0xd1, 0x36, 0x59, 0xa7, 0xaf, 0xf9, 0x0d, 0xc8, 0x3a, 0xa1, 0x36, - 0xa1, 0xe1, 0x67, 0x83, 0x1a, 0xdd, 0x70, 0xf6, 0xb2, 0xae, 0x97, 0x0d, 0xc3, 0x05, 0x4a, 0x95, - 0x09, 0x03, 0x5e, 0x41, 0x09, 0x4a, 0xfa, 0xae, 0x0e, 0xb9, 0x68, 0x51, 0x58, 0x4b, 0x2b, 0xa1, - 0x87, 0x73, 0x28, 0xa9, 0xf5, 0x4d, 0xcb, 0x00, 0x37, 0x17, 0xe3, 0x89, 0x89, 0x2b, 0x3d, 0x47, - 0x78, 0x87, 0x38, 0xcc, 0x55, 0x75, 0xb6, 0xd3, 0xa7, 0x8c, 0xd8, 0xbc, 0x63, 0x19, 0x2d, 0x82, - 0xa3, 0x5b, 0xea, 0x00, 0x5a, 0x5d, 0xf0, 0x82, 0x9e, 0x2b, 0x4b, 0xe3, 0x51, 0x01, 0xd5, 0x82, - 0xf0, 0x3e, 0x78, 0x0a, 0x82, 0xa9, 0x8d, 0x97, 0x51, 0xdc, 0x52, 0x35, 0xb0, 0xf8, 0x0c, 0x69, - 0x25, 0x70, 0xa4, 0xcf, 0x02, 0xca, 0x4c, 0xd8, 0x39, 0xef, 0x1d, 0x94, 0xe4, 0x4a, 0x98, 0x06, - 0xe7, 0x8c, 0x55, 0xd0, 0x78, 0x54, 0x48, 0x70, 0xa1, 0xaa, 0x4a, 0xc2, 0x4f, 0xd5, 0x8d, 0x3f, - 0xab, 0xc8, 0xb4, 0xb1, 0xd8, 0x5c, 0x63, 0xb8, 0x1a, 0x96, 0x00, 0x23, 0x17, 0x2f, 0x0a, 0x6b, - 0x8b, 0x5b, 0xeb, 0xbf, 0x5d, 0xb9, 0x46, 0x89, 0xd5, 0x67, 0x70, 0x34, 0x3c, 0x20, 0xd4, 0x64, - 0x26, 0x71, 0x94, 0xc9, 0x53, 0x49, 0x41, 0xf8, 0xe7, 0x34, 0xfe, 0x1f, 0x65, 0x34, 0x8b, 0xe8, - 0xdd, 0x56, 0x07, 0xcc, 0x76, 0x87, 0xf1, 0x41, 0xa3, 0xca, 0x22, 0x8f, 0xed, 0xf2, 0x10, 0x5e, - 0x45, 0x29, 0x36, 0x6c, 0x99, 0x8e, 0x01, 0x43, 0x3e, 0x62, 0x4c, 0x49, 0xb2, 0x61, 0xdd, 0x77, - 0x25, 0x13, 0xc5, 0x9f, 0x12, 0x03, 0x2c, 0xbc, 0x87, 0xa2, 0xfb, 0x53, 0xe9, 0x1f, 0xde, 0x8e, - 0x0a, 0x0f, 0xe6, 0x14, 0x60, 0xe0, 0x18, 0xe0, 0xda, 0xa6, 0xc3, 0xe6, 0x4d, 0xcb, 0xd4, 0xa8, - 0xac, 0x79, 0x0c, 0x68, 0x69, 0x17, 0x86, 0x15, 0xdf, 0x50, 0xa2, 0xe1, 0x76, 0x4e, 0xf8, 0x7d, - 0x73, 0x3d, 0x95, 0xc0, 0x59, 0xff, 0x28, 0x20, 0x34, 0xbb, 0x68, 0x7c, 0x17, 0xa5, 0x8f, 0x1b, - 0xd5, 0xda, 0xe3, 0x7a, 0xa3, 0x56, 0xcd, 0x46, 0xf2, 0xff, 0x9e, 0x5f, 0x14, 0xff, 0x9e, 0xa5, - 0x8f, 0x1d, 0x03, 0xce, 0x4c, 0x07, 0x0c, 0x5c, 0x44, 0x89, 0x46, 0xb3, 0xd2, 0xac, 0x9e, 0x66, - 0x85, 0xfc, 0xf2, 0xf9, 0x45, 0x31, 0x3b, 0x03, 0x35, 0x88, 0x46, 0x0c, 0x0f, 0xdf, 0x43, 0x99, - 0x66, 0xe3, 0xc9, 0x69, 0xab, 0x5c, 0xad, 0x2a, 0xb5, 0xc3, 0xc3, 0xec, 0x42, 0x7e, 0xf5, 0xfc, - 0xa2, 0xf8, 0xcf, 0x0c, 0xd7, 0x74, 0x2c, 0x2f, 0xdc, 0x94, 0x5f, 0xb6, 0x76, 0x52, 0x53, 0x4e, - 0x39, 0x63, 0xf4, 0xc7, 0xb2, 0xb5, 0x01, 0xb8, 0x9e, 0x4f, 0x9a, 0x4f, 0xbd, 0x7a, 0x27, 0x46, - 0x2e, 0xdf, 0x8b, 0x91, 0xca, 0x8b, 0xab, 0xaf, 0x62, 0xe4, 0x72, 0x2c, 0x0a, 0x57, 0x63, 0x51, - 0xb8, 0x1e, 0x8b, 0xc2, 0x97, 0xb1, 0x28, 0xbc, 0xbe, 0x11, 0x23, 0xd7, 0x37, 0x62, 0xe4, 0xd3, - 0x8d, 0x18, 0x79, 0xf6, 0x68, 0x4e, 0x2a, 0x70, 0xcc, 0xb6, 0xad, 0xda, 0x3d, 0x5d, 0x3e, 0xe4, - 0x1b, 0x6e, 0x00, 0x7b, 0x49, 0xdc, 0xae, 0x3c, 0x9c, 0xfe, 0x52, 0x4c, 0x87, 0x81, 0xeb, 0xa8, - 0x56, 0x70, 0x45, 0x5a, 0x82, 0xff, 0x26, 0xee, 0x7f, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x21, 0xd2, - 0xf1, 0xe2, 0x7a, 0x04, 0x00, 0x00, + // 747 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0x8f, 0x9b, 0x34, 0x6d, 0x26, 0x61, 0x89, 0x86, 0xb2, 0x64, 0x83, 0xe4, 0x04, 0x23, 0xa1, + 0x6a, 0x51, 0x63, 0x75, 0xe1, 0x80, 0x96, 0x53, 0x1c, 0x07, 0x35, 0x5b, 0x48, 0xaa, 0xe9, 0xee, + 0x4a, 0x05, 0xa1, 0xc8, 0x9e, 0x79, 0x9b, 0x58, 0xb1, 0x3d, 0x91, 0x67, 0x12, 0xe2, 0x6f, 0x80, + 0xca, 0x85, 0x23, 0x97, 0x4a, 0x48, 0x20, 0xb4, 0x5f, 0x80, 0xef, 0xb0, 0xc7, 0x3d, 0x72, 0x8a, + 0x20, 0xfd, 0x06, 0x1c, 0x7b, 0x42, 0x1e, 0x3b, 0x7f, 0xc4, 0x9f, 0x1b, 0x27, 0xbf, 0x3f, 0xbf, + 0xf9, 0xbd, 0xf7, 0x7e, 0xcf, 0x33, 0xc8, 0x10, 0x40, 0x23, 0x90, 0x26, 0xe5, 0xc1, 0x74, 0x26, + 0xc1, 0x9c, 0x9f, 0xba, 0x20, 0x9d, 0x53, 0x53, 0xc6, 0x53, 0x10, 0xad, 0x69, 0xc4, 0x25, 0xc7, + 0xf7, 0x53, 0x4c, 0x2b, 0xc3, 0xb4, 0x32, 0x4c, 0xfd, 0x68, 0xc4, 0x47, 0x5c, 0x41, 0xcc, 0xc4, + 0x4a, 0xd1, 0x06, 0x45, 0x6f, 0xb6, 0x29, 0x05, 0x21, 0x9e, 0xc6, 0x53, 0xb8, 0x70, 0x22, 0x27, + 0xc0, 0x4f, 0xd0, 0xfe, 0xdc, 0xf1, 0x67, 0x50, 0xd3, 0x9a, 0xda, 0xf1, 0xbd, 0x47, 0x46, 0xeb, + 0xdf, 0x09, 0x5b, 0xdb, 0x73, 0x56, 0xf5, 0xcf, 0x65, 0xa3, 0x12, 0x3b, 0x81, 0xff, 0xd8, 0x50, + 0x47, 0x0d, 0x92, 0x52, 0x3c, 0x2e, 0xfc, 0xf0, 0x63, 0x43, 0x33, 0x7e, 0xd1, 0xd0, 0x61, 0x87, + 0x33, 0xe8, 0x85, 0x2f, 0x38, 0x7e, 0x17, 0x95, 0x28, 0x67, 0x30, 0x1c, 0x3b, 0x62, 0xac, 0x4a, + 0x54, 0xc8, 0x61, 0x12, 0x38, 0x73, 0xc4, 0x18, 0x9f, 0xa3, 0x03, 0x1a, 0x81, 0x23, 0x79, 0x54, + 0xdb, 0x4b, 0x52, 0xd6, 0xe9, 0xdd, 0xb2, 0x71, 0x32, 0xf2, 0xe4, 0x78, 0xe6, 0x26, 0x0d, 0x98, + 0x94, 0x8b, 0x80, 0x8b, 0xec, 0x73, 0x22, 0xd8, 0x24, 0x9b, 0xbd, 0x4d, 0x69, 0x9b, 0xb1, 0x08, + 0x84, 0x20, 0x6b, 0x06, 0x7c, 0x1f, 0x15, 0x05, 0x9f, 0x45, 0x14, 0x6a, 0xf9, 0xa6, 0x76, 0x5c, + 0x22, 0x99, 0x87, 0x6b, 0xe8, 0xc0, 0x9d, 0x79, 0x3e, 0x83, 0xa8, 0x56, 0x50, 0x89, 0xb5, 0x6b, + 0x7c, 0x85, 0x70, 0x87, 0x87, 0x32, 0x72, 0xa8, 0xec, 0xcc, 0x84, 0xe4, 0x81, 0xea, 0xd8, 0x44, + 0x65, 0x08, 0xa9, 0xef, 0xcc, 0x61, 0x38, 0x81, 0x38, 0xed, 0xd9, 0xba, 0xb7, 0x5a, 0x36, 0x50, + 0x37, 0x0d, 0x9f, 0x43, 0x4c, 0x10, 0x6c, 0x6c, 0x7c, 0x84, 0xf6, 0x7d, 0xc7, 0x05, 0x5f, 0xcd, + 0x50, 0x22, 0xa9, 0x63, 0x7c, 0xb7, 0x87, 0x2a, 0x6b, 0x76, 0xc5, 0xfb, 0x3e, 0x3a, 0x50, 0x4a, + 0x78, 0x4c, 0x71, 0x16, 0x2c, 0xb4, 0x5a, 0x36, 0x8a, 0x4a, 0x28, 0x9b, 0x14, 0x93, 0x54, 0x8f, + 0xfd, 0xbf, 0x8a, 0x6c, 0x1a, 0x2b, 0xec, 0x34, 0x86, 0xed, 0xac, 0x04, 0xb0, 0xda, 0x7e, 0x53, + 0x3b, 0x2e, 0x3f, 0x7a, 0xf8, 0x9f, 0x2b, 0x77, 0x05, 0xf7, 0x67, 0x12, 0x9e, 0x2e, 0x2e, 0xb8, + 0xf0, 0xa4, 0xc7, 0x43, 0xb2, 0x3e, 0x8a, 0x4f, 0x50, 0xd9, 0x73, 0xe9, 0x70, 0xca, 0x23, 0x99, + 0x4c, 0x54, 0x4c, 0x2a, 0x58, 0x6f, 0xac, 0x96, 0x8d, 0x52, 0xcf, 0xea, 0x5c, 0xf0, 0x48, 0xf6, + 0x6c, 0x52, 0xf2, 0x5c, 0xaa, 0x4c, 0x66, 0x10, 0x84, 0xff, 0xc9, 0x86, 0xdf, 0x43, 0x15, 0xd7, + 0xe7, 0x74, 0x32, 0x1c, 0x83, 0x37, 0x1a, 0x4b, 0xa5, 0x4b, 0x9e, 0x94, 0x55, 0xec, 0x4c, 0x85, + 0xf0, 0x03, 0x74, 0x28, 0x17, 0x43, 0x2f, 0x64, 0xb0, 0x50, 0x8a, 0x14, 0xc8, 0x81, 0x5c, 0xf4, + 0x12, 0xd7, 0xf0, 0xd0, 0xfe, 0x17, 0x9c, 0x81, 0x8f, 0x9f, 0xa0, 0xfc, 0xf9, 0x66, 0x53, 0x9f, + 0xdc, 0x2d, 0x1b, 0x1f, 0xef, 0x08, 0x26, 0x21, 0x64, 0x10, 0x05, 0x5e, 0x28, 0x77, 0x4d, 0xdf, + 0x73, 0x85, 0xe9, 0xc6, 0x12, 0x44, 0xeb, 0x0c, 0x16, 0x56, 0x62, 0x90, 0x7c, 0xb6, 0xcc, 0xe7, + 0xea, 0x3a, 0x28, 0xf9, 0x49, 0xea, 0x3c, 0xfc, 0x55, 0x43, 0x68, 0x7b, 0x01, 0xf0, 0x07, 0xa8, + 0xf4, 0xac, 0x6f, 0x77, 0x3f, 0xeb, 0xf5, 0xbb, 0x76, 0x35, 0x57, 0x7f, 0xe7, 0xfa, 0xa6, 0xf9, + 0xd6, 0x36, 0xfd, 0x2c, 0x64, 0xf0, 0xc2, 0x0b, 0x81, 0xe1, 0x26, 0x2a, 0xf6, 0x07, 0xd6, 0xc0, + 0xbe, 0xaa, 0x6a, 0xf5, 0xa3, 0xeb, 0x9b, 0x66, 0x75, 0x0b, 0xea, 0x73, 0x97, 0xb3, 0x18, 0x7f, + 0x88, 0x2a, 0x83, 0xfe, 0xe7, 0x57, 0xc3, 0xb6, 0x6d, 0x93, 0xee, 0xe5, 0x65, 0x75, 0xaf, 0xfe, + 0xe0, 0xfa, 0xa6, 0xf9, 0xf6, 0x16, 0x37, 0x08, 0xfd, 0x38, 0x5b, 0x6c, 0x52, 0xb6, 0xfb, 0xbc, + 0x4b, 0xae, 0x14, 0x63, 0xfe, 0xef, 0x65, 0xbb, 0x73, 0x88, 0xe2, 0x84, 0xb4, 0x7e, 0xf8, 0xed, + 0x4f, 0x7a, 0xee, 0xe5, 0xcf, 0x7a, 0xce, 0xfa, 0xfa, 0xd5, 0x1f, 0x7a, 0xee, 0xe5, 0x4a, 0xd7, + 0x5e, 0xad, 0x74, 0xed, 0xf5, 0x4a, 0xd7, 0x7e, 0x5f, 0xe9, 0xda, 0xf7, 0xb7, 0x7a, 0xee, 0xf5, + 0xad, 0x9e, 0xfb, 0xed, 0x56, 0xcf, 0x7d, 0xf9, 0xe9, 0x8e, 0x54, 0x10, 0x7a, 0xa3, 0xc0, 0x09, + 0xa6, 0xd4, 0xbc, 0x54, 0x3f, 0x44, 0x1f, 0xe4, 0x37, 0x3c, 0x9a, 0x98, 0x8b, 0xcd, 0x0b, 0xe4, + 0x85, 0x12, 0xa2, 0xd0, 0xf1, 0xd3, 0x9f, 0xce, 0x2d, 0xaa, 0x57, 0xe5, 0xa3, 0xbf, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x76, 0x91, 0x9b, 0x7f, 0xa9, 0x04, 0x00, 0x00, } func (this *AccessTypeParam) Equal(that interface{}) bool { @@ -473,6 +475,9 @@ func (this *ContractInfo) Equal(that interface{}) bool { if !this.Created.Equal(that1.Created) { return false } + if this.IBCPortID != that1.IBCPortID { + return false + } return true } func (this *AbsoluteTxPosition) Equal(that interface{}) bool { @@ -665,6 +670,13 @@ func (m *ContractInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.IBCPortID) > 0 { + i -= len(m.IBCPortID) + copy(dAtA[i:], m.IBCPortID) + i = encodeVarintTypes(dAtA, i, uint64(len(m.IBCPortID))) + i-- + dAtA[i] = 0x32 + } if m.Created != nil { { size, err := m.Created.MarshalToSizedBuffer(dAtA[:i]) @@ -855,6 +867,10 @@ func (m *ContractInfo) Size() (n int) { l = m.Created.Size() n += 1 + l + sovTypes(uint64(l)) } + l = len(m.IBCPortID) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } return n } @@ -1413,6 +1429,38 @@ func (m *ContractInfo) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IBCPortID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IBCPortID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:])