Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

WIP: CosmWasm v1 IBC Receive Hooks #966

Merged
merged 48 commits into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b7c439a
WIP: Start to implement IBC receive hooks
assafmo Jul 14, 2022
f769b83
CosmWasm v1 IBC OnOpenChannel
assafmo Jul 19, 2022
26413fd
Parse IBC results in go-cosmwasm
assafmo Jul 25, 2022
d3cda94
Refactor IBC contract calls, lots of shared code
assafmo Jul 25, 2022
bd46776
IBC keeper
assafmo Jul 25, 2022
1277f83
Keeper OnRecvPacket
assafmo Jul 26, 2022
1d80153
WIP: IBC on the enclave side
assafmo Jul 26, 2022
0e412a9
Remove old CosmWasm remnants
assafmo Jul 27, 2022
a60a2cb
secret-contract-optimizer v1.0.8
assafmo Aug 2, 2022
a4a2b1c
Some IBC progress
assafmo Aug 2, 2022
88827c0
WIP: Start to implement IBC receive hooks
assafmo Jul 14, 2022
eb9f617
CosmWasm v1 IBC OnOpenChannel
assafmo Jul 19, 2022
a3e703a
Parse IBC results in go-cosmwasm
assafmo Jul 25, 2022
7929c34
Refactor IBC contract calls, lots of shared code
assafmo Jul 25, 2022
4604b60
IBC keeper
assafmo Jul 25, 2022
73b3e3a
Keeper OnRecvPacket
assafmo Jul 26, 2022
e4ffb9c
WIP: IBC on the enclave side
assafmo Jul 26, 2022
5bee32a
Remove old CosmWasm remnants
assafmo Jul 27, 2022
ee0a8e0
secret-contract-optimizer v1.0.8
assafmo Aug 2, 2022
a921247
Some IBC progress
assafmo Aug 2, 2022
2e60c05
Merge branch 'cw-1-ibc-receive-hooks' of github.com:scrtlabs/SecretNe…
assafmo Aug 11, 2022
d7ee442
Revert a stupid change
assafmo Aug 11, 2022
5c22a98
Decrypt only data from IBC
Aug 11, 2022
752c337
Fix compilation
Aug 11, 2022
05bad14
Parse every IBC submessage
Aug 14, 2022
92772fe
Make IBC handling nicer
Aug 15, 2022
084849d
Encrypt IBC outputs for encrypted inputs
Aug 16, 2022
ede75fa
Finalize output in a function
Aug 16, 2022
86501b0
Finalize plaintext messages
Aug 16, 2022
cc236c7
Support plaintext execute messages
Aug 17, 2022
190a6df
Merge branch 'cosmwasm-v1' into cw-1-ibc-receive-hooks
Aug 17, 2022
28a412a
Correct errors for replies
Aug 17, 2022
94b816a
parse the message correctly
Aug 18, 2022
18abe47
Create IBC tests suite
Aug 19, 2022
2152373
Fix compilation
Aug 20, 2022
f512b1c
Fix possible null dref in tests
Aug 22, 2022
68b8a00
Fix second optional null dref
Aug 22, 2022
32afa88
Merge pull request #1083 from scrtlabs/lior-fix-null-dref2
assafmo Aug 23, 2022
c87d153
Fix the majority of linting problems
Aug 24, 2022
c77d2c5
Merge pull request #1093 from scrtlabs/lior-fix-warnings
assafmo Aug 24, 2022
0d91925
Fix relay
Aug 28, 2022
22a04de
New contract for ibc tests
Aug 28, 2022
16455f0
New ibc test
Aug 28, 2022
488cf00
Fix ibc
Aug 28, 2022
171e769
Now channel open works
Aug 28, 2022
9f70972
IBC Channel Connect WIP
Aug 28, 2022
4c43604
Channel connect is now workins (Including submessages)
Aug 28, 2022
4058c9e
Channel close tests
Aug 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"./cosmwasm/Cargo.toml",
"./cosmwasm/enclaves/Cargo.toml",
"./x/compute/internal/keeper/testdata/v1-sanity-contract/Cargo.toml",
"./x/compute/internal/keeper/testdata/test-contract/Cargo.toml"
"./x/compute/internal/keeper/testdata/test-contract/Cargo.toml",
"./cosmwasm/enclaves/shared/cosmwasm-v1-types/Cargo.toml",
"./cosmwasm/enclaves/shared/cosmwasm-v010-types/Cargo.toml"
],
"rust-analyzer.diagnostics.experimental.enable": true,
"rust-analyzer.rustfmt.rangeFormatting.enable": true,
Expand Down
270 changes: 246 additions & 24 deletions cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use log::*;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::fmt::Debug;

use enclave_ffi_types::{Ctx, EnclaveError};

