Skip to content

Commit

Permalink
Run background relayer in test (#231)
Browse files Browse the repository at this point in the history
* Implement CanAssertEventualAmount

* Update test to use auto relayer

* Fix clone wrong relay

* Scaffold BuildStarknetIbcTransferMessage

* Scaffold IbcTokenTransferMessageBuilder types

* Leave implementation of IBC transfer message to later

* Use separate wallet for transferring token in test

* ICS transfer test with background auto relayer is working

* Use back main branch

* typo

---------

Co-authored-by: Farhad Shabani <[email protected]>
soareschen and Farhad-Shabani authored Jan 28, 2025
1 parent 34457fa commit ff5f389
Showing 8 changed files with 194 additions and 118 deletions.
62 changes: 31 additions & 31 deletions relayer/Cargo.lock

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

12 changes: 12 additions & 0 deletions relayer/crates/starknet-chain-components/src/components/chain.rs
Original file line number Diff line number Diff line change
@@ -42,7 +42,12 @@ pub use hermes_relayer_components::transaction::traits::submit_tx::TxSubmitterCo
pub use hermes_relayer_components::transaction::traits::types::transaction::TransactionTypeComponent;
pub use hermes_relayer_components::transaction::traits::types::tx_hash::TransactionHashTypeComponent;
pub use hermes_relayer_components::transaction::traits::types::tx_response::TxResponseTypeComponent;
use hermes_test_components::chain::impls::assert::default_assert_duration::ProvideDefaultPollAssertDuration;
use hermes_test_components::chain::impls::assert::poll_assert_eventual_amount::PollAssertEventualAmount;
use hermes_test_components::chain::impls::ibc_transfer::SendIbcTransferMessage;
pub use hermes_test_components::chain::traits::assert::eventual_amount::EventualAmountAsserterComponent;
pub use hermes_test_components::chain::traits::assert::poll_assert::PollAssertDurationGetterComponent;
use hermes_test_components::chain::traits::messages::ibc_transfer::IbcTokenTransferMessageBuilderComponent;
use hermes_test_components::chain::traits::queries::balance::BalanceQuerierComponent;
use hermes_test_components::chain::traits::transfer::ibc_transfer::TokenIbcTransferrerComponent;
use hermes_test_components::chain::traits::transfer::string_memo::ProvideStringMemoType;
@@ -63,6 +68,7 @@ use crate::impls::events::UseStarknetEvents;
use crate::impls::messages::channel::BuildStarknetChannelHandshakeMessages;
use crate::impls::messages::connection::BuildStarknetConnectionHandshakeMessages;
use crate::impls::messages::create_client::BuildCreateCometClientMessage;
use crate::impls::messages::ibc_transfer::BuildStarknetIbcTransferMessage;
use crate::impls::messages::packet::BuildStarknetPacketMessages;
use crate::impls::messages::update_client::BuildUpdateCometClientMessage;
use crate::impls::packet_fields::ReadPacketSrcStarknetFields;
@@ -391,5 +397,11 @@ cgp_preset! {
QueryPacketIsReceivedOnStarknet,
CounterpartyChainIdQuerierComponent:
QueryCosmosChainIdFromStarknetChannelId,
EventualAmountAsserterComponent:
PollAssertEventualAmount,
PollAssertDurationGetterComponent:
ProvideDefaultPollAssertDuration,
IbcTokenTransferMessageBuilderComponent:
BuildStarknetIbcTransferMessage,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use cgp::prelude::HasAsyncErrorType;
use hermes_chain_components::traits::types::height::HasHeightType;
use hermes_chain_components::traits::types::ibc::{HasChannelIdType, HasPortIdType};
use hermes_chain_components::traits::types::message::HasMessageType;
use hermes_chain_components::traits::types::timestamp::HasTimeoutType;
use hermes_chain_type_components::traits::types::address::HasAddressType;
use hermes_test_components::chain::traits::messages::ibc_transfer::IbcTokenTransferMessageBuilder;
use hermes_test_components::chain::traits::types::amount::HasAmountType;
use hermes_test_components::chain::traits::types::memo::HasMemoType;
use ibc::core::host::types::identifiers::PortId;
use ibc::primitives::Timestamp;

use crate::impls::types::message::StarknetMessage;
use crate::types::amount::StarknetAmount;
use crate::types::channel_id::ChannelId;

pub struct BuildStarknetIbcTransferMessage;

impl<Chain, Counterparty> IbcTokenTransferMessageBuilder<Chain, Counterparty>
for BuildStarknetIbcTransferMessage
where
Chain: HasAsyncErrorType
+ HasAmountType<Amount = StarknetAmount>
+ HasMemoType<Memo = Option<String>>
+ HasMessageType<Message = StarknetMessage>
+ HasHeightType<Height = u64>
+ HasTimeoutType<Timeout = Timestamp>
+ HasChannelIdType<Counterparty, ChannelId = ChannelId>
+ HasPortIdType<Counterparty, PortId = PortId>,
Counterparty: HasAddressType,
{
async fn build_ibc_token_transfer_message(
_chain: &Chain,
_channel_id: &ChannelId,
_port_id: &PortId,
_recipient_address: &Counterparty::Address,
_amount: &StarknetAmount,
_memo: &Option<String>,
_timeout_height: Option<&u64>,
_timeout_time: Option<&Timestamp>,
) -> Result<Chain::Message, Chain::Error> {
// FIXME: Implement the logic to build the token transfer message
todo!()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod channel;
pub mod connection;
pub mod create_client;
pub mod ibc_transfer;
pub mod packet;
pub mod update_client;
24 changes: 24 additions & 0 deletions relayer/crates/starknet-chain-components/src/impls/send_message.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::fmt::Debug;

use cgp::core::error::CanRaiseAsyncError;
use cgp::prelude::HasAsyncErrorType;
use hermes_chain_type_components::traits::types::message_response::HasMessageResponseType;
use hermes_relayer_components::chain::traits::send_message::MessageSender;
use hermes_relayer_components::chain::traits::types::message::HasMessageType;
@@ -30,6 +31,7 @@ where
+ HasTxResponseType<TxResponse = TxResponse>
+ HasMessageResponseType<MessageResponse = StarknetMessageResponse>
+ CanPollTxResponse
+ CanExtractMessageResponsesFromTxResponse
+ CanRaiseAsyncError<RevertedInvocation>
+ CanRaiseAsyncError<UnexpectedTransactionTraceType>,
{
@@ -45,6 +47,28 @@ where

let tx_response = chain.poll_tx_response(&tx_hash).await?;

Chain::extract_message_responses_from_tx_response(tx_response)
}
}

pub trait CanExtractMessageResponsesFromTxResponse:
HasTxResponseType + HasMessageResponseType + HasAsyncErrorType
{
fn extract_message_responses_from_tx_response(
tx_response: Self::TxResponse,
) -> Result<Vec<Self::MessageResponse>, Self::Error>;
}

impl<Chain> CanExtractMessageResponsesFromTxResponse for Chain
where
Chain: HasTxResponseType<TxResponse = TxResponse>
+ HasMessageResponseType<MessageResponse = StarknetMessageResponse>
+ CanRaiseAsyncError<RevertedInvocation>
+ CanRaiseAsyncError<UnexpectedTransactionTraceType>,
{
fn extract_message_responses_from_tx_response(
tx_response: TxResponse,
) -> Result<Vec<StarknetMessageResponse>, Chain::Error> {
match tx_response.trace {
TransactionTrace::Invoke(trace) => match trace.execute_invocation {
ExecuteInvocation::Success(invocation) => {
4 changes: 4 additions & 0 deletions relayer/crates/starknet-chain-context/src/contexts/chain.rs
Original file line number Diff line number Diff line change
@@ -165,6 +165,8 @@ use hermes_starknet_chain_components::types::events::packet::WriteAcknowledgemen
use hermes_starknet_chain_components::types::message_response::StarknetMessageResponse;
use hermes_starknet_chain_components::types::payloads::client::StarknetCreateClientPayloadOptions;
use hermes_starknet_test_components::impls::types::wallet::ProvideStarknetWalletType;
use hermes_test_components::chain::traits::assert::eventual_amount::CanAssertEventualAmount;
use hermes_test_components::chain::traits::messages::ibc_transfer::CanBuildIbcTokenTransferMessage;
use hermes_test_components::chain::traits::queries::balance::CanQueryBalance;
use hermes_test_components::chain::traits::types::address::HasAddressType;
use hermes_test_components::chain::traits::types::memo::HasMemoType;
@@ -424,6 +426,8 @@ pub trait CanUseStarknetChain:
+ CanQueryCounterpartyChainId<CosmosChain>
+ HasPacketDstChannelId<CosmosChain>
+ HasPacketDstPortId<CosmosChain>
+ CanAssertEventualAmount
+ CanBuildIbcTokenTransferMessage<CosmosChain>
// TODO(rano): need this to <Starknet as CanIbcTransferToken<CosmosChain>>::ibc_transfer_token
// + CanIbcTransferToken<CosmosChain>
{
4 changes: 4 additions & 0 deletions relayer/crates/starknet-chain-context/src/impls/error.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ use hermes_cairo_encoding_components::impls::encode_mut::bool::DecodeBoolError;
use hermes_cairo_encoding_components::impls::encode_mut::end::NonEmptyBuffer;
use hermes_cairo_encoding_components::impls::encode_mut::felt::UnexpectedEndOfBuffer;
use hermes_cairo_encoding_components::impls::encode_mut::variant::VariantIndexOutOfBound;
use hermes_chain_type_components::traits::types::address::HasAddressType;
use hermes_chain_type_components::traits::types::height::HasHeightType;
use hermes_error::handlers::debug::DebugError;
use hermes_error::handlers::display::DisplayError;
@@ -38,6 +39,8 @@ use hermes_starknet_chain_components::impls::queries::consensus_state::Consensus
use hermes_starknet_chain_components::impls::queries::contract_address::ContractAddressNotFound;
use hermes_starknet_chain_components::impls::send_message::UnexpectedTransactionTraceType;
use hermes_starknet_chain_components::types::event::UnknownEvent;
use hermes_test_components::chain::impls::assert::poll_assert_eventual_amount::EventualAmountTimeoutError;
use hermes_test_components::chain::traits::types::amount::HasAmountType;
use ibc::core::channel::types::error::ChannelError;
use ibc::core::client::types::error::ClientError;
use ibc::core::host::types::error::{DecodingError, IdentifierError};
@@ -98,6 +101,7 @@ delegate_components! {
EmptyMessageResponse,
ConsensusStateNotFound,
<'a> UnknownEvent<'a>,
<'a, Chain: HasAddressType + HasAmountType> EventualAmountTimeoutError<'a, Chain>,
<'a, Chain: HasTransactionHashType> TxNoResponseError<'a, Chain>,
<'a, Chain: HasClientIdType<Counterparty>, Counterparty: HasHeightType>
NoConsensusStateAtLessThanHeight<'a, Chain, Counterparty>,
160 changes: 73 additions & 87 deletions relayer/crates/starknet-integration-tests/src/tests/ics20.rs
Original file line number Diff line number Diff line change
@@ -5,13 +5,13 @@ use std::io::Write;
use std::path::PathBuf;
use std::time::SystemTime;

use cgp::extra::run::CanRun;
use cgp::prelude::*;
use flate2::write::GzEncoder;
use flate2::Compression;
use hermes_chain_components::traits::queries::chain_status::{
CanQueryChainHeight, CanQueryChainStatus,
};
use hermes_chain_components::traits::queries::chain_status::CanQueryChainStatus;
use hermes_chain_components::traits::queries::client_state::CanQueryClientStateWithLatestHeight;
use hermes_chain_components::traits::types::chain_id::HasChainId;
use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions;
use hermes_cosmos_chain_components::types::config::gas::dynamic_gas_config::DynamicGasConfig;
use hermes_cosmos_chain_components::types::config::gas::eip_type::EipQueryType;
@@ -29,10 +29,10 @@ use hermes_relayer_components::chain::traits::send_message::CanSendSingleMessage
use hermes_relayer_components::relay::impls::channel::bootstrap::CanBootstrapChannel;
use hermes_relayer_components::relay::impls::connection::bootstrap::CanBootstrapConnection;
use hermes_relayer_components::relay::traits::client_creator::CanCreateClient;
use hermes_relayer_components::relay::traits::event_relayer::CanRelayEvent;
use hermes_relayer_components::relay::traits::packet_relayer::CanRelayPacket;
use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget};
use hermes_relayer_components::transaction::traits::poll_tx_response::CanPollTxResponse;
use hermes_runtime_components::traits::fs::read_file::CanReadFileAsString;
use hermes_runtime_components::traits::sleep::CanSleep;
use hermes_starknet_chain_components::impls::subscription::CanCreateStarknetEventSubscription;
use hermes_starknet_chain_components::impls::types::message::StarknetMessage;
use hermes_starknet_chain_components::traits::contract::call::CanCallContract;
@@ -56,15 +56,18 @@ use hermes_starknet_chain_context::contexts::encoding::event::StarknetEventEncod
use hermes_starknet_relayer::contexts::cosmos_to_starknet_relay::CosmosToStarknetRelay;
use hermes_starknet_relayer::contexts::starknet_to_cosmos_relay::StarknetToCosmosRelay;
use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain;
use hermes_test_components::chain::traits::assert::eventual_amount::CanAssertEventualAmount;
use hermes_test_components::chain::traits::queries::balance::CanQueryBalance;
use hermes_test_components::chain::traits::transfer::ibc_transfer::CanIbcTransferToken;
use ibc::core::connection::types::version::Version as IbcConnectionVersion;
use ibc::core::host::types::identifiers::{ConnectionId, PortId as IbcPortId};
use poseidon::Poseidon3Hasher;
use sha2::{Digest, Sha256};
use starknet::accounts::Call;
use starknet::accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount};
use starknet::core::types::{Felt, U256};
use starknet::macros::{selector, short_string};
use starknet::providers::Provider;
use starknet::signers::{LocalWallet, SigningKey};
use tracing::info;

use crate::contexts::bootstrap::StarknetBootstrap;
@@ -286,12 +289,19 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {

info!("client state on Starknet: {:?}", client_state_on_starknet);

assert_eq!(&client_state_on_starknet.chain_id, cosmos_chain.chain_id());

let client_state_on_cosmos = cosmos_chain
.query_client_state_with_latest_height(PhantomData::<StarknetChain>, &cosmos_client_id)
.await?;

info!("client state on Cosmos: {:?}", client_state_on_cosmos);

assert_eq!(
&client_state_on_cosmos.client_state.chain_id,
starknet_chain.chain_id()
);

let ics20_contract_address = {
let owner_call_data = cairo_encoding.encode(&ibc_core_address)?;
let erc20_call_data = cairo_encoding.encode(&erc20_class_hash)?;
@@ -331,6 +341,20 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
starknet_client_id.clone(),
);

{
let starknet_to_cosmos_relay = starknet_to_cosmos_relay.clone();

let cosmos_to_starknet_relay = cosmos_to_starknet_relay.clone();

runtime.runtime.spawn(async move {
let _ = starknet_to_cosmos_relay.run().await;
});

runtime.runtime.spawn(async move {
let _ = cosmos_to_starknet_relay.run().await;
});
}

// connection handshake

let conn_init_option = CosmosInitConnectionOptions {
@@ -405,6 +429,16 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
let transfer_quantity = 1_000u128;
let denom_cosmos = &cosmos_chain_driver.genesis_config.transfer_denom;

let starknet_account_b = SingleOwnerAccount::new(
starknet_chain.rpc_client.clone(),
LocalWallet::from_signing_key(SigningKey::from_secret_scalar(
wallet_starknet_b.signing_key,
)),
wallet_starknet_b.account_address,
starknet_chain.rpc_client.chain_id().await?,
ExecutionEncoding::New,
);

let balance_cosmos_a_step_0 = cosmos_chain
.query_balance(address_cosmos_a, denom_cosmos)
.await?;
@@ -414,7 +448,7 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
balance_cosmos_a_step_0
);

let packet = <CosmosChain as CanIbcTransferToken<StarknetChain>>::ibc_transfer_token(
let _packet = <CosmosChain as CanIbcTransferToken<StarknetChain>>::ibc_transfer_token(
cosmos_chain,
&cosmos_channel_id,
&IbcPortId::transfer(),
@@ -425,7 +459,7 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
)
.await?;

cosmos_to_starknet_relay.relay_packet(&packet).await?;
// cosmos_to_starknet_relay.relay_packet(&packet).await?;

let balance_cosmos_a_step_1 = cosmos_chain
.query_balance(address_cosmos_a, denom_cosmos)
@@ -438,6 +472,11 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
balance_cosmos_a_step_1.quantity + transfer_quantity
);

// Wait for background relayer to relay packet.
// We cannot poll the balance here, because the IBC denom will only
// be relayed after the first token transfer.
runtime.sleep(Duration::from_secs(2)).await;

let ics20_token_address: Felt = {
let ibc_prefixed_denom = PrefixedDenom {
trace_path: vec![TracePrefix {
@@ -547,36 +586,17 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
calldata: call_data,
};

let message = StarknetMessage::new(call);

let response = starknet_chain.send_message(message).await?;
let execution = starknet_account_b.execute_v3(vec![call]);

let height = starknet_chain.query_chain_height().await?;
let tx_hash = execution.send().await?.transaction_hash;

for event in response.events {
<StarknetToCosmosRelay as CanRelayEvent<SourceTarget>>::relay_chain_event(
&starknet_to_cosmos_relay,
&height,
&event,
)
.await?;
}
starknet_chain.poll_tx_response(&tx_hash).await?;
};

let balance_cosmos_a_step_2 = cosmos_chain
.query_balance(address_cosmos_a, denom_cosmos)
cosmos_chain
.assert_eventual_amount(address_cosmos_a, &balance_cosmos_a_step_0)
.await?;

info!(
"cosmos balance after transfer back: {}",
balance_cosmos_a_step_2
);

assert_eq!(
balance_cosmos_a_step_0.quantity,
balance_cosmos_a_step_2.quantity
);

let balance_starknet_b_step_2 = starknet_chain
.query_token_balance(&ics20_token_address, address_starknet_b)
.await?;
@@ -590,20 +610,15 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {

// send starknet erc20 token to cosmos

let wallet_starknet_relayer = &starknet_chain_driver.relayer_wallet;
let address_starknet_relayer = &wallet_starknet_relayer.account_address;
let erc20_token_address = &starknet_chain_driver.genesis_config.transfer_denom;

info!("erc20 token address: {:?}", erc20_token_address);

let balance_starknet_relayer_step_0 = starknet_chain
.query_token_balance(erc20_token_address, address_starknet_relayer)
let balance_starknet_step_0 = starknet_chain
.query_token_balance(erc20_token_address, address_starknet_b)
.await?;

info!(
"erc20 balance on starknet: {}",
balance_starknet_relayer_step_0
);
info!("erc20 balance on starknet: {}", balance_starknet_step_0);

{
// approve ics20 contract to spend the tokens for address_starknet_b
@@ -618,11 +633,11 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
calldata: call_data,
};

let message = StarknetMessage::new(call);
let execution = starknet_account_b.execute_v3(vec![call]);

let response = starknet_chain.send_message(message).await?;
let tx_hash = execution.send().await?.transaction_hash;

info!("ERC20 approve response: {:?}", response);
starknet_chain.poll_tx_response(&tx_hash).await?;
}

// submit ics20 transfer from Starknet to Cosmos
@@ -635,7 +650,7 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {

let amount = transfer_quantity.into();

let sender = Participant::Native(*address_starknet_relayer);
let sender = Participant::Native(*address_starknet_b);

let receiver = Participant::External(address_cosmos_a.clone());

@@ -681,26 +696,13 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {
calldata: call_data,
};

let message = StarknetMessage::new(call);

let response = starknet_chain.send_message(message).await?;

info!("ICS20 send packet response: {:?}", response);
let execution = starknet_account_b.execute_v3(vec![call]);

let height = starknet_chain.query_chain_height().await?;
let tx_hash = execution.send().await?.transaction_hash;

for event in response.events {
<StarknetToCosmosRelay as CanRelayEvent<SourceTarget>>::relay_chain_event(
&starknet_to_cosmos_relay,
&height,
&event,
)
.await?;
}
starknet_chain.poll_tx_response(&tx_hash).await?;
};

// query balances

let cosmos_ibc_denom = derive_ibc_denom(
&ics20_port,
&cosmos_channel_id,
@@ -709,19 +711,15 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {

info!("cosmos ibc denom: {:?}", cosmos_ibc_denom);

let balance_cosmos_a_step_3 = cosmos_chain
.query_balance(address_cosmos_a, &cosmos_ibc_denom)
cosmos_chain
.assert_eventual_amount(
address_cosmos_a,
&Amount::new(transfer_quantity, cosmos_ibc_denom.clone()),
)
.await?;

info!(
"cosmos balance after transfer from starknet: {}",
balance_cosmos_a_step_3
);

assert_eq!(balance_cosmos_a_step_3.quantity, transfer_quantity);

let balance_starknet_relayer_step_3 = starknet_chain
.query_token_balance(erc20_token_address, address_starknet_relayer)
.query_token_balance(erc20_token_address, address_starknet_b)
.await?;

info!(
@@ -731,24 +729,22 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {

assert_eq!(
balance_starknet_relayer_step_3.quantity,
balance_starknet_relayer_step_0.quantity - transfer_quantity.into()
balance_starknet_step_0.quantity - transfer_quantity.into()
);

// send the tokens back to starknet

let packet = <CosmosChain as CanIbcTransferToken<StarknetChain>>::ibc_transfer_token(
let _packet = <CosmosChain as CanIbcTransferToken<StarknetChain>>::ibc_transfer_token(
cosmos_chain,
&cosmos_channel_id,
&IbcPortId::transfer(),
wallet_cosmos_a,
address_starknet_relayer,
address_starknet_b,
&Amount::new(transfer_quantity, cosmos_ibc_denom.clone()),
&None,
)
.await?;

cosmos_to_starknet_relay.relay_packet(&packet).await?;

let balance_cosmos_a_step_4 = cosmos_chain
.query_balance(address_cosmos_a, &cosmos_ibc_denom)
.await?;
@@ -760,20 +756,10 @@ fn test_starknet_ics20_contract() -> Result<(), Error> {

assert_eq!(balance_cosmos_a_step_4.quantity, 0u64.into());

let balance_starknet_relayer_step_4 = starknet_chain
.query_token_balance(erc20_token_address, address_starknet_relayer)
starknet_chain
.assert_eventual_amount(address_starknet_b, &balance_starknet_step_0)
.await?;

info!(
"starknet balance after transfer back to starknet: {}",
balance_starknet_relayer_step_4
);

assert_eq!(
balance_starknet_relayer_step_4.quantity,
balance_starknet_relayer_step_0.quantity
);

Ok(())
})
}

0 comments on commit ff5f389

Please sign in to comment.