Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix CI & Test Bank::MsgSend for CosmWasm v1 & v0.10 #958

Merged
merged 17 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ jobs:
with:
path: ~/.cache/sccache
key: ${{ runner.os }}-sccache
- run: rustup component add rust-src clippy
- run: |
rustup component add rust-src clippy
cd cosmwasm/enclaves/execute/
rustup component add rust-src clippy
- name: Install xargo
run: |
cargo --version
Expand Down Expand Up @@ -80,7 +83,10 @@ jobs:
with:
path: ~/.cache/sccache
key: ${{ runner.os }}-sccache
- run: rustup component add rust-src clippy
- run: |
rustup component add rust-src clippy
cd cosmwasm/enclaves/execute/
rustup component add rust-src clippy
- name: Install xargo
run: |
cargo --version
Expand Down Expand Up @@ -128,6 +134,10 @@ jobs:
with:
name: contract.wasm
path: ./x/compute/internal/keeper/testdata/test-contract/contract.wasm
- uses: actions/upload-artifact@v2
with:
name: v1-contract.wasm
path: ./x/compute/internal/keeper/testdata/v1-sanity-contract/contract.wasm
- uses: actions/upload-artifact@v2
with:
name: enclave
Expand Down Expand Up @@ -174,6 +184,10 @@ jobs:
- uses: actions/download-artifact@v2
with:
name: contract.wasm
- uses: actions/download-artifact@v2
with:
name: v1-contract.wasm
path: ./x/compute/internal/keeper/testdata/v1-sanity-contract
- uses: actions/download-artifact@v2
with:
name: contract_with_floats.wasm
Expand All @@ -185,12 +199,14 @@ jobs:
name: static-too-high-initial-memory.wasm
- name: Setup Files
run: |
find "$(pwd)" -name \*.wasm
cp libgo_cosmwasm.so ./go-cosmwasm/api/libgo_cosmwasm.so
cp librust_cosmwasm_enclave.signed.so ./go-cosmwasm/librust_cosmwasm_enclave.signed.so
cp contract.wasm ./x/compute/internal/keeper/testdata/test-contract/contract.wasm
cp too-high-initial-memory.wasm ./x/compute/internal/keeper/testdata/test-contract/too-high-initial-memory.wasm
cp contract_with_floats.wasm ./x/compute/internal/keeper/testdata/test-contract/contract_with_floats.wasm
cp static-too-high-initial-memory.wasm ./x/compute/internal/keeper/testdata/test-contract/static-too-high-initial-memory.wasm
find "$(pwd)" -name \*.wasm
- name: Test x/registration
run: |
source "$HOME/.sgxsdk/sgxsdk/environment"
Expand Down Expand Up @@ -234,9 +250,13 @@ jobs:
with:
path: ~/.cache/sccache
key: ${{ runner.os }}-sccache
- run: rustup component add rust-src clippy
- run: |
rustup component add rust-src clippy
cd cosmwasm/enclaves/execute/
rustup component add rust-src clippy
- name: Install xargo
run: |
cd cosmwasm/enclaves/execute/
cargo --version
rustc --version
cargo +stable install xargo --version 0.3.25
Expand Down
125 changes: 56 additions & 69 deletions cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use log::*;

use enclave_ffi_types::{Ctx, EnclaveError};

