feat(cosmos): ism dry-run (#3077)

### Description

Implements `dry_run_verify` for the aggregation ISM on cosmwasm. One
remaining issue is that the estimated gas is hardcoded to `1`, because
we're actually [just
querying](37fea49429/contracts/isms/aggregate/src/lib.rs (L108))
via rpc rather than simulating a tx. The `verify` tx isn't marked as a
contract
[entrypoint](https://book.cosmwasm.com/basics/entry-points.html) so it
can't be called from outside iiuc. (here's the
[verify](37fea49429/contracts/isms/aggregate/src/lib.rs (L124))
fn for reference).

Worth mentioning that the query interface for the aggregation ISM is
named incorrectly - it should return fields called `threshold` and
`modules`, but instead copies the response from the multisig ISM and
returns `threshold` and `validators`. This can be particularly
misleading because validators have 20-bytes long addresses, whereas
modules (contracts) have 32-bytes long addresses.

### Related issues

- Fixes https://github.com/hyperlane-xyz/issues/issues/807

### Backward compatibility

yes

### Testing

E2E. The ISM setup is `routing` -> `aggregation (1/1)` -> `multisig
(1/1)`
pull/3074/head
Daniel Savu 11 months ago committed by GitHub
parent f73ee0b273
commit c2cf7be8f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 32
      rust/chains/hyperlane-cosmos/src/aggregation_ism.rs
  2. 23
      rust/chains/hyperlane-cosmos/src/interchain_security_module.rs
  3. 25
      rust/chains/hyperlane-cosmos/src/payloads/aggregate_ism.rs
  4. 15
      rust/utils/run-locally/src/cosmos/deploy.rs
  5. 2
      rust/utils/run-locally/src/cosmos/link.rs
  6. 2
      rust/utils/run-locally/src/cosmos/types.rs

@ -1,15 +1,17 @@
use std::str::FromStr; use std::str::FromStr;
use crate::{ use crate::{
address::CosmosAddress,
grpc::WasmProvider, grpc::WasmProvider,
payloads::aggregate_ism::{ModulesAndThresholdRequest, ModulesAndThresholdResponse}, payloads::{
ism_routes::QueryIsmGeneralRequest,
multisig_ism::{VerifyInfoRequest, VerifyInfoRequestInner, VerifyInfoResponse},
},
ConnectionConf, CosmosProvider, Signer, ConnectionConf, CosmosProvider, Signer,
}; };
use async_trait::async_trait; use async_trait::async_trait;
use hyperlane_core::{ use hyperlane_core::{
AggregationIsm, ChainResult, ContractLocator, HyperlaneChain, HyperlaneContract, AggregationIsm, ChainResult, ContractLocator, HyperlaneChain, HyperlaneContract,
HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, H256, HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, RawHyperlaneMessage, H256,
}; };
use tracing::instrument; use tracing::instrument;
@ -66,15 +68,27 @@ impl AggregationIsm for CosmosAggregationIsm {
&self, &self,
message: &HyperlaneMessage, message: &HyperlaneMessage,
) -> ChainResult<(Vec<H256>, u8)> { ) -> ChainResult<(Vec<H256>, u8)> {
let payload = ModulesAndThresholdRequest::new(message); let payload = VerifyInfoRequest {
verify_info: VerifyInfoRequestInner {
message: hex::encode(RawHyperlaneMessage::from(message)),
},
};
let data = self.provider.grpc().wasm_query(payload, None).await?; let data = self
let response: ModulesAndThresholdResponse = serde_json::from_slice(&data)?; .provider
.grpc()
.wasm_query(QueryIsmGeneralRequest { ism: payload }, None)
.await?;
let response: VerifyInfoResponse = serde_json::from_slice(&data)?;
// Note that due to a misnomer in the CosmWasm implementation, the `modules` field is called `validators`.
let modules: ChainResult<Vec<H256>> = response let modules: ChainResult<Vec<H256>> = response
.modules .validators
.into_iter() .iter()
.map(|module| CosmosAddress::from_str(&module).map(|ca| ca.digest())) // The returned values are Bech32-decoded Cosmos addresses.
// Since they are not EOAs but rather contracts, they are 32 bytes long and
// need to be parsed directly as an `H256`.
.map(|module| H256::from_str(module).map_err(Into::into))
.collect(); .collect();
Ok((modules?, response.threshold)) Ok((modules?, response.threshold))

@ -1,12 +1,14 @@
use async_trait::async_trait; use async_trait::async_trait;
use hyperlane_core::{ use hyperlane_core::{
ChainResult, ContractLocator, HyperlaneChain, HyperlaneContract, HyperlaneDomain, ChainResult, ContractLocator, HyperlaneChain, HyperlaneContract, HyperlaneDomain,
HyperlaneMessage, HyperlaneProvider, InterchainSecurityModule, ModuleType, H256, U256, HyperlaneMessage, HyperlaneProvider, InterchainSecurityModule, ModuleType, RawHyperlaneMessage,
H256, U256,
}; };
use crate::{ use crate::{
grpc::WasmProvider, grpc::WasmProvider,
payloads::{ payloads::{
aggregate_ism::{VerifyRequest, VerifyRequestInner, VerifyResponse},
general::EmptyStruct, general::EmptyStruct,
ism_routes::{QueryIsmGeneralRequest, QueryIsmModuleTypeRequest}, ism_routes::{QueryIsmGeneralRequest, QueryIsmModuleTypeRequest},
}, },
@ -91,6 +93,23 @@ impl InterchainSecurityModule for CosmosInterchainSecurityModule {
message: &HyperlaneMessage, message: &HyperlaneMessage,
metadata: &[u8], metadata: &[u8],
) -> ChainResult<Option<U256>> { ) -> ChainResult<Option<U256>> {
Ok(Some(U256::from(1000))) // TODO let payload = VerifyRequest {
verify: VerifyRequestInner {
metadata: hex::encode(metadata),
message: hex::encode(RawHyperlaneMessage::from(message)),
},
};
let data = self
.provider
.grpc()
.wasm_query(QueryIsmGeneralRequest { ism: payload }, None)
.await?;
let response: VerifyResponse = serde_json::from_slice(&data)?;
// We can't simulate the `verify` call in CosmWasm because
// it's not marked as an entrypoint. So we just use the query interface
// and hardcode a gas value - this can be inefficient if one ISM is
// vastly cheaper than another one.
let dummy_gas_value = U256::one();
Ok(response.verified.then_some(dummy_gas_value))
} }
} }

