Skip to content

Commit

Permalink
Ethermint support (informalsystems#1295)
Browse files Browse the repository at this point in the history
* added Ethermint support (fixes informalsystems#1267 informalsystems#1071)

- collected changes from informalsystems#1267 (comment)
- EthAccount definition was directly pasted into the proto library
(as different chains the same proto definition, but under a different package path)
- added a new configuration option that allows specifying the address derivation
as well as the proto type of public keys
(e.g. "/injective.crypto.v1beta1.ethsecp256k1.PubKey"
or "/ethermint.crypto.v1alpha1.ethsecp256k1.PubKey")

* added a comment for eth address and change query_account return type back to BaseAccount

* check the public key type in ethermint address generation

* added a check on `sign_msg`

* added comments + reordered example config

* added links with information for testing Ethermint

* adjusted a comment for `EthAccount`

Co-authored-by: Romain Ruetschi <[email protected]>
  • Loading branch information
tomtau and romac authored Sep 10, 2021
1 parent 3a8a14a commit 5651fa3
Show file tree
Hide file tree
Showing 14 changed files with 194 additions and 46 deletions.
4 changes: 4 additions & 0 deletions .changelog/unreleased/features/1267-ethermint-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Added post-Stargate (v0.5+) Ethermint support ([#1267] [#1071])

[#1267]: https://github.com/informalsystems/ibc-rs/issues/1267
[#1071]: https://github.com/informalsystems/ibc-rs/issues/1071
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ This folder contains the files required to run the End to end testing in [Github

The [End to end (e2e) testing workflow](https://github.com/informalsystems/ibc-rs/actions?query=workflow%3A%22End+to+End+testing%22) spins up two `gaia` chains (`ibc-0` and `ibc-1`) in Docker containers and one container that runs the relayer. There's a script that configures the relayer (e.g. configure light clients and add keys) and runs transactions and queries. A successful run of this script ensures that the relayer is working properly with two chains that support `IBC`.

### Testing Ethermint-based networks
At this moment, the automated E2E workflow does not spin up a network with the (post-Stargate) Ethermint module. In the meantime, you can test it manually by following one of the resources below:

- [the official documentation on ethermint.dev](https://ethermint.dev/quickstart/run_node.html)
- [using the tweaked E2E scripts from the Injective's fork](https://github.com/InjectiveLabs/ibc-rs/commit/669535617a6e45be9916387e292d45a77e7d23d2)
- [using the nix-based integration test scripts in the Cronos project](https://github.com/crypto-org-chain/cronos#quitck-start)

### Running an End to end (e2e) test locally

If you want to run the end to end test locally, you will need [Docker](https://www.docker.com/) installed on your machine.
Expand Down
15 changes: 15 additions & 0 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ account_prefix = 'cosmos'
# https://hermes.informal.systems/commands/keys/index.html#adding-keys
key_name = 'testkey'

# Specify the address type which determines:
# 1) address derivation;
# 2) how to retrieve and decode accounts and pubkeys;
# 3) the message signing method.
# The current configuration options are for Cosmos SDK and Ethermint.
#
# Example configuration for Ethermint:
#
# address_type = { derivation = 'ethermint', proto_type = { pk_type = '/injective.crypto.v1beta1.ethsecp256k1.PubKey' } }
#
# Default: { derivation = 'cosmos' }, i.e. address derivation as in Cosmos SDK
# Warning: This is an advanced feature! Modify with caution.
address_type = { derivation = 'cosmos' }

# Specify the store prefix used by the on-chain IBC modules. Required
# Recommended value for Cosmos SDK: 'ibc'
store_prefix = 'ibc'
Expand Down Expand Up @@ -168,3 +182,4 @@ max_tx_size = 2097152
clock_drift = '5s'
trusting_period = '14days'
trust_threshold = { numerator = '1', denominator = '3' }
address_type = { derivation = 'cosmos' }
2 changes: 1 addition & 1 deletion relayer-cli/src/commands/keys/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub fn restore_key(
config: &ChainConfig,
) -> Result<KeyEntry, Box<dyn std::error::Error>> {
let mut keyring = KeyRing::new(Store::Test, &config.account_prefix, &config.id)?;
let key_entry = keyring.key_from_mnemonic(mnemonic, hdpath)?;
let key_entry = keyring.key_from_mnemonic(mnemonic, hdpath, &config.address_type)?;

keyring.add_key(key_name, key_entry.clone())?;
Ok(key_entry)
Expand Down
1 change: 1 addition & 0 deletions relayer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ bitcoin = { version = "=0.27", features = ["use-serde"] }
tiny-bip39 = "0.8.0"
hdpath = { version = "0.6.0", features = ["with-bitcoin"] }
sha2 = "0.9.6"
tiny-keccak = { version = "2.0.2", features = ["keccak"], default-features = false }
ripemd160 = "0.9.1"
bech32 = "0.8.1"
itertools = "0.10.1"
Expand Down
47 changes: 28 additions & 19 deletions relayer/src/chain/cosmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use ibc::ics24_host::{ClientUpgradePath, Path, IBC_QUERY_PATH, SDK_UPGRADE_QUERY
use ibc::query::{QueryTxHash, QueryTxRequest};
use ibc::signer::Signer;
use ibc::Height as ICSHeight;
use ibc_proto::cosmos::auth::v1beta1::{BaseAccount, QueryAccountRequest};
use ibc_proto::cosmos::auth::v1beta1::{BaseAccount, EthAccount, QueryAccountRequest};
use ibc_proto::cosmos::base::tendermint::v1beta1::service_client::ServiceClient;
use ibc_proto::cosmos::base::tendermint::v1beta1::GetNodeInfoRequest;
use ibc_proto::cosmos::base::v1beta1::Coin;
Expand All @@ -71,7 +71,7 @@ use ibc_proto::ibc::core::connection::v1::{
QueryClientConnectionsRequest, QueryConnectionsRequest,
};

use crate::config::{ChainConfig, GasPrice};
use crate::config::{AddressType, ChainConfig, GasPrice};
use crate::error::Error;
use crate::event::monitor::{EventMonitor, EventReceiver};
use crate::keyring::{KeyEntry, KeyRing, Store};
Expand Down Expand Up @@ -523,14 +523,12 @@ impl CosmosSdkChain {
fn account(&mut self) -> Result<&mut BaseAccount, Error> {
if self.account == None {
let account = self.block_on(query_account(self, self.key()?.account))?;

debug!(
sequence = %account.sequence,
number = %account.account_number,
"[{}] send_tx: retrieved account",
self.id()
);

self.account = Some(account);
}

Expand All @@ -555,9 +553,13 @@ impl CosmosSdkChain {

fn signer(&self, sequence: u64) -> Result<SignerInfo, Error> {
let (_key, pk_buf) = self.key_and_bytes()?;
let pk_type = match &self.config.address_type {
AddressType::Cosmos => "/cosmos.crypto.secp256k1.PubKey".to_string(),
AddressType::Ethermint { pk_type } => pk_type.clone(),
};
// Create a MsgSend proto Any message
let pk_any = Any {
type_url: "/cosmos.crypto.secp256k1.PubKey".to_string(),
type_url: pk_type,
value: pk_buf,
};

Expand Down Expand Up @@ -610,7 +612,11 @@ impl CosmosSdkChain {
// Sign doc
let signed = self
.keybase
.sign_msg(&self.config.key_name, signdoc_buf)
.sign_msg(
&self.config.key_name,
signdoc_buf,
&self.config.address_type,
)
.map_err(Error::key_base)?;

Ok(signed)
Expand Down Expand Up @@ -1948,19 +1954,22 @@ async fn query_account(chain: &CosmosSdkChain, address: String) -> Result<BaseAc
let request = tonic::Request::new(QueryAccountRequest { address });

let response = client.account(request).await;

let base_account = BaseAccount::decode(
response
.map_err(Error::grpc_status)?
.into_inner()
.account
.unwrap()
.value
.as_slice(),
)
.map_err(|e| Error::protobuf_decode("BaseAccount".to_string(), e))?;

Ok(base_account)
let resp_account = response
.map_err(Error::grpc_status)?
.into_inner()
.account
.unwrap();
if resp_account.type_url == "/cosmos.auth.v1beta1.BaseAccount" {
Ok(BaseAccount::decode(resp_account.value.as_slice())
.map_err(|e| Error::protobuf_decode("BaseAccount".to_string(), e))?)
} else if resp_account.type_url.ends_with(".EthAccount") {
Ok(EthAccount::decode(resp_account.value.as_slice())
.map_err(|e| Error::protobuf_decode("EthAccount".to_string(), e))?
.base_account
.ok_or_else(Error::empty_base_account)?)
} else {
Err(Error::unknown_account_type(resp_account.type_url))
}
}

fn encode_to_bech32(address: &str, account_prefix: &str) -> Result<String, Error> {
Expand Down
3 changes: 2 additions & 1 deletion relayer/src/chain/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ pub mod test_utils {

use ibc::ics24_host::identifier::ChainId;

use crate::config::{ChainConfig, GasPrice, PacketFilter};
use crate::config::{AddressType, ChainConfig, GasPrice, PacketFilter};

/// Returns a very minimal chain configuration, to be used in initializing `MockChain`s.
pub fn get_basic_chain_config(id: &str) -> ChainConfig {
Expand All @@ -423,6 +423,7 @@ pub mod test_utils {
trusting_period: Duration::from_secs(14 * 24 * 60 * 60), // 14 days
trust_threshold: Default::default(),
packet_filter: PacketFilter::default(),
address_type: AddressType::default(),
}
}
}
33 changes: 33 additions & 0 deletions relayer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,37 @@ impl Default for RestConfig {
}
}

/// It defines the address generation method
/// TODO: Ethermint `pk_type` to be restricted
/// after the Cosmos SDK release with ethsecp256k1
/// https://github.com/cosmos/cosmos-sdk/pull/9981
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[serde(
rename_all = "lowercase",
tag = "derivation",
content = "proto_type",
deny_unknown_fields
)]
pub enum AddressType {
Cosmos,
Ethermint { pk_type: String },
}

impl Default for AddressType {
fn default() -> Self {
AddressType::Cosmos
}
}

impl fmt::Display for AddressType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AddressType::Cosmos => write!(f, "cosmos"),
AddressType::Ethermint { .. } => write!(f, "ethermint"),
}
}
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ChainConfig {
Expand Down Expand Up @@ -291,6 +322,8 @@ pub struct ChainConfig {
pub gas_price: GasPrice,
#[serde(default)]
pub packet_filter: PacketFilter,
#[serde(default)]
pub address_type: AddressType,
}

/// Attempt to load and parse the TOML config file as a `Config`.
Expand Down
13 changes: 13 additions & 0 deletions relayer/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,19 @@ define_error! {
format!("Hermes health check failed while verifying the application compatibility for chain {0}:{1}; caused by: {2}",
e.chain_id, e.address, e.cause)
},

UnknownAccountType
{
type_url: String
}
|e| {
format!("Failed to deserialize account of an unknown protobuf type: {0}",
e.type_url)
},

EmptyBaseAccount
|_| { "Empty BaseAccount within EthAccount" },

}
}

Expand Down
Loading

0 comments on commit 5651fa3

Please sign in to comment.