use crate::contract_validation::{ReplyParams, ValidatedMessage};
use crate::external::results::{HandleSuccess, InitSuccess, QuerySuccess};
use crate::wasm::CosmWasmApiVersion;
use cosmos_proto::tx::signing::SignMode;
Expand Down Expand Up @@ -108,7 +109,10 @@ pub fn init(

let decrypted_msg = secret_msg.decrypt()?;

let (validated_msg, reply_params) = validate_msg(&decrypted_msg, contract_code.hash(), None)?;
let ValidatedMessage {
validated_msg,
reply_params,
} = validate_msg(&decrypted_msg, contract_code.hash(), None)?;

trace!(
"init input after decryption: {:?}",
Expand Down Expand Up @@ -142,8 +146,7 @@ pub fn init(
// TODO: ref: https://github.com/CosmWasm/cosmwasm/blob/b971c037a773bf6a5f5d08a88485113d9b9e8e7b/packages/std/src/query.rs#L13
let output = encrypt_output(
output,
secret_msg.nonce,
secret_msg.user_public_key,
&secret_msg,
&canonical_contract_address,
&env_v010.contract_code_hash,
reply_params,
Expand All @@ -167,25 +170,14 @@ pub fn init(
})
}

pub struct TaggedBool {
b: bool,
pub struct ParsedMessage {
pub should_validate_sig_info: bool,
pub was_msg_encrypted: bool,
pub secret_msg: SecretMessage,
pub decrypted_msg: Vec<u8>,
pub contract_hash_for_validation: Option<Vec<u8>>,
}

impl From<bool> for TaggedBool {
fn from(b: bool) -> Self {
TaggedBool { b }
}
}

impl Into<bool> for TaggedBool {
fn into(self) -> bool {
self.b
}
}

type ShouldValidateSigInfo = TaggedBool;
type WasMessageEncrypted = TaggedBool;

pub fn reduct_custom_events(reply: &mut Reply) {
reply.result = match &reply.result {
SubMsgResult::Ok(r) => {
Expand Down Expand Up @@ -228,16 +220,7 @@ pub fn parse_message(
message: &[u8],
sig_info: &SigInfo,
handle_type: &HandleType,
) -> Result<
(
ShouldValidateSigInfo,
WasMessageEncrypted,
SecretMessage,
Vec<u8>,
Option<Vec<u8>>,
),
EnclaveError,
> {
) -> Result<ParsedMessage, EnclaveError> {
let orig_secret_msg = SecretMessage::from_slice(message)?;

return match handle_type {
Expand All @@ -247,13 +230,13 @@ pub fn parse_message(
base64::encode(&message)
);
let decrypted_msg = orig_secret_msg.decrypt()?;
Ok((
ShouldValidateSigInfo::from(true),
WasMessageEncrypted::from(true),
orig_secret_msg,
Ok(ParsedMessage {
should_validate_sig_info: true,
was_msg_encrypted: true,
secret_msg: orig_secret_msg,
decrypted_msg,
None,
))
contract_hash_for_validation: None,
})
}

HandleType::HANDLE_TYPE_REPLY => {
Expand Down Expand Up @@ -315,13 +298,13 @@ pub fn parse_message(
EnclaveError::FailedToSerialize
})?;

return Ok((
ShouldValidateSigInfo::from(false),
WasMessageEncrypted::from(false),
reply_secret_msg,
serialized_reply,
None,
));
return Ok(ParsedMessage {
should_validate_sig_info: false,
was_msg_encrypted: false,
secret_msg: reply_secret_msg,
decrypted_msg: serialized_reply,
contract_hash_for_validation: None,
});
}

// Here we are sure the reply is OK because only OK is encrypted
Expand Down Expand Up @@ -420,13 +403,15 @@ pub fn parse_message(
msg: serialized_encrypted_reply,
};

Ok((
ShouldValidateSigInfo::from(true),
WasMessageEncrypted::from(true),
reply_secret_msg,
decrypted_reply_as_vec,
Some(tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec()),
))
Ok(ParsedMessage {
should_validate_sig_info: true,
was_msg_encrypted: true,
secret_msg: reply_secret_msg,
decrypted_msg: decrypted_reply_as_vec,
contract_hash_for_validation: Some(
tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec(),
),
})
}
SubMsgResult::Err(response) => {
let secret_msg = SecretMessage {
Expand Down Expand Up @@ -511,19 +496,22 @@ pub fn parse_message(
msg: serialized_encrypted_reply,
};

Ok((
ShouldValidateSigInfo::from(true),
WasMessageEncrypted::from(true),
reply_secret_msg,
decrypted_reply_as_vec,
Some(tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec()),
))
Ok(ParsedMessage {
should_validate_sig_info: true,
was_msg_encrypted: true,
secret_msg: reply_secret_msg,
decrypted_msg: decrypted_reply_as_vec,
contract_hash_for_validation: Some(
tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec(),
),
})
}
}
}
};
}

#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
pub fn handle(
context: Ctx,
gas_limit: u64,
Expand Down Expand Up @@ -584,33 +572,33 @@ pub fn handle(
// 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::try_from(handle_type)?;

let (
let ParsedMessage {
should_validate_sig_info,
was_msg_encrypted,
secret_msg,
decrypted_msg,
contract_hash_for_validation,
) = parse_message(msg, &parsed_sig_info, &parsed_handle_type)?;
} = parse_message(msg, &parsed_sig_info, &parsed_handle_type)?;

// There is no signature to verify when the input isn't signed.
// Receiving unsigned messages is only possible in Handle. (Init tx are always signed)
// All of these functions go through handle but the data isn't signed:
// Reply (that is not WASM reply)
if should_validate_sig_info.into() {
if should_validate_sig_info {
// Verify env parameters against the signed tx
verify_params(&parsed_sig_info, &env_v010, &secret_msg)?;
}

let mut validated_msg = decrypted_msg.clone();
let mut reply_params: Option<(Vec<u8>, u64)> = None;
if was_msg_encrypted.into() {
let mut reply_params: Option<ReplyParams> = None;
if was_msg_encrypted {
let x = validate_msg(
&decrypted_msg,
contract_code.hash(),
contract_hash_for_validation,
)?;
validated_msg = x.0;
reply_params = x.1;
validated_msg = x.validated_msg;
reply_params = x.reply_params;
}

trace!(
Expand Down Expand Up @@ -656,8 +644,7 @@ pub fn handle(

let output = encrypt_output(
output,
secret_msg.nonce,
secret_msg.user_public_key,
&secret_msg,
&canonical_contract_address,
&env_v010.contract_code_hash,
reply_params,
Expand Down Expand Up @@ -722,7 +709,8 @@ pub fn query(
"query input afer decryption: {:?}",
String::from_utf8_lossy(&decrypted_msg)
);
let validated_msg = validate_msg(&decrypted_msg, contract_code.hash(), None)?.0;
let ValidatedMessage { validated_msg, .. } =
validate_msg(&decrypted_msg, contract_code.hash(), None)?;

let mut engine = start_engine(
context,
Expand All @@ -749,8 +737,7 @@ pub fn query(

let output = encrypt_output(
output,
secret_msg.nonce,
secret_msg.user_public_key,
&secret_msg,
&CanonicalAddr(Binary(Vec::new())), // Not used for queries (can't init a new contract from a query)
&"".to_string(), // Not used for queries (can't call a sub-message from a query),
None, // Not used for queries (Query response is not replied to the caller),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,22 @@ pub fn validate_contract_key(
calculated_authentication_id == expected_authentication_id
}

pub struct ValidatedMessage {
pub validated_msg: Vec<u8>,
pub reply_params: Option<ReplyParams>,
}

pub struct ReplyParams {
pub recipient_contract_hash: Vec<u8>,
pub sub_msg_id: u64,
}

/// Validate that the message sent to the enclave (after decryption) was actually addressed to this contract.
pub fn validate_msg(
msg: &[u8],
contract_hash: [u8; HASH_SIZE],
contract_hash_for_validation: Option<Vec<u8>>,
) -> Result<(Vec<u8>, Option<(Vec<u8>, u64)>), EnclaveError> {
) -> Result<ValidatedMessage, EnclaveError> {
if contract_hash_for_validation.is_none() && msg.len() < HEX_ENCODED_HASH_SIZE {
warn!("Malformed message - expected contract code hash to be prepended to the msg");
return Err(EnclaveError::ValidationFailure);
Expand Down Expand Up @@ -182,13 +192,19 @@ pub fn validate_msg(
let mut reply_recipient_contract_hash: [u8; HEX_ENCODED_HASH_SIZE] =
[0u8; HEX_ENCODED_HASH_SIZE];
reply_recipient_contract_hash.copy_from_slice(&validated_msg[0..HEX_ENCODED_HASH_SIZE]);
return Ok((
validated_msg[HEX_ENCODED_HASH_SIZE..].to_vec(),
Some((reply_recipient_contract_hash.to_vec(), sub_msg_id)),
));
return Ok(ValidatedMessage {
validated_msg: validated_msg[HEX_ENCODED_HASH_SIZE..].to_vec(),
reply_params: Some(ReplyParams {
recipient_contract_hash: reply_recipient_contract_hash.to_vec(),
sub_msg_id,
}),
});
}

Ok((validated_msg, None))
Ok(ValidatedMessage {
validated_msg,
reply_params: None,
})
}

/// Verify all the parameters sent to the enclave match up, and were signed by the right account.
Expand Down
Loading