@ -1,30 +1,17 @@
use hyperlane_core::{HyperlaneMessage, RawHyperlaneMessage};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct ModulesAndThresholdRequest { pub struct VerifyRequest {
modules_and_threshold: ModulesAndThresholdRequestInner, pub verify: VerifyRequestInner,
}
impl ModulesAndThresholdRequest {
pub fn new(message: &HyperlaneMessage) -> Self {
Self {
modules_and_threshold: ModulesAndThresholdRequestInner {
message: hex::encode(RawHyperlaneMessage::from(message)),
},
}
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
struct ModulesAndThresholdRequestInner { pub struct VerifyRequestInner {
/// Hex-encoded Hyperlane message pub metadata: String,
pub message: String, pub message: String,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct ModulesAndThresholdResponse { pub struct VerifyResponse {
pub threshold: u8, pub verified: bool,
/// Bech32-encoded module addresses
pub modules: Vec<String>,
} }

@ -113,6 +113,20 @@ pub fn deploy_cw_hyperlane(
"hpl_ism_multisig", "hpl_ism_multisig",
); );
// deploy ism - aggregation
let ism_aggregate = cli.wasm_init(
&endpoint,
&deployer,
Some(deployer_addr),
codes.hpl_ism_aggregate,
ism::aggregate::InstantiateMsg {
owner: deployer_addr.clone(),
threshold: 1,
isms: vec![ism_multisig.clone()],
},
"hpl_ism_aggregate",
);
// deploy merkle hook // deploy merkle hook
let hook_merkle = cli.wasm_init( let hook_merkle = cli.wasm_init(
&endpoint, &endpoint,
@ -188,6 +202,7 @@ pub fn deploy_cw_hyperlane(
hook_routing, hook_routing,
igp, igp,
igp_oracle, igp_oracle,
ism_aggregate,
ism_routing, ism_routing,
ism_multisig, ism_multisig,
mailbox, mailbox,

@ -162,7 +162,7 @@ fn link_network(
ism::routing::ExecuteMsg::Set { ism::routing::ExecuteMsg::Set {
ism: ism::routing::IsmSet { ism: ism::routing::IsmSet {
domain: target_domain, domain: target_domain,
address: network.deployments.ism_multisig.clone(), address: network.deployments.ism_aggregate.clone(),
}, },
}, },
vec![], vec![],

@ -42,6 +42,7 @@ pub struct Codes {
pub hpl_hook_routing: u64, pub hpl_hook_routing: u64,
pub hpl_igp: u64, pub hpl_igp: u64,
pub hpl_igp_oracle: u64, pub hpl_igp_oracle: u64,
pub hpl_ism_aggregate: u64,
pub hpl_ism_multisig: u64, pub hpl_ism_multisig: u64,
pub hpl_ism_routing: u64, pub hpl_ism_routing: u64,
pub hpl_test_mock_ism: u64, pub hpl_test_mock_ism: u64,
@ -57,6 +58,7 @@ pub struct Deployments {
pub hook_routing: String, pub hook_routing: String,
pub igp: String, pub igp: String,
pub igp_oracle: String, pub igp_oracle: String,
pub ism_aggregate: String,
pub ism_routing: String, pub ism_routing: String,
pub ism_multisig: String, pub ism_multisig: String,
pub mailbox: String, pub mailbox: String,

Loading…
Cancel
Save