diff --git a/Cargo.lock b/Cargo.lock index 1ae437684..ba1b70a8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4986,6 +4986,7 @@ dependencies = [ "anyhow", "axelar-wasm-std", "bcs", + "client", "coordinator", "cosmwasm-schema", "cosmwasm-std", @@ -9306,6 +9307,7 @@ dependencies = [ "cw-storage-plus 1.2.0", "cw2 1.1.2", "error-stack", + "goldie", "integration-tests", "itertools 0.11.0", "msgs-derive", diff --git a/contracts/coordinator/src/client.rs b/contracts/coordinator/src/client.rs index cc803f20d..b3921fdb4 100644 --- a/contracts/coordinator/src/client.rs +++ b/contracts/coordinator/src/client.rs @@ -1,5 +1,8 @@ -use cosmwasm_std::Addr; +use std::collections::HashSet; + +use cosmwasm_std::{Addr, WasmMsg}; use error_stack::{Result, ResultExt}; +use router_api::ChainName; use crate::msg::{ExecuteMsg, QueryMsg}; @@ -28,7 +31,21 @@ pub struct Client<'a> { } impl<'a> Client<'a> { - // TODO: add execute methods + pub fn register_prover_contract( + &self, + chain_name: ChainName, + new_prover_addr: Addr, + ) -> WasmMsg { + self.client.execute(&ExecuteMsg::RegisterProverContract { + chain_name, + new_prover_addr, + }) + } + + pub fn set_active_verifiers(&self, verifiers: HashSet) -> WasmMsg { + self.client + .execute(&ExecuteMsg::SetActiveVerifiers { verifiers }) + } pub fn ready_to_unbond(&self, worker_address: Addr) -> Result { let msg = QueryMsg::ReadyToUnbond { worker_address }; diff --git a/contracts/multisig-prover/Cargo.toml b/contracts/multisig-prover/Cargo.toml index a88d237d2..67bf815b2 100644 --- a/contracts/multisig-prover/Cargo.toml +++ b/contracts/multisig-prover/Cargo.toml @@ -34,6 +34,7 @@ optimize = """docker run --rm -v "$(pwd)":/code \ [dependencies] axelar-wasm-std = { workspace = true, features = ["derive"] } bcs = "0.1.5" +client = { workspace = true } coordinator = { workspace = true } cosmwasm-schema = { workspace = true } cosmwasm-std = { workspace = true } diff --git a/contracts/multisig-prover/src/contract/execute.rs b/contracts/multisig-prover/src/contract/execute.rs index 197d78c5a..c279aafc1 100644 --- a/contracts/multisig-prover/src/contract/execute.rs +++ b/contracts/multisig-prover/src/contract/execute.rs @@ -2,17 +2,16 @@ use std::collections::{BTreeMap, HashSet}; use axelar_wasm_std::permission_control::Permission; use axelar_wasm_std::snapshot::{Participant, Snapshot}; -use axelar_wasm_std::{address, permission_control, FnExt, MajorityThreshold, VerificationStatus}; -use cosmwasm_std::{ - to_json_binary, wasm_execute, Addr, DepsMut, Env, QuerierWrapper, QueryRequest, Response, - Storage, SubMsg, WasmQuery, +use axelar_wasm_std::{ + address, nonempty, permission_control, FnExt, MajorityThreshold, VerificationStatus, }; -use error_stack::{report, ResultExt}; +use cosmwasm_std::{wasm_execute, Addr, DepsMut, Env, QuerierWrapper, Response, Storage, SubMsg}; +use error_stack::{report, Result, ResultExt}; use itertools::Itertools; use multisig::msg::Signer; use multisig::verifier_set::VerifierSet; use router_api::{ChainName, CrossChainId, Message}; -use service_registry::{Service, WeightedVerifier}; +use service_registry::WeightedVerifier; use crate::contract::START_MULTISIG_REPLY_ID; use crate::error::ContractError; @@ -89,11 +88,11 @@ fn messages( ) -> Result, ContractError> { let length = message_ids.len(); - let query = gateway_api::msg::QueryMsg::OutgoingMessages(message_ids); - let messages: Vec = querier.query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: gateway.into(), - msg: to_json_binary(&query)?, - }))?; + let gateway: gateway_api::Client = client::Client::new(querier, &gateway).into(); + + let messages = gateway + .outgoing_messages(message_ids) + .change_context(ContractError::FailedToGetMessages)?; assert_eq!( messages.len(), @@ -108,7 +107,8 @@ fn messages( Err(ContractError::InvalidDestinationChain { expected: chain_name, actual: wrong_destination.destination_chain.clone(), - }) + } + .into()) } else { Ok(messages) } @@ -119,39 +119,24 @@ fn make_verifier_set( env: &Env, config: &Config, ) -> Result { - let active_verifiers_query = service_registry::msg::QueryMsg::ActiveVerifiers { - service_name: config.service_name.clone(), - chain_name: config.chain_name.clone(), - }; + let service_registry: service_registry::Client = + client::Client::new(deps.querier, &config.service_registry).into(); + + let verifiers: Vec = service_registry + .active_verifiers(config.service_name.clone(), config.chain_name.to_owned()) + .change_context(ContractError::FailedToBuildVerifierSet)?; - let verifiers: Vec = - deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: config.service_registry.to_string(), - msg: to_json_binary(&active_verifiers_query)?, - }))?; - - let min_num_verifiers = deps - .querier - .query::(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: config.service_registry.to_string(), - msg: to_json_binary(&service_registry::msg::QueryMsg::Service { - service_name: config.service_name.clone(), - })?, - }))? + let min_num_verifiers = service_registry + .service(config.service_name.clone()) + .change_context(ContractError::FailedToBuildVerifierSet)? .min_num_verifiers; + let multisig: multisig::Client = client::Client::new(deps.querier, &config.multisig).into(); + let participants_with_pubkeys = verifiers .into_iter() .filter_map(|verifier| { - let pub_key_query = multisig::msg::QueryMsg::PublicKey { - verifier_address: verifier.verifier_info.address.to_string(), - key_type: config.key_type, - }; - - match deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: config.multisig.to_string(), - msg: to_json_binary(&pub_key_query).ok()?, - })) { + match multisig.public_key(verifier.verifier_info.address.to_string(), config.key_type) { Ok(pub_key) => Some((Participant::from(verifier), pub_key)), Err(_) => None, } @@ -159,16 +144,18 @@ fn make_verifier_set( .collect::>(); if participants_with_pubkeys.len() < min_num_verifiers as usize { - return Err(ContractError::NotEnoughVerifiers); + return Err(ContractError::NotEnoughVerifiers.into()); } let snapshot = Snapshot::new( config.signing_threshold, - participants_with_pubkeys - .iter() - .map(|(participant, _)| participant.clone()) - .collect::>() - .try_into()?, + nonempty::Vec::::try_from( + participants_with_pubkeys + .iter() + .map(|(participant, _)| participant.clone()) + .collect::>(), + ) + .change_context(ContractError::FailedToBuildVerifierSet)?, ); Ok(VerifierSet::new( @@ -184,10 +171,15 @@ fn next_verifier_set( config: &Config, ) -> Result, ContractError> { // if there's already a pending verifiers set update, just return it - if let Some(pending_verifier_set) = NEXT_VERIFIER_SET.may_load(deps.storage)? { + if let Some(pending_verifier_set) = NEXT_VERIFIER_SET + .may_load(deps.storage) + .change_context(ContractError::StorageError)? + { return Ok(Some(pending_verifier_set)); } - let cur_verifier_set = CURRENT_VERIFIER_SET.may_load(deps.storage)?; + let cur_verifier_set = CURRENT_VERIFIER_SET + .may_load(deps.storage) + .change_context(ContractError::StorageError)?; let new_verifier_set = make_verifier_set(deps, env, config)?; match cur_verifier_set { @@ -202,7 +194,7 @@ fn next_verifier_set( Ok(None) } } - None => Err(ContractError::NoVerifierSet), + None => Err(ContractError::NoVerifierSet.into()), } } @@ -211,10 +203,12 @@ fn save_next_verifier_set( new_verifier_set: &VerifierSet, ) -> Result<(), ContractError> { if different_set_in_progress(storage, new_verifier_set) { - return Err(ContractError::VerifierSetConfirmationInProgress); + return Err(ContractError::VerifierSetConfirmationInProgress.into()); } - NEXT_VERIFIER_SET.save(storage, new_verifier_set)?; + NEXT_VERIFIER_SET + .save(storage, new_verifier_set) + .change_context(ContractError::StorageError)?; Ok(()) } @@ -300,62 +294,60 @@ fn ensure_verifier_set_verification( config: &Config, deps: &DepsMut, ) -> Result<(), ContractError> { - let query = voting_verifier::msg::QueryMsg::VerifierSetStatus(verifier_set.clone()); - - let status: VerificationStatus = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: config.voting_verifier.to_string(), - msg: to_json_binary(&query)?, - }))?; + let verifier: voting_verifier::Client = + client::Client::new(deps.querier, &config.voting_verifier).into(); + let status = verifier + .verifier_set_status(verifier_set.clone()) + .change_context(ContractError::FailedToVerifyVerifierSet)?; if status != VerificationStatus::SucceededOnSourceChain { - Err(ContractError::VerifierSetNotConfirmed) + Err(ContractError::VerifierSetNotConfirmed.into()) } else { Ok(()) } } pub fn confirm_verifier_set(deps: DepsMut, sender: Addr) -> Result { - let config = CONFIG.load(deps.storage)?; + let config = CONFIG.load(deps.storage).expect("failed to load config"); let verifier_set = NEXT_VERIFIER_SET - .may_load(deps.storage)? + .may_load(deps.storage) + .change_context(ContractError::StorageError)? .ok_or(ContractError::NoVerifierSetToConfirm)?; - let sender_role = permission_control::sender_role(deps.storage, &sender)?; + let sender_role = permission_control::sender_role(deps.storage, &sender) + .change_context(ContractError::StorageError)?; if !sender_role.contains(Permission::Governance) { ensure_verifier_set_verification(&verifier_set, &config, &deps)?; } - CURRENT_VERIFIER_SET.save(deps.storage, &verifier_set)?; + CURRENT_VERIFIER_SET + .save(deps.storage, &verifier_set) + .change_context(ContractError::StorageError)?; NEXT_VERIFIER_SET.remove(deps.storage); let verifier_union_set = all_active_verifiers(&deps)?; + let coordinator: coordinator::Client = + client::Client::new(deps.querier, &config.coordinator).into(); + + let multisig: multisig::Client = client::Client::new(deps.querier, &config.multisig).into(); + Ok(Response::new() - .add_message(wasm_execute( - config.multisig, - &multisig::msg::ExecuteMsg::RegisterVerifierSet { - verifier_set: verifier_set.clone(), - }, - vec![], - )?) - .add_message(wasm_execute( - config.coordinator, - &coordinator::msg::ExecuteMsg::SetActiveVerifiers { - verifiers: verifier_union_set, - }, - vec![], - )?)) + .add_message(multisig.register_verifier_set(verifier_set)) + .add_message(coordinator.set_active_verifiers(verifier_union_set))) } fn all_active_verifiers(deps: &DepsMut) -> Result, ContractError> { let current_signers = CURRENT_VERIFIER_SET - .may_load(deps.storage)? + .may_load(deps.storage) + .change_context(ContractError::StorageError)? .map(|verifier_set| verifier_set.signers) .unwrap_or_default(); let next_signers = NEXT_VERIFIER_SET - .may_load(deps.storage)? + .may_load(deps.storage) + .change_context(ContractError::StorageError)? .map(|verifier_set| verifier_set.signers) .unwrap_or_default(); @@ -402,22 +394,23 @@ pub fn update_signing_threshold( deps: DepsMut, new_signing_threshold: MajorityThreshold, ) -> Result { - CONFIG.update( - deps.storage, - |mut config| -> Result { - config.signing_threshold = new_signing_threshold; - Ok(config) - }, - )?; + CONFIG + .update( + deps.storage, + |mut config| -> std::result::Result { + config.signing_threshold = new_signing_threshold; + Ok(config) + }, + ) + .change_context(ContractError::StorageError)?; Ok(Response::new()) } -pub fn update_admin( - deps: DepsMut, - new_admin_address: String, -) -> Result { - let new_admin = address::validate_cosmwasm_address(deps.api, &new_admin_address)?; - permission_control::set_admin(deps.storage, &new_admin)?; +pub fn update_admin(deps: DepsMut, new_admin_address: String) -> Result { + let new_admin = address::validate_cosmwasm_address(deps.api, &new_admin_address) + .change_context(ContractError::FailedToUpdateAdmin)?; + permission_control::set_admin(deps.storage, &new_admin) + .change_context(ContractError::FailedToUpdateAdmin)?; Ok(Response::new()) } diff --git a/contracts/multisig-prover/src/error.rs b/contracts/multisig-prover/src/error.rs index cafef424e..bdc8476d9 100644 --- a/contracts/multisig-prover/src/error.rs +++ b/contracts/multisig-prover/src/error.rs @@ -77,4 +77,25 @@ pub enum ContractError { #[error("failed to serialize data for the external gateway")] SerializeData, + + #[error("failed to get outgoing messages from gateway")] + FailedToGetMessages, + + #[error("failed to build verifier set")] + FailedToBuildVerifierSet, + + #[error("failed to check verifier set verification status")] + FailedToVerifyVerifierSet, + + #[error("failed to update admin")] + FailedToUpdateAdmin, + + #[error("failed to create wasm execute msg")] + FailedToCreateWasmExecuteMsg, + + // Generic error to wrap cw_storage_plus errors + // This should only be used for things that shouldn't happen, such as encountering + // an error when loading data that should always load successfully. + #[error("storage error")] + StorageError, } diff --git a/contracts/multisig/src/client.rs b/contracts/multisig/src/client.rs index 712035e2e..fe8917ca3 100644 --- a/contracts/multisig/src/client.rs +++ b/contracts/multisig/src/client.rs @@ -1,5 +1,7 @@ +use std::collections::HashMap; + use cosmwasm_schema::cw_serde; -use cosmwasm_std::Uint64; +use cosmwasm_std::{HexBinary, Uint64, WasmMsg}; use error_stack::{Result, ResultExt}; use router_api::ChainName; @@ -12,19 +14,19 @@ use crate::verifier_set::VerifierSet; #[cw_serde] pub enum Error { #[error("failed to query multisig contract for multisig session. session_id: {0}")] - QueryMultisigSession(Uint64), + MultisigSession(Uint64), #[error("failed to query multisig contract for verifier set: verifier_set_id: {0}")] - QueryVerifierSet(String), + VerifierSet(String), #[error("failed to query multisig contract for verifier public key. verifier_address: {verifier_address}, key_type: {key_type}")] - QueryPublicKey { + PublicKey { verifier_address: String, key_type: KeyType, }, #[error("failed to query multisig contract for caller authorization. contract_address: {contract_address}, chain_name: {chain_name}")] - QueryIsCallerAuthorized { + IsCallerAuthorized { contract_address: String, chain_name: ChainName, }, @@ -39,19 +41,19 @@ impl<'a> From> for Client<'a> { impl From for Error { fn from(value: QueryMsg) -> Self { match value { - QueryMsg::Multisig { session_id } => Error::QueryMultisigSession(session_id), - QueryMsg::VerifierSet { verifier_set_id } => Error::QueryVerifierSet(verifier_set_id), + QueryMsg::Multisig { session_id } => Error::MultisigSession(session_id), + QueryMsg::VerifierSet { verifier_set_id } => Error::VerifierSet(verifier_set_id), QueryMsg::PublicKey { verifier_address, key_type, - } => Error::QueryPublicKey { + } => Error::PublicKey { verifier_address, key_type, }, QueryMsg::IsCallerAuthorized { contract_address, chain_name, - } => Error::QueryIsCallerAuthorized { + } => Error::IsCallerAuthorized { contract_address, chain_name, }, @@ -64,6 +66,62 @@ pub struct Client<'a> { } impl<'a> Client<'a> { + pub fn start_signing_session( + &self, + verifier_set_id: String, + msg: HexBinary, + chain_name: ChainName, + sig_verifier: Option, + ) -> WasmMsg { + self.client.execute(&ExecuteMsg::StartSigningSession { + verifier_set_id, + msg, + chain_name, + sig_verifier, + }) + } + + pub fn submit_signature(&self, session_id: Uint64, signature: HexBinary) -> WasmMsg { + self.client.execute(&ExecuteMsg::SubmitSignature { + session_id, + signature, + }) + } + + pub fn register_verifier_set(&self, verifier_set: VerifierSet) -> WasmMsg { + self.client + .execute(&ExecuteMsg::RegisterVerifierSet { verifier_set }) + } + + pub fn register_public_key( + &self, + public_key: PublicKey, + signed_sender_address: HexBinary, + ) -> WasmMsg { + self.client.execute(&ExecuteMsg::RegisterPublicKey { + public_key, + signed_sender_address, + }) + } + + pub fn authorize_callers(&self, contracts: HashMap) -> WasmMsg { + self.client + .execute(&ExecuteMsg::AuthorizeCallers { contracts }) + } + + pub fn unauthorize_callers(&self, contracts: HashMap) -> WasmMsg { + self.client + .execute(&ExecuteMsg::UnauthorizeCallers { contracts }) + } + + pub fn disable_signing(&self) -> WasmMsg { + self.client.execute(&ExecuteMsg::DisableSigning) + } + + pub fn enable_signing(&self) -> WasmMsg { + self.client.execute(&ExecuteMsg::EnableSigning) + } + pub fn multisig(&self, session_id: Uint64) -> Result { let msg = QueryMsg::Multisig { session_id }; self.client.query(&msg).change_context_lazy(|| msg.into()) diff --git a/contracts/multisig/src/lib.rs b/contracts/multisig/src/lib.rs index 406ce2af1..f553f3b88 100644 --- a/contracts/multisig/src/lib.rs +++ b/contracts/multisig/src/lib.rs @@ -1,4 +1,5 @@ -pub mod client; +mod client; +pub use client::Client; pub mod contract; pub mod error; pub mod events; diff --git a/contracts/service-registry/src/client.rs b/contracts/service-registry/src/client.rs index 619dd69fd..6d90437cc 100644 --- a/contracts/service-registry/src/client.rs +++ b/contracts/service-registry/src/client.rs @@ -9,16 +9,16 @@ type Result = error_stack::Result; #[derive(thiserror::Error, Debug, PartialEq)] pub enum Error { #[error("failed to query service registry for active verifiers for service {service_name} and chain {chain_name}")] - QueryActiveVerifiers { + ActiveVerifiers { service_name: String, chain_name: ChainName, }, #[error("failed to query service registry for service {0}")] - QueryService(String), + Service(String), #[error("failed to query service registry for verifier {verifier} of service {service_name}")] - QueryVerifier { + Verifier { service_name: String, verifier: String, }, @@ -30,15 +30,15 @@ impl From for Error { QueryMsg::ActiveVerifiers { service_name, chain_name, - } => Error::QueryActiveVerifiers { + } => Error::ActiveVerifiers { service_name, chain_name, }, - QueryMsg::Service { service_name } => Error::QueryService(service_name), + QueryMsg::Service { service_name } => Error::Service(service_name), QueryMsg::Verifier { service_name, verifier, - } => Error::QueryVerifier { + } => Error::Verifier { service_name, verifier, }, @@ -168,7 +168,7 @@ mod test { } fn setup_queries_to_fail() -> (MockQuerier, Addr) { - let addr = "multisig"; + let addr = "service-registry"; let mut querier = MockQuerier::default(); querier.update_wasm(move |msg| match msg { diff --git a/contracts/service-registry/src/lib.rs b/contracts/service-registry/src/lib.rs index 1c84095b8..3a3417461 100644 --- a/contracts/service-registry/src/lib.rs +++ b/contracts/service-registry/src/lib.rs @@ -1,4 +1,5 @@ -pub mod client; +mod client; +pub use client::Client; pub mod contract; pub mod error; pub mod helpers; diff --git a/contracts/voting-verifier/Cargo.toml b/contracts/voting-verifier/Cargo.toml index e3fe453a3..b887b0df6 100644 --- a/contracts/voting-verifier/Cargo.toml +++ b/contracts/voting-verifier/Cargo.toml @@ -53,6 +53,7 @@ thiserror = { workspace = true } alloy-primitives = { version = "0.7.7", features = ["getrandom"] } assert_ok = { workspace = true } cw-multi-test = "0.15.1" +goldie = { workspace = true } integration-tests = { workspace = true } multisig = { workspace = true, features = ["test", "library"] } rand = "0.8.5" diff --git a/contracts/voting-verifier/src/client.rs b/contracts/voting-verifier/src/client.rs index 64d6d519d..832a7d014 100644 --- a/contracts/voting-verifier/src/client.rs +++ b/contracts/voting-verifier/src/client.rs @@ -1,7 +1,7 @@ use axelar_wasm_std::vec::VecExt; use axelar_wasm_std::voting::{PollId, Vote}; use axelar_wasm_std::{nonempty, MajorityThreshold, VerificationStatus}; -use cosmwasm_std::{Addr, WasmMsg}; +use cosmwasm_std::WasmMsg; use error_stack::ResultExt; use multisig::verifier_set::VerifierSet; use router_api::Message; @@ -12,8 +12,25 @@ type Result = error_stack::Result; #[derive(thiserror::Error, Debug)] pub enum Error { - #[error("failed to query the voting verifier contract at {0}")] - QueryVotingVerifier(Addr), + #[error("failed to query voting verifier for verifier set status. verifier_set: {0:?}")] + VerifierSetStatus(VerifierSet), + #[error("failed to query voting verifier for current voting threshold")] + CurrentThreshold, + #[error("failed to query voting verifier for messages status. messages: {0:?}")] + MessagesStatus(Vec), + #[error("failed to query voting verifier for poll. poll_id: {0}")] + Poll(PollId), +} + +impl From for Error { + fn from(value: QueryMsg) -> Self { + match value { + QueryMsg::MessagesStatus(messages) => Error::MessagesStatus(messages), + QueryMsg::VerifierSetStatus(verifier_set) => Error::VerifierSetStatus(verifier_set), + QueryMsg::Poll { poll_id } => Error::Poll(poll_id), + QueryMsg::CurrentThreshold => Error::CurrentThreshold, + } + } } impl<'a> From> for Client<'a> { @@ -59,31 +76,28 @@ impl<'a> Client<'a> { } pub fn poll(&self, poll_id: PollId) -> Result { - self.client - .query(&QueryMsg::Poll { poll_id }) - .change_context_lazy(|| Error::QueryVotingVerifier(self.client.address.clone())) + let msg = QueryMsg::Poll { poll_id }; + self.client.query(&msg).change_context_lazy(|| msg.into()) } pub fn messages_status(&self, messages: Vec) -> Result> { match messages.as_slice() { [] => Ok(vec![]), - _ => self - .client - .query(&QueryMsg::MessagesStatus(messages)) - .change_context_lazy(|| Error::QueryVotingVerifier(self.client.address.clone())), + _ => { + let msg = QueryMsg::MessagesStatus(messages); + self.client.query(&msg).change_context_lazy(|| msg.into()) + } } } pub fn verifier_set_status(&self, new_verifier_set: VerifierSet) -> Result { - self.client - .query(&QueryMsg::VerifierSetStatus(new_verifier_set)) - .change_context_lazy(|| Error::QueryVotingVerifier(self.client.address.clone())) + let msg = QueryMsg::VerifierSetStatus(new_verifier_set); + self.client.query(&msg).change_context_lazy(|| msg.into()) } pub fn current_threshold(&self) -> Result { - self.client - .query(&QueryMsg::CurrentThreshold) - .change_context_lazy(|| Error::QueryVotingVerifier(self.client.address.clone())) + let msg = QueryMsg::CurrentThreshold; + self.client.query(&msg).change_context_lazy(|| msg.into()) } } @@ -94,7 +108,9 @@ mod test { use axelar_wasm_std::msg_id::HexTxHashAndEventIndex; use axelar_wasm_std::{Threshold, VerificationStatus}; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockQuerier}; - use cosmwasm_std::{from_json, Addr, DepsMut, QuerierWrapper, Uint128, Uint64, WasmQuery}; + use cosmwasm_std::{ + from_json, Addr, DepsMut, QuerierWrapper, SystemError, Uint128, Uint64, WasmQuery, + }; use multisig::verifier_set::VerifierSet; use router_api::{CrossChainId, Message}; @@ -180,6 +196,82 @@ mod test { ); } + #[test] + fn query_verifier_set_returns_error_when_query_fails() { + let (querier, addr) = setup_queries_to_fail(); + let client: Client = client::Client::new(QuerierWrapper::new(&querier), &addr).into(); + let res = client.verifier_set_status(VerifierSet { + signers: BTreeMap::new(), + threshold: Uint128::one(), + created_at: 0, + }); + + assert!(res.is_err()); + goldie::assert!(res.unwrap_err().to_string()); + } + + #[test] + fn query_messages_status_returns_error_when_query_fails() { + let (querier, addr) = setup_queries_to_fail(); + let client: Client = client::Client::new(QuerierWrapper::new(&querier), &addr).into(); + let res = client.messages_status(vec![Message { + cc_id: CrossChainId::new( + "eth", + HexTxHashAndEventIndex { + tx_hash: [0; 32], + event_index: 0, + } + .to_string() + .as_str(), + ) + .unwrap(), + source_address: "0x1234".parse().unwrap(), + destination_address: "0x5678".parse().unwrap(), + destination_chain: "eth".parse().unwrap(), + payload_hash: [0; 32], + }]); + + assert!(res.is_err()); + goldie::assert!(res.unwrap_err().to_string()); + } + + #[test] + fn query_poll_returns_error_when_query_fails() { + let (querier, addr) = setup_queries_to_fail(); + let client: Client = client::Client::new(QuerierWrapper::new(&querier), &addr).into(); + let res = client.poll(1u64.into()); + + assert!(res.is_err()); + goldie::assert!(res.unwrap_err().to_string()); + } + + #[test] + fn query_current_threshold_returns_error_when_query_fails() { + let (querier, addr) = setup_queries_to_fail(); + let client: Client = client::Client::new(QuerierWrapper::new(&querier), &addr).into(); + let res = client.current_threshold(); + + assert!(res.is_err()); + goldie::assert!(res.unwrap_err().to_string()); + } + + fn setup_queries_to_fail() -> (MockQuerier, Addr) { + let addr = "voting-verifier"; + + let mut querier = MockQuerier::default(); + querier.update_wasm(move |msg| match msg { + WasmQuery::Smart { + contract_addr, + msg: _, + } if contract_addr == addr => { + Err(SystemError::Unknown {}).into() // simulate cryptic error seen in production + } + _ => panic!("unexpected query: {:?}", msg), + }); + + (querier, Addr::unchecked(addr)) + } + fn setup() -> (MockQuerier, InstantiateMsg, Addr) { let addr = "voting-verifier"; let mut deps = mock_dependencies(); diff --git a/contracts/voting-verifier/src/contract/execute.rs b/contracts/voting-verifier/src/contract/execute.rs index 66f03221d..bb63a4ba0 100644 --- a/contracts/voting-verifier/src/contract/execute.rs +++ b/contracts/voting-verifier/src/contract/execute.rs @@ -327,7 +327,7 @@ pub fn end_poll(deps: DepsMut, env: Env, poll_id: PollId) -> Result Result { let config = CONFIG.load(deps.storage).expect("failed to load config"); - let service_registry: service_registry::client::Client = + let service_registry: service_registry::Client = client::Client::new(deps.querier, &config.service_registry_contract).into(); let verifiers: Vec = service_registry diff --git a/contracts/voting-verifier/src/testdata/query_current_threshold_returns_error_when_query_fails.golden b/contracts/voting-verifier/src/testdata/query_current_threshold_returns_error_when_query_fails.golden new file mode 100644 index 000000000..a2406e780 --- /dev/null +++ b/contracts/voting-verifier/src/testdata/query_current_threshold_returns_error_when_query_fails.golden @@ -0,0 +1 @@ +failed to query voting verifier for current voting threshold \ No newline at end of file diff --git a/contracts/voting-verifier/src/testdata/query_messages_status_returns_error_when_query_fails.golden b/contracts/voting-verifier/src/testdata/query_messages_status_returns_error_when_query_fails.golden new file mode 100644 index 000000000..7e8a15a0b --- /dev/null +++ b/contracts/voting-verifier/src/testdata/query_messages_status_returns_error_when_query_fails.golden @@ -0,0 +1 @@ +failed to query voting verifier for messages status. messages: [Message { cc_id: CrossChainId { source_chain: ChainNameRaw("eth"), message_id: String("0x0000000000000000000000000000000000000000000000000000000000000000-0") }, source_address: Address(String("0x1234")), destination_chain: ChainName("eth"), destination_address: Address(String("0x5678")), payload_hash: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }] \ No newline at end of file diff --git a/contracts/voting-verifier/src/testdata/query_poll_returns_error_when_query_fails.golden b/contracts/voting-verifier/src/testdata/query_poll_returns_error_when_query_fails.golden new file mode 100644 index 000000000..3c65c2b67 --- /dev/null +++ b/contracts/voting-verifier/src/testdata/query_poll_returns_error_when_query_fails.golden @@ -0,0 +1 @@ +failed to query voting verifier for poll. poll_id: 1 \ No newline at end of file diff --git a/contracts/voting-verifier/src/testdata/query_verifier_set_returns_error_when_query_fails.golden b/contracts/voting-verifier/src/testdata/query_verifier_set_returns_error_when_query_fails.golden new file mode 100644 index 000000000..14f3b07fe --- /dev/null +++ b/contracts/voting-verifier/src/testdata/query_verifier_set_returns_error_when_query_fails.golden @@ -0,0 +1 @@ +failed to query voting verifier for verifier set status. verifier_set: VerifierSet { signers: {}, threshold: Uint128(1), created_at: 0 } \ No newline at end of file diff --git a/packages/gateway-api/src/client.rs b/packages/gateway-api/src/client.rs index 1254f00a4..6e34f620b 100644 --- a/packages/gateway-api/src/client.rs +++ b/packages/gateway-api/src/client.rs @@ -10,13 +10,13 @@ type Result = error_stack::Result; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("failed to query gateway for outgoing messages. message ids: {0:?}")] - QueryOutgoingMessages(Vec), + OutgoingMessages(Vec), } impl From for Error { fn from(value: QueryMsg) -> Self { match value { - QueryMsg::OutgoingMessages(message_ids) => Error::QueryOutgoingMessages(message_ids), + QueryMsg::OutgoingMessages(message_ids) => Error::OutgoingMessages(message_ids), } } } diff --git a/packages/gateway-api/src/lib.rs b/packages/gateway-api/src/lib.rs index 9952fef07..9550e12ab 100644 --- a/packages/gateway-api/src/lib.rs +++ b/packages/gateway-api/src/lib.rs @@ -1,2 +1,3 @@ -pub mod client; +mod client; +pub use client::Client; pub mod msg;