Skip to content

Commit

Permalink
Merge branch 'main' into feat/bcs-encode-proof
Browse files Browse the repository at this point in the history
  • Loading branch information
cjcobb23 committed Sep 22, 2023
2 parents fe3e875 + 5bbcdf1 commit d750cc0
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 14 deletions.
4 changes: 2 additions & 2 deletions contracts/multisig-prover/src/encoding/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub fn encode(data: &Data) -> HexBinary {
.into()
}

pub fn msg_to_sign(command_batch: &CommandBatch) -> HexBinary {
pub fn msg_digest(command_batch: &CommandBatch) -> HexBinary {
let msg = Keccak256::digest(encode(&command_batch.data).as_slice());

// Prefix for standard EVM signed data https://eips.ethereum.org/EIPS/eip-191
Expand Down Expand Up @@ -614,7 +614,7 @@ mod test {
encoder: Encoder::Abi,
};

let res = batch.msg_to_sign();
let res = batch.msg_digest();
let expected_msg = test_data::msg_to_sign();

assert_eq!(res, expected_msg);
Expand Down
223 changes: 217 additions & 6 deletions contracts/multisig-prover/src/encoding/bcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use multisig::{key::Signature, msg::Signer};

use crate::{error::ContractError, types::Operator};

fn u256_to_u128(val: Uint256) -> u128 {
val.to_string().parse().expect("value is larger than u128")
}
use super::Data;

// TODO: all of the public functions in this file should be moved to a trait,
// that has an abi and bcs implementation (and possibly others)

#[allow(dead_code)]
fn encode_proof(
Expand Down Expand Up @@ -44,6 +45,83 @@ fn make_operators_with_sigs(signers_with_sigs: Vec<(Signer, Option<Signature>)>)
.collect()
}

pub fn command_params(
source_chain: String,
source_address: String,
destination_address: String,
payload_hash: HexBinary,
) -> Result<HexBinary, ContractError> {
if payload_hash.len() != 32 {
return Err(ContractError::InvalidMessage {
reason: format!("payload hash is not 32 bytes {}", payload_hash.to_hex()),
});
}

let destination_address = <[u8; 32]>::try_from(
HexBinary::from_hex(&destination_address)?.to_vec(),
)
.map_err(|_| ContractError::InvalidMessage {
reason: format!(
"destination_address is not a valid Sui address: {}",
destination_address
),
})?;

Ok(to_bytes(&(
source_chain,
source_address,
destination_address,
payload_hash.to_vec(),
))
.expect("couldn't serialize command as bcs")
.into())
}

fn make_command_id(command_id: &HexBinary) -> [u8; 32] {
// command-ids are fixed length sequences
command_id
.to_vec()
.try_into()
.expect("couldn't convert command id to 32 byte array")
}

pub fn encode(data: &Data) -> HexBinary {
// destination chain id must be u64 for sui
let destination_chain_id = u256_to_u64(data.destination_chain_id);

let (commands_ids, command_types, command_params): (Vec<[u8; 32]>, Vec<String>, Vec<Vec<u8>>) =
data.commands
.iter()
.map(|command| {
(
make_command_id(&command.id),
command.ty.to_string(),
command.params.to_vec(),
)
})
.multiunzip();

to_bytes(&(
destination_chain_id,
commands_ids,
command_types,
command_params,
))
.expect("couldn't encode batch as bcs")
.into()
}

fn u256_to_u128(val: Uint256) -> u128 {
val.to_string().parse().expect("value is larger than u128")
}

fn u256_to_u64(chain_id: Uint256) -> u64 {
chain_id
.to_string()
.parse()
.expect("value is larger than u64")
}

#[cfg(test)]
mod test {

Expand All @@ -56,16 +134,28 @@ mod test {
msg::Signer,
};

use crate::encoding::bcs::u256_to_u128;

use super::encode_proof;
use crate::{
encoding::{
bcs::{
command_params, encode, encode_proof, make_command_id, u256_to_u128, u256_to_u64,
},
Data,
},
types::Command,
};

#[test]
fn test_u256_to_u128() {
let val = u128::MAX;
assert_eq!(val, u256_to_u128(Uint256::from(val)));
}

#[test]
fn test_chain_id_as_u64() {
let chain_id = 1u64;
assert_eq!(chain_id, u256_to_u64(Uint256::from(chain_id as u128)));
}

#[test]
#[should_panic]
fn test_u256_to_u128_fails() {
Expand Down Expand Up @@ -132,4 +222,125 @@ mod test {
);
}
}

#[test]
#[should_panic]
fn test_chain_id_as_u64_fails() {
let chain_id = u128::MAX;
u256_to_u64(Uint256::from(chain_id));
}

#[test]
fn test_make_command_id() {
assert_eq!([0; 32], make_command_id(&HexBinary::from(vec![0; 32])));
}

#[test]
#[should_panic]
fn test_make_command_id_fails_too_large() {
make_command_id(&HexBinary::from(vec![0; 30]));
}

#[test]
fn test_command_params() {
let res = command_params(
"Ethereum".into(),
"00".into(),
"01".repeat(32).into(),
HexBinary::from_hex(&"02".repeat(32)).unwrap(),
);
assert!(res.is_ok());

let res = res.unwrap();
let params = from_bytes(&res.to_vec());
assert!(params.is_ok());
let (source_chain, source_address, destination_address, payload_hash): (
String,
String,
[u8; 32],
Vec<u8>,
) = params.unwrap();
assert_eq!(source_chain, "Ethereum".to_string());

assert_eq!(source_address, "00".to_string());

assert_eq!(
destination_address.to_vec(),
HexBinary::from_hex(&"01".repeat(32)).unwrap().to_vec()
);

assert_eq!(payload_hash, vec![2; 32]);
}

#[test]
fn test_invalid_destination_address() {
let res = command_params(
"Ethereum".into(),
"00".into(),
"01".into(),
HexBinary::from_hex("02").unwrap(),
);
assert!(!res.is_ok());
}

#[test]
fn test_encode() {
let source_chain = "Ethereum";
let source_address = "AA";
let destination_address = "BB".repeat(32);
let payload_hash = HexBinary::from_hex(&"CC".repeat(32)).unwrap();
let destination_chain_id = 1u64;
let command_id = HexBinary::from_hex(&"FF".repeat(32)).unwrap();
let data = Data {
destination_chain_id: destination_chain_id.into(),
commands: vec![Command {
id: command_id.clone(),
ty: crate::types::CommandType::ApproveContractCall,
params: command_params(
source_chain.into(),
source_address.into(),
destination_address.clone().into(),
payload_hash.clone().into(),
)
.unwrap(),
}],
};
let encoded = encode(&data);
let decoded: Result<(u64, Vec<[u8; 32]>, Vec<String>, Vec<Vec<u8>>), _> =
from_bytes(&encoded.to_vec());
assert!(decoded.is_ok());
let (chain_id, command_ids, command_types, params) = decoded.unwrap();

assert_eq!(chain_id, destination_chain_id);

assert_eq!(command_ids.len(), 1);
assert_eq!(command_ids[0].to_vec(), command_id.to_vec());

assert_eq!(command_types.len(), 1);
assert_eq!(
command_types[0],
crate::types::CommandType::ApproveContractCall.to_string()
);

assert_eq!(params.len(), 1);
let command = from_bytes(&params[0]);
assert!(command.is_ok());
let (
source_chain_decoded,
source_address_decoded,
destination_address_decoded,
payload_hash_decoded,
): (String, String, [u8; 32], Vec<u8>) = command.unwrap();

assert_eq!(source_chain_decoded, source_chain);

assert_eq!(source_address_decoded, source_address);

assert_eq!(
destination_address_decoded.to_vec(),
HexBinary::from_hex(&destination_address).unwrap().to_vec()
);

assert_eq!(payload_hash_decoded, payload_hash.to_vec());
}
}
27 changes: 23 additions & 4 deletions contracts/multisig-prover/src/encoding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ fn make_command(msg: Message, encoding: Encoder) -> Result<Command, ContractErro
msg.destination_address,
msg.payload_hash,
)?,
Encoder::Bcs => todo!(),
Encoder::Bcs => bcs::command_params(
msg.source_chain,
msg.source_address,
msg.destination_address,
msg.payload_hash,
)?,
},
id: command_id(msg.id),
})
Expand Down Expand Up @@ -105,9 +110,9 @@ impl CommandBatchBuilder {
}

