diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/Cargo.toml b/contracts/cosmwasm-vm/cw-cluster-connection/Cargo.toml index 958ee7ad..4f706dad 100644 --- a/contracts/cosmwasm-vm/cw-cluster-connection/Cargo.toml +++ b/contracts/cosmwasm-vm/cw-cluster-connection/Cargo.toml @@ -39,9 +39,6 @@ cw-xcall-lib = { path="../cw-xcall-lib" } hex = "0.4.3" serde-json-wasm = {workspace=true} sha2 = { version = "0.10.6", default-features = false } -sha3 = { version = "0.10.6", default-features = false } -ripemd = "0.1.3" -bech32 = "0.9.1" k256 = "0.11.6" [dev-dependencies] diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/src/contract.rs b/contracts/cosmwasm-vm/cw-cluster-connection/src/contract.rs index c1cafe6d..67f5f47b 100644 --- a/contracts/cosmwasm-vm/cw-cluster-connection/src/contract.rs +++ b/contracts/cosmwasm-vm/cw-cluster-connection/src/contract.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{coins, Addr, BankMsg, Event, SubMsgResult, Uint128}; +use cosmwasm_std::{coins, Addr, BankMsg, Event, Uint128}; use cw_xcall_lib::network_address::NetId; use super::*; @@ -87,7 +87,7 @@ impl<'a> ClusterConnection<'a> { let validators_set = self.get_validators(deps.storage)?; - if threshold as usize > validators_set.len() { + if validators_set.len() < threshold as usize { return Err(ContractError::InvalidThreshold { msg: "threshold should be at most the size of validators".to_string(), }); @@ -132,29 +132,6 @@ impl<'a> ClusterConnection<'a> { )) } - pub fn recv_message( - &mut self, - deps: DepsMut, - info: MessageInfo, - src_network: NetId, - conn_sn: u128, - msg: String, - ) -> Result { - self.ensure_relayer(deps.storage, info.sender)?; - - let vec_msg: Vec = self.hex_decode(msg)?; - - if self.get_receipt(deps.as_ref().storage, src_network.clone(), conn_sn) { - return Err(ContractError::DuplicateMessage); - } - self.store_receipt(deps.storage, src_network.clone(), conn_sn)?; - - let xcall_submessage = - self.call_xcall_handle_message(deps.storage, &src_network, vec_msg)?; - - Ok(Response::new().add_submessage(xcall_submessage)) - } - pub fn set_signature_threshold( &mut self, deps: DepsMut, @@ -168,7 +145,7 @@ impl<'a> ClusterConnection<'a> { Ok(Response::new().add_attribute("action", "set_signature_threshold")) } - pub fn recv_message_with_signatures( + pub fn recv_message( &mut self, deps: DepsMut, info: MessageInfo, @@ -179,22 +156,16 @@ impl<'a> ClusterConnection<'a> { ) -> Result { self.ensure_relayer(deps.storage, info.sender)?; + if self.get_receipt(deps.as_ref().storage, src_network.clone(), conn_sn) { + return Err(ContractError::DuplicateMessage); + } + let vec_msg: Vec = self.hex_decode(msg)?; let threshold = self.get_signature_threshold(deps.storage); - let validators = self.get_validators(deps.storage)?; - self.verify_signatures( - deps.as_ref(), - threshold, - validators, - vec_msg.clone(), - signatures, - )?; + self.verify_signatures(deps.as_ref(), threshold, vec_msg.clone(), signatures)?; - if self.get_receipt(deps.as_ref().storage, src_network.clone(), conn_sn) { - return Err(ContractError::DuplicateMessage); - } self.store_receipt(deps.storage, src_network.clone(), conn_sn)?; let xcall_submessage = @@ -246,49 +217,6 @@ impl<'a> ClusterConnection<'a> { Ok(fee.into()) } - fn xcall_handle_message_reply( - &self, - _deps: DepsMut, - message: Reply, - ) -> Result { - match message.result { - SubMsgResult::Ok(_) => Ok(Response::new() - .add_attribute("action", "call_message") - .add_attribute("method", "xcall_handle_message_reply")), - SubMsgResult::Err(error) => Err(ContractError::ReplyError { - code: message.id, - msg: error, - }), - } - } - - fn xcall_handle_error_reply( - &self, - _deps: DepsMut, - message: Reply, - ) -> Result { - match message.result { - SubMsgResult::Ok(_) => Ok(Response::new() - .add_attribute("action", "call_message") - .add_attribute("method", "xcall_handle_error_reply")), - SubMsgResult::Err(error) => Err(ContractError::ReplyError { - code: message.id, - msg: error, - }), - } - } - - pub fn reply(&self, deps: DepsMut, _env: Env, msg: Reply) -> Result { - match msg.id { - XCALL_HANDLE_MESSAGE_REPLY_ID => self.xcall_handle_message_reply(deps, msg), - XCALL_HANDLE_ERROR_REPLY_ID => self.xcall_handle_error_reply(deps, msg), - _ => Err(ContractError::ReplyError { - code: msg.id, - msg: "Unknown".to_string(), - }), - } - } - pub fn migrate( &self, deps: DepsMut, diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/src/helper.rs b/contracts/cosmwasm-vm/cw-cluster-connection/src/helper.rs index 4426befd..7beef7b4 100644 --- a/contracts/cosmwasm-vm/cw-cluster-connection/src/helper.rs +++ b/contracts/cosmwasm-vm/cw-cluster-connection/src/helper.rs @@ -1,14 +1,16 @@ use std::collections::HashMap; -use crate::utils::sha256; use cosmwasm_std::{ensure_eq, Addr, BalanceResponse, BankQuery, Coin}; use cw_xcall_lib::network_address::NetId; use k256::ecdsa::VerifyingKey; -pub const XCALL_HANDLE_MESSAGE_REPLY_ID: u64 = 1; -pub const XCALL_HANDLE_ERROR_REPLY_ID: u64 = 2; use super::*; +pub fn sha256(data: &[u8]) -> Vec { + use sha2::Digest; + sha2::Sha256::digest(&data).to_vec() +} + impl<'a> ClusterConnection<'a> { pub fn ensure_admin(&self, store: &dyn Storage, address: Addr) -> Result<(), ContractError> { let admin = self.get_admin(store)?; @@ -78,25 +80,7 @@ impl<'a> ClusterConnection<'a> { msg: to_json_binary(&xcall_msg).unwrap(), funds: vec![], }); - let sub_msg: SubMsg = SubMsg::reply_always(call_message, XCALL_HANDLE_MESSAGE_REPLY_ID); - Ok(sub_msg) - } - - pub fn call_xcall_handle_error( - &self, - store: &dyn Storage, - sn: u128, - ) -> Result { - let xcall_host = self.get_xcall(store)?; - let xcall_msg = cw_xcall_lib::xcall_msg::ExecuteMsg::HandleError { - sn: sn.try_into().unwrap(), - }; - let call_message: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: xcall_host.to_string(), - msg: to_json_binary(&xcall_msg).unwrap(), - funds: vec![], - }); - let sub_msg: SubMsg = SubMsg::reply_always(call_message, XCALL_HANDLE_ERROR_REPLY_ID); + let sub_msg: SubMsg = SubMsg::new(call_message); Ok(sub_msg) } @@ -104,7 +88,6 @@ impl<'a> ClusterConnection<'a> { &self, deps: Deps, threshold: u8, - relayers: Vec, data: Vec, signatures: Vec>, ) -> Result<(), ContractError> { @@ -129,12 +112,13 @@ impl<'a> ClusterConnection<'a> { .map_err(|_| ContractError::InvalidSignature)?; let pk_hex = hex::encode(pk.to_bytes()); - if relayers.contains(&pk_hex) && !signers.contains_key(&pk_hex) { + if self.is_validator(deps.storage, pk_hex.clone()) + && !signers.contains_key(&pk_hex) + { signers.insert(pk_hex, true); if signers.len() >= threshold.into() { return Ok(()); } - break; } } Err(_) => continue, @@ -144,33 +128,3 @@ impl<'a> ClusterConnection<'a> { return Err(ContractError::InsufficientSignatures); } } - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::testing::mock_dependencies; - #[test] - fn test_verify_signatures_simple() { - let deps = mock_dependencies(); - let connection = ClusterConnection::new(); - let message = b"hello"; - let threshold = 1; - let relayers = - vec!["02e5e9769497fbc7c7ee57ab39ccedcb612018577d30ca090033dc67ba5d68b8ab".to_string()]; - - let hex_sign = "62249c41d09297800f35174e041ad53ec85c5dcad6a6bd0db3267d36a56eb92d7645b7a64c22ae7e1f93c6c3867d2a33e6534e64093600861916e3299e4cc922"; - let mut signature = hex::decode(hex_sign).expect("Failed to decode hex signature"); - signature.push(1); - let signatures = vec![signature]; - - let result = connection.verify_signatures( - deps.as_ref(), - threshold, - relayers, - message.to_vec(), - signatures, - ); - - assert!(result.is_ok()); - } -} diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/src/lib.rs b/contracts/cosmwasm-vm/cw-cluster-connection/src/lib.rs index 33b1167e..308310d9 100644 --- a/contracts/cosmwasm-vm/cw-cluster-connection/src/lib.rs +++ b/contracts/cosmwasm-vm/cw-cluster-connection/src/lib.rs @@ -4,11 +4,10 @@ pub mod helper; pub mod msg; pub mod state; pub mod types; -pub mod utils; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - entry_point, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Reply, + entry_point, to_json_binary, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, StdResult, Storage, SubMsg, WasmMsg, }; @@ -68,14 +67,8 @@ pub fn execute( src_network, conn_sn, msg, - } => conn.recv_message(deps, info, src_network, conn_sn, msg), - - ExecuteMsg::RecvMessageWithSignatures { - src_network, - conn_sn, - msg, signatures, - } => conn.recv_message_with_signatures(deps, info, src_network, conn_sn, msg, signatures), + } => conn.recv_message(deps, info, src_network, conn_sn, msg, signatures), } } @@ -116,12 +109,6 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { } } -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result { - let conn = ClusterConnection::default(); - conn.reply(deps, env, msg) -} - #[cfg_attr(not(feature = "library"), entry_point)] pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result { let conn = ClusterConnection::default(); diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/src/msg.rs b/contracts/cosmwasm-vm/cw-cluster-connection/src/msg.rs index f35a1647..60ae302f 100644 --- a/contracts/cosmwasm-vm/cw-cluster-connection/src/msg.rs +++ b/contracts/cosmwasm-vm/cw-cluster-connection/src/msg.rs @@ -39,12 +39,6 @@ pub enum ExecuteMsg { src_network: NetId, conn_sn: u128, msg: String, - }, - - RecvMessageWithSignatures { - src_network: NetId, - conn_sn: u128, - msg: String, signatures: Vec>, }, } diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/src/state.rs b/contracts/cosmwasm-vm/cw-cluster-connection/src/state.rs index afe368cb..e89da4c0 100644 --- a/contracts/cosmwasm-vm/cw-cluster-connection/src/state.rs +++ b/contracts/cosmwasm-vm/cw-cluster-connection/src/state.rs @@ -165,6 +165,10 @@ impl<'a> ClusterConnection<'a> { Ok(validators_list) } + pub fn is_validator(&self, store: &dyn Storage, pub_key: String) -> bool { + self.validators.has(store, pub_key) + } + pub fn store_signature_threshold( &mut self, store: &mut dyn Storage, diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/src/utils.rs b/contracts/cosmwasm-vm/cw-cluster-connection/src/utils.rs deleted file mode 100644 index 4c79ee44..00000000 --- a/contracts/cosmwasm-vm/cw-cluster-connection/src/utils.rs +++ /dev/null @@ -1,49 +0,0 @@ -use super::*; -use bech32::ToBase32; -use cosmwasm_std::Addr; - -pub fn keccak256(input: &[u8]) -> [u8; 32] { - use sha3::{Digest, Keccak256}; - let mut hasher = Keccak256::new(); - hasher.update(input); - let out: [u8; 32] = hasher.finalize().to_vec().try_into().unwrap(); - out -} - -pub fn sha256(data: &[u8]) -> Vec { - use sha2::Digest; - sha2::Sha256::digest(&data).to_vec() -} - -pub fn ripemd160(data: &[u8]) -> Vec { - use ripemd::Digest; - ripemd::Ripemd160::digest(&data).to_vec() -} - -pub fn pubkey_to_address(pubkey: &[u8], prefix: &str) -> Result { - use bech32::{encode, Variant}; - let sha256_hash = sha256(pubkey); - let ripemd160_hash = ripemd160(&sha256_hash); - - let base32_data_slice = ripemd160_hash.as_slice(); - let base32_data = base32_data_slice.to_base32(); - - let encoded = encode(prefix, base32_data, Variant::Bech32) - .map_err(|_| ContractError::InvalidSignature)?; - Ok(Addr::unchecked(encoded)) -} - -#[cfg(test)] -mod tests { - use super::*; - use hex; - - #[test] - fn test_pubkey_to_address() { - // Test case 1: 33-byte compressed public key (Archway prefix) - let pubkey_hex = "03c414dbe1812580741f0ebe71830226f8304e74daa5a1fad32d1e97da2d719493"; - let pubkey = hex::decode(pubkey_hex).unwrap(); - let address = pubkey_to_address(&pubkey, "archway").unwrap(); - assert_eq!(address, "archway1a06mhyewfajqcf5dujzyqd6ps9a4v9usauxxqw"); - } -} diff --git a/contracts/cosmwasm-vm/cw-cluster-connection/tests/test.rs b/contracts/cosmwasm-vm/cw-cluster-connection/tests/test.rs index ae9aba97..9e63302a 100644 --- a/contracts/cosmwasm-vm/cw-cluster-connection/tests/test.rs +++ b/contracts/cosmwasm-vm/cw-cluster-connection/tests/test.rs @@ -370,53 +370,6 @@ pub fn test_send_message_unauthorized() { #[test] pub fn test_recv_message() { - let (mut deps, env, mut _ctx) = instantiate(ADMIN); - let src_network = NetId::from_str("0x2.icon").unwrap(); - let msg = ExecuteMsg::RecvMessage { - src_network, - conn_sn: 1, - msg: "".to_string(), - }; - - let res = execute( - deps.as_mut(), - env.clone(), - mock_info(RELAYER, &[]), - msg.clone(), - ); - assert!(res.is_ok()); - - let receipt = _ctx.get_receipt( - deps.as_ref().storage, - NetId::from_str("0x2.icon").unwrap(), - 1, - ); - - assert_eq!(receipt, true); -} - -#[test] -pub fn test_recv_message_unauthorized() { - let (mut deps, env, mut _ctx) = instantiate(ADMIN); - let src_network = NetId::from_str("0x2.icon").unwrap(); - let msg = ExecuteMsg::RecvMessage { - src_network, - conn_sn: 1, - msg: "".to_string(), - }; - - let res = execute( - deps.as_mut(), - env.clone(), - mock_info("Unauthorized User", &[]), - msg.clone(), - ); - assert!(res.is_err()); - assert_eq!("Only Relayer", res.unwrap_err().to_string()); -} - -#[test] -pub fn test_recv_message_with_signatures() { let (mut deps, env, ctx) = instantiate(ADMIN); let validators = @@ -441,7 +394,7 @@ pub fn test_recv_message_with_signatures() { let signatures = vec![sign_1]; // Test with non-relayer sender (should fail) - let msg_with_signatures = ExecuteMsg::RecvMessageWithSignatures { + let msg_with_signatures = ExecuteMsg::RecvMessage { src_network: src_network.clone(), conn_sn, msg: msg.to_string(), @@ -471,7 +424,7 @@ pub fn test_recv_message_with_signatures() { } #[test] -pub fn test_recv_message_with_signatures_insufficient() { +pub fn test_recv_message_signatures_insufficient() { let (mut deps, env, ctx) = instantiate(ADMIN); let validators = vec![ @@ -497,7 +450,7 @@ pub fn test_recv_message_with_signatures_insufficient() { sign_1.push(1); let signatures = vec![sign_1]; - let msg_with_signatures = ExecuteMsg::RecvMessageWithSignatures { + let msg_with_signatures = ExecuteMsg::RecvMessage { src_network: src_network.clone(), conn_sn, msg: msg.to_string(),