Expand All @@ -11,6 +14,9 @@ use enclave_cosmos_types::types::{ContractCode, HandleType, SigInfo};
use enclave_cosmwasm_v010_types as cosmwasm_v010_types;
use enclave_cosmwasm_v010_types::encoding::Binary;
use enclave_cosmwasm_v1_types::addresses::Addr;
use enclave_cosmwasm_v1_types::ibc::{
IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcPacketTrait,
};
use enclave_cosmwasm_v1_types::results::{
DecryptedReply, Event, Reply, SubMsgResponse, SubMsgResult,
};
Expand All @@ -24,7 +30,7 @@ use super::contract_validation::{
verify_params, ContractKey,
};
use super::gas::WasmCosts;
use super::io::encrypt_output;
use super::io::{encrypt_output, finalize_raw_output, RawWasmOutput};
use super::module_cache::create_module_instance;
use super::types::{IoNonce, SecretMessage};
use super::wasm::{ContractInstance, ContractOperation, Engine};
Expand Down Expand Up @@ -178,6 +184,11 @@ pub struct ParsedMessage {
pub contract_hash_for_validation: Option<Vec<u8>>,
}

pub struct DecryptedSecretMessage {
pub secret_msg: SecretMessage,
pub decrypted_msg: Vec<u8>,
}