impl CommandBatch {
pub fn msg_to_sign(&self) -> HexBinary {
pub fn msg_digest(&self) -> HexBinary {
match self.encoder {
Encoder::Abi => abi::msg_to_sign(self),
Encoder::Abi => abi::msg_digest(self),
Encoder::Bcs => todo!(),
}
}
Expand All @@ -134,7 +139,7 @@ impl Data {
pub fn encode(&self, encoder: Encoder) -> HexBinary {
match encoder {
Encoder::Abi => abi::encode(self),
Encoder::Bcs => todo!(),
Encoder::Bcs => bcs::encode(self),
}
}
}
Expand Down Expand Up @@ -188,6 +193,20 @@ mod test {
.unwrap()
);
assert_eq!(res.ty, CommandType::ApproveContractCall);

let mut router_message = router_message.to_owned();
router_message.destination_address = "FF".repeat(32);
let res = make_command(router_message.to_owned(), Encoder::Bcs);
assert!(res.is_ok());

let res = res.unwrap();

assert_eq!(
res.id,
HexBinary::from_hex("3ee2f8af2201994e3518c9ce6848774785c2eef3bdbf9f954899497616dd59af")
.unwrap()
);
assert_eq!(res.ty, CommandType::ApproveContractCall);
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions contracts/multisig-prover/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn construct_proof(deps: DepsMut, message_ids: Vec<String>) -> Result<Respon

let start_sig_msg = multisig::msg::ExecuteMsg::StartSigningSession {
key_id,
msg: command_batch.msg_to_sign(),
msg: command_batch.msg_digest(),
};

let wasm_msg = wasm_execute(config.multisig, &start_sig_msg, vec![])?;
Expand Down Expand Up @@ -211,7 +211,7 @@ pub fn update_worker_set(deps: DepsMut, env: Env) -> Result<Response, ContractEr

let start_sig_msg = multisig::msg::ExecuteMsg::StartSigningSession {
key_id: cur_worker_set.id(), // TODO remove the key_id
msg: batch.msg_to_sign(),
msg: batch.msg_digest(),
};

Ok(Response::new().add_submessage(SubMsg::reply_on_success(
Expand Down

0 comments on commit d750cc0

Please sign in to comment.