From b0165e21d928a53cd5df7c566476e2a9e25bd5e3 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Tue, 6 Jun 2023 11:08:18 -0400 Subject: [PATCH 01/11] Use ICA-enabled ibc test chain instead of gaia --- tests/dockerfile/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dockerfile/Dockerfile b/tests/dockerfile/Dockerfile index 547590f6e..ac7de3ea4 100644 --- a/tests/dockerfile/Dockerfile +++ b/tests/dockerfile/Dockerfile @@ -7,7 +7,7 @@ RUN npm install -g ts-node && npm install -g typescript ADD https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.10.10-bb74230f.tar.gz /geth/ RUN cd /geth && tar -xvf * && mv /geth/**/geth /usr/bin/geth # Download gaia as a IBC test chain -ADD https://github.com/cosmos/gaia/releases/download/v7.0.0/gaiad-v7.0.0-linux-amd64 /usr/bin/gaiad +ADD https://github.com/althea-net/ibc-test-chain/releases/download/v9.1.2/gaiad-v9.1.2-linux-amd64 /usr/bin/gaiad # Setup Hermes for IBC connections between chains ADD https://github.com/informalsystems/ibc-rs/releases/download/v0.13.0/hermes-v0.13.0-x86_64-unknown-linux-gnu.tar.gz /tmp/ RUN cd /tmp/ && tar -xvf hermes-v0.13.0-x86_64-unknown-linux-gnu.tar.gz && mv hermes /usr/bin/ From 04f8d0cf79f462bfa3a4a183982d893cc5b1abe9 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Tue, 6 Jun 2023 14:11:12 -0400 Subject: [PATCH 02/11] Remove gravity_proto, use gravity_proto crate v0.2.1 --- orchestrator/Cargo.lock | 104 +- orchestrator/Cargo.toml | 3 +- orchestrator/cosmos_gravity/Cargo.toml | 2 +- orchestrator/gbt/Cargo.toml | 2 +- orchestrator/gravity_proto/Cargo.toml | 14 - .../gravity_proto/src/ethereum_claim.rs | 135 -- orchestrator/gravity_proto/src/lib.rs | 11 - .../src/prost/cosmos.bank.v1beta1.rs | 83 - .../gravity_proto/src/prost/gravity.v1.rs | 1985 ----------------- orchestrator/gravity_utils/Cargo.toml | 2 +- orchestrator/orchestrator/Cargo.toml | 2 +- orchestrator/proto_build/Cargo.toml | 14 - orchestrator/proto_build/src/main.rs | 175 -- orchestrator/relayer/Cargo.toml | 2 +- orchestrator/test_runner/Cargo.toml | 2 +- 15 files changed, 11 insertions(+), 2525 deletions(-) delete mode 100644 orchestrator/gravity_proto/Cargo.toml delete mode 100644 orchestrator/gravity_proto/src/ethereum_claim.rs delete mode 100644 orchestrator/gravity_proto/src/lib.rs delete mode 100644 orchestrator/gravity_proto/src/prost/cosmos.bank.v1beta1.rs delete mode 100644 orchestrator/gravity_proto/src/prost/gravity.v1.rs delete mode 100644 orchestrator/proto_build/Cargo.toml delete mode 100644 orchestrator/proto_build/src/main.rs diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 428edbf0a..dfea7edeb 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -695,15 +695,6 @@ dependencies = [ "sha3", ] -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - [[package]] name = "const-oid" version = "0.9.2" @@ -1194,12 +1185,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.0.26" @@ -1403,10 +1388,11 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gravity_proto" -version = "0.1.0" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a817efef97ba2f5a12ff58d3d9ef6857a1d5c45f85ebc4d6d4fff2069066062" dependencies = [ "cosmos-sdk-proto-althea", - "deep_space", "prost 0.10.4", "prost-types 0.10.1", "tonic 0.7.2", @@ -2092,12 +2078,6 @@ dependencies = [ "uuid 1.3.2", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "num" version = "0.4.0" @@ -2405,16 +2385,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" -[[package]] -name = "petgraph" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" -dependencies = [ - "fixedbitset", - "indexmap", -] - [[package]] name = "pin-project" version = "1.0.12" @@ -2469,16 +2439,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "primitive-types" version = "0.11.1" @@ -2579,28 +2539,6 @@ dependencies = [ "prost-derive 0.11.9", ] -[[package]] -name = "prost-build" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" -dependencies = [ - "bytes", - "cfg-if 1.0.0", - "cmake", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost 0.10.4", - "prost-types 0.10.1", - "regex", - "tempfile", - "which", -] - [[package]] name = "prost-derive" version = "0.10.1" @@ -2646,18 +2584,6 @@ dependencies = [ "prost 0.11.9", ] -[[package]] -name = "proto_build" -version = "0.1.0" -dependencies = [ - "prost 0.10.4", - "prost-build", - "regex", - "tonic 0.7.2", - "tonic-build", - "walkdir", -] - [[package]] name = "ptr_meta" version = "0.1.4" @@ -3963,19 +3889,6 @@ dependencies = [ "tracing-futures", ] -[[package]] -name = "tonic-build" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9263bf4c9bfaae7317c1c2faf7f18491d2fe476f70c414b73bf5d445b00ffa1" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 1.0.109", -] - [[package]] name = "tower" version = "0.4.13" @@ -4351,17 +4264,6 @@ dependencies = [ "webpki 0.21.4", ] -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/orchestrator/Cargo.toml b/orchestrator/Cargo.toml index c265c54d8..083bc3791 100644 --- a/orchestrator/Cargo.toml +++ b/orchestrator/Cargo.toml @@ -1,8 +1,9 @@ [workspace] -members = ["orchestrator", "cosmos_gravity", "ethereum_gravity", "gravity_utils", "proto_build", "test_runner", "gravity_proto", "relayer", "gbt", "metrics_exporter"] +members = ["orchestrator", "cosmos_gravity", "ethereum_gravity", "gravity_utils", "test_runner", "relayer", "gbt", "metrics_exporter"] default-members = ["gbt"] [workspace.dependencies] +gravity_proto = "0.2.1" num256 = "0.5" clarity = "0.7" web30 = "0.23" diff --git a/orchestrator/cosmos_gravity/Cargo.toml b/orchestrator/cosmos_gravity/Cargo.toml index 72afc64ed..afb079585 100644 --- a/orchestrator/cosmos_gravity/Cargo.toml +++ b/orchestrator/cosmos_gravity/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] gravity_utils = {path = "../gravity_utils"} ethereum_gravity = {path = "../ethereum_gravity"} -gravity_proto = {path = "../gravity_proto/"} +gravity_proto = {workspace = true} deep_space = {workspace = true} clarity = {workspace = true} diff --git a/orchestrator/gbt/Cargo.toml b/orchestrator/gbt/Cargo.toml index 8a63793be..785aedf5e 100644 --- a/orchestrator/gbt/Cargo.toml +++ b/orchestrator/gbt/Cargo.toml @@ -15,7 +15,7 @@ homepage = "https://gravitybridge.althea.net/" ethereum_gravity = {path = "../ethereum_gravity"} cosmos_gravity = {path = "../cosmos_gravity"} gravity_utils = {path = "../gravity_utils"} -gravity_proto = {path = "../gravity_proto/"} +gravity_proto = {workspace = true} relayer = {path = "../relayer/"} orchestrator = {path = "../orchestrator/"} metrics_exporter = {path = "../metrics_exporter/"} diff --git a/orchestrator/gravity_proto/Cargo.toml b/orchestrator/gravity_proto/Cargo.toml deleted file mode 100644 index 8f4516f82..000000000 --- a/orchestrator/gravity_proto/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "gravity_proto" -version = "0.1.0" -authors = ["Justin Kilpatrick "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -prost = {workspace = true} -prost-types = {workspace = true} -cosmos-sdk-proto = {package = "cosmos-sdk-proto-althea", version = "0.14", features = ["bech32ibc", "ethermint"]} -tonic = {workspace = true} -deep_space = {workspace = true} diff --git a/orchestrator/gravity_proto/src/ethereum_claim.rs b/orchestrator/gravity_proto/src/ethereum_claim.rs deleted file mode 100644 index 5779795dd..000000000 --- a/orchestrator/gravity_proto/src/ethereum_claim.rs +++ /dev/null @@ -1,135 +0,0 @@ - - -/// A mirror of the EthereumClaim interface on the Go side -/// EthereumClaim represents a claim on ethereum state -pub trait EthereumClaim { - /// All Ethereum claims that we relay from the Gravity contract and into the module - /// have a nonce that is strictly increasing and unique, since this nonce is - /// issued by the Ethereum contract it is immutable and must be agreed on by all validators - /// any disagreement on what claim goes to what nonce means someone is lying. - fn get_event_nonce(&self) -> u64; - - /// The block height that the claimed event occurred on. This EventNonce provides sufficient - /// ordering for the execution of all claims. The block height is used only for batchTimeouts + logicTimeouts - /// when we go to create a new batch we set the timeout some number of batches out from the last - /// known height plus projected block progress since then. - fn get_eth_block_height(&self) -> u64; - - /// the delegate address of the claimer, for MsgDepositClaim and MsgWithdrawClaim - /// this is sent in as the sdk.AccAddress of the delegated key. it is up to the user - /// to disambiguate this into a sdk.ValAddress - /// - fn get_claimer(&self) -> String; - - /// Which type of claim this is - fn get_type(&self) -> ClaimType; - - /* - TODO: Consider implementing ClaimHash, although it should be queryable via a cosmos node - fn validate_basic(&self) -> error; - - /// The claim hash of this claim. This is used to store these claims and also used to check if two different - /// validators claims agree. Therefore it's extremely important that this include all elements of the claim - /// with the exception of the orchestrator who sent it in, which will be used as a different part of the index - fn claim_hash(&self) -> Result, error>; - */ -} - -impl ToString for ClaimType { - fn to_string(&self) -> String { - match self { - ClaimType::Unspecified => "CLAIM_TYPE_UNSPECIFIED".to_string(), - ClaimType::SendToCosmos => "CLAIM_TYPE_SEND_TO_COSMOS".to_string(), - ClaimType::BatchSendToEth => "CLAIM_TYPE_BATCH_SEND_TO_ETH".to_string(), - ClaimType::Erc20Deployed => "CLAIM_TYPE_ERC20_DEPLOYED".to_string(), - ClaimType::LogicCallExecuted => "CLAIM_TYPE_LOGIC_CALL_EXECUTED".to_string(), - ClaimType::ValsetUpdated => "CLAIM_TYPE_VALSET_UPDATED".to_string(), - } - } -} - -impl EthereumClaim for MsgSendToCosmosClaim { - fn get_event_nonce(&self) -> u64 { - self.event_nonce - } - - fn get_eth_block_height(&self) -> u64 { - self.eth_block_height - } - - fn get_claimer(&self) -> String { - self.orchestrator.clone() - } - - fn get_type(&self) -> ClaimType { - ClaimType::SendToCosmos - } -} -impl EthereumClaim for MsgBatchSendToEthClaim { - fn get_event_nonce(&self) -> u64 { - self.event_nonce - } - - fn get_eth_block_height(&self) -> u64 { - self.eth_block_height - } - - fn get_claimer(&self) -> String { - self.orchestrator.clone() - } - - fn get_type(&self) -> ClaimType { - ClaimType::BatchSendToEth - } -} -impl EthereumClaim for MsgErc20DeployedClaim { - fn get_event_nonce(&self) -> u64 { - self.event_nonce - } - - fn get_eth_block_height(&self) -> u64 { - self.eth_block_height - } - - fn get_claimer(&self) -> String { - self.orchestrator.clone() - } - - fn get_type(&self) -> ClaimType { - ClaimType::Erc20Deployed - } -} -impl EthereumClaim for MsgLogicCallExecutedClaim { - fn get_event_nonce(&self) -> u64 { - self.event_nonce - } - - fn get_eth_block_height(&self) -> u64 { - self.eth_block_height - } - - fn get_claimer(&self) -> String { - self.orchestrator.clone() - } - - fn get_type(&self) -> ClaimType { - ClaimType::LogicCallExecuted - } -} -impl EthereumClaim for MsgValsetUpdatedClaim { - fn get_event_nonce(&self) -> u64 { - self.event_nonce - } - - fn get_eth_block_height(&self) -> u64 { - self.eth_block_height - } - - fn get_claimer(&self) -> String { - self.orchestrator.clone() - } - - fn get_type(&self) -> ClaimType { - ClaimType::ValsetUpdated - } -} diff --git a/orchestrator/gravity_proto/src/lib.rs b/orchestrator/gravity_proto/src/lib.rs deleted file mode 100644 index ee61421ba..000000000 --- a/orchestrator/gravity_proto/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! This crate provides Gravity proto definitions in Rust and also re-exports cosmos_sdk_proto for use by downstream -//! crates. By default around a dozen proto files are generated and places into the prost folder. We could then proceed -//! to fix up all these files and use them as the required dependencies to the Gravity file, but we chose instead to replace -//! those paths with references ot upstream cosmos-sdk-proto and delete the other files. This reduces cruft in this repo even -//! if it does make for a somewhat more confusing proto generation process. - -pub use cosmos_sdk_proto; -pub mod gravity { - include!("prost/gravity.v1.rs"); - include!("ethereum_claim.rs"); -} diff --git a/orchestrator/gravity_proto/src/prost/cosmos.bank.v1beta1.rs b/orchestrator/gravity_proto/src/prost/cosmos.bank.v1beta1.rs deleted file mode 100644 index e4bd3f4ba..000000000 --- a/orchestrator/gravity_proto/src/prost/cosmos.bank.v1beta1.rs +++ /dev/null @@ -1,83 +0,0 @@ -/// Params defines the parameters for the bank module. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Params { - #[prost(message, repeated, tag="1")] - pub send_enabled: ::prost::alloc::vec::Vec, - #[prost(bool, tag="2")] - pub default_send_enabled: bool, -} -/// SendEnabled maps coin denom to a send_enabled status (whether a denom is -/// sendable). -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SendEnabled { - #[prost(string, tag="1")] - pub denom: ::prost::alloc::string::String, - #[prost(bool, tag="2")] - pub enabled: bool, -} -/// Input models transaction input. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Input { - #[prost(string, tag="1")] - pub address: ::prost::alloc::string::String, - #[prost(message, repeated, tag="2")] - pub coins: ::prost::alloc::vec::Vec, -} -/// Output models transaction outputs. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Output { - #[prost(string, tag="1")] - pub address: ::prost::alloc::string::String, - #[prost(message, repeated, tag="2")] - pub coins: ::prost::alloc::vec::Vec, -} -/// Supply represents a struct that passively keeps track of the total supply -/// amounts in the network. -/// This message is deprecated now that supply is indexed by denom. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Supply { - #[prost(message, repeated, tag="1")] - pub total: ::prost::alloc::vec::Vec, -} -/// DenomUnit represents a struct that describes a given -/// denomination unit of the basic token. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DenomUnit { - /// denom represents the string name of the given denom unit (e.g uatom). - #[prost(string, tag="1")] - pub denom: ::prost::alloc::string::String, - /// exponent represents power of 10 exponent that one must - /// raise the base_denom to in order to equal the given DenomUnit's denom - /// 1 denom = 1^exponent base_denom - /// (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with - /// exponent = 6, thus: 1 atom = 10^6 uatom). - #[prost(uint32, tag="2")] - pub exponent: u32, - /// aliases is a list of string aliases for the given denom - #[prost(string, repeated, tag="3")] - pub aliases: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -/// Metadata represents a struct that describes -/// a basic token. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Metadata { - #[prost(string, tag="1")] - pub description: ::prost::alloc::string::String, - /// denom_units represents the list of DenomUnit's for a given coin - #[prost(message, repeated, tag="2")] - pub denom_units: ::prost::alloc::vec::Vec, - /// base represents the base denom (should be the DenomUnit with exponent = 0). - #[prost(string, tag="3")] - pub base: ::prost::alloc::string::String, - /// display indicates the suggested denom that should be - /// displayed in clients. - #[prost(string, tag="4")] - pub display: ::prost::alloc::string::String, - /// name defines the name of the token (eg: Cosmos Atom) - #[prost(string, tag="5")] - pub name: ::prost::alloc::string::String, - /// symbol is the token symbol usually shown on exchanges (eg: ATOM). This can - /// be the same as the display. - #[prost(string, tag="6")] - pub symbol: ::prost::alloc::string::String, -} diff --git a/orchestrator/gravity_proto/src/prost/gravity.v1.rs b/orchestrator/gravity_proto/src/prost/gravity.v1.rs deleted file mode 100644 index 4f4c903a6..000000000 --- a/orchestrator/gravity_proto/src/prost/gravity.v1.rs +++ /dev/null @@ -1,1985 +0,0 @@ -/// IDSet represents a set of IDs -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct IdSet { - #[prost(uint64, repeated, tag = "1")] - pub ids: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct BatchFees { - #[prost(string, tag = "1")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub total_fees: ::prost::alloc::string::String, - #[prost(uint64, tag = "3")] - pub tx_count: u64, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventWithdrawalReceived { - #[prost(string, tag = "1")] - pub bridge_contract: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub bridge_chain_id: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub outgoing_tx_id: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventWithdrawCanceled { - #[prost(string, tag = "1")] - pub sender: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub tx_id: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub bridge_contract: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub bridge_chain_id: ::prost::alloc::string::String, -} -/// BridgeValidator represents a validator's ETH address and its power -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct BridgeValidator { - #[prost(uint64, tag = "1")] - pub power: u64, - #[prost(string, tag = "2")] - pub ethereum_address: ::prost::alloc::string::String, -} -/// Valset is the Ethereum Bridge Multsig Set, each gravity validator also -/// maintains an ETH key to sign messages, these are used to check signatures on -/// ETH because of the significant gas savings -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct Valset { - #[prost(uint64, tag = "1")] - pub nonce: u64, - #[prost(message, repeated, tag = "2")] - pub members: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "3")] - pub height: u64, - #[prost(string, tag = "4")] - pub reward_amount: ::prost::alloc::string::String, - /// the reward token in it's Ethereum hex address representation - #[prost(string, tag = "5")] - pub reward_token: ::prost::alloc::string::String, -} -/// LastObservedEthereumBlockHeight stores the last observed -/// Ethereum block height along with the Cosmos block height that -/// it was observed at. These two numbers can be used to project -/// outward and always produce batches with timeouts in the future -/// even if no Ethereum block height has been relayed for a long time -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct LastObservedEthereumBlockHeight { - #[prost(uint64, tag = "1")] - pub cosmos_block_height: u64, - #[prost(uint64, tag = "2")] - pub ethereum_block_height: u64, -} -/// This records the relationship between an ERC20 token and the denom -/// of the corresponding Cosmos originated asset -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct Erc20ToDenom { - #[prost(string, tag = "1")] - pub erc20: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub denom: ::prost::alloc::string::String, -} -/// UnhaltBridgeProposal defines a custom governance proposal useful for restoring -/// the bridge after a oracle disagreement. Once this proposal is passed bridge state will roll back events -/// to the nonce provided in target_nonce if and only if those events have not yet been observed (executed on the Cosmos chain). This allows for easy -/// handling of cases where for example an Ethereum hardfork has occured and more than 1/3 of the vlaidtor set -/// disagrees with the rest. Normally this would require a chain halt, manual genesis editing and restar to resolve -/// with this feature a governance proposal can be used instead -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct UnhaltBridgeProposal { - #[prost(string, tag = "1")] - pub title: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub description: ::prost::alloc::string::String, - #[prost(uint64, tag = "4")] - pub target_nonce: u64, -} -/// AirdropProposal defines a custom governance proposal type that allows an airdrop to occur in a decentralized -/// fashion. A list of destination addresses and an amount per airdrop recipient is provided. The funds for this -/// airdrop are removed from the Community Pool, if the community pool does not have sufficient funding to perform -/// the airdrop to all provided recipients nothing will occur -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct AirdropProposal { - #[prost(string, tag = "1")] - pub title: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub description: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub denom: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "4")] - pub recipients: ::prost::alloc::vec::Vec, - #[prost(uint64, repeated, tag = "5")] - pub amounts: ::prost::alloc::vec::Vec, -} -/// IBCMetadataProposal defines a custom governance proposal type that allows governance to set the -/// metadata for an IBC token, this will allow Gravity to deploy an ERC20 representing this token on -/// Ethereum -/// Name: the token name -/// Symbol: the token symbol -/// Description: the token description, not sent to ETH at all, only used on Cosmos -/// Display: the token display name (only used on Cosmos to decide ERC20 Decimals) -/// Deicmals: the decimals for the display unit -/// ibc_denom is the denom of the token in question on this chain -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct IbcMetadataProposal { - #[prost(string, tag = "1")] - pub title: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub description: ::prost::alloc::string::String, - #[prost(message, optional, tag = "3")] - pub metadata: ::core::option::Option, - #[prost(string, tag = "4")] - pub ibc_denom: ::prost::alloc::string::String, -} -/// PendingIbcAutoForward represents a SendToCosmos transaction with a foreign CosmosReceiver which will be added to the -/// PendingIbcAutoForward queue in attestation_handler and sent over IBC on some submission of a MsgExecuteIbcAutoForwards -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PendingIbcAutoForward { - /// the destination address. sdk.AccAddress does not preserve foreign prefixes - #[prost(string, tag = "1")] - pub foreign_receiver: ::prost::alloc::string::String, - /// the token sent from ethereum to the ibc-enabled chain over `IbcChannel` - #[prost(message, optional, tag = "2")] - pub token: ::core::option::Option, - /// the IBC channel to send `Amount` over via ibc-transfer module - #[prost(string, tag = "3")] - pub ibc_channel: ::prost::alloc::string::String, - /// the EventNonce from the MsgSendToCosmosClaim, used for ordering the queue - #[prost(uint64, tag = "4")] - pub event_nonce: u64, -} -/// MsgSetOrchestratorAddress -/// this message allows validators to delegate their voting responsibilities -/// to a given key. This key is then used as an optional authentication method -/// for sigining oracle claims -/// VALIDATOR -/// The validator field is a cosmosvaloper1... string (i.e. sdk.ValAddress) -/// that references a validator in the active set -/// ORCHESTRATOR -/// The orchestrator field is a cosmos1... string (i.e. sdk.AccAddress) that -/// references the key that is being delegated to -/// ETH_ADDRESS -/// This is a hex encoded 0x Ethereum public key that will be used by this validator -/// on Ethereum -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgSetOrchestratorAddress { - #[prost(string, tag = "1")] - pub validator: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub orchestrator: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub eth_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgSetOrchestratorAddressResponse {} -/// MsgValsetConfirm -/// this is the message sent by the validators when they wish to submit their -/// signatures over the validator set at a given block height. A validator must -/// first call MsgSetEthAddress to set their Ethereum address to be used for -/// signing. Then someone (anyone) must make a ValsetRequest, the request is -/// essentially a messaging mechanism to determine which block all validators -/// should submit signatures over. Finally validators sign the validator set, -/// powers, and Ethereum addresses of the entire validator set at the height of a -/// ValsetRequest and submit that signature with this message. -/// -/// If a sufficient number of validators (66% of voting power) (A) have set -/// Ethereum addresses and (B) submit ValsetConfirm messages with their -/// signatures it is then possible for anyone to view these signatures in the -/// chain store and submit them to Ethereum to update the validator set -/// ------------- -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgValsetConfirm { - #[prost(uint64, tag = "1")] - pub nonce: u64, - #[prost(string, tag = "2")] - pub orchestrator: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub eth_address: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub signature: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgValsetConfirmResponse {} -/// MsgSendToEth -/// This is the message that a user calls when they want to bridge an asset -/// it will later be removed when it is included in a batch and successfully -/// submitted tokens are removed from the users balance immediately -/// ------------- -/// AMOUNT: -/// the coin to send across the bridge, note the restriction that this is a -/// single coin not a set of coins that is normal in other Cosmos messages -/// BRIDGE_FEE: -/// the fee paid for the bridge, distinct from the fee paid to the chain to -/// actually send this message in the first place. So a successful send has -/// two layers of fees for the user -/// CHAIN_FEE: -/// the fee paid to the chain for handling the request, which must be a -/// certain percentage of the AMOUNT, as determined by governance. -/// This Msg will be rejected if CHAIN_FEE is insufficient. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgSendToEth { - #[prost(string, tag = "1")] - pub sender: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub eth_dest: ::prost::alloc::string::String, - #[prost(message, optional, tag = "3")] - pub amount: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub bridge_fee: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub chain_fee: ::core::option::Option, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgSendToEthResponse {} -/// MsgRequestBatch -/// this is a message anyone can send that requests a batch of transactions to -/// send across the bridge be created for whatever block height this message is -/// included in. This acts as a coordination point, the handler for this message -/// looks at the AddToOutgoingPool tx's in the store and generates a batch, also -/// available in the store tied to this message. The validators then grab this -/// batch, sign it, submit the signatures with a MsgConfirmBatch before a relayer -/// can finally submit the batch -/// ------------- -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgRequestBatch { - #[prost(string, tag = "1")] - pub sender: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub denom: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgRequestBatchResponse {} -/// MsgConfirmBatch -/// When validators observe a MsgRequestBatch they form a batch by ordering -/// transactions currently in the txqueue in order of highest to lowest fee, -/// cutting off when the batch either reaches a hardcoded maximum size (to be -/// decided, probably around 100) or when transactions stop being profitable -/// (TODO determine this without nondeterminism) This message includes the batch -/// as well as an Ethereum signature over this batch by the validator -/// ------------- -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgConfirmBatch { - #[prost(uint64, tag = "1")] - pub nonce: u64, - #[prost(string, tag = "2")] - pub token_contract: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub eth_signer: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub orchestrator: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub signature: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgConfirmBatchResponse {} -/// MsgConfirmLogicCall -/// When validators observe a MsgRequestBatch they form a batch by ordering -/// transactions currently in the txqueue in order of highest to lowest fee, -/// cutting off when the batch either reaches a hardcoded maximum size (to be -/// decided, probably around 100) or when transactions stop being profitable -/// (TODO determine this without nondeterminism) This message includes the batch -/// as well as an Ethereum signature over this batch by the validator -/// ------------- -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgConfirmLogicCall { - #[prost(string, tag = "1")] - pub invalidation_id: ::prost::alloc::string::String, - #[prost(uint64, tag = "2")] - pub invalidation_nonce: u64, - #[prost(string, tag = "3")] - pub eth_signer: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub orchestrator: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub signature: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgConfirmLogicCallResponse {} -/// MsgSendToCosmosClaim -/// When more than 66% of the active validator set has -/// claimed to have seen the deposit enter the ethereum blockchain coins are -/// issued to the Cosmos address in question -/// ------------- -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgSendToCosmosClaim { - #[prost(uint64, tag = "1")] - pub event_nonce: u64, - #[prost(uint64, tag = "2")] - pub eth_block_height: u64, - #[prost(string, tag = "3")] - pub token_contract: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub amount: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub ethereum_sender: ::prost::alloc::string::String, - #[prost(string, tag = "6")] - pub cosmos_receiver: ::prost::alloc::string::String, - #[prost(string, tag = "7")] - pub orchestrator: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgSendToCosmosClaimResponse {} -/// MsgExecuteIbcAutoForwards -/// Prompts the forwarding of Pending IBC Auto-Forwards in the queue -/// The Pending forwards will be executed in order of their original SendToCosmos.EventNonce -/// The funds in the queue will be sent to a local gravity-prefixed address if IBC transfer is not possible -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgExecuteIbcAutoForwards { - /// How many queued forwards to clear, be careful about gas limits - #[prost(uint64, tag = "1")] - pub forwards_to_clear: u64, - /// This message's sender - #[prost(string, tag = "2")] - pub executor: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgExecuteIbcAutoForwardsResponse {} -/// BatchSendToEthClaim claims that a batch of send to eth -/// operations on the bridge contract was executed. -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgBatchSendToEthClaim { - #[prost(uint64, tag = "1")] - pub event_nonce: u64, - #[prost(uint64, tag = "2")] - pub eth_block_height: u64, - #[prost(uint64, tag = "3")] - pub batch_nonce: u64, - #[prost(string, tag = "4")] - pub token_contract: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub orchestrator: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgBatchSendToEthClaimResponse {} -/// ERC20DeployedClaim allows the Cosmos module -/// to learn about an ERC20 that someone deployed -/// to represent a Cosmos asset -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgErc20DeployedClaim { - #[prost(uint64, tag = "1")] - pub event_nonce: u64, - #[prost(uint64, tag = "2")] - pub eth_block_height: u64, - #[prost(string, tag = "3")] - pub cosmos_denom: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub token_contract: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub name: ::prost::alloc::string::String, - #[prost(string, tag = "6")] - pub symbol: ::prost::alloc::string::String, - #[prost(uint64, tag = "7")] - pub decimals: u64, - #[prost(string, tag = "8")] - pub orchestrator: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgErc20DeployedClaimResponse {} -/// This informs the Cosmos module that a logic -/// call has been executed -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgLogicCallExecutedClaim { - #[prost(uint64, tag = "1")] - pub event_nonce: u64, - #[prost(uint64, tag = "2")] - pub eth_block_height: u64, - #[prost(bytes = "vec", tag = "3")] - pub invalidation_id: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "4")] - pub invalidation_nonce: u64, - #[prost(string, tag = "5")] - pub orchestrator: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgLogicCallExecutedClaimResponse {} -/// This informs the Cosmos module that a validator -/// set has been updated. -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgValsetUpdatedClaim { - #[prost(uint64, tag = "1")] - pub event_nonce: u64, - #[prost(uint64, tag = "2")] - pub valset_nonce: u64, - #[prost(uint64, tag = "3")] - pub eth_block_height: u64, - #[prost(message, repeated, tag = "4")] - pub members: ::prost::alloc::vec::Vec, - #[prost(string, tag = "5")] - pub reward_amount: ::prost::alloc::string::String, - #[prost(string, tag = "6")] - pub reward_token: ::prost::alloc::string::String, - #[prost(string, tag = "7")] - pub orchestrator: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgValsetUpdatedClaimResponse {} -/// This call allows the sender (and only the sender) -/// to cancel a given MsgSendToEth and recieve a refund -/// of the tokens -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgCancelSendToEth { - #[prost(uint64, tag = "1")] - pub transaction_id: u64, - #[prost(string, tag = "2")] - pub sender: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgCancelSendToEthResponse {} -/// This call allows anyone to submit evidence that a -/// validator has signed a valset, batch, or logic call that never -/// existed on the Cosmos chain. -/// Subject contains the batch, valset, or logic call. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgSubmitBadSignatureEvidence { - #[prost(message, optional, tag = "1")] - pub subject: ::core::option::Option<::prost_types::Any>, - #[prost(string, tag = "2")] - pub signature: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub sender: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct MsgSubmitBadSignatureEvidenceResponse {} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventSetOperatorAddress { - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventValsetConfirmKey { - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub key: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventBatchCreated { - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub batch_nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventBatchConfirmKey { - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub batch_confirm_key: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventBatchSendToEthClaim { - #[prost(string, tag = "1")] - pub nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventClaim { - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub claim_hash: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub attestation_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventBadSignatureEvidence { - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub bad_eth_signature: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub bad_eth_signature_subject: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventErc20DeployedClaim { - #[prost(string, tag = "1")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventValsetUpdatedClaim { - #[prost(string, tag = "1")] - pub nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventMultisigUpdateRequest { - #[prost(string, tag = "1")] - pub bridge_contract: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub bridge_chain_id: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub multisig_id: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventOutgoingLogicCallCanceled { - #[prost(string, tag = "1")] - pub logic_call_invalidation_id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub logic_call_invalidation_nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventSignatureSlashing { - #[prost(string, tag = "1")] - pub r#type: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventOutgoingTxId { - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub tx_id: ::prost::alloc::string::String, -} -/// Generated client implementations. -pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Msg defines the state transitions possible within gravity - #[derive(Debug, Clone)] - pub struct MsgClient { - inner: tonic::client::Grpc, - } - impl MsgClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: std::convert::TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl MsgClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_interceptor(inner: T, interceptor: F) -> MsgClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + Send + Sync, - { - MsgClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with `gzip`. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_gzip(mut self) -> Self { - self.inner = self.inner.send_gzip(); - self - } - /// Enable decompressing responses with `gzip`. - #[must_use] - pub fn accept_gzip(mut self) -> Self { - self.inner = self.inner.accept_gzip(); - self - } - pub async fn valset_confirm( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/ValsetConfirm"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn send_to_eth( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/SendToEth"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn request_batch( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/RequestBatch"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn confirm_batch( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/ConfirmBatch"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn confirm_logic_call( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/ConfirmLogicCall"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn send_to_cosmos_claim( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/SendToCosmosClaim"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn execute_ibc_auto_forwards( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Msg/ExecuteIbcAutoForwards"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn batch_send_to_eth_claim( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/BatchSendToEthClaim"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn valset_update_claim( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/ValsetUpdateClaim"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn erc20_deployed_claim( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/ERC20DeployedClaim"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn logic_call_executed_claim( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Msg/LogicCallExecutedClaim"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn set_orchestrator_address( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Msg/SetOrchestratorAddress"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn cancel_send_to_eth( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Msg/CancelSendToEth"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn submit_bad_signature_evidence( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Msg/SubmitBadSignatureEvidence"); - self.inner.unary(request.into_request(), path, codec).await - } - } -} -/// Attestation is an aggregate of `claims` that eventually becomes `observed` by -/// all orchestrators -/// EVENT_NONCE: -/// EventNonce a nonce provided by the gravity contract that is unique per event fired -/// These event nonces must be relayed in order. This is a correctness issue, -/// if relaying out of order transaction replay attacks become possible -/// OBSERVED: -/// Observed indicates that >67% of validators have attested to the event, -/// and that the event should be executed by the gravity state machine -/// -/// The actual content of the claims is passed in with the transaction making the claim -/// and then passed through the call stack alongside the attestation while it is processed -/// the key in which the attestation is stored is keyed on the exact details of the claim -/// but there is no reason to store those exact details becuause the next message sender -/// will kindly provide you with them. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Attestation { - #[prost(bool, tag = "1")] - pub observed: bool, - #[prost(string, repeated, tag = "2")] - pub votes: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(uint64, tag = "3")] - pub height: u64, - #[prost(message, optional, tag = "4")] - pub claim: ::core::option::Option<::prost_types::Any>, -} -/// ERC20Token unique identifier for an Ethereum ERC20 token. -/// CONTRACT: -/// The contract address on ETH of the token, this could be a Cosmos -/// originated token, if so it will be the ERC20 address of the representation -/// (note: developers should look up the token symbol using the address on ETH to display for UI) -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct Erc20Token { - #[prost(string, tag = "1")] - pub contract: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub amount: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventObservation { - #[prost(string, tag = "1")] - pub attestation_type: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub bridge_contract: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub bridge_chain_id: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub attestation_id: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventInvalidSendToCosmosReceiver { - #[prost(string, tag = "1")] - pub amount: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub nonce: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub sender: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventSendToCosmos { - #[prost(string, tag = "1")] - pub amount: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub nonce: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub token: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventSendToCosmosLocal { - #[prost(string, tag = "1")] - pub nonce: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub receiver: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub amount: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventSendToCosmosPendingIbcAutoForward { - #[prost(string, tag = "1")] - pub nonce: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub receiver: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub amount: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub channel: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventSendToCosmosExecutedIbcAutoForward { - #[prost(string, tag = "1")] - pub nonce: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub receiver: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub amount: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub channel: ::prost::alloc::string::String, - #[prost(string, tag = "6")] - pub timeout_time: ::prost::alloc::string::String, - #[prost(string, tag = "7")] - pub timeout_height: ::prost::alloc::string::String, -} -/// ClaimType is the cosmos type of an event from the counterpart chain that can -/// be handled -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ClaimType { - /// An unspecified claim type - Unspecified = 0, - /// A claim for a SendToCosmos transaction - SendToCosmos = 1, - /// A claim for when batches are relayed - BatchSendToEth = 2, - /// A claim for when an erc20 contract has been deployed - Erc20Deployed = 3, - /// A claim for when a logic call has been executed - LogicCallExecuted = 4, - /// A claim for when a valset update has happened - ValsetUpdated = 5, -} -/// OutgoingTxBatch represents a batch of transactions going from gravity to ETH -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct OutgoingTxBatch { - #[prost(uint64, tag = "1")] - pub batch_nonce: u64, - #[prost(uint64, tag = "2")] - pub batch_timeout: u64, - #[prost(message, repeated, tag = "3")] - pub transactions: ::prost::alloc::vec::Vec, - #[prost(string, tag = "4")] - pub token_contract: ::prost::alloc::string::String, - #[prost(uint64, tag = "5")] - pub cosmos_block_created: u64, -} -/// OutgoingTransferTx represents an individual send from gravity to ETH -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct OutgoingTransferTx { - #[prost(uint64, tag = "1")] - pub id: u64, - #[prost(string, tag = "2")] - pub sender: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub dest_address: ::prost::alloc::string::String, - #[prost(message, optional, tag = "4")] - pub erc20_token: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub erc20_fee: ::core::option::Option, -} -/// OutgoingLogicCall represents an individual logic call from gravity to ETH -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct OutgoingLogicCall { - #[prost(message, repeated, tag = "1")] - pub transfers: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "2")] - pub fees: ::prost::alloc::vec::Vec, - #[prost(string, tag = "3")] - pub logic_contract_address: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "4")] - pub payload: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "5")] - pub timeout: u64, - #[prost(bytes = "vec", tag = "6")] - pub invalidation_id: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "7")] - pub invalidation_nonce: u64, - #[prost(uint64, tag = "8")] - pub cosmos_block_created: u64, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventOutgoingBatchCanceled { - #[prost(string, tag = "1")] - pub bridge_contract: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub bridge_chain_id: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub batch_id: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub nonce: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct EventOutgoingBatch { - #[prost(string, tag = "1")] - pub bridge_contract: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub bridge_chain_id: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub batch_id: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub nonce: ::prost::alloc::string::String, -} -// Params represent the Gravity genesis and store parameters -// gravity_id: -// a random 32 byte value to prevent signature reuse, for example if the -// cosmos validators decided to use the same Ethereum keys for another chain -// also running Gravity we would not want it to be possible to play a deposit -// from chain A back on chain B's Gravity. This value IS USED ON ETHEREUM so -// it must be set in your genesis.json before launch and not changed after -// deploying Gravity - -// contract_hash: -// the code hash of a known good version of the Gravity contract -// solidity code. This can be used to verify the correct version -// of the contract has been deployed. This is a reference value for -// goernance action only it is never read by any Gravity code - -// bridge_ethereum_address: -// is address of the bridge contract on the Ethereum side, this is a -// reference value for governance only and is not actually used by any -// Gravity code - -// bridge_chain_id: -// the unique identifier of the Ethereum chain, this is a reference value -// only and is not actually used by any Gravity code - -// These reference values may be used by future Gravity client implemetnations -// to allow for saftey features or convenience features like the Gravity address -// in your relayer. A relayer would require a configured Gravity address if -// governance had not set the address on the chain it was relaying for. - -// signed_valsets_window -// signed_batches_window -// signed_logiccall_window -// signed_claims_window - -// These values represent the time in blocks that a validator has to submit -// a signature for a batch or valset, or to submit a claim for a particular -// attestation nonce. In the case of attestations this clock starts when the -// attestation is created, but only allows for slashing once the event has passed - -// target_batch_timeout: - -// This is the 'target' value for when batches time out, this is a target becuase -// Ethereum is a probabalistic chain and you can't say for sure what the block -// frequency is ahead of time. - -// average_block_time -// average_ethereum_block_time - -// These values are the average Cosmos block time and Ethereum block time repsectively -// and they are used to compute what the target batch timeout is. It is important that -// governance updates these in case of any major, prolonged change in the time it takes -// to produce a block - -// slash_fraction_valset -// slash_fraction_batch -// slash_fraction_claim -// slash_fraction_conflicting_claim - -/// The slashing fractions for the various gravity related slashing conditions. The first three -/// refer to not submitting a particular message, the third for submitting a different claim -/// for the same Ethereum event -/// -/// unbond_slashing_valsets_window -/// -/// The unbond slashing valsets window is used to determine how many blocks after starting to unbond -/// a validator needs to continue signing blocks. The goal of this paramater is that when a validator leaves -/// the set, if their leaving creates enough change in the validator set to justify an update they will sign -/// a validator set update for the Ethereum bridge that does not include themselves. Allowing us to remove them -/// from the Ethereum bridge and replace them with the new set gracefully. -/// -/// valset_reward -/// -/// These parameters allow for the bridge oracle to resolve a fork on the Ethereum chain without halting -/// the chain. Once set reset bridge state will roll back events to the nonce provided in reset_bridge_nonce -/// if and only if those events have not yet been observed (executed on the Cosmos chain). This allows for easy -/// handling of cases where for example an Ethereum hardfork has occured and more than 1/3 of the vlaidtor set -/// disagrees with the rest. Normally this would require a chain halt, manual genesis editing and restar to resolve -/// with this feature a governance proposal can be used instead -/// -/// bridge_active -/// -/// This boolean flag can be used by governance to temporarily halt the bridge due to a vulnerability or other issue -/// In this context halting the bridge means prevent the execution of any oracle events from Ethereum and preventing -/// the creation of new batches that may be relayed to Ethereum. -/// This does not prevent the creation of validator sets -/// or slashing for not submitting validator set signatures as either of these might allow key signers to leave the validator -/// set and steal funds on Ethereum without consequence. -/// The practical outcome of this flag being set to 'false' is that deposits from Ethereum will not show up and withdraws from -/// Cosmos will not execute on Ethereum. -/// -/// min_chain_fee_basis_points -/// -/// The minimum SendToEth `chain_fee` amount, in terms of basis points. e.g. 10% fee = 1000, and 0.02% fee = 2 -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Params { - #[prost(string, tag = "1")] - pub gravity_id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub contract_source_hash: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub bridge_ethereum_address: ::prost::alloc::string::String, - #[prost(uint64, tag = "5")] - pub bridge_chain_id: u64, - #[prost(uint64, tag = "6")] - pub signed_valsets_window: u64, - #[prost(uint64, tag = "7")] - pub signed_batches_window: u64, - #[prost(uint64, tag = "8")] - pub signed_logic_calls_window: u64, - #[prost(uint64, tag = "9")] - pub target_batch_timeout: u64, - #[prost(uint64, tag = "10")] - pub average_block_time: u64, - #[prost(uint64, tag = "11")] - pub average_ethereum_block_time: u64, - #[prost(bytes = "vec", tag = "12")] - pub slash_fraction_valset: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "13")] - pub slash_fraction_batch: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "14")] - pub slash_fraction_logic_call: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "15")] - pub unbond_slashing_valsets_window: u64, - #[prost(bytes = "vec", tag = "16")] - pub slash_fraction_bad_eth_signature: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "17")] - pub valset_reward: ::core::option::Option, - #[prost(bool, tag = "18")] - pub bridge_active: bool, - /// addresses on this blacklist are forbidden from depositing or withdrawing - /// from Ethereum to the bridge - #[prost(string, repeated, tag = "19")] - pub ethereum_blacklist: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(uint64, tag = "20")] - pub min_chain_fee_basis_points: u64, -} -/// GenesisState struct, containing all persistant data required by the Gravity module -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GenesisState { - #[prost(message, optional, tag = "1")] - pub params: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub gravity_nonces: ::core::option::Option, - #[prost(message, repeated, tag = "3")] - pub valsets: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "4")] - pub valset_confirms: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "5")] - pub batches: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "6")] - pub batch_confirms: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "7")] - pub logic_calls: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "8")] - pub logic_call_confirms: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "9")] - pub attestations: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "10")] - pub delegate_keys: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "11")] - pub erc20_to_denoms: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "12")] - pub unbatched_transfers: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "13")] - pub pending_ibc_auto_forwards: ::prost::alloc::vec::Vec, -} -/// GravityCounters contains the many noces and counters required to maintain the bridge state in the genesis -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct GravityNonces { - /// the nonce of the last generated validator set - #[prost(uint64, tag = "1")] - pub latest_valset_nonce: u64, - /// the last observed Gravity.sol contract event nonce - #[prost(uint64, tag = "2")] - pub last_observed_nonce: u64, - /// the last valset nonce we have slashed, to prevent double slashing - #[prost(uint64, tag = "3")] - pub last_slashed_valset_nonce: u64, - /// the last batch Cosmos chain block that batch slashing has completed for - /// there is an individual batch nonce for each token type so this removes - /// the need to store them all - #[prost(uint64, tag = "4")] - pub last_slashed_batch_block: u64, - /// the last cosmos block that logic call slashing has completed for - #[prost(uint64, tag = "5")] - pub last_slashed_logic_call_block: u64, - /// the last transaction id from the Gravity TX pool, this prevents ID - /// duplication during chain upgrades - #[prost(uint64, tag = "6")] - pub last_tx_pool_id: u64, - /// the last batch id from the Gravity batch pool, this prevents ID duplication - /// during chain upgrades - #[prost(uint64, tag = "7")] - pub last_batch_id: u64, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryParamsRequest {} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryParamsResponse { - #[prost(message, optional, tag = "1")] - pub params: ::core::option::Option, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryCurrentValsetRequest {} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryCurrentValsetResponse { - #[prost(message, optional, tag = "1")] - pub valset: ::core::option::Option, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryValsetRequestRequest { - #[prost(uint64, tag = "1")] - pub nonce: u64, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryValsetRequestResponse { - #[prost(message, optional, tag = "1")] - pub valset: ::core::option::Option, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryValsetConfirmRequest { - #[prost(uint64, tag = "1")] - pub nonce: u64, - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryValsetConfirmResponse { - #[prost(message, optional, tag = "1")] - pub confirm: ::core::option::Option, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryValsetConfirmsByNonceRequest { - #[prost(uint64, tag = "1")] - pub nonce: u64, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryValsetConfirmsByNonceResponse { - #[prost(message, repeated, tag = "1")] - pub confirms: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastValsetRequestsRequest {} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastValsetRequestsResponse { - #[prost(message, repeated, tag = "1")] - pub valsets: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastPendingValsetRequestByAddrRequest { - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastPendingValsetRequestByAddrResponse { - #[prost(message, repeated, tag = "1")] - pub valsets: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryBatchFeeRequest {} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryBatchFeeResponse { - #[prost(message, repeated, tag = "1")] - pub batch_fees: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastPendingBatchRequestByAddrRequest { - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastPendingBatchRequestByAddrResponse { - #[prost(message, repeated, tag = "1")] - pub batch: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastPendingLogicCallByAddrRequest { - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastPendingLogicCallByAddrResponse { - #[prost(message, repeated, tag = "1")] - pub call: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryOutgoingTxBatchesRequest {} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryOutgoingTxBatchesResponse { - #[prost(message, repeated, tag = "1")] - pub batches: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryOutgoingLogicCallsRequest {} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryOutgoingLogicCallsResponse { - #[prost(message, repeated, tag = "1")] - pub calls: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryBatchRequestByNonceRequest { - #[prost(uint64, tag = "1")] - pub nonce: u64, - #[prost(string, tag = "2")] - pub contract_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryBatchRequestByNonceResponse { - #[prost(message, optional, tag = "1")] - pub batch: ::core::option::Option, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryBatchConfirmsRequest { - #[prost(uint64, tag = "1")] - pub nonce: u64, - #[prost(string, tag = "2")] - pub contract_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryBatchConfirmsResponse { - #[prost(message, repeated, tag = "1")] - pub confirms: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLogicConfirmsRequest { - #[prost(bytes = "vec", tag = "1")] - pub invalidation_id: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "2")] - pub invalidation_nonce: u64, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLogicConfirmsResponse { - #[prost(message, repeated, tag = "1")] - pub confirms: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastEventNonceByAddrRequest { - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastEventNonceByAddrResponse { - #[prost(uint64, tag = "1")] - pub event_nonce: u64, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryErc20ToDenomRequest { - #[prost(string, tag = "1")] - pub erc20: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryErc20ToDenomResponse { - #[prost(string, tag = "1")] - pub denom: ::prost::alloc::string::String, - #[prost(bool, tag = "2")] - pub cosmos_originated: bool, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDenomToErc20Request { - #[prost(string, tag = "1")] - pub denom: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDenomToErc20Response { - #[prost(string, tag = "1")] - pub erc20: ::prost::alloc::string::String, - #[prost(bool, tag = "2")] - pub cosmos_originated: bool, -} -/// QueryLastObservedEthBlockRequest defines the request for getting the height of the -/// last applied Ethereum Event on the bridge. This is expected to lag the actual -/// Ethereum block height significantly due to 1. Ethereum Finality and -/// 2. Consensus mirroring the state on Ethereum -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastObservedEthBlockRequest { - /// indicates whether to search for store data using the old Gravity v1 key "LastObservedEthereumBlockHeightKey" - /// Note that queries before the Mercury upgrade at height 1282013 must set this to true - #[prost(bool, tag = "1")] - pub use_v1_key: bool, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastObservedEthBlockResponse { - /// a response of 0 indicates that no Ethereum events have been observed, and thus - /// the bridge is inactive - #[prost(uint64, tag = "1")] - pub block: u64, -} -/// QueryLastObservedEthNonceRequest defines the request for getting the event nonce -/// of the last applied Ethereum Event on the bridge. -/// Note that this is likely to lag the last executed event a little -/// due to 1. Ethereum Finality and 2. Consensus mirroring the Ethereum state -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastObservedEthNonceRequest { - /// indicates whether to search for store data using the old Gravity v1 key "LastObservedEventNonceKey" - /// Note that queries before the Mercury upgrade at height 1282013 must set this to true - #[prost(bool, tag = "1")] - pub use_v1_key: bool, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryLastObservedEthNonceResponse { - /// a response of 0 indicates that no Ethereum events have been observed, and thus - /// the bridge is inactive - #[prost(uint64, tag = "1")] - pub nonce: u64, -} -/// QueryAttestationsRequest defines the request structure for getting recent -/// attestations with optional query parameters. By default, a limited set of -/// recent attestations will be returned, defined by 'limit'. These attestations -/// can be ordered ascending or descending by nonce, that defaults to ascending. -/// Filtering criteria may also be provided, including nonce, claim type, and -/// height. Note, that an attestation will be returned if it matches ANY of the -/// filter query parameters provided. -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryAttestationsRequest { - /// limit defines how many attestations to limit in the response. - #[prost(uint64, tag = "1")] - pub limit: u64, - /// order_by provides ordering of atteststions by nonce in the response. Either - /// 'asc' or 'desc' can be provided. If no value is provided, it defaults to - /// 'asc'. - #[prost(string, tag = "2")] - pub order_by: ::prost::alloc::string::String, - /// claim_type allows filtering attestations by Ethereum claim type. - #[prost(string, tag = "3")] - pub claim_type: ::prost::alloc::string::String, - /// nonce allows filtering attestations by Ethereum claim nonce. - #[prost(uint64, tag = "4")] - pub nonce: u64, - /// height allows filtering attestations by Ethereum claim height. - #[prost(uint64, tag = "5")] - pub height: u64, - /// indicates whether to search for store data using the old Gravity v1 key "OracleAttestationKey" - /// Note that queries before the Mercury upgrade at height 1282013 must set this to true - #[prost(bool, tag = "6")] - pub use_v1_key: bool, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryAttestationsResponse { - #[prost(message, repeated, tag = "1")] - pub attestations: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDelegateKeysByValidatorAddress { - #[prost(string, tag = "1")] - pub validator_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDelegateKeysByValidatorAddressResponse { - #[prost(string, tag = "1")] - pub eth_address: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub orchestrator_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDelegateKeysByEthAddress { - #[prost(string, tag = "1")] - pub eth_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDelegateKeysByEthAddressResponse { - #[prost(string, tag = "1")] - pub validator_address: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub orchestrator_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDelegateKeysByOrchestratorAddress { - #[prost(string, tag = "1")] - pub orchestrator_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryDelegateKeysByOrchestratorAddressResponse { - #[prost(string, tag = "1")] - pub validator_address: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub eth_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryPendingSendToEth { - #[prost(string, tag = "1")] - pub sender_address: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryPendingSendToEthResponse { - #[prost(message, repeated, tag = "1")] - pub transfers_in_batches: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "2")] - pub unbatched_transfers: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, Eq, ::prost::Message)] -pub struct QueryPendingIbcAutoForwards { - /// limit defines the number of pending forwards to return, in order of their SendToCosmos.EventNonce - #[prost(uint64, tag = "1")] - pub limit: u64, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryPendingIbcAutoForwardsResponse { - #[prost(message, repeated, tag = "1")] - pub pending_ibc_auto_forwards: ::prost::alloc::vec::Vec, -} -/// Generated client implementations. -pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Query defines the gRPC querier service - #[derive(Debug, Clone)] - pub struct QueryClient { - inner: tonic::client::Grpc, - } - impl QueryClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: std::convert::TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl QueryClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> QueryClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + Send + Sync, - { - QueryClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with `gzip`. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_gzip(mut self) -> Self { - self.inner = self.inner.send_gzip(); - self - } - /// Enable decompressing responses with `gzip`. - #[must_use] - pub fn accept_gzip(mut self) -> Self { - self.inner = self.inner.accept_gzip(); - self - } - /// Deployments queries deployments - pub async fn params( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/Params"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn current_valset( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/CurrentValset"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn valset_request( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/ValsetRequest"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn valset_confirm( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/ValsetConfirm"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn valset_confirms_by_nonce( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/ValsetConfirmsByNonce"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn last_valset_requests( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/LastValsetRequests"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn last_pending_valset_request_by_addr( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/gravity.v1.Query/LastPendingValsetRequestByAddr", - ); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn last_pending_batch_request_by_addr( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/gravity.v1.Query/LastPendingBatchRequestByAddr", - ); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn last_pending_logic_call_by_addr( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/gravity.v1.Query/LastPendingLogicCallByAddr", - ); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn last_event_nonce_by_addr( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/LastEventNonceByAddr"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn batch_fees( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/BatchFees"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn outgoing_tx_batches( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/OutgoingTxBatches"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn outgoing_logic_calls( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/OutgoingLogicCalls"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn batch_request_by_nonce( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/BatchRequestByNonce"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn batch_confirms( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/BatchConfirms"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn logic_confirms( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/LogicConfirms"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn erc20_to_denom( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/ERC20ToDenom"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn denom_to_erc20( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/DenomToERC20"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_last_observed_eth_block( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/GetLastObservedEthBlock"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_last_observed_eth_nonce( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/GetLastObservedEthNonce"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_attestations( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/gravity.v1.Query/GetAttestations"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_delegate_key_by_validator( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/GetDelegateKeyByValidator"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_delegate_key_by_eth( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/GetDelegateKeyByEth"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_delegate_key_by_orchestrator( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/gravity.v1.Query/GetDelegateKeyByOrchestrator", - ); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_pending_send_to_eth( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/GetPendingSendToEth"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_pending_ibc_auto_forwards( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/gravity.v1.Query/GetPendingIbcAutoForwards"); - self.inner.unary(request.into_request(), path, codec).await - } - } -} -/// SignType defines messages that have been signed by an orchestrator -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum SignType { - /// An unspecified type - Unspecified = 0, - /// A type for multi-sig updates - OrchestratorSignedMultiSigUpdate = 1, - /// A type for batches - OrchestratorSignedWithdrawBatch = 2, -} diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 5d71efdd0..fbebbb52f 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -gravity_proto = {path = "../gravity_proto/"} +gravity_proto = {workspace = true} deep_space = {workspace = true} web30 = {workspace = true} diff --git a/orchestrator/orchestrator/Cargo.toml b/orchestrator/orchestrator/Cargo.toml index f3ffc2560..9e0984cb2 100644 --- a/orchestrator/orchestrator/Cargo.toml +++ b/orchestrator/orchestrator/Cargo.toml @@ -14,7 +14,7 @@ relayer = {path = "../relayer/"} ethereum_gravity = {path = "../ethereum_gravity"} cosmos_gravity = {path = "../cosmos_gravity"} gravity_utils = {path = "../gravity_utils"} -gravity_proto = {path = "../gravity_proto/"} +gravity_proto = {workspace = true} metrics_exporter = {path = "../metrics_exporter/"} deep_space = {workspace = true} diff --git a/orchestrator/proto_build/Cargo.toml b/orchestrator/proto_build/Cargo.toml deleted file mode 100644 index 7908cd30b..000000000 --- a/orchestrator/proto_build/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "proto_build" -version = "0.1.0" -authors = ["Justin Kilpatrick "] -edition = "2018" - - -[dependencies] -prost = {workspace = true} -tonic = {workspace = true} -prost-build = "0.10" -walkdir = "2" -tonic-build = "0.7" -regex = "1.5" diff --git a/orchestrator/proto_build/src/main.rs b/orchestrator/proto_build/src/main.rs deleted file mode 100644 index a5cff18a8..000000000 --- a/orchestrator/proto_build/src/main.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Protobuf files in the gravity repo, copying the result to the gravity_proto crate for import -//! and use. While this builder generates about a dozen files only one contains all the gravity -//! proto info and the rest are discarded in favor of upstream cosmos-sdk-proto - -// Building new Gravity rust proto definitions -// run 'cargo run' -// go to gravity_proto/prost -// delete all files except gravity.v1.rs -// re-write calls to super::super::cosmos as cosmos-sdk-proto::cosmos - -use regex::Regex; -use std::{ - ffi::OsStr, - fs::{self, create_dir_all, remove_dir_all}, - path::PathBuf, -}; -use std::{io, path::Path}; -use walkdir::WalkDir; - -/// Protos belonging to these Protobuf packages will be excluded -/// (i.e. because they are sourced from `tendermint-proto` or `cosmos-sdk-proto`) -const EXCLUDED_PROTO_PACKAGES: &[&str] = &[ - "gogoproto", - "google", - "tendermint", - "cosmos.base", - "cosmos_proto", -]; -/// Attribute preceeding a Tonic client definition -const TONIC_CLIENT_ATTRIBUTE: &str = "#[doc = r\" Generated client implementations.\"]"; -/// Attributes to add to gRPC clients -const GRPC_CLIENT_ATTRIBUTES: &[&str] = &[ - "#[cfg(feature = \"grpc\")]", - "#[cfg_attr(docsrs, doc(cfg(feature = \"grpc\")))]", - TONIC_CLIENT_ATTRIBUTE, -]; -/// Regex for locating instances of `cosmos-sdk-proto` in prost/tonic build output -const COSMOS_SDK_PROTO_REGEX: &str = "(super::)+cosmos"; - -/// A temporary directory for proto building -const TMP_PATH: &str = "/tmp/gravity/"; -/// the output directory -const OUT_PATH: &str = "../gravity_proto/src/prost/"; - -// All paths must end with a / and either be absolute or include a ./ to reference the current -// working directory. - -fn main() { - let out_path = Path::new(&OUT_PATH); - let tmp_path = Path::new(&TMP_PATH); - compile_protos(out_path, tmp_path); -} - -fn compile_protos(out_dir: &Path, tmp_dir: &Path) { - println!( - "[info] Compiling .proto files to Rust into '{}'...", - out_dir.display() - ); - - let root = env!("CARGO_MANIFEST_DIR"); - let root: PathBuf = root.parse().unwrap(); - // this gives us the repo root by going up two levels from the module root - let root = root.parent().unwrap().parent().unwrap().to_path_buf(); - - let mut gravity_proto_dir = root.clone(); - gravity_proto_dir.push("module/proto/gravity/v1"); - let mut gravity_proto_include_dir = root.clone(); - gravity_proto_include_dir.push("module/proto"); - let mut third_party_proto_include_dir = root; - third_party_proto_include_dir.push("module/third_party/proto"); - - // Paths - let proto_paths = [gravity_proto_dir]; - // we need to have an include which is just the folder of our protos to satisfy protoc - // which insists that any passed file be included in a directory passed as an include - let proto_include_paths = [gravity_proto_include_dir, third_party_proto_include_dir]; - - // List available proto files - let mut protos: Vec = vec![]; - for proto_path in &proto_paths { - protos.append( - &mut WalkDir::new(proto_path) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| { - e.file_type().is_file() - && e.path().extension().is_some() - && e.path().extension().unwrap() == "proto" - }) - .map(|e| e.into_path()) - .collect(), - ); - } - - // create directories for temporary build dirs - fs::create_dir_all(tmp_dir) - .unwrap_or_else(|_| panic!("Failed to create {:?}", tmp_dir.to_str())); - - // Compile all proto files - let mut config = prost_build::Config::default(); - config.out_dir(tmp_dir); - config - .compile_protos(&protos, &proto_include_paths) - .unwrap(); - - // Compile all proto client for GRPC services - println!("[info ] Compiling proto clients for GRPC services!"); - tonic_build::configure() - .build_client(true) - .build_server(false) - .out_dir(tmp_dir) - .compile(&protos, &proto_include_paths) - .unwrap(); - - copy_generated_files(tmp_dir, out_dir); - - println!("[info ] => Done!"); -} - -fn copy_generated_files(from_dir: &Path, to_dir: &Path) { - println!("Copying generated files into '{}'...", to_dir.display()); - - // Remove old compiled files - remove_dir_all(to_dir).unwrap_or_default(); - create_dir_all(to_dir).unwrap(); - - let mut filenames = Vec::new(); - - // Copy new compiled files (prost does not use folder structures) - let errors = WalkDir::new(from_dir) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().is_file()) - .map(|e| { - let filename = e.file_name().to_os_string().to_str().unwrap().to_string(); - filenames.push(filename.clone()); - copy_and_patch(e.path(), format!("{}/{}", to_dir.display(), &filename)) - }) - .filter_map(|e| e.err()) - .collect::>(); - - if !errors.is_empty() { - for e in errors { - eprintln!("[error] Error while copying compiled file: {}", e); - } - - panic!("[error] Aborted."); - } -} - -fn copy_and_patch(src: impl AsRef, dest: impl AsRef) -> io::Result<()> { - // Skip proto files belonging to `EXCLUDED_PROTO_PACKAGES` - for package in EXCLUDED_PROTO_PACKAGES { - if let Some(filename) = src.as_ref().file_name().and_then(OsStr::to_str) { - if filename.starts_with(&format!("{}.", package)) { - return Ok(()); - } - } - } - - let contents = fs::read_to_string(src)?; - - // `prost-build` output references types from `tendermint-proto` crate - // relative paths, which we need to munge into `tendermint_proto` in - // order to leverage types from the upstream crate. - let contents = Regex::new(COSMOS_SDK_PROTO_REGEX) - .unwrap() - .replace_all(&contents, "cosmos_sdk_proto::cosmos"); - - // Patch each service definition with a feature attribute - let patched_contents = - contents.replace(TONIC_CLIENT_ATTRIBUTE, &GRPC_CLIENT_ATTRIBUTES.join("\n")); - - fs::write(dest, patched_contents) -} diff --git a/orchestrator/relayer/Cargo.toml b/orchestrator/relayer/Cargo.toml index 2189e236f..b8f03bdc4 100644 --- a/orchestrator/relayer/Cargo.toml +++ b/orchestrator/relayer/Cargo.toml @@ -12,7 +12,7 @@ path = "src/lib.rs" ethereum_gravity = {path = "../ethereum_gravity"} cosmos_gravity = {path = "../cosmos_gravity"} gravity_utils = {path = "../gravity_utils"} -gravity_proto = {path = "../gravity_proto/"} +gravity_proto = {workspace = true} deep_space = {workspace = true} serde_derive = "1.0" diff --git a/orchestrator/test_runner/Cargo.toml b/orchestrator/test_runner/Cargo.toml index b812b34a0..ad52129c6 100644 --- a/orchestrator/test_runner/Cargo.toml +++ b/orchestrator/test_runner/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" ethereum_gravity = {path = "../ethereum_gravity"} cosmos_gravity = {path = "../cosmos_gravity"} gravity_utils = {path = "../gravity_utils"} -gravity_proto = {path = "../gravity_proto/"} +gravity_proto = {workspace = true} orchestrator = {path = "../orchestrator/"} bytes = "1" From 5c1730a95196eda2fdfeacc10e2290d910d3607f Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 9 Jun 2023 17:55:21 -0400 Subject: [PATCH 03/11] Skip verifying go modules when testing --- module/Makefile | 7 ++++++- tests/container-scripts/reload-code.sh | 3 +-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/module/Makefile b/module/Makefile index d1c1c46b0..a3bd72617 100644 --- a/module/Makefile +++ b/module/Makefile @@ -53,12 +53,17 @@ BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)' -gcflags="all=-N -l" all: install -install: go.sum +# First run `go mod verify` then `go install` +install: go.sum install-no-verify + +# Runs go install without verifying dependencies, used to make testing faster +install-no-verify: export GOFLAGS='-buildmode=pie' export CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2" export CGO_LDFLAGS="-Wl,-z,relro,-z,now -fstack-protector" go install $(BUILD_FLAGS) ./cmd/gravity +# Verifies the go modules go.sum: go.mod @echo "--> Ensure dependencies have not been modified" GO111MODULE=on go mod verify diff --git a/tests/container-scripts/reload-code.sh b/tests/container-scripts/reload-code.sh index ce9957a01..aa9463c74 100755 --- a/tests/container-scripts/reload-code.sh +++ b/tests/container-scripts/reload-code.sh @@ -19,8 +19,7 @@ done pushd /gravity/module/ export PATH=$PATH:/usr/local/go/bin -make -make install +make install-no-verify popd pushd /gravity/ tests/container-scripts/setup-validators.sh $NODES From 97f03cc4167a80c159127a8c5018e4b9195fe186 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 9 Jun 2023 17:56:31 -0400 Subject: [PATCH 04/11] Update rust proto crates --- orchestrator/Cargo.lock | 8 ++++---- orchestrator/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index dfea7edeb..019dcdd61 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -736,9 +736,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cosmos-sdk-proto-althea" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98eeb7a45d67fa29a15341608585bae1b3b76ca0438e2739a6ea87467eaeab58" +checksum = "6946d8fbccfd3e1e9968d2698e34a4625009bade454c64932caadfe89cb6106c" dependencies = [ "prost 0.10.4", "prost-types 0.10.1", @@ -1388,9 +1388,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gravity_proto" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a817efef97ba2f5a12ff58d3d9ef6857a1d5c45f85ebc4d6d4fff2069066062" +checksum = "3b33e9fa67a16c988cb9c4cbfc0284786d8c1e37db48d638b5445d758f3de818" dependencies = [ "cosmos-sdk-proto-althea", "prost 0.10.4", diff --git a/orchestrator/Cargo.toml b/orchestrator/Cargo.toml index 083bc3791..65b621951 100644 --- a/orchestrator/Cargo.toml +++ b/orchestrator/Cargo.toml @@ -3,7 +3,7 @@ members = ["orchestrator", "cosmos_gravity", "ethereum_gravity", "gravity_utils" default-members = ["gbt"] [workspace.dependencies] -gravity_proto = "0.2.1" +gravity_proto = "0.2.2" num256 = "0.5" clarity = "0.7" web30 = "0.23" From a02352bd45ceff069d7156d4f10f735ad6a8f2fe Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 9 Jun 2023 17:57:47 -0400 Subject: [PATCH 05/11] Add ICA Host module --- module/app/app.go | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/module/app/app.go b/module/app/app.go index 7985593b3..bf377bc80 100644 --- a/module/app/app.go +++ b/module/app/app.go @@ -87,6 +87,11 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" // Cosmos IBC-Go + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" + icahost "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" transfer "github.com/cosmos/ibc-go/v4/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" @@ -155,6 +160,7 @@ var ( vesting.AppModuleBasic{}, gravity.AppModuleBasic{}, bech32ibc.AppModuleBasic{}, + ica.AppModuleBasic{}, ) // module account permissions @@ -168,6 +174,7 @@ var ( govtypes.ModuleName: {authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, gravitytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + icatypes.ModuleName: nil, } // module accounts that are allowed to receive tokens @@ -228,11 +235,13 @@ type Gravity struct { ibcTransferKeeper *ibctransferkeeper.Keeper gravityKeeper *keeper.Keeper bech32IbcKeeper *bech32ibckeeper.Keeper + icaHostKeeper *icahostkeeper.Keeper // make scoped keepers public for test purposes // NOTE: If you add anything to this struct, add a nil check to ValidateMembers below! ScopedIBCKeeper *capabilitykeeper.ScopedKeeper ScopedTransferKeeper *capabilitykeeper.ScopedKeeper + ScopedIcaHostKeeper *capabilitykeeper.ScopedKeeper // Module Manager mm *module.Manager @@ -302,6 +311,9 @@ func (app Gravity) ValidateMembers() { if app.bech32IbcKeeper == nil { panic("Nil bech32IbcKeeper!") } + if app.icaHostKeeper == nil { + panic("Nil icaHostKeeper!") + } // scoped keepers if app.ScopedIBCKeeper == nil { @@ -350,6 +362,7 @@ func NewGravityApp( ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, gravitytypes.StoreKey, bech32ibctypes.StoreKey, + icahosttypes.StoreKey, ) tKeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -384,6 +397,9 @@ func NewGravityApp( scopedTransferKeeper := capabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) app.ScopedTransferKeeper = &scopedTransferKeeper + scopedIcaHostKeeper := capabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) + app.ScopedIcaHostKeeper = &scopedIcaHostKeeper + // Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating // their scoped modules in `NewApp` with `ScopeToModule` capabilityKeeper.Seal() @@ -474,6 +490,13 @@ func NewGravityApp( ) app.bech32IbcKeeper = &bech32IbcKeeper + icaHostKeeper := icahostkeeper.NewKeeper( + appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), + ibcKeeper.ChannelKeeper, &ibcKeeper.PortKeeper, + accountKeeper, scopedIcaHostKeeper, app.MsgServiceRouter(), + ) + app.icaHostKeeper = &icaHostKeeper + gravityKeeper := keeper.NewKeeper( keys[gravitytypes.StoreKey], app.GetSubspace(gravitytypes.ModuleName), @@ -538,9 +561,12 @@ func NewGravityApp( ibcTransferAppModule := transfer.NewAppModule(ibcTransferKeeper) ibcTransferIBCModule := transfer.NewIBCModule(ibcTransferKeeper) + icaAppModule := ica.NewAppModule(nil, &icaHostKeeper) + icaHostIBCModule := icahost.NewIBCModule(icaHostKeeper) ibcRouter := porttypes.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, ibcTransferIBCModule) + ibcRouter.AddRoute(ibctransfertypes.ModuleName, ibcTransferIBCModule). + AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) ibcKeeper.SetRouter(ibcRouter) evidenceKeeper := *evidencekeeper.NewKeeper( @@ -634,6 +660,7 @@ func NewGravityApp( appCodec, bech32IbcKeeper, ), + icaAppModule, ) app.mm = &mm @@ -658,11 +685,13 @@ func NewGravityApp( authz.ModuleName, govtypes.ModuleName, paramstypes.ModuleName, + icatypes.ModuleName, ) mm.SetOrderEndBlockers( crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName, + icatypes.ModuleName, gravitytypes.ModuleName, upgradetypes.ModuleName, capabilitytypes.ModuleName, @@ -700,6 +729,7 @@ func NewGravityApp( crisistypes.ModuleName, vestingtypes.ModuleName, paramstypes.ModuleName, + icatypes.ModuleName, ) mm.RegisterInvariants(&crisisKeeper) @@ -949,6 +979,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(gravitytypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) + paramsKeeper.Subspace(icahosttypes.SubModuleName) return paramsKeeper } From 8192dec1ef9b9b86fdcb144099ace382352893ba Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 9 Jun 2023 18:01:49 -0400 Subject: [PATCH 06/11] Test env Hermes to v1.5.1, gaiad -> althea-net/ibc-test-chain --- orchestrator/test_runner/src/bootstrapping.rs | 14 +++++++++----- tests/assets/ibc-relayer-config.toml | 14 +++++++------- tests/dockerfile/Dockerfile | 6 +++--- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/orchestrator/test_runner/src/bootstrapping.rs b/orchestrator/test_runner/src/bootstrapping.rs index b1b3d2e4e..3837aed2a 100644 --- a/orchestrator/test_runner/src/bootstrapping.rs +++ b/orchestrator/test_runner/src/bootstrapping.rs @@ -310,12 +310,16 @@ pub fn create_ibc_channel(hermes_base: &mut Command) { let create_channel = hermes_base.args([ "create", "channel", + "--a-chain", &get_gravity_chain_id(), + "--b-chain", &get_ibc_chain_id(), - "--port-a", + "--a-port", "transfer", - "--port-b", + "--b-port", "transfer", + "--new-client-connection", + "--yes", ]); let out_file = File::options() @@ -339,7 +343,7 @@ pub fn create_ibc_channel(hermes_base: &mut Command) { pub fn run_ibc_relayer(hermes_base: &mut Command, full_scan: bool) { let mut start = hermes_base.arg("start"); if full_scan { - start = start.arg("-f"); + start = start.arg("--full-scan"); } let out_file = File::options() .write(true) @@ -370,12 +374,12 @@ pub async fn start_ibc_relayer(contact: &Contact, keys: &[ValidatorKeys], ibc_ph .unwrap(); info!("test-runner starting IBC relayer mode: init hermes, create ibc channel, start hermes"); let mut hermes_base = Command::new("hermes"); - let hermes_base = hermes_base.arg("-c").arg(HERMES_CONFIG); + let hermes_base = hermes_base.arg("--config").arg(HERMES_CONFIG); setup_relayer_keys(&RELAYER_MNEMONIC, &ibc_phrases[0]).unwrap(); create_ibc_channel(hermes_base); thread::spawn(|| { let mut hermes_base = Command::new("hermes"); - let hermes_base = hermes_base.arg("-c").arg(HERMES_CONFIG); + let hermes_base = hermes_base.arg("--config").arg(HERMES_CONFIG); run_ibc_relayer(hermes_base, true); // likely will not return from here, just keep running }); info!("Running ibc relayer in the background, directing output to /ibc-relayer-logs"); diff --git a/tests/assets/ibc-relayer-config.toml b/tests/assets/ibc-relayer-config.toml index 4a7ea4803..fccf6a37b 100644 --- a/tests/assets/ibc-relayer-config.toml +++ b/tests/assets/ibc-relayer-config.toml @@ -2,7 +2,7 @@ [global] # Specify the verbosity for the relayer logging output. Default: 'info' # Valid options are 'error', 'warn', 'info', 'debug', 'trace'. -log_level = 'debug' +log_level = 'info' # Specify the mode to be used by the relayer. [Required] @@ -22,12 +22,12 @@ misbehaviour = false # Specify the connections mode. [mode.connections] # Whether or not to enable the connection workers for handshake completion. [Required] -enabled = false +enabled = true # Specify the channels mode. [mode.channels] # Whether or not to enable the channel workers for handshake completion. [Required] -enabled = false +enabled = true # Specify the packets mode. [mode.packets] @@ -116,9 +116,9 @@ max_gas = 4000000 # the denomination of the fee. Required gas_price = { price = 0.000, denom = 'stake' } # Specify the ratio by which to increase the gas estimate used to compute the fee, -# to account for potential estimation error. Default: 0.1, ie. 10%. -# Valid range: 0.0 to 1.0 (inclusive) -gas_adjustment = 1.0 +# to account for potential estimation error. Default: 1.1, ie. 10%. +# Valid range: 0.0+ +gas_multiplier = 2.0 # Specify how many IBC messages at most to include in a single transaction. # Default: 30 max_msg_num = 30 @@ -183,7 +183,7 @@ store_prefix = 'ibc' default_gas = 100000 max_gas = 4000000 gas_price = { price = 0.000, denom = 'stake' } -gas_adjustment = 0.1 +gas_multiplier = 1.1 max_msg_num = 30 max_tx_size = 2097152 clock_drift = '5s' diff --git a/tests/dockerfile/Dockerfile b/tests/dockerfile/Dockerfile index ac7de3ea4..c95b9801f 100644 --- a/tests/dockerfile/Dockerfile +++ b/tests/dockerfile/Dockerfile @@ -6,11 +6,11 @@ RUN dnf install -y git make gcc gcc-c++ which iproute iputils procps-ng vim-mini RUN npm install -g ts-node && npm install -g typescript ADD https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.10.10-bb74230f.tar.gz /geth/ RUN cd /geth && tar -xvf * && mv /geth/**/geth /usr/bin/geth -# Download gaia as a IBC test chain +# Download the althea gaia fork as a IBC test chain ADD https://github.com/althea-net/ibc-test-chain/releases/download/v9.1.2/gaiad-v9.1.2-linux-amd64 /usr/bin/gaiad # Setup Hermes for IBC connections between chains -ADD https://github.com/informalsystems/ibc-rs/releases/download/v0.13.0/hermes-v0.13.0-x86_64-unknown-linux-gnu.tar.gz /tmp/ -RUN cd /tmp/ && tar -xvf hermes-v0.13.0-x86_64-unknown-linux-gnu.tar.gz && mv hermes /usr/bin/ +ADD https://github.com/informalsystems/ibc-rs/releases/download/v1.5.1/hermes-v1.5.1-x86_64-unknown-linux-gnu.tar.gz /tmp/ +RUN cd /tmp/ && tar -xvf hermes-v1.5.1-x86_64-unknown-linux-gnu.tar.gz && mv hermes /usr/bin/ RUN mkdir /ibc-relayer-logs && touch /ibc-relayer-logs/hermes-logs && touch /ibc-relayer-logs/channel-creation # the actual source code for this repo, this **only** includes checked in files! # this is a bit of a pain but it does speed things up a lot From 8518c0c3c3a241899d97efc42b13762083ca9426 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 9 Jun 2023 18:02:29 -0400 Subject: [PATCH 07/11] Add ICA Host happy path test This test will register an interchain account, fund it, and then submit a MsgSendToEth via althea-net/ibc-test-chain --- .github/workflows/integration-tests.yml | 14 + .../test_runner/src/airdrop_proposal.rs | 4 +- orchestrator/test_runner/src/bootstrapping.rs | 79 ++- .../test_runner/src/ibc_auto_forward.rs | 19 +- orchestrator/test_runner/src/ibc_metadata.rs | 4 +- orchestrator/test_runner/src/ica_host.rs | 563 ++++++++++++++++++ orchestrator/test_runner/src/main.rs | 122 ++-- .../test_runner/src/send_to_eth_fees.rs | 2 +- orchestrator/test_runner/src/unhalt_bridge.rs | 2 +- orchestrator/test_runner/src/utils.rs | 4 +- 10 files changed, 745 insertions(+), 68 deletions(-) create mode 100644 orchestrator/test_runner/src/ica_host.rs diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index ceaf945d2..fbd89fd85 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -402,3 +402,17 @@ jobs: run: tests/all-up-test.sh SEND_TO_ETH_FEES env: NO_IMAGE_BUILD: True + ica_host_happy_path: + runs-on: ubuntu-latest + needs: happy-path-geth + steps: + - uses: actions/checkout@v2 + - uses: jpribyl/action-docker-layer-caching@v0.1.1 + with: + key: integration-test-cache-{hash} + restore-keys: | + integration-test-cache- + - name: Test the Interchain Accounts Host module functionality with Gravity + run: tests/all-up-test.sh ICA_HOST_HAPPY_PATH + env: + NO_IMAGE_BUILD: True \ No newline at end of file diff --git a/orchestrator/test_runner/src/airdrop_proposal.rs b/orchestrator/test_runner/src/airdrop_proposal.rs index 29e170a27..98fdce69c 100644 --- a/orchestrator/test_runner/src/airdrop_proposal.rs +++ b/orchestrator/test_runner/src/airdrop_proposal.rs @@ -87,7 +87,7 @@ async fn submit_and_pass_airdrop_proposal( let res = submit_airdrop_proposal( proposal_content, - get_deposit(), + get_deposit(None), get_fee(None), contact, keys[0].validator_key, @@ -219,7 +219,7 @@ async fn submit_and_fail_airdrop_proposal( let res = contact .create_gov_proposal( any, - get_deposit(), + get_deposit(None), get_fee(None), keys[0].validator_key, Some(TOTAL_TIMEOUT), diff --git a/orchestrator/test_runner/src/bootstrapping.rs b/orchestrator/test_runner/src/bootstrapping.rs index 3837aed2a..c975938bc 100644 --- a/orchestrator/test_runner/src/bootstrapping.rs +++ b/orchestrator/test_runner/src/bootstrapping.rs @@ -1,11 +1,16 @@ use core::str::FromStr; use std::thread; +use std::time::Duration; use crate::get_deposit; +use crate::ibc_auto_forward::get_channel; +use crate::COSMOS_NODE_GRPC; +use crate::GRAVITY_RELAYER_ADDRESS; use crate::HERMES_CONFIG; +use crate::IBC_RELAYER_ADDRESS; +use crate::IBC_STAKING_TOKEN; use crate::MINER_PRIVATE_KEY; use crate::OPERATION_TIMEOUT; -use crate::RELAYER_ADDRESS; use crate::RELAYER_MNEMONIC; use crate::TOTAL_TIMEOUT; use crate::{get_gravity_chain_id, get_ibc_chain_id, ETH_NODE}; @@ -14,6 +19,7 @@ use clarity::Address as EthAddress; use clarity::PrivateKey as EthPrivateKey; use deep_space::private_key::{CosmosPrivateKey, PrivateKey, DEFAULT_COSMOS_HD_PATH}; use deep_space::Contact; +use gravity_proto::cosmos_sdk_proto::ibc::core::channel::v1::query_client::QueryClient as IbcChannelQueryClient; use ibc::core::ics24_host::identifier::ChainId; use ibc_relayer::config::AddressType; use ibc_relayer::keyring::{HDPath, KeyRing, Store}; @@ -271,34 +277,31 @@ fn return_existing<'a>(a: [&'a str; 3], b: [&'a str; 3]) -> [&'a str; 3] { // Creates a key in the relayer's test keyring, which the relayer should use // Hermes stores its keys in hermes_home/ gravity_phrase is for the main chain /// ibc phrase is for the test chain -pub fn setup_relayer_keys( - gravity_phrase: &str, - ibc_phrase: &str, -) -> Result<(), Box> { - let mut keyring = KeyRing::new( +pub fn setup_relayer_keys(shared_phrase: &str) -> Result<(), Box> { + let mut gkeyring = KeyRing::new( Store::Test, "gravity", &ChainId::from_string(&get_gravity_chain_id()), )?; - let key = keyring.key_from_mnemonic( - gravity_phrase, + let key = gkeyring.key_from_mnemonic( + shared_phrase, &HDPath::from_str(DEFAULT_COSMOS_HD_PATH).unwrap(), &AddressType::Cosmos, )?; - keyring.add_key("gravitykey", key)?; + gkeyring.add_key("gravitykey", key)?; - keyring = KeyRing::new( + let mut ckeyring = KeyRing::new( Store::Test, "cosmos", &ChainId::from_string(&get_ibc_chain_id()), )?; - let key = keyring.key_from_mnemonic( - ibc_phrase, + let key = ckeyring.key_from_mnemonic( + shared_phrase, &HDPath::from_str(DEFAULT_COSMOS_HD_PATH).unwrap(), &AddressType::Cosmos, )?; - keyring.add_key("ibckey", key)?; + ckeyring.add_key("ibckey", key)?; Ok(()) } @@ -361,22 +364,60 @@ pub fn run_ibc_relayer(hermes_base: &mut Command, full_scan: bool) { } // starts up the IBC relayer (hermes) in a background thread -pub async fn start_ibc_relayer(contact: &Contact, keys: &[ValidatorKeys], ibc_phrases: &[String]) { - contact +pub async fn start_ibc_relayer( + gravity_contact: &Contact, + ibc_contact: &Contact, + keys: &[ValidatorKeys], + ibc_keys: &[CosmosPrivateKey], +) { + let grav_deposit = get_deposit(None); + let ibc_deposit = get_deposit(Some(IBC_STAKING_TOKEN.to_string())); + info!("Sending relayer {grav_deposit:?} on gravity"); + gravity_contact .send_coins( - get_deposit(), + grav_deposit, None, - *RELAYER_ADDRESS, + *GRAVITY_RELAYER_ADDRESS, Some(OPERATION_TIMEOUT), keys[0].validator_key, ) .await .unwrap(); + info!("Sending relayer {ibc_deposit:?} on ibc-test"); + ibc_contact + .send_coins( + ibc_deposit, + Some(deep_space::Coin { + amount: 100u8.into(), + denom: IBC_STAKING_TOKEN.to_string(), + }), + *IBC_RELAYER_ADDRESS, + Some(OPERATION_TIMEOUT), + ibc_keys[0], + ) + .await + .unwrap(); info!("test-runner starting IBC relayer mode: init hermes, create ibc channel, start hermes"); let mut hermes_base = Command::new("hermes"); let hermes_base = hermes_base.arg("--config").arg(HERMES_CONFIG); - setup_relayer_keys(&RELAYER_MNEMONIC, &ibc_phrases[0]).unwrap(); - create_ibc_channel(hermes_base); + setup_relayer_keys(&RELAYER_MNEMONIC).unwrap(); + + let gravity_channel_qc = IbcChannelQueryClient::connect(COSMOS_NODE_GRPC.as_str()) + .await + .expect("Could not connect channel query client"); + + // Wait for the ibc channel to be created and find the channel ids + let channel_id_timeout = Duration::from_secs(60 * 5); + let gravity_channel = get_channel( + gravity_channel_qc, + get_ibc_chain_id(), + Some(channel_id_timeout), + ) + .await; + if gravity_channel.is_err() { + info!("No IBC channels exist between gravity-test-1 and ibc-test-1, creating one now..."); + create_ibc_channel(hermes_base); + } thread::spawn(|| { let mut hermes_base = Command::new("hermes"); let hermes_base = hermes_base.arg("--config").arg(HERMES_CONFIG); diff --git a/orchestrator/test_runner/src/ibc_auto_forward.rs b/orchestrator/test_runner/src/ibc_auto_forward.rs index 04761b322..0f950a5a8 100644 --- a/orchestrator/test_runner/src/ibc_auto_forward.rs +++ b/orchestrator/test_runner/src/ibc_auto_forward.rs @@ -26,6 +26,7 @@ use gravity_proto::cosmos_sdk_proto::ibc::applications::transfer::{ v1 as IbcTransferV1, v1::query_client::QueryClient as IbcTransferQueryClient, }; use gravity_proto::cosmos_sdk_proto::ibc::core::channel::v1::query_client::QueryClient as IbcChannelQueryClient; +use gravity_proto::cosmos_sdk_proto::ibc::core::channel::v1::IdentifiedChannel; use gravity_proto::cosmos_sdk_proto::ibc::core::channel::v1::{ QueryChannelClientStateRequest, QueryChannelsRequest, }; @@ -291,11 +292,11 @@ pub async fn test_ibc_transfer( // Retrieves the channel connecting the chain behind `ibc_channel_qc` and the chain with id `foreign_chain_id` // Retries up to `timeout` (or OPERATION_TIMEOUT if None), checking each channel's client state to find the foreign chain's id -pub async fn get_channel_id( +pub async fn get_channel( ibc_channel_qc: IbcChannelQueryClient, // The Src chain's IbcChannelQueryClient foreign_chain_id: String, // The chain-id of the Dst chain timeout: Option, -) -> Result { +) -> Result { let mut ibc_channel_qc = ibc_channel_qc; let timeout = match timeout { Some(t) => t, @@ -340,13 +341,25 @@ pub async fn get_channel_id( // Check to see if this client state contains foreign_chain_id (e.g. "cavity-1") let client_state = decode_any::(client_state_any).unwrap(); if client_state.chain_id == foreign_chain_id { - return Ok(channel.channel_id); + return Ok(channel); } } } Err(CosmosGrpcError::BadResponse("No such channel".to_string())) } +// Retrieves just the ID of the channel connecting the chain behind `ibc_channel_qc` and the chain with id `foreign_chain_id` +// Retries up to `timeout` (or OPERATION_TIMEOUT if None), checking each channel's client state to find the foreign chain's id +pub async fn get_channel_id( + ibc_channel_qc: IbcChannelQueryClient, // The Src chain's IbcChannelQueryClient + foreign_chain_id: String, // The chain-id of the Dst chain + timeout: Option, +) -> Result { + Ok(get_channel(ibc_channel_qc, foreign_chain_id, timeout) + .await? + .channel_id) +} + // Retrieves the balance `account` holds of `src_denom`'s IBC representation // Note: The Coin returned has the ibc/ denom, not the `src_chain` denom // Retries up to `timeout` or OPERATION_TIMEOUT if not provided diff --git a/orchestrator/test_runner/src/ibc_metadata.rs b/orchestrator/test_runner/src/ibc_metadata.rs index 57372d680..a15a215de 100644 --- a/orchestrator/test_runner/src/ibc_metadata.rs +++ b/orchestrator/test_runner/src/ibc_metadata.rs @@ -137,7 +137,7 @@ pub async fn submit_and_pass_ibc_metadata_proposal( }; let res = submit_ibc_metadata_proposal( proposal_content, - get_deposit(), + get_deposit(None), get_fee(None), contact, keys[0].validator_key, @@ -163,7 +163,7 @@ async fn submit_and_fail_ibc_metadata_proposal( }; let res = submit_ibc_metadata_proposal( proposal_content, - get_deposit(), + get_deposit(None), get_fee(None), contact, keys[0].validator_key, diff --git a/orchestrator/test_runner/src/ica_host.rs b/orchestrator/test_runner/src/ica_host.rs new file mode 100644 index 000000000..ef1b78bf6 --- /dev/null +++ b/orchestrator/test_runner/src/ica_host.rs @@ -0,0 +1,563 @@ +use std::str::FromStr; +/// Tests basic interchain accounts functionality +use std::time::{Duration, Instant}; + +use cosmos_gravity::send::MSG_SEND_TO_ETH_TYPE_URL; +use cosmos_gravity::utils::get_reasonable_send_to_eth_fee; +use deep_space::error::CosmosGrpcError; +use deep_space::utils::encode_any; +use deep_space::{Address, Coin, Contact, CosmosPrivateKey, Msg, PrivateKey}; +use gravity_proto::cosmos_sdk_proto::cosmos::base::abci::v1beta1::TxResponse; +use gravity_proto::cosmos_sdk_proto::cosmos::params::v1beta1::ParamChange; +use gravity_proto::cosmos_sdk_proto::ibc::applications::interchain_accounts::controller::v1::QueryInterchainAccountRequest; +use gravity_proto::cosmos_sdk_proto::ibc::applications::interchain_accounts::controller::v1::QueryParamsRequest as ControllerQueryParamsRequest; +use gravity_proto::cosmos_sdk_proto::ibc::applications::interchain_accounts::host::v1::QueryParamsRequest as HostQueryParamsRequest; +use gravity_proto::gravity::{MsgSendToEth, QueryDenomToErc20Request}; +use gravity_proto::gravity_test::gaia::icaauth::v1::{MsgRegisterAccount, MsgSubmitTx}; +use gravity_utils::num_conversion::one_atom; +use num256::Uint256; + +use tokio::time::sleep; +use tonic::transport::Channel; +use web30::client::Web3; +use gravity_proto::cosmos_sdk_proto::cosmos::params::v1beta1::ParameterChangeProposal; +use gravity_proto::cosmos_sdk_proto::ibc::core::channel::v1::query_client::QueryClient as IbcChannelQueryClient; +use gravity_proto::cosmos_sdk_proto::ibc::applications::interchain_accounts::controller::v1::query_client::QueryClient as ICAControllerQueryClient; +use gravity_proto::cosmos_sdk_proto::ibc::applications::interchain_accounts::host::v1::query_client::QueryClient as ICAHostQueryClient; +use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use clarity::Address as EthAddress; + +use crate::airdrop_proposal::wait_for_proposals_to_execute; +use crate::happy_path_v2::deploy_cosmos_representing_erc20_and_check_adoption; +use crate::ibc_auto_forward::get_channel; +use crate::utils::{footoken_metadata, get_erc20_balance_safe, vote_yes_on_proposals}; +use crate::{get_fee, IBC_STAKING_TOKEN, OPERATION_TIMEOUT, STAKING_TOKEN, TOTAL_TIMEOUT}; +use crate::{ + get_ibc_chain_id, + utils::{create_default_test_config, start_orchestrators, ValidatorKeys}, + COSMOS_NODE_GRPC, IBC_ADDRESS_PREFIX, IBC_NODE_GRPC, +}; + +pub const MSG_REGISTER_ACCOUNT_TYPE_URL: &str = "/gaia.icaauth.v1.MsgRegisterAccount"; +pub const MSG_SUBMIT_TX_TYPE_URL: &str = "/gaia.icaauth.v1.MsgSubmitTx"; + +// ---------------------------------------TEST FUNCTIONS--------------------------------------- + +/// Runs the "happy-path" functionality of the Interchain Accounts (ICA) Host Module on Gravity Bridge Chain: +/// 1. Enable Host on Gravity and Controller on the IBC test chain +/// 2. Register an Interchain Account controlled by the IBC test chain and fund it with footoken +/// 3. Deploy an ERC20 for footoken on Ethereum +/// 4. Submit a MsgSendToEth to the ICA Controller module +pub async fn ica_host_happy_path( + web30: &Web3, + grpc_client: GravityQueryClient, + gravity_contact: &Contact, + ibc_contact: &Contact, + keys: Vec, + ibc_keys: Vec, + gravity_address: EthAddress, +) { + let mut grpc_client = grpc_client; + let no_relay_market_config = create_default_test_config(); + start_orchestrators(keys.clone(), gravity_address, false, no_relay_market_config).await; + + let gravity_channel_qc = IbcChannelQueryClient::connect(COSMOS_NODE_GRPC.as_str()) + .await + .expect("Could not connect channel query client"); + let ica_controller_qc = ICAControllerQueryClient::connect(IBC_NODE_GRPC.as_str()) + .await + .expect("Cound not connect ica controller query client"); + + // Wait for the ibc channel to be created and find the channel ids + let channel_id_timeout = Duration::from_secs(60 * 5); + let gravity_channel = get_channel( + gravity_channel_qc, + get_ibc_chain_id(), + Some(channel_id_timeout), + ) + .await + .expect("Could not find gravity-test-1 channel"); + let gravity_connection_id = gravity_channel.connection_hops[0].clone(); + + info!("\n\n!!!!!!!!!! Start ICA Host Happy Path Test !!!!!!!!!!\n\n"); + enable_ica_host(gravity_contact, &keys).await; + enable_ica_controller(ibc_contact, &keys).await; + + let zero_fee = Coin { + amount: 0u8.into(), + denom: STAKING_TOKEN.to_string(), + }; + + let ica_owner = ibc_keys[0]; + let ica_owner_addr = ica_owner.to_address(&IBC_ADDRESS_PREFIX).unwrap(); + let ica_addr: String = get_or_register_ica( + ibc_contact, + ica_controller_qc.clone(), + ica_owner, + ica_owner_addr.to_string(), + gravity_connection_id.clone(), + zero_fee.clone(), + ) + .await + .expect("Could not get/register interchain account"); + let ica_address = Address::from_bech32(ica_addr).expect("invalid interchain account address?"); + + info!("Funding interchain account"); + let fund_amt = Coin { + amount: one_atom(), + denom: STAKING_TOKEN.to_string(), + }; + gravity_contact + .send_coins( + fund_amt, + Some(zero_fee), + ica_address, + Some(OPERATION_TIMEOUT), + keys[0].validator_key, + ) + .await + .expect("Failed to fund ICA"); + + let footoken = footoken_metadata(gravity_contact).await; + let footoken_deployed = grpc_client.denom_to_erc20(QueryDenomToErc20Request{ denom: footoken.base.clone() }).await; + let erc20_contract = match footoken_deployed { + Ok(res) => EthAddress::from_str(&res.into_inner().erc20).expect("invalid erc20 returned from grpc query"), + Err(_) => { + deploy_cosmos_representing_erc20_and_check_adoption( + gravity_address, + web30, + Some(keys.clone()), + &mut grpc_client, + false, + footoken.clone(), + ) + .await + } + }; + + let token_to_send_to_eth = footoken.base; + let amount_to_bridge: Uint256 = one_atom(); + let chain_fee: Uint256 = 500u64.into(); // A typical chain fee is 2 basis points, this gives us a bit of wiggle room + let send_to_user_coin = Coin { + denom: token_to_send_to_eth.clone(), + amount: amount_to_bridge + chain_fee + one_atom(), + }; + let send_to_eth_coin = Coin { + denom: token_to_send_to_eth.clone(), + amount: amount_to_bridge, + }; + let chain_fee_coin = Coin { + denom: token_to_send_to_eth.clone(), + amount: chain_fee, + }; + + // send the user some footoken + gravity_contact + .send_coins( + send_to_user_coin.clone(), + Some(get_fee(None)), + ica_address, + Some(TOTAL_TIMEOUT), + keys[0].validator_key, + ) + .await + .unwrap(); + + let simple_fee = get_fee(Some(token_to_send_to_eth.clone())); + send_to_eth_via_ica_and_confirm( + web30, + ibc_contact, + gravity_contact, + ica_address, + ica_owner, + ica_owner_addr, + gravity_connection_id.clone(), + keys[2].eth_key.to_address(), + send_to_eth_coin, + simple_fee.clone(), + Some(chain_fee_coin), + erc20_contract, + ) + .await; + + info!("Successful ICA Host Happy Path Test"); +} + +// ---------------------------------------HELPER FUNCTIONS--------------------------------------- + +/// Submits a MsgRegisterAccount to x/icaauth to create an account over `connection_id` for `owner` +pub async fn register_interchain_account( + contact: &Contact, + owner_key: impl PrivateKey, + owner: String, + connection_id: String, + fee: Coin, +) -> Result { + let register = MsgRegisterAccount { + owner, + connection_id, + version: String::new(), + }; + let register_msg = Msg::new(MSG_REGISTER_ACCOUNT_TYPE_URL.to_string(), register); + contact + .send_message( + &[register_msg], + None, + &[fee], + Some(OPERATION_TIMEOUT), + owner_key, + ) + .await +} + +/// Queries x/icaauth for `owner`'s interchain account over `connection_id` +pub async fn get_interchain_account_address( + ica_controller_qc: ICAControllerQueryClient, + owner: String, + connection_id: String, + timeout: Option, +) -> Result { + let timeout = timeout.unwrap_or(OPERATION_TIMEOUT); + let start = Instant::now(); + let mut ica_controller_qc = ica_controller_qc; + while Instant::now() - start < timeout { + let res = ica_controller_qc + .interchain_account(QueryInterchainAccountRequest { + owner: owner.clone(), + connection_id: connection_id.clone(), + }) + .await + .map(|r| r.into_inner().address) + .map_err(|e| CosmosGrpcError::BadResponse(e.to_string())); + if res.is_ok() { + return res; + } + sleep(Duration::from_secs(5)).await; + } + Err(CosmosGrpcError::BadResponse(format!( + "Failed to get account after {timeout:?}" + ))) +} + +/// Either locates an already registered interchain account or creates one for the given `ctrlr`, over connection `ctrl_to_host_conn_id` +pub async fn get_or_register_ica( + ctrl_contact: &Contact, + ctrl_qc: ICAControllerQueryClient, + ctrlr_key: impl PrivateKey, + ctrlr_addr: String, + ctrl_to_host_conn_id: String, + fee: Coin, +) -> Result { + info!("Finding/Making ICA for {ctrlr_addr} on conneciton {ctrl_to_host_conn_id}"); + let ica_addr: String; + let ica_already_exists = get_interchain_account_address( + ctrl_qc.clone(), + ctrlr_addr.to_string(), + ctrl_to_host_conn_id.clone(), + None, + ) + .await; + if ica_already_exists.is_ok() { + ica_addr = ica_already_exists.unwrap(); + info!("Interchain account {ica_addr} already registered"); + } else { + let register_res = register_interchain_account( + ctrl_contact, + ctrlr_key.clone(), + ctrlr_addr.clone(), + ctrl_to_host_conn_id.clone(), + fee.clone(), + ) + .await?; + info!("Registered Interchain Account: {}", register_res.raw_log); + + ica_addr = get_interchain_account_address( + ctrl_qc.clone(), + ctrlr_addr, + ctrl_to_host_conn_id.clone(), + Some(TOTAL_TIMEOUT), + ) + .await?; + info!("Discovered interchain account with address {ica_addr:?}"); + } + Ok(ica_addr) +} + +/// Creates and ratifies a ParameterChangeProposal to enable the ICA Host module and allow all messages +/// Note: Skips governance if the host module is already enabled +pub async fn enable_ica_host( + contact: &Contact, // Src chain's deep_space client + keys: &[ValidatorKeys], +) { + let mut host_qc = ICAHostQueryClient::connect(contact.get_url()) + .await + .expect("Unable to connect to ica host query client"); + let host_params = host_qc + .params(HostQueryParamsRequest {}) + .await + .unwrap() + .into_inner() + .params + .expect("No ica host params returned?"); + if host_params.host_enabled + && host_params + .allow_messages + .get(0) + .map(|m| m == "*") + .unwrap_or(false) + { + info!("ICA Host already enabled, skipping governance vote"); + return; + } else { + info!("Host params are {host_params:?}: Enabling ICA Host via governance, will set AllowMessages to [\"*\"]"); + } + + let deposit = Coin { + amount: one_atom() * 100u8.into(), + denom: STAKING_TOKEN.clone(), + }; + let fee = Coin { + amount: 0u8.into(), + denom: STAKING_TOKEN.clone(), + }; + let res = contact + .submit_parameter_change_proposal( + ParameterChangeProposal { + title: "Enable ICA Host".to_string(), + description: "Enable ICA Host".to_string(), + changes: vec![ + // subspace defined at ibc-go/modules/apps/27-interchain-accounts/host/types/keys.go + // keys defined at ibc-go/modules/apps/27-interchain-accounts/host/types/params.go + ParamChange { + subspace: "icahost".to_string(), + key: "HostEnabled".to_string(), + value: "true".to_string(), + }, + ParamChange { + subspace: "icahost".to_string(), + key: "AllowMessages".to_string(), + value: "[\"*\"]".to_string(), + }, + ], + }, + deposit, + fee, + keys[0].validator_key, + Some(OPERATION_TIMEOUT), + ) + .await; + vote_yes_on_proposals(contact, keys, None).await; + wait_for_proposals_to_execute(contact).await; + trace!("Gov proposal executed with {:?}", res); +} + +/// Creates and ratifies a ParameterChangeProposal to enable the ICA Controller module +pub async fn enable_ica_controller( + contact: &Contact, // Src chain's deep_space client + keys: &[ValidatorKeys], +) { + let mut controller_qc = ICAControllerQueryClient::connect(contact.get_url()) + .await + .expect("Unable to connect to ica controller query client"); + let controller_params = controller_qc + .params(ControllerQueryParamsRequest {}) + .await + .unwrap() + .into_inner() + .params + .expect("No ica controller params returned?"); + if controller_params.controller_enabled { + info!("ICA Controller already enabled, skipping governance vote"); + return; + } else { + info!("Enabling ICA Controller via governance"); + } + + let deposit = Coin { + amount: one_atom() * 100u8.into(), + denom: STAKING_TOKEN.clone(), + }; + let fee = Coin { + amount: 0u8.into(), + denom: STAKING_TOKEN.clone(), + }; + let res = contact + .submit_parameter_change_proposal( + ParameterChangeProposal { + title: "Enable ICA Controller".to_string(), + description: "Enable ICA Controller".to_string(), + changes: vec![ + // subspace defined at ibc-go/modules/apps/27-interchain-accounts/controller/types/keys.go + // keys defined at ibc-go/modules/apps/27-interchain-accounts/controller/types/params.go + ParamChange { + subspace: "icacontroller".to_string(), + key: "icacontroller".to_string(), + value: "true".to_string(), + }, + ], + }, + deposit, + fee, + keys[0].validator_key, + Some(OPERATION_TIMEOUT), + ) + .await; + vote_yes_on_proposals(contact, keys, None).await; + wait_for_proposals_to_execute(contact).await; + trace!("Gov proposal executed with {:?}", res); +} + +/// Very similar to `send_to_eth_and_confirm()`, but submits the MsgSendToEth to the ICA Controller chain +#[allow(clippy::too_many_arguments)] +pub async fn send_to_eth_via_ica_and_confirm( + web30: &Web3, + controller_contact: &Contact, // Contact for the ICA Controller chain + gravity_contact: &Contact, // Contact for Gravity chain + grav_ica: Address, // The address of the ICA on Gravity sending tokens to Ethereum + ctrl_owner: impl PrivateKey, // The key for the ICA owner account on the ICA Controller chain + ctrl_owner_addr: Address, // The address for the ICA owner account on the ICA Controller chain + ctrl_to_grav_conn_id: String, // The connection id (e.g. connection-0) on the controller chain which connects to Gravity chain + eth_receiver: EthAddress, // The Eth address which should receive the funds + send_to_eth_coin: Coin, // The funds to send to Ethereum + bridge_fee_coin: Coin, // The amount to pay a relayer for bridging the funds + cosmos_chain_fee_coin: Option, // If Gravity's MinChainFeeBasisPoints param is set, the amount needed to fulfil that fee req + erc20_contract: EthAddress, // The ERC20, used for balance change verification +) -> bool { + let starting_balance = get_erc20_balance_safe(erc20_contract, web30, eth_receiver) + .await + .unwrap(); + let amount_to_bridge = send_to_eth_coin.amount; + let res = send_to_eth_via_ica( + controller_contact, + gravity_contact, + grav_ica, + ctrl_owner, + ctrl_owner_addr, + ctrl_to_grav_conn_id, + eth_receiver, + send_to_eth_coin, + bridge_fee_coin, + cosmos_chain_fee_coin, + ) + .await + .unwrap(); + info!("Send to eth res {:?}", res); + info!("Locked up {} to send to Cosmos", amount_to_bridge); + + info!("Waiting for batch to be signed and relayed to Ethereum"); + + let start = Instant::now(); + // overly complicated retry logic allows us to handle the possibility that gas prices change between blocks + // and cause any individual request to fail. + + while Instant::now() - start < TOTAL_TIMEOUT { + let new_balance = get_erc20_balance_safe(erc20_contract, web30, eth_receiver).await; + // only keep trying if our error is gas related + if new_balance.is_err() { + continue; + } + let balance = new_balance.unwrap(); + if balance - starting_balance == amount_to_bridge { + info!("Successfully bridged {} to Ethereum!", amount_to_bridge); + assert!(balance == amount_to_bridge); + return true; + } else if balance - starting_balance != 0u8.into() { + error!("Expected {} but got {} instead", amount_to_bridge, balance); + return false; + } + sleep(Duration::from_secs(1)).await; + } + error!("Timed out waiting for ethereum balance"); + false +} + +/// Very similar to `send_to_eth()` but the MsgSendToEth is submitted to the ICA Controller chain +#[allow(clippy::too_many_arguments)] +pub async fn send_to_eth_via_ica( + ctrl_contact: &Contact, // Contact for the ICA Controller chain + gravity_contact: &Contact, // Contact for Gravity chain + ica_address: Address, // The address of the ICA on Gravity sending tokens to Ethereum + owner_key: impl PrivateKey, // The key for the ICA owner account on the ICA Controller chain + owner_addr: Address, // The address for the ICA owner account on the ICA Controller chain + ctrl_to_host_conn_id: String, // The connection id (e.g. connection-0) on the controller chain which connects to Gravity chain + destination: EthAddress, // The Eth address which should receive the funds + amount: Coin, // The funds to send + bridge_fee: Coin, // The amount to pay a relayer for bridging the funds + chain_fee: Option, // If Gravity's MinChainFeeBasisPoints param is set, the amount needed to fulfil that fee req +) -> Result { + if amount.denom != bridge_fee.denom { + return Err(CosmosGrpcError::BadInput(format!( + "{} {} is an invalid denom set for SendToEth you must pay ethereum fees in the same token your sending", + amount.denom, bridge_fee.denom, + ))); + } + let chain_fee = match chain_fee { + Some(fee) => fee, + None => Coin { + amount: get_reasonable_send_to_eth_fee(gravity_contact, amount.amount) + .await + .expect("Unable to get reasonable SendToEth fee"), + denom: amount.denom.clone(), + }, + }; + if amount.denom != chain_fee.denom { + return Err(CosmosGrpcError::BadInput(format!( + "{} {} is an invalid denom set for SendToEth you must pay chain fees in the same token your sending", + amount.denom, chain_fee.denom, + ))); + } + let balances = gravity_contact.get_balances(ica_address).await.unwrap(); + let mut found = false; + for balance in balances { + if balance.denom == amount.denom { + let total_amount = amount.amount + (bridge_fee.amount + chain_fee.amount); + if balance.amount < total_amount { + return Err(CosmosGrpcError::BadInput(format!( + "Insufficient balance of {} to send {}, only have {}", + amount.denom, total_amount, balance.amount, + ))); + } + found = true; + } + } + if !found { + return Err(CosmosGrpcError::BadInput(format!( + "No balance of {} to send", + amount.denom, + ))); + } + + let msg_send_to_eth = MsgSendToEth { + sender: ica_address.to_string(), + eth_dest: destination.to_string(), + amount: Some(amount.into()), + bridge_fee: Some(bridge_fee.into()), + chain_fee: Some(chain_fee.into()), + }; + info!( + "Sending to Ethereum with MsgSendToEth: {:?}", + msg_send_to_eth + ); + let msg = encode_any(msg_send_to_eth, MSG_SEND_TO_ETH_TYPE_URL); + + let ica_submit = MsgSubmitTx { + connection_id: ctrl_to_host_conn_id, + owner: owner_addr.to_string(), + msgs: vec![msg], + }; + info!("Submitting MsgSubmitTx: {ica_submit:?}"); + let ica_msg = Msg::new(MSG_SUBMIT_TX_TYPE_URL, ica_submit); + let ctrl_fee = Coin { + amount: 100u8.into(), + denom: IBC_STAKING_TOKEN.to_string(), + }; + ctrl_contact + .send_message( + &[ica_msg], + None, + &[ctrl_fee], + Some(OPERATION_TIMEOUT), + owner_key, + ) + .await +} diff --git a/orchestrator/test_runner/src/main.rs b/orchestrator/test_runner/src/main.rs index 3cb4cbefc..8f6c780f9 100644 --- a/orchestrator/test_runner/src/main.rs +++ b/orchestrator/test_runner/src/main.rs @@ -14,6 +14,7 @@ use crate::ethereum_blacklist_test::ethereum_blacklist_test; use crate::ethereum_keys::ethereum_keys_test; use crate::ibc_auto_forward::ibc_auto_forward_test; use crate::ibc_metadata::ibc_metadata_proposal_test; +use crate::ica_host::ica_host_happy_path; use crate::invalid_events::invalid_events; use crate::pause_bridge::pause_bridge_test; use crate::send_to_eth_fees::send_to_eth_fees_test; @@ -58,6 +59,7 @@ mod happy_path; mod happy_path_v2; mod ibc_auto_forward; mod ibc_metadata; +mod ica_host; mod invalid_events; mod orch_keys; mod orch_only; @@ -131,7 +133,8 @@ lazy_static! { // it's a distinct address to prevent sequence collisions static ref RELAYER_MNEMONIC: String = "below great use captain upon ship tiger exhaust orient burger network uphold wink theory focus cloud energy flavor recall joy phone beach symptom hobby".to_string(); static ref RELAYER_PRIVATE_KEY: CosmosPrivateKey = CosmosPrivateKey::from_phrase(&RELAYER_MNEMONIC, "").unwrap(); - static ref RELAYER_ADDRESS: CosmosAddress = RELAYER_PRIVATE_KEY.to_address(ADDRESS_PREFIX.as_str()).unwrap(); + static ref GRAVITY_RELAYER_ADDRESS: CosmosAddress = RELAYER_PRIVATE_KEY.to_address(ADDRESS_PREFIX.as_str()).unwrap(); // IBC relayer on Gravity + static ref IBC_RELAYER_ADDRESS: CosmosAddress = RELAYER_PRIVATE_KEY.to_address(IBC_ADDRESS_PREFIX.as_str()).unwrap(); // IBC relayer on test chain } /// Gets the standard non-token fee for the testnet. We deploy the test chain with STAKE @@ -151,9 +154,10 @@ pub fn get_fee(denom: Option) -> Coin { } } -pub fn get_deposit() -> Coin { +pub fn get_deposit(denom_override: Option) -> Coin { + let denom = denom_override.unwrap_or_else(|| STAKING_TOKEN.to_string()); Coin { - denom: STAKING_TOKEN.to_string(), + denom, amount: 1_000_000_000u64.into(), } } @@ -195,15 +199,21 @@ pub fn should_deploy_contracts() -> bool { pub async fn main() { env_logger::init(); info!("Starting Gravity test-runner"); - let contact = Contact::new( + let gravity_contact = Contact::new( COSMOS_NODE_GRPC.as_str(), OPERATION_TIMEOUT, ADDRESS_PREFIX.as_str(), ) .unwrap(); + let ibc_contact = Contact::new( + IBC_NODE_GRPC.as_str(), + OPERATION_TIMEOUT, + IBC_ADDRESS_PREFIX.as_str(), + ) + .unwrap(); info!("Waiting for Cosmos chain to come online"); - wait_for_cosmos_online(&contact, TOTAL_TIMEOUT).await; + wait_for_cosmos_online(&gravity_contact, TOTAL_TIMEOUT).await; let grpc_client = GravityQueryClient::connect(COSMOS_NODE_GRPC.as_str()) .await @@ -212,11 +222,11 @@ pub async fn main() { // keys for the primary test chain let keys = get_keys(); // keys for the IBC chain connected to the main test chain - let (ibc_keys, ibc_phrases) = parse_ibc_validator_keys(); + let (ibc_keys, _ibc_phrases) = parse_ibc_validator_keys(); // if we detect this env var we are only deploying contracts, do that then exit. if should_deploy_contracts() { info!("test-runner in contract deploying mode, deploying contracts, then exiting"); - deploy_contracts(&contact).await; + deploy_contracts(&gravity_contact).await; return; } @@ -235,11 +245,11 @@ pub async fn main() { // assert that the validators have a balance of the footoken we use // for test transfers - assert!(contact + assert!(gravity_contact .get_balance( keys[0] .validator_key - .to_address(&contact.get_prefix()) + .to_address(&gravity_contact.get_prefix()) .unwrap(), get_test_token_name(), ) @@ -247,7 +257,7 @@ pub async fn main() { .unwrap() .is_some()); - start_ibc_relayer(&contact, &keys, &ibc_phrases).await; + start_ibc_relayer(&gravity_contact, &ibc_contact, &keys, &ibc_keys).await; // This segment contains optional tests, by default we run a happy path test // this tests all major functionality of Gravity once or twice. @@ -276,11 +286,14 @@ pub async fn main() { // ERC721_HAPPY_PATH tests ERC721 extension for Gravity.sol, solidity only // UPGRADE_PART_1 handles creating a chain upgrade proposal and passing it // UPGRADE_PART_2 upgrades the chain binaries and starts the upgraded chain after being halted in part 1 + // UPGRADE_ONLY performs an upgrade without making any testing assertions // IBC_AUTO_FORWARD tests ibc auto forwarding functionality. - // RUN_ORCH_ONLY runs only the orchestrators, for local testing where you want the chain to just run. // ETHERMINT_KEYS runs a gamut of transactions using a Ethermint key to test no loss of functionality // BATCH_TIMEOUT is a stress test for batch timeouts, setting an extremely agressive timeout value // VESTING checks that the vesting module delivers partially and fully vested accounts + // SEND_TO_ETH_FEES tests that Cosmos->Eth fees are collected and in the right amounts + // ICA_HOST_HAPPY_PATH tests that the interchain accounts host module is correctly configured on Gravity + // RUN_ORCH_ONLY runs only the orchestrators, for local testing where you want the chain to just run. let test_type = env::var("TEST_TYPE"); info!("Starting tests with {:?}", test_type); if let Ok(test_type) = test_type { @@ -289,7 +302,7 @@ pub async fn main() { happy_path_test( &web30, grpc_client, - &contact, + &gravity_contact, keys, gravity_address, erc20_addresses[0], @@ -298,6 +311,7 @@ pub async fn main() { .await; return; } else if test_type == "BATCH_STRESS" { + // 300s timeout contact instead of 30s let contact = Contact::new( COSMOS_NODE_GRPC.as_str(), TOTAL_TIMEOUT, @@ -316,18 +330,19 @@ pub async fn main() { return; } else if test_type == "VALSET_STRESS" { info!("Starting Valset update stress test"); - validator_set_stress_test(&web30, grpc_client, &contact, keys, gravity_address).await; + validator_set_stress_test(&web30, grpc_client, &gravity_contact, keys, gravity_address) + .await; return; } else if test_type == "VALSET_REWARDS" { info!("Starting Valset rewards test"); - valset_rewards_test(&web30, grpc_client, &contact, keys, gravity_address).await; + valset_rewards_test(&web30, grpc_client, &gravity_contact, keys, gravity_address).await; return; } else if test_type == "V2_HAPPY_PATH" || test_type == "HAPPY_PATH_V2" { info!("Starting happy path for Gravity v2"); happy_path_test_v2( &web30, grpc_client, - &contact, + &gravity_contact, keys, gravity_address, false, @@ -337,25 +352,33 @@ pub async fn main() { return; } else if test_type == "V2_HAPPY_PATH_NATIVE" || test_type == "HAPPY_PATH_V2_NATIVE" { info!("Starting happy path for ERC20 representation of the Native staking token"); - happy_path_test_v2_native(&web30, grpc_client, &contact, keys, gravity_address, false) - .await; + happy_path_test_v2_native( + &web30, + grpc_client, + &gravity_contact, + keys, + gravity_address, + false, + ) + .await; return; } else if test_type == "RELAY_MARKET" { info!("Starting relay market tests!"); - relay_market_test(&web30, grpc_client, &contact, keys, gravity_address).await; + relay_market_test(&web30, grpc_client, &gravity_contact, keys, gravity_address).await; return; } else if test_type == "ORCHESTRATOR_KEYS" { info!("Starting orchestrator key update tests!"); - orch_keys(grpc_client, &contact, keys).await; + orch_keys(grpc_client, &gravity_contact, keys).await; return; } else if test_type == "EVIDENCE" { info!("Starting evidence based slashing tests!"); - evidence_based_slashing(&web30, grpc_client, &contact, keys, gravity_address).await; + evidence_based_slashing(&web30, grpc_client, &gravity_contact, keys, gravity_address) + .await; return; } else if test_type == "TXCANCEL" { info!("Starting SendToEth cancellation test!"); send_to_eth_and_cancel( - &contact, + &gravity_contact, grpc_client, &web30, keys, @@ -368,7 +391,7 @@ pub async fn main() { info!("Starting invalid events test!"); invalid_events( &web30, - &contact, + &gravity_contact, keys, gravity_address, erc20_addresses[0], @@ -381,7 +404,7 @@ pub async fn main() { unhalt_bridge_test( &web30, grpc_client, - &contact, + &gravity_contact, keys, gravity_address, erc20_addresses[0], @@ -393,7 +416,7 @@ pub async fn main() { pause_bridge_test( &web30, grpc_client, - &contact, + &gravity_contact, keys, gravity_address, erc20_addresses[0], @@ -402,33 +425,43 @@ pub async fn main() { return; } else if test_type == "DEPOSIT_OVERFLOW" { info!("Starting deposit overflow test!"); - deposit_overflow_test(&web30, &contact, keys, erc20_addresses, grpc_client).await; + deposit_overflow_test(&web30, &gravity_contact, keys, erc20_addresses, grpc_client) + .await; return; } else if test_type == "ETHEREUM_BLACKLIST" { info!("Starting ethereum blacklist test"); - ethereum_blacklist_test(grpc_client, &contact, keys).await; + ethereum_blacklist_test(grpc_client, &gravity_contact, keys).await; return; } else if test_type == "AIRDROP_PROPOSAL" { info!("Starting airdrop governance proposal test"); - airdrop_proposal_test(&contact, keys).await; + airdrop_proposal_test(&gravity_contact, keys).await; return; } else if test_type == "SIGNATURE_SLASHING" { info!("Starting Signature Slashing test"); - signature_slashing_test(&web30, grpc_client, &contact, keys, gravity_address).await; + signature_slashing_test(&web30, grpc_client, &gravity_contact, keys, gravity_address) + .await; return; } else if test_type == "SLASHING_DELEGATION" { info!("Starting Slashing Delegation test"); - slashing_delegation_test(&web30, grpc_client, &contact, keys, gravity_address).await; + slashing_delegation_test(&web30, grpc_client, &gravity_contact, keys, gravity_address) + .await; return; } else if test_type == "IBC_METADATA" { info!("Starting IBC metadata proposal test"); - ibc_metadata_proposal_test(gravity_address, keys, grpc_client, &contact, &web30).await; + ibc_metadata_proposal_test( + gravity_address, + keys, + grpc_client, + &gravity_contact, + &web30, + ) + .await; return; } else if test_type == "ERC721_HAPPY_PATH" { info!("Starting ERC 721 transfer test"); erc721_happy_path_test( &web30, - &contact, + &gravity_contact, keys, gravity_address, gravity_erc721_address, @@ -491,7 +524,7 @@ pub async fn main() { ibc_auto_forward_test( &web30, grpc_client, - &contact, + &gravity_contact, keys, ibc_keys, gravity_address, @@ -504,7 +537,7 @@ pub async fn main() { let result = ethereum_keys_test( &web30, grpc_client, - &contact, + &gravity_contact, keys, ibc_keys, gravity_address, @@ -517,7 +550,7 @@ pub async fn main() { info!("Starting Batch Timeout/Timeout Stress test"); batch_timeout_test( &web30, - &contact, + &gravity_contact, grpc_client, keys, gravity_address, @@ -528,12 +561,12 @@ pub async fn main() { } else if test_type == "VESTING" { info!("Starting Vesting test"); let vesting_keys = parse_vesting_keys(); - vesting_test(&contact, vesting_keys).await; + vesting_test(&gravity_contact, vesting_keys).await; return; } else if test_type == "SEND_TO_ETH_FEES" { send_to_eth_fees_test( &web30, - &contact, + &gravity_contact, grpc_client, keys, gravity_address, @@ -541,6 +574,19 @@ pub async fn main() { ) .await; return; + } else if test_type == "ICA_HOST_HAPPY_PATH" { + info!("Starting Interchain Accounts Host Module Happy Path Test"); + ica_host_happy_path( + &web30, + grpc_client, + &gravity_contact, + &ibc_contact, + keys, + ibc_keys, + gravity_address, + ) + .await; + return; } else if test_type == "RUN_ORCH_ONLY" { orch_only_test(keys, gravity_address).await; sleep(Duration::from_secs(1_000_000_000)).await; @@ -559,7 +605,7 @@ pub async fn main() { happy_path_test( &web30, grpc_client, - &contact, + &gravity_contact, keys, gravity_address, erc20_addresses[0], @@ -568,7 +614,7 @@ pub async fn main() { .await; // this checks that the chain is continuing at the end of each test. - contact + gravity_contact .wait_for_next_block(TOTAL_TIMEOUT) .await .expect("Error chain has halted unexpectedly!"); diff --git a/orchestrator/test_runner/src/send_to_eth_fees.rs b/orchestrator/test_runner/src/send_to_eth_fees.rs index a97540f24..412cda9cf 100644 --- a/orchestrator/test_runner/src/send_to_eth_fees.rs +++ b/orchestrator/test_runner/src/send_to_eth_fees.rs @@ -992,7 +992,7 @@ pub async fn submit_and_pass_send_to_eth_fees_proposal( }; let res = submit_send_to_eth_fees_proposal( proposal_content, - get_deposit(), + get_deposit(None), get_fee(None), contact, keys[0].validator_key, diff --git a/orchestrator/test_runner/src/unhalt_bridge.rs b/orchestrator/test_runner/src/unhalt_bridge.rs index 24983b660..8a1acc420 100644 --- a/orchestrator/test_runner/src/unhalt_bridge.rs +++ b/orchestrator/test_runner/src/unhalt_bridge.rs @@ -246,7 +246,7 @@ async fn submit_and_pass_unhalt_bridge_proposal( info!("Submit and pass gov proposal: nonce is {}", nonce); let res = submit_unhalt_bridge_proposal( proposal_content, - get_deposit(), + get_deposit(None), get_fee(None), contact, keys[0].validator_key, diff --git a/orchestrator/test_runner/src/utils.rs b/orchestrator/test_runner/src/utils.rs index f8d6b3434..a1535641e 100644 --- a/orchestrator/test_runner/src/utils.rs +++ b/orchestrator/test_runner/src/utils.rs @@ -455,7 +455,7 @@ pub async fn create_parameter_change_proposal( }; let res = submit_parameter_change_proposal( proposal, - get_deposit(), + get_deposit(None), fee_coin, contact, key, @@ -522,7 +522,7 @@ pub async fn execute_upgrade_proposal( }; let res = submit_upgrade_proposal( proposal, - get_deposit(), + get_deposit(None), get_fee(None), contact, keys[0].validator_key, From b75a19a0eb368ef9dfa74b1c94ab74276881e2e8 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 14 Jun 2023 13:55:28 -0400 Subject: [PATCH 08/11] Add Antares upgrade + update integration test When adding a new store via an in-place migration, the SDK expects us to set a store loader which will add any store keys introduced in the upgrade. This is about all the Antares upgrade handler will do apart from invariant assertions. --- .github/workflows/integration-tests.yml | 4 +- module/app/app.go | 39 ++++++++++----- module/app/upgrades/antares/README.md | 10 ++++ module/app/upgrades/antares/constants.go | 3 ++ module/app/upgrades/antares/handler.go | 51 +++++++++++++++++++ module/app/upgrades/register.go | 8 +++ orchestrator/test_runner/src/main.rs | 2 + orchestrator/test_runner/src/upgrade.rs | 62 +++++++++++------------- 8 files changed, 132 insertions(+), 47 deletions(-) create mode 100644 module/app/upgrades/antares/README.md create mode 100644 module/app/upgrades/antares/constants.go create mode 100644 module/app/upgrades/antares/handler.go diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index fbd89fd85..3b251b0bb 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -328,8 +328,8 @@ jobs: key: integration-test-cache-{hash} restore-keys: | integration-test-cache- - - name: Test Pleiades upgrade - run: tests/run-upgrade-test.sh v1.8.2 + - name: Test Antares upgrade + run: tests/run-upgrade-test.sh v1.9.3 env: NO_IMAGE_BUILD: True ibc_auto_forward_test: diff --git a/module/app/app.go b/module/app/app.go index bf377bc80..5fd64b2a7 100644 --- a/module/app/app.go +++ b/module/app/app.go @@ -117,6 +117,7 @@ import ( "github.com/Gravity-Bridge/Gravity-Bridge/module/app/ante" gravityparams "github.com/Gravity-Bridge/Gravity-Bridge/module/app/params" "github.com/Gravity-Bridge/Gravity-Bridge/module/app/upgrades" + "github.com/Gravity-Bridge/Gravity-Bridge/module/app/upgrades/antares" v2 "github.com/Gravity-Bridge/Gravity-Bridge/module/app/upgrades/v2" "github.com/Gravity-Bridge/Gravity-Bridge/module/x/gravity" "github.com/Gravity-Bridge/Gravity-Bridge/module/x/gravity/keeper" @@ -999,22 +1000,36 @@ func (app *Gravity) registerStoreLoaders() { if err != nil { panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) } + if app.upgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + return + } + + // STORE LOADER CONFIGURATION: + // Added: []string{"newmodule"}, // We are adding these modules + // Renamed: []storetypes.StoreRename{{"foo", "bar"}}, example foo to bar rename + // Deleted: []string{"bazmodule"}, example deleted bazmodule // v1->v2 STORE LOADER SETUP // Register the new v2 modules and the special StoreLoader to add them if upgradeInfo.Name == v2.V1ToV2PlanName { - if !app.upgradeKeeper.IsSkipHeight(upgradeInfo.Height) { // Recognized the plan, need to skip this one though - storeUpgrades := storetypes.StoreUpgrades{ - Added: []string{bech32ibctypes.ModuleName}, // We are adding these modules - // Check upgrade docs to see which type of store loader is necessary for deletes/renames - // Renamed: []storetypes.StoreRename{{"foo", "bar"}}, example foo to bar rename - // Deleted: []string{"bazmodule"}, example deleted bazmodule - Renamed: nil, - Deleted: nil, - } - - // configure store loader that checks if version == upgradeHeight and applies store upgrades - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{bech32ibctypes.ModuleName}, + Renamed: nil, + Deleted: nil, + } + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } + // ANTARES ICA Host module store loader setup + if upgradeInfo.Name == antares.OrionToAntaresPlanName { + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{icahosttypes.StoreKey}, + Renamed: nil, + Deleted: nil, } + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) } } diff --git a/module/app/upgrades/antares/README.md b/module/app/upgrades/antares/README.md new file mode 100644 index 000000000..77e2bdade --- /dev/null +++ b/module/app/upgrades/antares/README.md @@ -0,0 +1,10 @@ +# Antares UPGRADE +The *Antares* upgrade contains the following changes. + +## Summary of Changes + +* Updating Cosmos SDK version to v0.45.16, which is the end of the v0.45 line. A migration to v0.46 will happen in the next upgrade. +* Updating IBC version to v4.3.1, since IBC v3 is no longer supported. +* Adding Interchain Accounts Host module: + * By enabling ICA it will be possible to send tokens to and from chains without interacting with your Gravity Bridge account. Combining Interchain Accounts and IBC Auto Forwarding, users on an ICA Controller chain will be able to send tokens to Cosmos via Gravity or transfer tokens to Ethereum through Gravity while only submitting messages to Ethereum and the Controller chain. That means a sophisticated UI can present all transactions through Metamask for convenience! + * ICA will also enable Liquid Staking using platforms like Persistence, Quicksilver, Stride, and more! \ No newline at end of file diff --git a/module/app/upgrades/antares/constants.go b/module/app/upgrades/antares/constants.go new file mode 100644 index 000000000..52ee9f6cd --- /dev/null +++ b/module/app/upgrades/antares/constants.go @@ -0,0 +1,3 @@ +package antares + +var OrionToAntaresPlanName = "antares" diff --git a/module/app/upgrades/antares/handler.go b/module/app/upgrades/antares/handler.go new file mode 100644 index 000000000..c6d7a7814 --- /dev/null +++ b/module/app/upgrades/antares/handler.go @@ -0,0 +1,51 @@ +package antares + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" + icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" +) + +func GetAntaresUpgradeHandler( + mm *module.Manager, configurator *module.Configurator, crisisKeeper *crisiskeeper.Keeper, +) func( + ctx sdk.Context, plan upgradetypes.Plan, vmap module.VersionMap, +) (module.VersionMap, error) { + if mm == nil { + panic("Nil argument to GetAntaresUpgradeHandler") + } + return func(ctx sdk.Context, plan upgradetypes.Plan, vmap module.VersionMap) (module.VersionMap, error) { + ctx.Logger().Info("Antares upgrade: Starting upgrade") + + vmap[icatypes.ModuleName] = mm.Modules[icatypes.ModuleName].ConsensusVersion() + icaHostParams := icahosttypes.Params{ + HostEnabled: false, + AllowMessages: []string{}, + } + icaControllerParams := icacontrollertypes.Params{ + ControllerEnabled: false, + } + + icaModule, ok := mm.Modules[icatypes.ModuleName].(ica.AppModule) + if !ok { + panic("module manager's ica module is not an ica.AppModule") + } + icaModule.InitModule(ctx, icaControllerParams, icaHostParams) + ctx.Logger().Info("Antares Upgrade: Running any configured module migrations") + out, outErr := mm.RunMigrations(ctx, *configurator, vmap) + if outErr != nil { + return out, outErr + } + ctx.Logger().Info("Asserting invariants after upgrade") + crisisKeeper.AssertInvariants(ctx) + + ctx.Logger().Info("Antares Upgrade Successful") + return out, nil + } +} diff --git a/module/app/upgrades/register.go b/module/app/upgrades/register.go index 2d42e2c02..8b630b563 100644 --- a/module/app/upgrades/register.go +++ b/module/app/upgrades/register.go @@ -12,6 +12,7 @@ import ( upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + "github.com/Gravity-Bridge/Gravity-Bridge/module/app/upgrades/antares" "github.com/Gravity-Bridge/Gravity-Bridge/module/app/upgrades/orion" "github.com/Gravity-Bridge/Gravity-Bridge/module/app/upgrades/pleiades" polaris "github.com/Gravity-Bridge/Gravity-Bridge/module/app/upgrades/polaris" @@ -60,8 +61,15 @@ func RegisterUpgradeHandlers( pleiades.GetPleiades2UpgradeHandler(mm, configurator, crisisKeeper, stakingKeeper), ) + // Orion upgrade handler upgradeKeeper.SetUpgradeHandler( orion.PleiadesPart2ToOrionPlanName, orion.GetOrionUpgradeHandler(mm, configurator, crisisKeeper), ) + + // Antares upgrade handler + upgradeKeeper.SetUpgradeHandler( + antares.OrionToAntaresPlanName, + antares.GetAntaresUpgradeHandler(mm, configurator, crisisKeeper), + ) } diff --git a/orchestrator/test_runner/src/main.rs b/orchestrator/test_runner/src/main.rs index 8f6c780f9..0f225d116 100644 --- a/orchestrator/test_runner/src/main.rs +++ b/orchestrator/test_runner/src/main.rs @@ -481,6 +481,7 @@ pub async fn main() { upgrade_part_1( &web30, &contact, + &ibc_contact, grpc_client, keys, ibc_keys, @@ -500,6 +501,7 @@ pub async fn main() { upgrade_part_2( &web30, &contact, + &ibc_contact, grpc_client, keys, ibc_keys, diff --git a/orchestrator/test_runner/src/upgrade.rs b/orchestrator/test_runner/src/upgrade.rs index 32675e3d9..00a33627e 100644 --- a/orchestrator/test_runner/src/upgrade.rs +++ b/orchestrator/test_runner/src/upgrade.rs @@ -1,4 +1,5 @@ use crate::ibc_metadata::submit_and_pass_ibc_metadata_proposal; +use crate::ica_host::ica_host_happy_path; use crate::{happy_path_test, happy_path_test_v2, utils::*}; use clarity::Address as EthAddress; use deep_space::client::ChainStatus; @@ -39,7 +40,8 @@ const MINIMUM_VALSETS: u64 = 4; // There may be more valsets depending on how lo #[allow(clippy::too_many_arguments)] pub async fn upgrade_part_1( web30: &Web3, - contact: &Contact, + gravity_contact: &Contact, + ibc_contact: &Contact, grpc_client: GravityQueryClient, keys: Vec, ibc_keys: Vec, @@ -47,12 +49,12 @@ pub async fn upgrade_part_1( erc20_addresses: Vec, ) { info!("Starting upgrade test part 1"); - let metadata = footoken_metadata(contact).await; - submit_and_pass_ibc_metadata_proposal(metadata.name.clone(), metadata.clone(), contact, &keys) + let metadata = footoken_metadata(gravity_contact).await; + submit_and_pass_ibc_metadata_proposal(metadata.name.clone(), metadata.clone(), gravity_contact, &keys) .await; run_all_recoverable_tests( web30, - contact, + gravity_contact, grpc_client.clone(), keys.clone(), gravity_address, @@ -62,7 +64,8 @@ pub async fn upgrade_part_1( .await; run_upgrade_specific_tests( web30, - contact, + gravity_contact, + ibc_contact, grpc_client.clone(), keys.clone(), ibc_keys.clone(), @@ -72,7 +75,7 @@ pub async fn upgrade_part_1( ) .await; - let upgrade_height = run_upgrade(contact, keys, "orion".to_string(), false).await; + let upgrade_height = run_upgrade(gravity_contact, keys, "antares".to_string(), false).await; // Check that the expected attestations exist check_attestations(grpc_client.clone(), MINIMUM_ATTESTATIONS).await; @@ -82,13 +85,13 @@ pub async fn upgrade_part_1( upgrade_height ); // Wait for the block before the upgrade height, we won't get a response from the chain - let res = wait_for_block(contact, (upgrade_height - 1) as u64).await; + let res = wait_for_block(gravity_contact, (upgrade_height - 1) as u64).await; if res.is_err() { panic!("Unable to wait for upgrade! {}", res.err().unwrap()); } delay_for(Duration::from_secs(10)).await; // wait for the new block to halt the chain - let status = contact.get_chain_status().await; + let status = gravity_contact.get_chain_status().await; info!( "Done waiting, chain should be halted, status response: {:?}", status @@ -100,7 +103,8 @@ pub async fn upgrade_part_1( /// then finally run tests/run-tests.sh with V2_UPGRADE_PART_2 as the test type. pub async fn upgrade_part_2( web30: &Web3, - contact: &Contact, + gravity_contact: &Contact, + ibc_contact: &Contact, grpc_client: GravityQueryClient, keys: Vec, ibc_keys: Vec, @@ -113,7 +117,7 @@ pub async fn upgrade_part_2( let mut metadata: Option = None; { - let all_metadata = contact.get_all_denoms_metadata().await.unwrap(); + let all_metadata = gravity_contact.get_all_denoms_metadata().await.unwrap(); for m in all_metadata { if m.base == "footoken2" { metadata = Some(m) @@ -125,11 +129,11 @@ pub async fn upgrade_part_2( } let metadata = metadata.unwrap(); - submit_and_pass_ibc_metadata_proposal(metadata.name.clone(), metadata.clone(), contact, &keys) + submit_and_pass_ibc_metadata_proposal(metadata.name.clone(), metadata.clone(), gravity_contact, &keys) .await; run_all_recoverable_tests( web30, - contact, + gravity_contact, grpc_client.clone(), keys.clone(), gravity_address, @@ -139,7 +143,8 @@ pub async fn upgrade_part_2( .await; run_upgrade_specific_tests( web30, - contact, + gravity_contact, + ibc_contact, grpc_client.clone(), keys.clone(), ibc_keys, @@ -236,28 +241,19 @@ pub async fn run_all_recoverable_tests( // These tests should fail in upgrade_part_1() but pass in upgrade_part_2() #[allow(clippy::too_many_arguments)] pub async fn run_upgrade_specific_tests( - _web30: &Web3, - _contact: &Contact, - _grpc_client: GravityQueryClient, - _keys: Vec, - _ibc_keys: Vec, - _gravity_address: EthAddress, + web30: &Web3, + gravity_contact: &Contact, + ibc_contact: &Contact, + grpc_client: GravityQueryClient, + keys: Vec, + ibc_keys: Vec, + gravity_address: EthAddress, _erc20_addresses: Vec, - _post_upgrade: bool, + post_upgrade: bool, ) { - // TODO: Add a new test for Pleiades let res = new_test().await; - // if !post_upgrade { - // // Expect failure - // assert!(!res); - // info!("Ethereum keys are not supported before the upgrade, waiting for upgrade then testing again!"); - // } else { - // // Expect success - // assert!( - // res, - // "Ethereum keys are not supported after the upgrade, investigation needed!!" - // ); - // info!("Successful Ethereum keys test after the upgrade!"); - // } + if post_upgrade { + ica_host_happy_path(web30, grpc_client, gravity_contact, ibc_contact, keys, ibc_keys, gravity_address).await; + } } /// Checks that the expected attestations are returned from the grpc endpoint From 68498070667ff540b290c56880b48432b56e1a95 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 14 Jun 2023 14:46:03 -0400 Subject: [PATCH 09/11] Give vesting more buffer time --- tests/container-scripts/setup-validators.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/container-scripts/setup-validators.sh b/tests/container-scripts/setup-validators.sh index 95e7ab052..e55c1d817 100755 --- a/tests/container-scripts/setup-validators.sh +++ b/tests/container-scripts/setup-validators.sh @@ -49,8 +49,8 @@ jq '.app_state.bank.balances += [{"address": "gravity1jv65s3grqf6v6jl3dp4t6c9t9r mv /edited-genesis.json /genesis.json VESTING_AMOUNT="1000000000stake" -START_VESTING=$(expr $(date +%s) + 300) # Start vesting 5 minutes from now -END_VESTING=$(expr $START_VESTING + 600) # End vesting 10 minutes from now, giving a 5 minute window for the test to work +START_VESTING=$(expr $(date +%s) + 600) # Start vesting 10 minutes from now +END_VESTING=$(expr $START_VESTING + 900) # End vesting 15 minutes from now, giving a 5 minute window for the test to work # Sets up an arbitrary number of validators on a single machine by manipulating # the --home parameter on gaiad From ef45f3c934e0e2bf2b0646a016e7c1e4ac21eed6 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 14 Jun 2023 20:34:05 -0400 Subject: [PATCH 10/11] Cargo clippy + fmt --- orchestrator/test_runner/src/ica_host.rs | 9 +++++-- orchestrator/test_runner/src/upgrade.rs | 30 ++++++++++++++++++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/orchestrator/test_runner/src/ica_host.rs b/orchestrator/test_runner/src/ica_host.rs index ef1b78bf6..8e3d8df78 100644 --- a/orchestrator/test_runner/src/ica_host.rs +++ b/orchestrator/test_runner/src/ica_host.rs @@ -119,9 +119,14 @@ pub async fn ica_host_happy_path( .expect("Failed to fund ICA"); let footoken = footoken_metadata(gravity_contact).await; - let footoken_deployed = grpc_client.denom_to_erc20(QueryDenomToErc20Request{ denom: footoken.base.clone() }).await; + let footoken_deployed = grpc_client + .denom_to_erc20(QueryDenomToErc20Request { + denom: footoken.base.clone(), + }) + .await; let erc20_contract = match footoken_deployed { - Ok(res) => EthAddress::from_str(&res.into_inner().erc20).expect("invalid erc20 returned from grpc query"), + Ok(res) => EthAddress::from_str(&res.into_inner().erc20) + .expect("invalid erc20 returned from grpc query"), Err(_) => { deploy_cosmos_representing_erc20_and_check_adoption( gravity_address, diff --git a/orchestrator/test_runner/src/upgrade.rs b/orchestrator/test_runner/src/upgrade.rs index 00a33627e..a9364b9d6 100644 --- a/orchestrator/test_runner/src/upgrade.rs +++ b/orchestrator/test_runner/src/upgrade.rs @@ -50,8 +50,13 @@ pub async fn upgrade_part_1( ) { info!("Starting upgrade test part 1"); let metadata = footoken_metadata(gravity_contact).await; - submit_and_pass_ibc_metadata_proposal(metadata.name.clone(), metadata.clone(), gravity_contact, &keys) - .await; + submit_and_pass_ibc_metadata_proposal( + metadata.name.clone(), + metadata.clone(), + gravity_contact, + &keys, + ) + .await; run_all_recoverable_tests( web30, gravity_contact, @@ -101,6 +106,7 @@ pub async fn upgrade_part_1( /// Perform a series of integration tests after an upgrade has executed /// NOTE: To run this test, follow the instructions for v2_upgrade_part_1 and WAIT FOR CHAIN HALT, /// then finally run tests/run-tests.sh with V2_UPGRADE_PART_2 as the test type. +#[allow(clippy::too_many_arguments)] pub async fn upgrade_part_2( web30: &Web3, gravity_contact: &Contact, @@ -129,8 +135,13 @@ pub async fn upgrade_part_2( } let metadata = metadata.unwrap(); - submit_and_pass_ibc_metadata_proposal(metadata.name.clone(), metadata.clone(), gravity_contact, &keys) - .await; + submit_and_pass_ibc_metadata_proposal( + metadata.name.clone(), + metadata.clone(), + gravity_contact, + &keys, + ) + .await; run_all_recoverable_tests( web30, gravity_contact, @@ -252,7 +263,16 @@ pub async fn run_upgrade_specific_tests( post_upgrade: bool, ) { if post_upgrade { - ica_host_happy_path(web30, grpc_client, gravity_contact, ibc_contact, keys, ibc_keys, gravity_address).await; + ica_host_happy_path( + web30, + grpc_client, + gravity_contact, + ibc_contact, + keys, + ibc_keys, + gravity_address, + ) + .await; } } From b610552cc97b4768d295608444be5d5d453e33a2 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 16 Jun 2023 11:37:56 -0400 Subject: [PATCH 11/11] Bump gbt for v1.10.0 --- orchestrator/Cargo.lock | 2 +- orchestrator/gbt/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 019dcdd61..efe45f9fa 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -1326,7 +1326,7 @@ dependencies = [ [[package]] name = "gbt" -version = "1.9.3" +version = "1.10.0" dependencies = [ "actix-rt", "clap", diff --git a/orchestrator/gbt/Cargo.toml b/orchestrator/gbt/Cargo.toml index 785aedf5e..e37b7e57d 100644 --- a/orchestrator/gbt/Cargo.toml +++ b/orchestrator/gbt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gbt" -version = "1.9.3" +version = "1.10.0" authors = ["Justin Kilpatrick "] edition = "2018" license = "Apache-2.0"