pub fn redact_custom_events(reply: &mut Reply) {
reply.result = match &reply.result {
SubMsgResult::Ok(r) => {
Expand Down Expand Up @@ -214,33 +225,171 @@ pub fn redact_custom_events(reply: &mut Reply) {
};
}

// 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(
pub fn get_secret_msg(message: &[u8]) -> SecretMessage {
match SecretMessage::from_slice(message) {
Ok(orig_secret_msg) => orig_secret_msg,
Err(_) => {
trace!(
"Msg is not SecretMessage (probably plaintext): {:?}",
base64::encode(&message)
);

return SecretMessage {
nonce: [0; 32],
user_public_key: [0; 32],
msg: message.into(),
};
}
}
}

pub fn try_get_decrypted_secret_msg(message: &[u8]) -> Option<DecryptedSecretMessage> {
let secret_msg = get_secret_msg(message);
match secret_msg.decrypt() {
Ok(decrypted_msg) => Some(DecryptedSecretMessage {
secret_msg,
decrypted_msg,
}),
Err(_) => None,
}
}

pub fn parse_ibc_packet<T>(
_t: T,
message: &[u8],
sig_info: &SigInfo,
handle_type: &HandleType,
) -> Result<ParsedMessage, EnclaveError> {
let orig_secret_msg = SecretMessage::from_slice(message)?;
orig_secret_msg: SecretMessage,
function_name: &str,
) -> Result<ParsedMessage, EnclaveError>
where
T: IbcPacketTrait<Data = Binary> + Serialize + DeserializeOwned + Debug,
{
let mut parsed_encrypted_ibc_packet: T =
serde_json::from_slice(&orig_secret_msg.msg.as_slice().to_vec()).map_err(|err| {
warn!(
"{} msg got an error while trying to deserialize msg input bytes into json {:?}: {}",
function_name,
String::from_utf8_lossy(&orig_secret_msg.msg),
err
);
EnclaveError::FailedToDeserialize
})?;

let tmp_secret_data = SecretMessage {
nonce: orig_secret_msg.nonce,
user_public_key: orig_secret_msg.user_public_key,
msg: parsed_encrypted_ibc_packet.get_packet().as_slice().to_vec(),
};

match tmp_secret_data.decrypt() {
Ok(decrypted_msg) => {
// IBC packet was encrypted

return match handle_type {
HandleType::HANDLE_TYPE_EXECUTE => {
trace!(
"handle input before decryption: {:?}",
"{} input before decryption: {:?}",
function_name,
base64::encode(&message)
);
let decrypted_msg = orig_secret_msg.decrypt()?;

parsed_encrypted_ibc_packet.set_packet(decrypted_msg.as_slice().into());

match parsed_encrypted_ibc_packet.get_ack() {
Some(ack_data) => {
let tmp_secret_ack_data = SecretMessage {
nonce: orig_secret_msg.nonce,
user_public_key: orig_secret_msg.user_public_key,
msg: ack_data.as_slice().to_vec(),
};

parsed_encrypted_ibc_packet
.set_ack(tmp_secret_ack_data.decrypt()?.as_slice().into());
}
None => {}
}

Ok(ParsedMessage {
should_validate_sig_info: true,
should_validate_sig_info: false,
was_msg_encrypted: true,
secret_msg: orig_secret_msg,
decrypted_msg: serde_json::to_vec(&parsed_encrypted_ibc_packet).map_err(|err| {
warn!(
"got an error while trying to serialize {} msg into bytes {:?}: {}",
function_name, parsed_encrypted_ibc_packet, err
);
EnclaveError::FailedToSerialize
})?,
contract_hash_for_validation: None,
})
}
Err(_) => {
// assume packet is not encrypted, continue in plaintext mode

trace!(
"{} input was plaintext: {:?}",
function_name,
base64::encode(&message)
);

let decrypted_msg = orig_secret_msg.msg.clone();

Ok(ParsedMessage {
should_validate_sig_info: false,
was_msg_encrypted: false,
secret_msg: orig_secret_msg,
decrypted_msg,
contract_hash_for_validation: None,
})
}
}
}

// 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<ParsedMessage, EnclaveError> {
return match handle_type {
HandleType::HANDLE_TYPE_EXECUTE => match try_get_decrypted_secret_msg(message) {
Some(decrypted_secret_msg) => {
trace!(
"execute input before decryption: {:?}",
base64::encode(&message)
);

Ok(ParsedMessage {
should_validate_sig_info: true,
was_msg_encrypted: true,
secret_msg: decrypted_secret_msg.secret_msg,
decrypted_msg: decrypted_secret_msg.decrypted_msg,
contract_hash_for_validation: None,
})
}
None => {
trace!(
"execute input was plaintext: {:?}",
base64::encode(&message)
);

let secret_msg = get_secret_msg(message);
let decrypted_msg = secret_msg.msg.clone();

Ok(ParsedMessage {
should_validate_sig_info: true,
was_msg_encrypted: false,
secret_msg,
decrypted_msg,
contract_hash_for_validation: None,
})
}
},
HandleType::HANDLE_TYPE_REPLY => {
let orig_secret_msg = SecretMessage::from_slice(message)?;

if sig_info.sign_mode == SignMode::SIGN_MODE_UNSPECIFIED {
trace!("reply input is not encrypted");
trace!(
"reply input is not encrypted: {:?}",
base64::encode(&message)
);
let decrypted_msg = orig_secret_msg.msg.clone();
let mut reply: Reply = serde_json::from_slice(&decrypted_msg)
.map_err(|err| {
Expand Down Expand Up @@ -306,7 +455,6 @@ pub fn parse_message(
});
}

// Here we are sure the reply is OK because only OK is encrypted
trace!(
"reply input before decryption: {:?}",
base64::encode(&message)
Expand Down Expand Up @@ -507,6 +655,61 @@ pub fn parse_message(
}
}
}
HandleType::HANDLE_TYPE_IBC_CHANNEL_OPEN
| HandleType::HANDLE_TYPE_IBC_CHANNEL_CONNECT
| HandleType::HANDLE_TYPE_IBC_CHANNEL_CLOSE => {
trace!(
"parsing {} msg (Should always be plaintext): {:?}",
HandleType::to_export_name(&handle_type),
base64::encode(&message)
);

let scrt_msg = SecretMessage {
nonce: [0; 32],
user_public_key: [0; 32],
msg: message.into(),
};

let decrypted_msg = scrt_msg.msg.clone();

Ok(ParsedMessage {
should_validate_sig_info: false,
was_msg_encrypted: false,
secret_msg: scrt_msg,
decrypted_msg,
contract_hash_for_validation: None,
})
}
HandleType::HANDLE_TYPE_IBC_PACKET_RECEIVE => {
// LIORRR TODO: Maybe mark whether the message was encrypted or not.
let orig_secret_msg = get_secret_msg(message);
parse_ibc_packet(
IbcPacketReceiveMsg::default(),
message,
orig_secret_msg,
"ibc_packet_receive",
)
}
HandleType::HANDLE_TYPE_IBC_PACKET_ACK => {
// LIORRR TODO: Maybe mark whether the message was encrypted or not.
let orig_secret_msg = get_secret_msg(message);
parse_ibc_packet(
IbcPacketAckMsg::default(),
message,
orig_secret_msg,
"ibc_packet_receive",
)
}
HandleType::HANDLE_TYPE_IBC_PACKET_TIMEOUT => {
// LIORRR TODO: Maybe mark whether the message was encrypted or not.
let orig_secret_msg = get_secret_msg(message);
parse_ibc_packet(
IbcPacketTimeoutMsg::default(),
message,
orig_secret_msg,
"ibc_packet_timeout",
)
}
};
}

Expand Down Expand Up @@ -634,22 +837,41 @@ pub fn handle(
let output = coalesce!(EnclaveError, {
let vec_ptr = engine.handle(env_ptr, msg_info_ptr, msg_ptr, parsed_handle_type)?;

let output = engine.extract_vector(vec_ptr)?;
let mut output = engine.extract_vector(vec_ptr)?;

debug!(
"(2) nonce just before encrypt_output: nonce = {:?} pubkey = {:?}",
secret_msg.nonce, secret_msg.user_public_key
);

let output = encrypt_output(
output,
&secret_msg,
&canonical_contract_address,
&env_v010.contract_code_hash,
reply_params,
&canonical_sender_address,
false,
)?;
if was_msg_encrypted {
output = encrypt_output(
output,
&secret_msg,
&canonical_contract_address,
&env_v010.contract_code_hash,
reply_params,
&canonical_sender_address,
false,
)?;
} else {
let raw_output: RawWasmOutput = serde_json::from_slice(&output).map_err(|err| {
warn!("got an error while trying to deserialize output bytes into json");
trace!("output: {:?} error: {:?}", output, err);
EnclaveError::FailedToDeserialize
})?;

let finalized_output = finalize_raw_output(raw_output, false);

output = serde_json::to_vec(&finalized_output).map_err(|err| {
debug!(
"got an error while trying to serialize output json into bytes {:?}: {}",
finalized_output, err
);
EnclaveError::FailedToSerialize
})?;
}

Ok(output)
})
.map_err(|err| {
Expand Down
Loading