From c722b398012088546c4264363ddb67c384a706e4 Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 9 Sep 2024 04:27:36 +0000 Subject: [PATCH 01/32] Add method to fetch deposit events from ERC20Treasury --- ethereum/client/src/abi.rs | 6 ++++ ethereum/client/src/lib.rs | 69 +++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/ethereum/client/src/abi.rs b/ethereum/client/src/abi.rs index 6c887496..d9cf77e4 100644 --- a/ethereum/client/src/abi.rs +++ b/ethereum/client/src/abi.rs @@ -38,6 +38,12 @@ sol! { } } +sol!( + #[sol(rpc)] + IERC20Treasury, + "../out/IERC20Treasury.sol/IERC20Treasury.json" +); + impl ContentMessage { pub fn to_bytes(&self) -> Vec { let mut ret: Vec = Vec::with_capacity(32 + 32 + 20 + self.data.len()); diff --git a/ethereum/client/src/lib.rs b/ethereum/client/src/lib.rs index fc5a9164..231129ed 100644 --- a/ethereum/client/src/lib.rs +++ b/ethereum/client/src/lib.rs @@ -1,7 +1,5 @@ use std::{marker::PhantomData, str::FromStr}; -use abi::IRelayer::MerkleRoot; - use alloy::{ contract::Event, network::{Ethereum, EthereumWallet}, @@ -18,22 +16,22 @@ use alloy::{ Transport, }, }; - +use primitive_types::{H160, H256}; use reqwest::Url; -pub use error::Error; - -use crate::abi::{ - ContentMessage, IMessageQueue, IMessageQueue::IMessageQueueInstance, IRelayer, - IRelayer::IRelayerInstance, -}; pub use alloy::primitives::TxHash; #[cfg(test)] mod tests; mod abi; +use abi::{ + ContentMessage, IERC20Treasury, IMessageQueue, IMessageQueue::IMessageQueueInstance, IRelayer, + IRelayer::IRelayerInstance, IRelayer::MerkleRoot, +}; + pub mod error; +pub use error::Error; type ProviderType = FillProvider< JoinFill< @@ -58,6 +56,14 @@ pub struct MerkleRootEntry { pub block_number: u64, } +#[derive(Debug, Clone)] +pub struct DepositEventEntry { + pub from: H160, + pub to: H256, + pub token: H160, + pub amount: primitive_types::U256, +} + #[derive(Debug)] pub enum TxStatus { Finalized, @@ -152,6 +158,32 @@ impl EthApi { self.contracts.fetch_merkle_roots_in_range(from, to).await } + pub async fn fetch_deposit_events( + &self, + contract_address: H160, + block: u64, + ) -> Result, Error> { + Ok(self + .contracts + .fetch_deposit_events(Address::from_slice(contract_address.as_bytes()), block) + .await? + .into_iter() + .map( + |IERC20Treasury::Deposit { + from, + to, + token, + amount, + }| DepositEventEntry { + from: H160(*from.0), + to: H256(to.0), + token: H160(*token.0), + amount: primitive_types::U256::from_little_endian(&amount.to_le_bytes_vec()), + }, + ) + .collect()) + } + pub async fn block_number(&self) -> Result { self.contracts.block_number().await } @@ -285,6 +317,25 @@ where .collect()) } + pub async fn fetch_deposit_events( + &self, + contract_address: Address, + block: u64, + ) -> Result, Error> { + let filter = Filter::new() + .address(contract_address) + .event_signature(IERC20Treasury::Deposit::SIGNATURE_HASH) + .from_block(block) + .to_block(block); + + let event: Event = + Event::new(self.provider.clone(), filter); + + let logs = event.query().await.map_err(Error::ErrorQueryingEvent)?; + + Ok(logs.into_iter().map(|(event, _)| event).collect()) + } + #[allow(clippy::too_many_arguments)] pub async fn provide_content_message( &self, From 8188931f3b39fbfe9a5dbbbc2a77c10817d4df72 Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 9 Sep 2024 05:10:06 +0000 Subject: [PATCH 02/32] Re-arrange modules --- relayer/src/main.rs | 2 +- .../block_listener.rs} | 8 ++++---- .../ethereum/deposit_event_extractor.rs | 1 + .../{ => ethereum}/merkle_root_extractor.rs | 4 +++- .../message_sender}/era.rs | 0 .../message_sender}/mod.rs | 8 ++++---- .../message_relayer/common/ethereum/mod.rs | 4 ++++ .../block_listener.rs} | 8 ++++---- .../message_paid_event_extractor.rs | 2 +- .../message_queued_event_extractor.rs | 2 +- .../src/message_relayer/common/gear/mod.rs | 3 +++ relayer/src/message_relayer/common/mod.rs | 8 ++------ .../eth_to_gear/all_token_transfers.rs | 1 + .../src/message_relayer/eth_to_gear/mod.rs | 1 + .../{ => gear_to_eth}/all_token_transfers.rs | 17 +++++++++++------ .../src/message_relayer/gear_to_eth/mod.rs | 2 ++ .../{ => gear_to_eth}/paid_token_transfers.rs | 19 ++++++++++++------- relayer/src/message_relayer/mod.rs | 4 ++-- 18 files changed, 57 insertions(+), 37 deletions(-) rename relayer/src/message_relayer/common/{ethereum_block_listener.rs => ethereum/block_listener.rs} (93%) create mode 100644 relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs rename relayer/src/message_relayer/common/{ => ethereum}/merkle_root_extractor.rs (96%) rename relayer/src/message_relayer/common/{ethereum_message_sender => ethereum/message_sender}/era.rs (100%) rename relayer/src/message_relayer/common/{ethereum_message_sender => ethereum/message_sender}/mod.rs (96%) create mode 100644 relayer/src/message_relayer/common/ethereum/mod.rs rename relayer/src/message_relayer/common/{gear_block_listener.rs => gear/block_listener.rs} (94%) rename relayer/src/message_relayer/common/{ => gear}/message_paid_event_extractor.rs (97%) rename relayer/src/message_relayer/common/{ => gear}/message_queued_event_extractor.rs (97%) create mode 100644 relayer/src/message_relayer/common/gear/mod.rs create mode 100644 relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs create mode 100644 relayer/src/message_relayer/eth_to_gear/mod.rs rename relayer/src/message_relayer/{ => gear_to_eth}/all_token_transfers.rs (82%) create mode 100644 relayer/src/message_relayer/gear_to_eth/mod.rs rename relayer/src/message_relayer/{ => gear_to_eth}/paid_token_transfers.rs (85%) diff --git a/relayer/src/main.rs b/relayer/src/main.rs index 775da11c..192fd42c 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -3,7 +3,7 @@ extern crate pretty_env_logger; use std::time::Duration; use clap::{Args, Parser, Subcommand}; -use message_relayer::{all_token_transfers, paid_token_transfers}; +use message_relayer::gear_to_eth::{all_token_transfers, paid_token_transfers}; use pretty_env_logger::env_logger::fmt::TimestampPrecision; use ethereum_client::EthApi; diff --git a/relayer/src/message_relayer/common/ethereum_block_listener.rs b/relayer/src/message_relayer/common/ethereum/block_listener.rs similarity index 93% rename from relayer/src/message_relayer/common/ethereum_block_listener.rs rename to relayer/src/message_relayer/common/ethereum/block_listener.rs index cb02f8de..07499201 100644 --- a/relayer/src/message_relayer/common/ethereum_block_listener.rs +++ b/relayer/src/message_relayer/common/ethereum/block_listener.rs @@ -7,18 +7,18 @@ use ethereum_client::EthApi; use prometheus::IntGauge; use utils_prometheus::{impl_metered_service, MeteredService}; -use super::EthereumBlockNumber; +use crate::message_relayer::common::EthereumBlockNumber; const ETHEREUM_BLOCK_TIME_APPROX: Duration = Duration::from_secs(12); -pub struct EthereumBlockListener { +pub struct BlockListener { eth_api: EthApi, from_block: u64, metrics: Metrics, } -impl MeteredService for EthereumBlockListener { +impl MeteredService for BlockListener { fn get_sources(&self) -> impl IntoIterator> { self.metrics.get_sources() } @@ -33,7 +33,7 @@ impl_metered_service! { } } -impl EthereumBlockListener { +impl BlockListener { pub fn new(eth_api: EthApi, from_block: u64) -> Self { Self { eth_api, diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -0,0 +1 @@ + diff --git a/relayer/src/message_relayer/common/merkle_root_extractor.rs b/relayer/src/message_relayer/common/ethereum/merkle_root_extractor.rs similarity index 96% rename from relayer/src/message_relayer/common/merkle_root_extractor.rs rename to relayer/src/message_relayer/common/ethereum/merkle_root_extractor.rs index 42b55ac6..235d25df 100644 --- a/relayer/src/message_relayer/common/merkle_root_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/merkle_root_extractor.rs @@ -6,7 +6,9 @@ use gear_rpc_client::GearApi; use prometheus::IntGauge; use utils_prometheus::{impl_metered_service, MeteredService}; -use super::{AuthoritySetId, EthereumBlockNumber, GearBlockNumber, RelayedMerkleRoot}; +use crate::message_relayer::common::{ + AuthoritySetId, EthereumBlockNumber, GearBlockNumber, RelayedMerkleRoot, +}; pub struct MerkleRootExtractor { eth_api: EthApi, diff --git a/relayer/src/message_relayer/common/ethereum_message_sender/era.rs b/relayer/src/message_relayer/common/ethereum/message_sender/era.rs similarity index 100% rename from relayer/src/message_relayer/common/ethereum_message_sender/era.rs rename to relayer/src/message_relayer/common/ethereum/message_sender/era.rs diff --git a/relayer/src/message_relayer/common/ethereum_message_sender/mod.rs b/relayer/src/message_relayer/common/ethereum/message_sender/mod.rs similarity index 96% rename from relayer/src/message_relayer/common/ethereum_message_sender/mod.rs rename to relayer/src/message_relayer/common/ethereum/message_sender/mod.rs index a0df272f..510b72c8 100644 --- a/relayer/src/message_relayer/common/ethereum_message_sender/mod.rs +++ b/relayer/src/message_relayer/common/ethereum/message_sender/mod.rs @@ -14,9 +14,9 @@ use crate::message_relayer::common::{AuthoritySetId, MessageInBlock}; mod era; use era::{Era, Metrics as EraMetrics}; -use super::RelayedMerkleRoot; +use crate::message_relayer::common::RelayedMerkleRoot; -pub struct EthereumMessageSender { +pub struct MessageSender { eth_api: EthApi, gear_api: GearApi, @@ -24,7 +24,7 @@ pub struct EthereumMessageSender { era_metrics: EraMetrics, } -impl MeteredService for EthereumMessageSender { +impl MeteredService for MessageSender { fn get_sources(&self) -> impl IntoIterator> { self.metrics .get_sources() @@ -46,7 +46,7 @@ impl_metered_service! { } } -impl EthereumMessageSender { +impl MessageSender { pub fn new(eth_api: EthApi, gear_api: GearApi) -> Self { Self { eth_api, diff --git a/relayer/src/message_relayer/common/ethereum/mod.rs b/relayer/src/message_relayer/common/ethereum/mod.rs new file mode 100644 index 00000000..ba28c5a9 --- /dev/null +++ b/relayer/src/message_relayer/common/ethereum/mod.rs @@ -0,0 +1,4 @@ +pub mod block_listener; +pub mod deposit_event_extractor; +pub mod merkle_root_extractor; +pub mod message_sender; diff --git a/relayer/src/message_relayer/common/gear_block_listener.rs b/relayer/src/message_relayer/common/gear/block_listener.rs similarity index 94% rename from relayer/src/message_relayer/common/gear_block_listener.rs rename to relayer/src/message_relayer/common/gear/block_listener.rs index 5e1b932a..ec5ba037 100644 --- a/relayer/src/message_relayer/common/gear_block_listener.rs +++ b/relayer/src/message_relayer/common/gear/block_listener.rs @@ -7,18 +7,18 @@ use gear_rpc_client::GearApi; use prometheus::IntGauge; use utils_prometheus::{impl_metered_service, MeteredService}; -use super::GearBlockNumber; +use crate::message_relayer::common::GearBlockNumber; const GEAR_BLOCK_TIME_APPROX: Duration = Duration::from_secs(3); -pub struct GearBlockListener { +pub struct BlockListener { gear_api: GearApi, from_block: u32, metrics: Metrics, } -impl MeteredService for GearBlockListener { +impl MeteredService for BlockListener { fn get_sources(&self) -> impl IntoIterator> { self.metrics.get_sources() } @@ -33,7 +33,7 @@ impl_metered_service! { } } -impl GearBlockListener { +impl BlockListener { pub fn new(gear_api: GearApi, from_block: u32) -> Self { Self { gear_api, diff --git a/relayer/src/message_relayer/common/message_paid_event_extractor.rs b/relayer/src/message_relayer/common/gear/message_paid_event_extractor.rs similarity index 97% rename from relayer/src/message_relayer/common/message_paid_event_extractor.rs rename to relayer/src/message_relayer/common/gear/message_paid_event_extractor.rs index 1a0e0cc8..0f601c33 100644 --- a/relayer/src/message_relayer/common/message_paid_event_extractor.rs +++ b/relayer/src/message_relayer/common/gear/message_paid_event_extractor.rs @@ -7,7 +7,7 @@ use prometheus::IntCounter; use sails_rs::events::EventIo; use utils_prometheus::{impl_metered_service, MeteredService}; -use super::{GearBlockNumber, PaidMessage}; +use crate::message_relayer::common::{GearBlockNumber, PaidMessage}; #[allow(dead_code)] mod bridging_payment_client { diff --git a/relayer/src/message_relayer/common/message_queued_event_extractor.rs b/relayer/src/message_relayer/common/gear/message_queued_event_extractor.rs similarity index 97% rename from relayer/src/message_relayer/common/message_queued_event_extractor.rs rename to relayer/src/message_relayer/common/gear/message_queued_event_extractor.rs index 140afb4e..cdb91b2c 100644 --- a/relayer/src/message_relayer/common/message_queued_event_extractor.rs +++ b/relayer/src/message_relayer/common/gear/message_queued_event_extractor.rs @@ -5,7 +5,7 @@ use gear_rpc_client::GearApi; use prometheus::IntCounter; use utils_prometheus::{impl_metered_service, MeteredService}; -use super::{GearBlockNumber, MessageInBlock}; +use crate::message_relayer::common::{GearBlockNumber, MessageInBlock}; pub struct MessageQueuedEventExtractor { gear_api: GearApi, diff --git a/relayer/src/message_relayer/common/gear/mod.rs b/relayer/src/message_relayer/common/gear/mod.rs new file mode 100644 index 00000000..8a8df707 --- /dev/null +++ b/relayer/src/message_relayer/common/gear/mod.rs @@ -0,0 +1,3 @@ +pub mod block_listener; +pub mod message_paid_event_extractor; +pub mod message_queued_event_extractor; diff --git a/relayer/src/message_relayer/common/mod.rs b/relayer/src/message_relayer/common/mod.rs index 8924cfdc..6c608857 100644 --- a/relayer/src/message_relayer/common/mod.rs +++ b/relayer/src/message_relayer/common/mod.rs @@ -1,12 +1,8 @@ use gear_rpc_client::dto::Message; use primitive_types::H256; -pub mod ethereum_block_listener; -pub mod ethereum_message_sender; -pub mod gear_block_listener; -pub mod merkle_root_extractor; -pub mod message_paid_event_extractor; -pub mod message_queued_event_extractor; +pub mod ethereum; +pub mod gear; pub mod paid_messages_filter; #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, derive_more::Display)] diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs new file mode 100644 index 00000000..70b786d1 --- /dev/null +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -0,0 +1 @@ +// TODO diff --git a/relayer/src/message_relayer/eth_to_gear/mod.rs b/relayer/src/message_relayer/eth_to_gear/mod.rs new file mode 100644 index 00000000..7fb6b8d1 --- /dev/null +++ b/relayer/src/message_relayer/eth_to_gear/mod.rs @@ -0,0 +1 @@ +pub mod all_token_transfers; diff --git a/relayer/src/message_relayer/all_token_transfers.rs b/relayer/src/message_relayer/gear_to_eth/all_token_transfers.rs similarity index 82% rename from relayer/src/message_relayer/all_token_transfers.rs rename to relayer/src/message_relayer/gear_to_eth/all_token_transfers.rs index 19cb4404..9fc7d818 100644 --- a/relayer/src/message_relayer/all_token_transfers.rs +++ b/relayer/src/message_relayer/gear_to_eth/all_token_transfers.rs @@ -4,10 +4,15 @@ use ethereum_client::EthApi; use gear_rpc_client::GearApi; use utils_prometheus::MeteredService; -use super::common::{ - ethereum_block_listener::EthereumBlockListener, ethereum_message_sender::EthereumMessageSender, - gear_block_listener::GearBlockListener, merkle_root_extractor::MerkleRootExtractor, - message_queued_event_extractor::MessageQueuedEventExtractor, +use crate::message_relayer::common::{ + ethereum::{ + block_listener::BlockListener as EthereumBlockListener, + merkle_root_extractor::MerkleRootExtractor, message_sender::MessageSender, + }, + gear::{ + block_listener::BlockListener as GearBlockListener, + message_queued_event_extractor::MessageQueuedEventExtractor, + }, }; pub struct Relayer { @@ -17,7 +22,7 @@ pub struct Relayer { message_sent_listener: MessageQueuedEventExtractor, merkle_root_extractor: MerkleRootExtractor, - message_sender: EthereumMessageSender, + message_sender: MessageSender, } impl MeteredService for Relayer { @@ -54,7 +59,7 @@ impl Relayer { let merkle_root_listener = MerkleRootExtractor::new(eth_api.clone(), gear_api.clone()); - let message_sender = EthereumMessageSender::new(eth_api, gear_api); + let message_sender = MessageSender::new(eth_api, gear_api); Ok(Self { gear_block_listener, diff --git a/relayer/src/message_relayer/gear_to_eth/mod.rs b/relayer/src/message_relayer/gear_to_eth/mod.rs new file mode 100644 index 00000000..a85883fb --- /dev/null +++ b/relayer/src/message_relayer/gear_to_eth/mod.rs @@ -0,0 +1,2 @@ +pub mod all_token_transfers; +pub mod paid_token_transfers; diff --git a/relayer/src/message_relayer/paid_token_transfers.rs b/relayer/src/message_relayer/gear_to_eth/paid_token_transfers.rs similarity index 85% rename from relayer/src/message_relayer/paid_token_transfers.rs rename to relayer/src/message_relayer/gear_to_eth/paid_token_transfers.rs index 09dc3968..82cf4cff 100644 --- a/relayer/src/message_relayer/paid_token_transfers.rs +++ b/relayer/src/message_relayer/gear_to_eth/paid_token_transfers.rs @@ -5,11 +5,16 @@ use gear_rpc_client::GearApi; use primitive_types::H256; use utils_prometheus::MeteredService; -use super::common::{ - ethereum_block_listener::EthereumBlockListener, ethereum_message_sender::EthereumMessageSender, - gear_block_listener::GearBlockListener, merkle_root_extractor::MerkleRootExtractor, - message_paid_event_extractor::MessagePaidEventExtractor, - message_queued_event_extractor::MessageQueuedEventExtractor, +use crate::message_relayer::common::{ + ethereum::{ + block_listener::BlockListener as EthereumBlockListener, + merkle_root_extractor::MerkleRootExtractor, message_sender::MessageSender, + }, + gear::{ + block_listener::BlockListener as GearBlockListener, + message_paid_event_extractor::MessagePaidEventExtractor, + message_queued_event_extractor::MessageQueuedEventExtractor, + }, paid_messages_filter::PaidMessagesFilter, }; @@ -23,7 +28,7 @@ pub struct Relayer { paid_messages_filter: PaidMessagesFilter, merkle_root_extractor: MerkleRootExtractor, - message_sender: EthereumMessageSender, + message_sender: MessageSender, } impl MeteredService for Relayer { @@ -74,7 +79,7 @@ impl Relayer { let merkle_root_listener = MerkleRootExtractor::new(eth_api.clone(), gear_api.clone()); - let message_sender = EthereumMessageSender::new(eth_api, gear_api); + let message_sender = MessageSender::new(eth_api, gear_api); Ok(Self { gear_block_listener, diff --git a/relayer/src/message_relayer/mod.rs b/relayer/src/message_relayer/mod.rs index d6dca88f..ffd77c61 100644 --- a/relayer/src/message_relayer/mod.rs +++ b/relayer/src/message_relayer/mod.rs @@ -1,4 +1,4 @@ mod common; -pub mod all_token_transfers; -pub mod paid_token_transfers; +pub mod eth_to_gear; +pub mod gear_to_eth; From 354b91e0d54c8c16ec38a1954dff1c2b073eebfc Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 9 Sep 2024 05:31:17 +0000 Subject: [PATCH 03/32] deposit event extractor --- ethereum/client/src/lib.rs | 30 ++++-- .../ethereum/deposit_event_extractor.rs | 100 ++++++++++++++++++ relayer/src/message_relayer/common/mod.rs | 13 ++- 3 files changed, 134 insertions(+), 9 deletions(-) diff --git a/ethereum/client/src/lib.rs b/ethereum/client/src/lib.rs index 231129ed..bcef3775 100644 --- a/ethereum/client/src/lib.rs +++ b/ethereum/client/src/lib.rs @@ -62,6 +62,8 @@ pub struct DepositEventEntry { pub to: H256, pub token: H160, pub amount: primitive_types::U256, + + pub tx_hash: TxHash, } #[derive(Debug)] @@ -169,16 +171,20 @@ impl EthApi { .await? .into_iter() .map( - |IERC20Treasury::Deposit { - from, - to, - token, - amount, - }| DepositEventEntry { + |( + IERC20Treasury::Deposit { + from, + to, + token, + amount, + }, + tx_hash, + )| DepositEventEntry { from: H160(*from.0), to: H256(to.0), token: H160(*token.0), amount: primitive_types::U256::from_little_endian(&amount.to_le_bytes_vec()), + tx_hash, }, ) .collect()) @@ -321,7 +327,7 @@ where &self, contract_address: Address, block: u64, - ) -> Result, Error> { + ) -> Result, Error> { let filter = Filter::new() .address(contract_address) .event_signature(IERC20Treasury::Deposit::SIGNATURE_HASH) @@ -333,7 +339,15 @@ where let logs = event.query().await.map_err(Error::ErrorQueryingEvent)?; - Ok(logs.into_iter().map(|(event, _)| event).collect()) + logs.into_iter() + .map(|(event, log)| { + Ok(( + event, + log.transaction_hash + .ok_or(Error::ErrorFetchingTransaction)?, + )) + }) + .collect() } #[allow(clippy::too_many_arguments)] diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index 8b137891..a1e2ae74 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -1 +1,101 @@ +use std::sync::mpsc::{channel, Receiver, Sender}; +use ethereum_client::{DepositEventEntry, EthApi}; +use futures::executor::block_on; +use prometheus::IntCounter; +use sails_rs::H160; +use utils_prometheus::{impl_metered_service, MeteredService}; + +use crate::message_relayer::common::{ERC20DepositTx, EthereumBlockNumber}; + +pub struct DepositEventExtractor { + eth_api: EthApi, + erc20_treasury_address: H160, + + metrics: Metrics, +} + +impl MeteredService for DepositEventExtractor { + fn get_sources(&self) -> impl IntoIterator> { + self.metrics.get_sources() + } +} + +impl_metered_service! { + struct Metrics { + total_deposits_found: IntCounter = IntCounter::new( + "deposit_event_extractor_total_deposits_found", + "Total amount of deposit events discovered", + ), + } +} + +impl DepositEventExtractor { + pub fn new(eth_api: EthApi, erc20_treasury_address: H160) -> Self { + Self { + eth_api, + erc20_treasury_address, + + metrics: Metrics::new(), + } + } + + pub fn run(self, blocks: Receiver) -> Receiver { + let (sender, receiver) = channel(); + + tokio::task::spawn_blocking(move || loop { + let res = block_on(self.run_inner(&sender, &blocks)); + if let Err(err) = res { + log::error!("Message queued extractor failed: {}", err); + } + }); + + receiver + } + + async fn run_inner( + &self, + sender: &Sender, + blocks: &Receiver, + ) -> anyhow::Result<()> { + loop { + for block in blocks.try_iter() { + self.process_block_events(block, sender).await?; + } + } + } + + async fn process_block_events( + &self, + block: EthereumBlockNumber, + sender: &Sender, + ) -> anyhow::Result<()> { + let events = self + .eth_api + .fetch_deposit_events(self.erc20_treasury_address, block.0) + .await?; + + self.metrics + .total_deposits_found + .inc_by(events.len() as u64); + + for DepositEventEntry { + from, + to, + token, + amount, + tx_hash, + } in events + { + sender.send(ERC20DepositTx { + from, + to, + token, + amount, + tx_hash, + })?; + } + + Ok(()) + } +} diff --git a/relayer/src/message_relayer/common/mod.rs b/relayer/src/message_relayer/common/mod.rs index 6c608857..fa9042fb 100644 --- a/relayer/src/message_relayer/common/mod.rs +++ b/relayer/src/message_relayer/common/mod.rs @@ -1,5 +1,6 @@ +use ethereum_client::TxHash; use gear_rpc_client::dto::Message; -use primitive_types::H256; +use primitive_types::{H160, H256, U256}; pub mod ethereum; pub mod gear; @@ -31,3 +32,13 @@ pub struct RelayedMerkleRoot { pub block: GearBlockNumber, pub authority_set_id: AuthoritySetId, } + +#[derive(Clone, Debug)] +pub struct ERC20DepositTx { + pub from: H160, + pub to: H256, + pub token: H160, + pub amount: U256, + + pub tx_hash: TxHash, +} From 92e0788e7818f5bb8329ae49cc72b11b950fc2e5 Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 9 Sep 2024 08:11:36 +0000 Subject: [PATCH 04/32] Checkpoint extractor --- gear-rpc-client/src/lib.rs | 2 +- .../common/gear/checkpoints_extractor.rs | 136 ++++++++++++++++++ .../src/message_relayer/common/gear/mod.rs | 1 + 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 relayer/src/message_relayer/common/gear/checkpoints_extractor.rs diff --git a/gear-rpc-client/src/lib.rs b/gear-rpc-client/src/lib.rs index e8e984de..74a2b516 100644 --- a/gear-rpc-client/src/lib.rs +++ b/gear-rpc-client/src/lib.rs @@ -55,7 +55,7 @@ type GearHeader = sp_runtime::generic::Header, + + metrics: Metrics, +} + +impl MeteredService for CheckpointsExtractor { + fn get_sources(&self) -> impl IntoIterator> { + self.metrics.get_sources() + } +} + +impl_metered_service! { + struct Metrics { + latest_checkpoint_slot: IntGauge = IntGauge::new( + "checkpoint_extractor_latest_checkpoint_slot", + "Latest slot found in checkpoint light client program state", + ), + } +} + +impl CheckpointsExtractor { + pub fn new(gear_api: GearApi, checkpoint_light_client_address: H256) -> Self { + Self { + checkpoint_light_client_address, + gear_api, + latest_checkpoint: None, + metrics: Metrics::new(), + } + } + + pub fn run(mut self, blocks: Receiver) -> Receiver { + let (sender, receiver) = channel(); + + tokio::task::spawn_blocking(move || loop { + let res = block_on(self.run_inner(&sender, &blocks)); + if let Err(err) = res { + log::error!("Message paid event extractor failed: {}", err); + } + }); + + receiver + } + + async fn run_inner( + &mut self, + sender: &Sender, + blocks: &Receiver, + ) -> anyhow::Result<()> { + loop { + for block in blocks.try_iter() { + self.process_block_events(block.0, sender).await?; + } + } + } + + async fn process_block_events( + &mut self, + block: u32, + sender: &Sender, + ) -> anyhow::Result<()> { + let block_hash = self.gear_api.block_number_to_hash(block).await?; + + let request = StateRequest { + order: Order::Reverse, + index_start: 0, + count: 1, + } + .encode(); + + let state = self + .gear_api + .api + .read_state( + self.checkpoint_light_client_address, + request, + Some(block_hash), + ) + .await?; + + let state = hex::decode(state)?; + + let state = State::decode(&mut &state[..])?; + + assert!(state.checkpoints.len() <= 1); + + let latest_checkpoint = state.checkpoints.get(0); + + match (latest_checkpoint, self.latest_checkpoint) { + (None, None) => {} + (None, Some(_)) => { + panic!( + "Invalid state detected: checkpoint-light-client program contains no checkpoints \ + but there's one in checkpoints extractor state" + ); + } + (Some(checkpoint), None) => { + self.latest_checkpoint = Some(EthereumBlockNumber(checkpoint.0)); + + self.metrics.latest_checkpoint_slot.set(checkpoint.0 as i64); + + sender.send(EthereumBlockNumber(checkpoint.0))?; + } + (Some(latest), Some(stored)) => { + if latest.0 > stored.0 { + self.metrics.latest_checkpoint_slot.set(latest.0 as i64); + + let latest = EthereumBlockNumber(latest.0); + + self.latest_checkpoint = Some(latest); + + sender.send(latest)?; + } + } + } + + Ok(()) + } +} diff --git a/relayer/src/message_relayer/common/gear/mod.rs b/relayer/src/message_relayer/common/gear/mod.rs index 8a8df707..0cd6fa90 100644 --- a/relayer/src/message_relayer/common/gear/mod.rs +++ b/relayer/src/message_relayer/common/gear/mod.rs @@ -1,3 +1,4 @@ pub mod block_listener; +pub mod checkpoints_extractor; pub mod message_paid_event_extractor; pub mod message_queued_event_extractor; From acb116678580d01a8bed8ea1112229336d75be3b Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 9 Sep 2024 08:19:08 +0000 Subject: [PATCH 05/32] Newtype for ethereum slot --- .../common/gear/checkpoints_extractor.rs | 16 ++++++++-------- relayer/src/message_relayer/common/mod.rs | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs b/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs index f29c7e2f..3909c3e6 100644 --- a/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs +++ b/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs @@ -9,14 +9,14 @@ use utils_prometheus::{impl_metered_service, MeteredService}; use checkpoint_light_client_io::meta::{Order, State, StateRequest}; -use crate::message_relayer::common::{EthereumBlockNumber, GearBlockNumber}; +use crate::message_relayer::common::{EthereumSlotNumber, GearBlockNumber}; pub struct CheckpointsExtractor { checkpoint_light_client_address: H256, gear_api: GearApi, - latest_checkpoint: Option, + latest_checkpoint: Option, metrics: Metrics, } @@ -46,7 +46,7 @@ impl CheckpointsExtractor { } } - pub fn run(mut self, blocks: Receiver) -> Receiver { + pub fn run(mut self, blocks: Receiver) -> Receiver { let (sender, receiver) = channel(); tokio::task::spawn_blocking(move || loop { @@ -61,7 +61,7 @@ impl CheckpointsExtractor { async fn run_inner( &mut self, - sender: &Sender, + sender: &Sender, blocks: &Receiver, ) -> anyhow::Result<()> { loop { @@ -74,7 +74,7 @@ impl CheckpointsExtractor { async fn process_block_events( &mut self, block: u32, - sender: &Sender, + sender: &Sender, ) -> anyhow::Result<()> { let block_hash = self.gear_api.block_number_to_hash(block).await?; @@ -112,17 +112,17 @@ impl CheckpointsExtractor { ); } (Some(checkpoint), None) => { - self.latest_checkpoint = Some(EthereumBlockNumber(checkpoint.0)); + self.latest_checkpoint = Some(EthereumSlotNumber(checkpoint.0)); self.metrics.latest_checkpoint_slot.set(checkpoint.0 as i64); - sender.send(EthereumBlockNumber(checkpoint.0))?; + sender.send(EthereumSlotNumber(checkpoint.0))?; } (Some(latest), Some(stored)) => { if latest.0 > stored.0 { self.metrics.latest_checkpoint_slot.set(latest.0 as i64); - let latest = EthereumBlockNumber(latest.0); + let latest = EthereumSlotNumber(latest.0); self.latest_checkpoint = Some(latest); diff --git a/relayer/src/message_relayer/common/mod.rs b/relayer/src/message_relayer/common/mod.rs index fa9042fb..7d3e5a92 100644 --- a/relayer/src/message_relayer/common/mod.rs +++ b/relayer/src/message_relayer/common/mod.rs @@ -15,6 +15,9 @@ pub struct GearBlockNumber(pub u32); #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, derive_more::Display)] pub struct EthereumBlockNumber(pub u64); +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, derive_more::Display)] +pub struct EthereumSlotNumber(pub u64); + #[derive(Clone, Debug)] pub struct MessageInBlock { pub message: Message, From 48c59c38456627cd20abd6758b2afae272199b22 Mon Sep 17 00:00:00 2001 From: mertwole Date: Thu, 12 Sep 2024 06:53:18 +0000 Subject: [PATCH 06/32] Add message_sender --- relayer/src/message_relayer/common/gear/message_sender.rs | 0 relayer/src/message_relayer/common/gear/mod.rs | 1 + 2 files changed, 1 insertion(+) create mode 100644 relayer/src/message_relayer/common/gear/message_sender.rs diff --git a/relayer/src/message_relayer/common/gear/message_sender.rs b/relayer/src/message_relayer/common/gear/message_sender.rs new file mode 100644 index 00000000..e69de29b diff --git a/relayer/src/message_relayer/common/gear/mod.rs b/relayer/src/message_relayer/common/gear/mod.rs index 0cd6fa90..1b2d71ba 100644 --- a/relayer/src/message_relayer/common/gear/mod.rs +++ b/relayer/src/message_relayer/common/gear/mod.rs @@ -2,3 +2,4 @@ pub mod block_listener; pub mod checkpoints_extractor; pub mod message_paid_event_extractor; pub mod message_queued_event_extractor; +pub mod message_sender; From d01fe5f6b36620e60edd88ca4eea5c73ee5e20f4 Mon Sep 17 00:00:00 2001 From: mertwole Date: Thu, 12 Sep 2024 09:01:51 +0000 Subject: [PATCH 07/32] message sender draft --- .../ethereum/deposit_event_extractor.rs | 29 +++-- .../common/gear/message_sender.rs | 115 ++++++++++++++++++ relayer/src/message_relayer/common/mod.rs | 16 ++- 3 files changed, 148 insertions(+), 12 deletions(-) diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index a1e2ae74..fea5ee14 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -6,7 +6,9 @@ use prometheus::IntCounter; use sails_rs::H160; use utils_prometheus::{impl_metered_service, MeteredService}; -use crate::message_relayer::common::{ERC20DepositTx, EthereumBlockNumber}; +use crate::message_relayer::common::{ + ERC20Deposit, ERC20DepositData, ERC20DepositTx, EthereumBlockNumber, +}; pub struct DepositEventExtractor { eth_api: EthApi, @@ -40,7 +42,7 @@ impl DepositEventExtractor { } } - pub fn run(self, blocks: Receiver) -> Receiver { + pub fn run(self, blocks: Receiver) -> Receiver { let (sender, receiver) = channel(); tokio::task::spawn_blocking(move || loop { @@ -55,7 +57,7 @@ impl DepositEventExtractor { async fn run_inner( &self, - sender: &Sender, + sender: &Sender, blocks: &Receiver, ) -> anyhow::Result<()> { loop { @@ -68,13 +70,15 @@ impl DepositEventExtractor { async fn process_block_events( &self, block: EthereumBlockNumber, - sender: &Sender, + sender: &Sender, ) -> anyhow::Result<()> { let events = self .eth_api .fetch_deposit_events(self.erc20_treasury_address, block.0) .await?; + let slot_number = todo!(); + self.metrics .total_deposits_found .inc_by(events.len() as u64); @@ -87,12 +91,17 @@ impl DepositEventExtractor { tx_hash, } in events { - sender.send(ERC20DepositTx { - from, - to, - token, - amount, - tx_hash, + sender.send(ERC20Deposit { + data: ERC20DepositData { + from, + to, + token, + amount, + }, + tx: ERC20DepositTx { + slot_number, + tx_hash, + }, })?; } diff --git a/relayer/src/message_relayer/common/gear/message_sender.rs b/relayer/src/message_relayer/common/gear/message_sender.rs index e69de29b..35b83b7d 100644 --- a/relayer/src/message_relayer/common/gear/message_sender.rs +++ b/relayer/src/message_relayer/common/gear/message_sender.rs @@ -0,0 +1,115 @@ +use std::sync::mpsc::Receiver; + +use futures::executor::block_on; +use gear_core::ids::MessageId; +use gear_rpc_client::GearApi; +use prometheus::{Gauge, IntGauge}; +use utils_prometheus::{impl_metered_service, MeteredService}; + +use crate::message_relayer::common::{ERC20DepositTx, EthereumSlotNumber}; + +pub struct MessageSender { + gear_api: GearApi, + + metrics: Metrics, +} + +impl MeteredService for MessageSender { + fn get_sources(&self) -> impl IntoIterator> { + self.metrics.get_sources() + } +} + +impl_metered_service! { + struct Metrics { + messages_waiting_checkpoint: IntGauge = IntGauge::new( + "gear_message_sender_messages_waiting_checkpoint", + "Amount of messages waiting for corresponding checkpoint", + ), + messages_waiting_finality: IntGauge = IntGauge::new( + "gear_message_sender_messages_waiting_finality", + "Amount of messages waiting for finality on gear", + ), + fee_payer_balance: Gauge = Gauge::new( + "gear_message_sender_fee_payer_balance", + "Transaction fee payer balance", + ) + } +} + +impl MessageSender { + pub fn new(gear_api: GearApi) -> Self { + Self { + gear_api, + + metrics: Metrics::new(), + } + } + + pub fn run( + self, + messages: Receiver, + checkpoints: Receiver, + ) { + tokio::task::spawn_blocking(move || loop { + let res = block_on(self.run_inner(&messages, &checkpoints)); + if let Err(err) = res { + log::error!("Ethereum message sender failed: {}", err); + } + }); + } + + async fn run_inner( + &self, + messages: &Receiver, + checkpoints: &Receiver, + ) -> anyhow::Result<()> { + let mut waiting_checkpoint: Vec = vec![]; + let mut waiting_finality: Vec<(ERC20DepositTx, MessageId)> = vec![]; + + let mut latest_checkpoint_slot = None; + + loop { + // TODO: update balance metric. + + for checkpoint in checkpoints.try_iter() { + if latest_checkpoint_slot.unwrap_or_default() < checkpoint { + latest_checkpoint_slot = Some(checkpoint); + } else { + log::error!( + "Received checkpoints not in sequential order. \ + Previously found checkpoint: {:?} and new checkpoint is {}", + latest_checkpoint_slot, + checkpoint + ); + } + } + + for message in messages.try_iter() { + waiting_checkpoint.push(message); + } + + for i in (0..waiting_checkpoint.len()).rev() { + if waiting_checkpoint[i].slot_number <= latest_checkpoint_slot.unwrap_or_default() { + // TODO: Submit tx + let message_id = todo!(); + + let message = waiting_checkpoint.remove(i); + waiting_finality.push((message, message_id)); + } + } + + self.metrics + .messages_waiting_checkpoint + .set(waiting_checkpoint.len() as i64); + + for i in (0..waiting_finality.len()).rev() { + // TODO: check status of tx. If it's finalized - remove from vec. + } + + self.metrics + .messages_waiting_finality + .set(waiting_finality.len() as i64); + } + } +} diff --git a/relayer/src/message_relayer/common/mod.rs b/relayer/src/message_relayer/common/mod.rs index 7d3e5a92..165f6e35 100644 --- a/relayer/src/message_relayer/common/mod.rs +++ b/relayer/src/message_relayer/common/mod.rs @@ -15,7 +15,9 @@ pub struct GearBlockNumber(pub u32); #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, derive_more::Display)] pub struct EthereumBlockNumber(pub u64); -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, derive_more::Display)] +#[derive( + Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Default, derive_more::Display, +)] pub struct EthereumSlotNumber(pub u64); #[derive(Clone, Debug)] @@ -37,11 +39,21 @@ pub struct RelayedMerkleRoot { } #[derive(Clone, Debug)] -pub struct ERC20DepositTx { +pub struct ERC20Deposit { + pub data: ERC20DepositData, + pub tx: ERC20DepositTx, +} + +#[derive(Clone, Debug)] +pub struct ERC20DepositData { pub from: H160, pub to: H256, pub token: H160, pub amount: U256, +} +#[derive(Clone, Debug)] +pub struct ERC20DepositTx { + pub slot_number: EthereumSlotNumber, pub tx_hash: TxHash, } From 9e1aa3e18469a499b4d4729a5d8448b2a2b4b576 Mon Sep 17 00:00:00 2001 From: mertwole Date: Thu, 12 Sep 2024 09:27:01 +0000 Subject: [PATCH 08/32] Update balance metric --- .../common/gear/message_sender.rs | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/relayer/src/message_relayer/common/gear/message_sender.rs b/relayer/src/message_relayer/common/gear/message_sender.rs index 35b83b7d..d0622925 100644 --- a/relayer/src/message_relayer/common/gear/message_sender.rs +++ b/relayer/src/message_relayer/common/gear/message_sender.rs @@ -1,9 +1,9 @@ use std::sync::mpsc::Receiver; use futures::executor::block_on; +use gclient::GearApi; use gear_core::ids::MessageId; -use gear_rpc_client::GearApi; -use prometheus::{Gauge, IntGauge}; +use prometheus::IntGauge; use utils_prometheus::{impl_metered_service, MeteredService}; use crate::message_relayer::common::{ERC20DepositTx, EthereumSlotNumber}; @@ -30,7 +30,7 @@ impl_metered_service! { "gear_message_sender_messages_waiting_finality", "Amount of messages waiting for finality on gear", ), - fee_payer_balance: Gauge = Gauge::new( + fee_payer_balance: IntGauge = IntGauge::new( "gear_message_sender_fee_payer_balance", "Transaction fee payer balance", ) @@ -70,7 +70,7 @@ impl MessageSender { let mut latest_checkpoint_slot = None; loop { - // TODO: update balance metric. + self.update_balance_metric().await?; for checkpoint in checkpoints.try_iter() { if latest_checkpoint_slot.unwrap_or_default() < checkpoint { @@ -91,8 +91,7 @@ impl MessageSender { for i in (0..waiting_checkpoint.len()).rev() { if waiting_checkpoint[i].slot_number <= latest_checkpoint_slot.unwrap_or_default() { - // TODO: Submit tx - let message_id = todo!(); + let message_id = self.submit_message(&waiting_checkpoint[i]).await?; let message = waiting_checkpoint.remove(i); waiting_finality.push((message, message_id)); @@ -112,4 +111,24 @@ impl MessageSender { .set(waiting_finality.len() as i64); } } + + async fn submit_message(&self, message: &ERC20DepositTx) -> anyhow::Result { + // TODO: submit message to gear. + + todo!() + } + + async fn update_balance_metric(&self) -> anyhow::Result<()> { + let balance = self + .gear_api + .total_balance(self.gear_api.account_id()) + .await?; + + let balance = balance / 1_000_000_000_000; + let balance: i64 = balance.try_into().unwrap_or(i64::MAX); + + self.metrics.fee_payer_balance.set(balance); + + Ok(()) + } } From 4f95998f0159d94d59f5b0584cc1505c9bb037ef Mon Sep 17 00:00:00 2001 From: mertwole Date: Thu, 12 Sep 2024 09:31:27 +0000 Subject: [PATCH 09/32] Add todo --- .../message_relayer/common/ethereum/deposit_event_extractor.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index fea5ee14..cda9a64d 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -77,6 +77,7 @@ impl DepositEventExtractor { .fetch_deposit_events(self.erc20_treasury_address, block.0) .await?; + // TODO: fetch slot number by block number. let slot_number = todo!(); self.metrics From bd235e96924e5171b6b870586f38840d3016da5c Mon Sep 17 00:00:00 2001 From: mertwole Date: Tue, 8 Oct 2024 09:55:23 +0000 Subject: [PATCH 10/32] Fix merge --- .../common/gear/message_paid_event_extractor.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/relayer/src/message_relayer/common/gear/message_paid_event_extractor.rs b/relayer/src/message_relayer/common/gear/message_paid_event_extractor.rs index cac2b0e6..f55aabea 100644 --- a/relayer/src/message_relayer/common/gear/message_paid_event_extractor.rs +++ b/relayer/src/message_relayer/common/gear/message_paid_event_extractor.rs @@ -7,9 +7,10 @@ use prometheus::IntCounter; use sails_rs::events::EventIo; use utils_prometheus::{impl_metered_service, MeteredService}; -use super::{GearBlockNumber, PaidMessage}; use bridging_payment_client::bridging_payment::events::BridgingPaymentEvents; +use crate::message_relayer::common::{GearBlockNumber, PaidMessage}; + pub struct MessagePaidEventExtractor { bridging_payment_address: H256, From 18fd443a00daa886bc93d2e813e0654606c95faa Mon Sep 17 00:00:00 2001 From: mertwole Date: Tue, 8 Oct 2024 10:51:55 +0000 Subject: [PATCH 11/32] Compose relayer --- .../eth_to_gear/all_token_transfers.rs | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs index 70b786d1..3d4ce71f 100644 --- a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -1 +1,87 @@ -// TODO +use std::iter; + +use primitive_types::{H160, H256}; + +use ethereum_client::EthApi; +use gear_rpc_client::GearApi; +use utils_prometheus::MeteredService; + +use crate::message_relayer::common::{ + self, + ethereum::{ + block_listener::BlockListener as EthereumBlockListener, + deposit_event_extractor::DepositEventExtractor, merkle_root_extractor::MerkleRootExtractor, + }, + gear::{ + block_listener::BlockListener as GearBlockListener, + checkpoints_extractor::CheckpointsExtractor, + message_queued_event_extractor::MessageQueuedEventExtractor, message_sender::MessageSender, + }, +}; + +pub struct Relayer { + gear_block_listener: GearBlockListener, + ethereum_block_listener: EthereumBlockListener, + + deposit_event_extractor: DepositEventExtractor, + checkpoints_extractor: CheckpointsExtractor, + + gear_message_sender: MessageSender, +} + +impl MeteredService for Relayer { + fn get_sources(&self) -> impl IntoIterator> { + iter::empty() + .chain(self.gear_block_listener.get_sources()) + .chain(self.ethereum_block_listener.get_sources()) + .chain(self.deposit_event_extractor.get_sources()) + .chain(self.checkpoints_extractor.get_sources()) + .chain(self.gear_message_sender.get_sources()) + } +} + +impl Relayer { + pub async fn new( + gear_api: GearApi, + eth_api: EthApi, + erc20_treasury_address: H160, + checkpoint_light_client_address: H256, + ) -> anyhow::Result { + let from_eth_block = eth_api.block_number().await?; + + let from_gear_block = gear_api.latest_finalized_block().await?; + let from_gear_block = gear_api.block_hash_to_number(block).await?; + + let gear_block_listener = GearBlockListener::new(gear_api.clone(), from_gear_block); + + let ethereum_block_listener = EthereumBlockListener::new(eth_api.clone(), from_eth_block); + + let deposit_event_extractor = + DepositEventExtractor::new(eth_api.clone(), erc20_treasury_address); + + let checkpoints_extractor = + CheckpointsExtractor::new(gear_api.clone(), checkpoint_light_client_address); + + let gear_message_sender = MessageSender::new(gear_api); + + Ok(Self { + gear_block_listener, + ethereum_block_listener, + + deposit_event_extractor, + checkpoints_extractor, + + gear_message_sender, + }) + } + + pub fn run(self) { + let [gear_blocks] = self.gear_block_listener.run(); + let ethereum_blocks = self.ethereum_block_listener.run(); + + let deposit_events = self.deposit_event_extractor.run(ethereum_blocks); + let checkpoints = self.checkpoints_extractor.run(gear_blocks); + + self.gear_message_sender.run(deposit_events, checkpoints); + } +} From 0f216c8da7d9fc640994df2e3b536a4def3c3d47 Mon Sep 17 00:00:00 2001 From: mertwole Date: Wed, 9 Oct 2024 09:37:16 +0000 Subject: [PATCH 12/32] Split message sender to parts --- ethereum/client/build.rs | 3 +- relayer/src/main.rs | 3 +- .../ethereum/deposit_event_extractor.rs | 20 ++---- .../gear/message_sender/compose_payload.rs} | 68 ++++--------------- .../mod.rs} | 67 +++++++++++++----- .../eth_to_gear/all_token_transfers.rs | 14 +++- 6 files changed, 86 insertions(+), 89 deletions(-) rename relayer/src/{erc20/mod.rs => message_relayer/common/gear/message_sender/compose_payload.rs} (80%) rename relayer/src/message_relayer/common/gear/{message_sender.rs => message_sender/mod.rs} (68%) diff --git a/ethereum/client/build.rs b/ethereum/client/build.rs index d32febc2..3902f266 100644 --- a/ethereum/client/build.rs +++ b/ethereum/client/build.rs @@ -1,7 +1,8 @@ use std::process::Command; fn main() { - println!("cargo::rerun-if-changed=*"); + println!("cargo::rerun-if-changed=../src"); + println!("cargo::rerun-if-changed=../lib"); Command::new("forge") .arg("build") diff --git a/relayer/src/main.rs b/relayer/src/main.rs index 461f61d0..84b8f071 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -12,7 +12,6 @@ use proof_storage::{FileSystemProofStorage, GearProofStorage, ProofStorage}; use relay_merkle_roots::MerkleRootRelayer; use utils_prometheus::MetricsBuilder; -mod erc20; mod ethereum_checkpoints; mod genesis_config; mod message_relayer; @@ -324,7 +323,7 @@ async fn main() { .await .expect("Failed to fetch authority set state"); } - CliCommands::RelayErc20(args) => erc20::relay(args).await, + CliCommands::RelayErc20(args) => todo!(), }; } diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index cda9a64d..2d07e79a 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -42,7 +42,7 @@ impl DepositEventExtractor { } } - pub fn run(self, blocks: Receiver) -> Receiver { + pub fn run(self, blocks: Receiver) -> Receiver { let (sender, receiver) = channel(); tokio::task::spawn_blocking(move || loop { @@ -57,7 +57,7 @@ impl DepositEventExtractor { async fn run_inner( &self, - sender: &Sender, + sender: &Sender, blocks: &Receiver, ) -> anyhow::Result<()> { loop { @@ -70,7 +70,7 @@ impl DepositEventExtractor { async fn process_block_events( &self, block: EthereumBlockNumber, - sender: &Sender, + sender: &Sender, ) -> anyhow::Result<()> { let events = self .eth_api @@ -92,18 +92,12 @@ impl DepositEventExtractor { tx_hash, } in events { - sender.send(ERC20Deposit { - data: ERC20DepositData { - from, - to, - token, - amount, - }, - tx: ERC20DepositTx { + sender.send( + ERC20DepositTx { slot_number, tx_hash, - }, - })?; + } + )?; } Ok(()) diff --git a/relayer/src/erc20/mod.rs b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs similarity index 80% rename from relayer/src/erc20/mod.rs rename to relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs index 827b3e67..26fad65c 100644 --- a/relayer/src/erc20/mod.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs @@ -1,6 +1,8 @@ -use super::{ethereum_checkpoints::utils, *}; +use crate::{ethereum_checkpoints::utils, RelayErc20Args}; + use alloy::{ network::primitives::BlockTransactionsKind, + primitives::TxHash, providers::{Provider, ProviderBuilder}, rpc::types::{Log, Receipt, ReceiptEnvelope, ReceiptWithBloom}, }; @@ -25,35 +27,17 @@ use reqwest::Client; use sails_rs::{calls::*, events::*, gclient::calls::*, prelude::*}; use std::cmp::Ordering; -pub async fn relay(args: RelayErc20Args) { - if let Err(e) = relay_inner(args).await { - log::error!("{e:?}"); - } -} - -async fn relay_inner(args: RelayErc20Args) -> AnyResult<()> { - log::info!("Started"); - - let RelayErc20Args { - program_id, - beacon_endpoint, - vara_domain, - vara_port, - vara_suri, - eth_endpoint, - tx_hash, - } = args; - - let program_id: [u8; 32] = - utils::try_from_hex_encoded(&program_id).expect("Expecting correct ProgramId"); - let tx_hash: [u8; 32] = - utils::try_from_hex_encoded(&tx_hash).expect("Expecting correct hash of a transaction"); - +// TODO: Don't create ethereum clients inside. +pub async fn compose( + beacon_endpoint: String, + eth_endpoint: String, + tx_hash: TxHash, +) -> AnyResult { let rpc_url = eth_endpoint.parse()?; let provider = ProviderBuilder::new().on_http(rpc_url); let receipt = provider - .get_transaction_receipt(tx_hash.into()) + .get_transaction_receipt(tx_hash) .await? .ok_or(anyhow!("Transaction receipt is missing"))?; @@ -132,7 +116,8 @@ async fn relay_inner(args: RelayErc20Args) -> AnyResult<()> { let mut receipt_rlp = Vec::with_capacity(Encodable::length(receipt)); Encodable::encode(receipt, &mut receipt_rlp); - let message = EthToVaraEvent { + + Ok(EthToVaraEvent { proof_block, proof: recorder .drain() @@ -141,34 +126,7 @@ async fn relay_inner(args: RelayErc20Args) -> AnyResult<()> { .collect::>(), transaction_index: *tx_index, receipt_rlp, - }; - - let client = GearApi::init_with(WSAddress::new(vara_domain, vara_port), vara_suri).await?; - let gas_limit_block = client.block_gas_limit()?; - // use 95% of block gas limit for all extrinsics - let gas_limit = gas_limit_block / 100 * 95; - - let remoting = GClientRemoting::new(client); - - let mut erc20_service = Erc20Relay::new(remoting.clone()); - let mut listener = erc20_relay_client::erc_20_relay::events::listener(remoting.clone()); - let mut events = listener.listen().await.unwrap(); - - let result = erc20_service - .relay(message) - .with_gas_limit(gas_limit) - .send_recv(program_id.into()) - .await - .unwrap(); - - log::debug!("result = {result:?}"); - if result.is_ok() { - let event = events.next().await.unwrap(); - - log::debug!("event = {event:?}"); - } - - Ok(()) + }) } async fn build_inclusion_proof( diff --git a/relayer/src/message_relayer/common/gear/message_sender.rs b/relayer/src/message_relayer/common/gear/message_sender/mod.rs similarity index 68% rename from relayer/src/message_relayer/common/gear/message_sender.rs rename to relayer/src/message_relayer/common/gear/message_sender/mod.rs index d0622925..02339093 100644 --- a/relayer/src/message_relayer/common/gear/message_sender.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/mod.rs @@ -3,13 +3,27 @@ use std::sync::mpsc::Receiver; use futures::executor::block_on; use gclient::GearApi; use gear_core::ids::MessageId; +use primitive_types::H256; use prometheus::IntGauge; +use sails_rs::{ + calls::{Action, Call}, + gclient::calls::GClientRemoting, +}; + +use erc20_relay_client::{traits::Erc20Relay as _, Erc20Relay}; use utils_prometheus::{impl_metered_service, MeteredService}; use crate::message_relayer::common::{ERC20DepositTx, EthereumSlotNumber}; +mod compose_payload; + pub struct MessageSender { gear_api: GearApi, + // TODO: Don't store strings here. + beacon_endpoint: String, + eth_endpoint: String, + + ethereum_event_client_address: H256, metrics: Metrics, } @@ -38,10 +52,20 @@ impl_metered_service! { } impl MessageSender { - pub fn new(gear_api: GearApi) -> Self { + pub fn new( + gear_api: GearApi, + beacon_endpoint: String, + eth_endpoint: String, + ethereum_event_client_address: H256, + ) -> Self { Self { gear_api, + beacon_endpoint, + eth_endpoint, + + ethereum_event_client_address, + metrics: Metrics::new(), } } @@ -91,31 +115,42 @@ impl MessageSender { for i in (0..waiting_checkpoint.len()).rev() { if waiting_checkpoint[i].slot_number <= latest_checkpoint_slot.unwrap_or_default() { - let message_id = self.submit_message(&waiting_checkpoint[i]).await?; - - let message = waiting_checkpoint.remove(i); - waiting_finality.push((message, message_id)); + self.submit_message(&waiting_checkpoint[i]).await?; + let _ = waiting_checkpoint.remove(i); } } self.metrics .messages_waiting_checkpoint .set(waiting_checkpoint.len() as i64); - - for i in (0..waiting_finality.len()).rev() { - // TODO: check status of tx. If it's finalized - remove from vec. - } - - self.metrics - .messages_waiting_finality - .set(waiting_finality.len() as i64); } } - async fn submit_message(&self, message: &ERC20DepositTx) -> anyhow::Result { - // TODO: submit message to gear. + async fn submit_message(&self, message: &ERC20DepositTx) -> anyhow::Result<()> { + let message = compose_payload::compose( + self.beacon_endpoint.clone(), + self.eth_endpoint.clone(), + message.tx_hash, + ) + .await?; + + let gas_limit_block = self.gear_api.block_gas_limit()?; + // Use 95% of block gas limit for all extrinsics. + let gas_limit = gas_limit_block / 100 * 95; - todo!() + let remoting = GClientRemoting::new(self.gear_api.clone()); + + let mut erc20_service = Erc20Relay::new(remoting.clone()); + + erc20_service + .relay(message) + .with_gas_limit(gas_limit) + .send_recv(self.ethereum_event_client_address.into()) + .await + .map_err(|_| anyhow::anyhow!("Failed to send message to ethereum event client"))? + .map_err(|_| anyhow::anyhow!("Internal ethereum event clint error"))?; + + Ok(()) } async fn update_balance_metric(&self) -> anyhow::Result<()> { diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs index 3d4ce71f..068fc0e0 100644 --- a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -1,5 +1,6 @@ use std::iter; +use gclient::GearApi as GclientGearApi; use primitive_types::{H160, H256}; use ethereum_client::EthApi; @@ -43,14 +44,18 @@ impl MeteredService for Relayer { impl Relayer { pub async fn new( gear_api: GearApi, + gclient_gear_api: GclientGearApi, eth_api: EthApi, + beacon_endpoint: String, + eth_endpoint: String, erc20_treasury_address: H160, checkpoint_light_client_address: H256, + ethereum_event_client_address: H256, ) -> anyhow::Result { let from_eth_block = eth_api.block_number().await?; let from_gear_block = gear_api.latest_finalized_block().await?; - let from_gear_block = gear_api.block_hash_to_number(block).await?; + let from_gear_block = gear_api.block_hash_to_number(from_gear_block).await?; let gear_block_listener = GearBlockListener::new(gear_api.clone(), from_gear_block); @@ -62,7 +67,12 @@ impl Relayer { let checkpoints_extractor = CheckpointsExtractor::new(gear_api.clone(), checkpoint_light_client_address); - let gear_message_sender = MessageSender::new(gear_api); + let gear_message_sender = MessageSender::new( + gclient_gear_api, + beacon_endpoint, + eth_endpoint, + ethereum_event_client_address, + ); Ok(Self { gear_block_listener, From 8573a855c7848647ac14b75020dc231113a096aa Mon Sep 17 00:00:00 2001 From: mertwole Date: Fri, 11 Oct 2024 15:21:43 +0000 Subject: [PATCH 13/32] Fix merge --- .../common/gear/message_sender/compose_payload.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs index 7f46f3b9..93c17235 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs @@ -90,9 +90,6 @@ pub async fn compose( let mut receipt_rlp = Vec::with_capacity(Encodable::length(&receipt)); Encodable::encode(&receipt, &mut receipt_rlp); - let message = EthToVaraEvent { - let mut receipt_rlp = Vec::with_capacity(Encodable::length(receipt)); - Encodable::encode(receipt, &mut receipt_rlp); Ok(EthToVaraEvent { proof_block, From ab7c4bf3e5600f2b86be613372b256bf7a66465b Mon Sep 17 00:00:00 2001 From: mertwole Date: Fri, 11 Oct 2024 15:43:51 +0000 Subject: [PATCH 14/32] Move code from utils to ethereum_beacon_client --- Cargo.lock | 1 + relayer/Cargo.toml | 1 + .../utils => ethereum_beacon_client}/mod.rs | 26 +++--- .../slots_batch.rs | 0 relayer/src/ethereum_checkpoints/mod.rs | 6 +- .../src/ethereum_checkpoints/replay_back.rs | 16 +++- .../src/ethereum_checkpoints/sync_update.rs | 9 +- relayer/src/ethereum_checkpoints/tests/mod.rs | 84 +++++++++++++------ relayer/src/main.rs | 1 + .../gear/message_sender/compose_payload.rs | 28 +++++-- 10 files changed, 113 insertions(+), 59 deletions(-) rename relayer/src/{ethereum_checkpoints/utils => ethereum_beacon_client}/mod.rs (94%) rename relayer/src/{ethereum_checkpoints/utils => ethereum_beacon_client}/slots_batch.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 8283fd15..7b121b3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9881,6 +9881,7 @@ dependencies = [ "dotenv", "erc20-relay-client", "ethereum-client", + "ethereum-common", "futures", "gclient 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gear-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/relayer/Cargo.toml b/relayer/Cargo.toml index 83a12f3d..6cf2cf06 100644 --- a/relayer/Cargo.toml +++ b/relayer/Cargo.toml @@ -24,6 +24,7 @@ clap.workspace = true derive_more.workspace = true dotenv.workspace = true erc20-relay-client.workspace = true +ethereum-common.workspace = true futures.workspace = true gear-core.workspace = true gclient.workspace = true diff --git a/relayer/src/ethereum_checkpoints/utils/mod.rs b/relayer/src/ethereum_beacon_client/mod.rs similarity index 94% rename from relayer/src/ethereum_checkpoints/utils/mod.rs rename to relayer/src/ethereum_beacon_client/mod.rs index b5bd50d5..ade8b66a 100644 --- a/relayer/src/ethereum_checkpoints/utils/mod.rs +++ b/relayer/src/ethereum_beacon_client/mod.rs @@ -1,21 +1,23 @@ +use std::{cmp, error::Error, fmt}; + use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; use ark_serialize::CanonicalDeserialize; +// TODO: Fix this import use checkpoint_light_client_io::{ - ethereum_common::{ - base_types::{BytesFixed, FixedArray}, - beacon::{BLSPubKey, Block as BeaconBlock}, - utils, MAX_REQUEST_LIGHT_CLIENT_UPDATES, - }, ArkScale, BeaconBlockHeader, G1TypeInfo, G2TypeInfo, Slot, SyncCommitteeKeys, SyncCommitteeUpdate, G1, G2, SYNC_COMMITTEE_SIZE, }; +use ethereum_common::{ + base_types::{BytesFixed, FixedArray}, + beacon::{BLSPubKey, Block as BeaconBlock}, + utils::{ + BeaconBlockHeaderResponse, BeaconBlockResponse, Bootstrap, BootstrapResponse, + FinalityUpdate, FinalityUpdateResponse, Update, UpdateResponse, + }, + MAX_REQUEST_LIGHT_CLIENT_UPDATES, +}; use reqwest::{Client, RequestBuilder}; use serde::{de::DeserializeOwned, Deserialize}; -use std::{cmp, error::Error, fmt}; -use utils::{ - BeaconBlockHeaderResponse, BeaconBlockResponse, FinalityUpdate, FinalityUpdateResponse, Update, - UpdateResponse, -}; pub mod slots_batch; @@ -57,7 +59,7 @@ pub async fn get_bootstrap( client: &Client, rpc_url: &str, checkpoint: &str, -) -> AnyResult { +) -> AnyResult { let checkpoint_no_prefix = match checkpoint.starts_with("0x") { true => &checkpoint[2..], false => checkpoint, @@ -65,7 +67,7 @@ pub async fn get_bootstrap( let url = format!("{rpc_url}/eth/v1/beacon/light_client/bootstrap/0x{checkpoint_no_prefix}",); - get::(client.get(&url)) + get::(client.get(&url)) .await .map(|response| response.data) } diff --git a/relayer/src/ethereum_checkpoints/utils/slots_batch.rs b/relayer/src/ethereum_beacon_client/slots_batch.rs similarity index 100% rename from relayer/src/ethereum_checkpoints/utils/slots_batch.rs rename to relayer/src/ethereum_beacon_client/slots_batch.rs diff --git a/relayer/src/ethereum_checkpoints/mod.rs b/relayer/src/ethereum_checkpoints/mod.rs index 7fdd3a62..d996518d 100644 --- a/relayer/src/ethereum_checkpoints/mod.rs +++ b/relayer/src/ethereum_checkpoints/mod.rs @@ -6,6 +6,7 @@ use checkpoint_light_client_io::{ tree_hash::Hash256, Handle, HandleResult, Slot, SyncCommitteeUpdate, G2, }; +use ethereum_beacon_client::slots_batch::Iter as SlotsBatchIter; use futures::{ future::{self, Either}, pin_mut, @@ -18,7 +19,6 @@ use tokio::{ sync::mpsc::{self, Sender}, time::{self, Duration}, }; -use utils::slots_batch::Iter as SlotsBatchIter; #[cfg(test)] mod tests; @@ -26,7 +26,6 @@ mod tests; mod metrics; mod replay_back; mod sync_update; -pub mod utils; const SIZE_CHANNEL: usize = 100_000; const SIZE_BATCH: u64 = 30 * SLOTS_PER_EPOCH; @@ -50,7 +49,8 @@ pub async fn relay(args: RelayCheckpointsArgs) { }, } = args; - let program_id = utils::try_from_hex_encoded(&program_id).expect("Expecting correct ProgramId"); + let program_id = ethereum_beacon_client::try_from_hex_encoded(&program_id) + .expect("Expecting correct ProgramId"); let client_http = ClientBuilder::new() .timeout(Duration::from_secs(beacon_timeout)) diff --git a/relayer/src/ethereum_checkpoints/replay_back.rs b/relayer/src/ethereum_checkpoints/replay_back.rs index 3062ac83..7febcb08 100644 --- a/relayer/src/ethereum_checkpoints/replay_back.rs +++ b/relayer/src/ethereum_checkpoints/replay_back.rs @@ -1,4 +1,5 @@ use super::*; +use crate::ethereum_beacon_client; #[allow(clippy::too_many_arguments)] pub async fn execute( @@ -36,7 +37,7 @@ pub async fn execute( } let period_start = 1 + eth_utils::calculate_period(slot_start); - let updates = utils::get_updates( + let updates = ethereum_beacon_client::get_updates( client_http, beacon_endpoint, period_start, @@ -58,7 +59,7 @@ pub async fn execute( ) .map_err(|e| anyhow!("Failed to deserialize point on G2 (replay back): {e:?}"))?; - let sync_update = utils::sync_update_from_update(signature, update.data); + let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update.data); replay_back_slots_start( client_http, beacon_endpoint, @@ -151,7 +152,8 @@ async fn replay_back_slots_inner( gas_limit: u64, ) -> AnyResult<()> { let payload = Handle::ReplayBack( - utils::request_headers(client_http, beacon_endpoint, slot_start, slot_end).await?, + ethereum_beacon_client::request_headers(client_http, beacon_endpoint, slot_start, slot_end) + .await?, ); let mut listener = client.subscribe().await?; @@ -195,7 +197,13 @@ async fn replay_back_slots_start( let payload = Handle::ReplayBackStart { sync_update, - headers: utils::request_headers(client_http, beacon_endpoint, slot_start, slot_end).await?, + headers: ethereum_beacon_client::request_headers( + client_http, + beacon_endpoint, + slot_start, + slot_end, + ) + .await?, }; let mut listener = client.subscribe().await?; diff --git a/relayer/src/ethereum_checkpoints/sync_update.rs b/relayer/src/ethereum_checkpoints/sync_update.rs index d211f88b..b17bbd4b 100644 --- a/relayer/src/ethereum_checkpoints/sync_update.rs +++ b/relayer/src/ethereum_checkpoints/sync_update.rs @@ -1,4 +1,5 @@ use super::*; +use crate::ethereum_beacon_client; pub use checkpoint_light_client_io::sync_update::Error; use std::ops::ControlFlow::{self, *}; @@ -35,12 +36,12 @@ async fn receive( beacon_endpoint: &str, sender: &Sender, ) -> AnyResult> { - let finality_update = utils::get_finality_update(client_http, beacon_endpoint) + let finality_update = ethereum_beacon_client::get_finality_update(client_http, beacon_endpoint) .await .map_err(|e| anyhow!("Unable to fetch FinalityUpdate: {e:?}"))?; let period = eth_utils::calculate_period(finality_update.finalized_header.slot); - let mut updates = utils::get_updates(client_http, beacon_endpoint, period, 1) + let mut updates = ethereum_beacon_client::get_updates(client_http, beacon_endpoint, period, 1) .await .map_err(|e| anyhow!("Unable to fetch Updates: {e:?}"))?; @@ -61,9 +62,9 @@ async fn receive( .map_err(|e| anyhow!("Failed to deserialize point on G2: {e:?}"))?; let sync_update = if update.finalized_header.slot >= finality_update.finalized_header.slot { - utils::sync_update_from_update(signature, update) + ethereum_beacon_client::sync_update_from_update(signature, update) } else { - utils::sync_update_from_finality(signature, finality_update) + ethereum_beacon_client::sync_update_from_finality(signature, finality_update) }; if sender.send(sync_update).await.is_err() { diff --git a/relayer/src/ethereum_checkpoints/tests/mod.rs b/relayer/src/ethereum_checkpoints/tests/mod.rs index b8002695..1e4990fa 100644 --- a/relayer/src/ethereum_checkpoints/tests/mod.rs +++ b/relayer/src/ethereum_checkpoints/tests/mod.rs @@ -1,4 +1,4 @@ -use super::utils::{self, slots_batch}; +use crate::ethereum_beacon_client::{self, slots_batch}; use checkpoint_light_client::WASM_BINARY; use checkpoint_light_client_io::{ ethereum_common::{ @@ -69,10 +69,12 @@ async fn init(network: Network) -> Result<()> { let client_http = Client::new(); // use the latest finality header as a checkpoint for bootstrapping - let finality_update = utils::get_finality_update(&client_http, RPC_URL).await?; + let finality_update = + ethereum_beacon_client::get_finality_update(&client_http, RPC_URL).await?; let slot = finality_update.finalized_header.slot; let current_period = eth_utils::calculate_period(slot); - let mut updates = utils::get_updates(&client_http, RPC_URL, current_period, 1).await?; + let mut updates = + ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period, 1).await?; println!( "finality_update slot = {}, period = {}", @@ -92,17 +94,19 @@ async fn init(network: Network) -> Result<()> { update.finalized_header.slot, checkpoint_hex ); - let bootstrap = utils::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; + let bootstrap = + ethereum_beacon_client::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; let signature = ::deserialize_compressed( &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = utils::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); println!("bootstrap slot = {}", bootstrap.header.slot); - let pub_keys = utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + let pub_keys = + ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network, sync_committee_current_pub_keys: pub_keys, @@ -149,9 +153,11 @@ async fn init_and_updating() -> Result<()> { let client_http = Client::new(); // use the latest finality header as a checkpoint for bootstrapping - let finality_update = utils::get_finality_update(&client_http, RPC_URL).await?; + let finality_update = + ethereum_beacon_client::get_finality_update(&client_http, RPC_URL).await?; let current_period = eth_utils::calculate_period(finality_update.finalized_header.slot); - let mut updates = utils::get_updates(&client_http, RPC_URL, current_period, 1).await?; + let mut updates = + ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period, 1).await?; println!( "finality_update slot = {}, period = {}", @@ -171,17 +177,19 @@ async fn init_and_updating() -> Result<()> { update.finalized_header.slot, checkpoint_hex ); - let bootstrap = utils::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; + let bootstrap = + ethereum_beacon_client::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; let signature = ::deserialize_compressed( &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = utils::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); println!("bootstrap slot = {}", bootstrap.header.slot); - let pub_keys = utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + let pub_keys = + ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network: Network::Holesky, sync_committee_current_pub_keys: pub_keys, @@ -205,11 +213,12 @@ async fn init_and_updating() -> Result<()> { println!(); for _ in 0..30 { - let update = utils::get_finality_update(&client_http, RPC_URL).await?; + let update = ethereum_beacon_client::get_finality_update(&client_http, RPC_URL).await?; let slot: u64 = update.finalized_header.slot; let current_period = eth_utils::calculate_period(slot); - let mut updates = utils::get_updates(&client_http, RPC_URL, current_period, 1).await?; + let mut updates = + ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period, 1).await?; match updates.pop() { Some(update) if updates.is_empty() && update.data.finalized_header.slot >= slot => { println!("update sync committee"); @@ -218,8 +227,10 @@ async fn init_and_updating() -> Result<()> { &update.data.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let payload = - Handle::SyncUpdate(utils::sync_update_from_update(signature, update.data)); + let payload = Handle::SyncUpdate(ethereum_beacon_client::sync_update_from_update( + signature, + update.data, + )); let gas_limit = client .calculate_handle_gas(None, program_id.into(), payload.encode(), 0, true) .await? @@ -251,8 +262,9 @@ async fn init_and_updating() -> Result<()> { continue; }; - let payload = - Handle::SyncUpdate(utils::sync_update_from_finality(signature, update)); + let payload = Handle::SyncUpdate( + ethereum_beacon_client::sync_update_from_finality(signature, update), + ); let gas_limit = client .calculate_handle_gas(None, program_id.into(), payload.encode(), 0, true) @@ -296,7 +308,8 @@ async fn replaying_back() -> Result<()> { // This SyncCommittee operated for about 13K slots, so we make adjustments let current_period = eth_utils::calculate_period(finality_update.finalized_header.slot); - let mut updates = utils::get_updates(&client_http, RPC_URL, current_period - 1, 1).await?; + let mut updates = + ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period - 1, 1).await?; let update = match updates.pop() { Some(update) if updates.is_empty() => update.data, @@ -305,7 +318,8 @@ async fn replaying_back() -> Result<()> { let checkpoint = update.finalized_header.tree_hash_root(); let checkpoint_hex = hex::encode(checkpoint); - let bootstrap = utils::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; + let bootstrap = + ethereum_beacon_client::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; println!("bootstrap slot = {}", bootstrap.header.slot); println!("update slot = {}", update.finalized_header.slot); @@ -313,7 +327,7 @@ async fn replaying_back() -> Result<()> { &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = utils::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); let slot_start = sync_update.finalized_header.slot; let slot_end = finality_update.finalized_header.slot; println!( @@ -321,7 +335,8 @@ async fn replaying_back() -> Result<()> { slot_end - slot_start ); - let pub_keys = utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + let pub_keys = + ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network: Network::Sepolia, sync_committee_current_pub_keys: pub_keys, @@ -350,7 +365,11 @@ async fn replaying_back() -> Result<()> { if let Some((slot_start, slot_end)) = slots_batch_iter.next() { let mut requests_headers = Vec::with_capacity(batch_size as usize); for i in slot_start..slot_end { - requests_headers.push(utils::get_block_header(&client_http, RPC_URL, i)); + requests_headers.push(ethereum_beacon_client::get_block_header( + &client_http, + RPC_URL, + i, + )); } let headers = futures::future::join_all(requests_headers) @@ -365,7 +384,10 @@ async fn replaying_back() -> Result<()> { .unwrap(); let payload = Handle::ReplayBackStart { - sync_update: utils::sync_update_from_finality(signature, finality_update), + sync_update: ethereum_beacon_client::sync_update_from_finality( + signature, + finality_update, + ), headers, }; @@ -391,7 +413,11 @@ async fn replaying_back() -> Result<()> { for (slot_start, slot_end) in slots_batch_iter { let mut requests_headers = Vec::with_capacity(batch_size as usize); for i in slot_start..slot_end { - requests_headers.push(utils::get_block_header(&client_http, RPC_URL, i)); + requests_headers.push(ethereum_beacon_client::get_block_header( + &client_http, + RPC_URL, + i, + )); } let headers = futures::future::join_all(requests_headers) @@ -460,9 +486,10 @@ async fn sync_update_requires_replaying_back() -> Result<()> { &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = utils::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); - let pub_keys = utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + let pub_keys = + ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network: Network::Sepolia, sync_committee_current_pub_keys: pub_keys, @@ -494,7 +521,10 @@ async fn sync_update_requires_replaying_back() -> Result<()> { ) .unwrap(); - let payload = Handle::SyncUpdate(utils::sync_update_from_finality(signature, finality_update)); + let payload = Handle::SyncUpdate(ethereum_beacon_client::sync_update_from_finality( + signature, + finality_update, + )); let gas_limit = client .calculate_handle_gas(None, program_id.into(), payload.encode(), 0, true) diff --git a/relayer/src/main.rs b/relayer/src/main.rs index 84b8f071..ac8cb313 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -12,6 +12,7 @@ use proof_storage::{FileSystemProofStorage, GearProofStorage, ProofStorage}; use relay_merkle_roots::MerkleRootRelayer; use utils_prometheus::MetricsBuilder; +mod ethereum_beacon_client; mod ethereum_checkpoints; mod genesis_config; mod message_relayer; diff --git a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs index 93c17235..7fa1bf28 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs @@ -1,4 +1,4 @@ -use crate::{ethereum_checkpoints::utils, RelayErc20Args}; +use crate::{ethereum_beacon_client, RelayErc20Args}; use alloy::{ network::primitives::BlockTransactionsKind, @@ -106,7 +106,7 @@ async fn build_inclusion_proof( block_number: u64, ) -> AnyResult { let beacon_block_parent = - utils::get_block_by_hash(client_http, rpc_url, beacon_root_parent).await?; + ethereum_beacon_client::get_block_by_hash(client_http, rpc_url, beacon_root_parent).await?; let beacon_block = LightBeaconBlock::from( find_beacon_block(client_http, rpc_url, block_number, &beacon_block_parent).await?, @@ -125,10 +125,15 @@ async fn build_inclusion_proof( Ok(BlockInclusionProof { block: beacon_block, - headers: utils::request_headers(client_http, rpc_url, slot + 1, slot_checkpoint + 1) - .await? - .into_iter() - .collect(), + headers: ethereum_beacon_client::request_headers( + client_http, + rpc_url, + slot + 1, + slot_checkpoint + 1, + ) + .await? + .into_iter() + .collect(), }) } @@ -148,16 +153,21 @@ async fn find_beacon_block( Ordering::Greater => (), } - let block_finalized = utils::get_block_finalized(client_http, rpc_url).await?; + let block_finalized = ethereum_beacon_client::get_block_finalized(client_http, rpc_url).await?; let slot_start = block_start.slot + 1; for slot in slot_start..=block_finalized.slot { - match utils::get_block(client_http, rpc_url, slot).await { + match ethereum_beacon_client::get_block(client_http, rpc_url, slot).await { Ok(block) if block.body.execution_payload.block_number == block_number => { return Ok(block) } Ok(_) => (), - Err(e) if e.downcast_ref::().is_some() => (), + Err(e) + if e.downcast_ref::() + .is_some() => + { + () + } Err(e) => return Err(e), } } From c7d081609f21c9c7823d90ecd8069790848426df Mon Sep 17 00:00:00 2001 From: mertwole Date: Fri, 11 Oct 2024 15:55:17 +0000 Subject: [PATCH 15/32] Fix clippy --- relayer/src/ethereum_beacon_client/mod.rs | 4 +- relayer/src/main.rs | 2 +- .../ethereum/deposit_event_extractor.rs | 45 +++++++------------ .../common/gear/checkpoints_extractor.rs | 2 +- .../gear/message_sender/compose_payload.rs | 15 ++----- .../common/gear/message_sender/mod.rs | 2 - relayer/src/message_relayer/common/mod.rs | 16 +------ .../eth_to_gear/all_token_transfers.rs | 7 ++- 8 files changed, 29 insertions(+), 64 deletions(-) diff --git a/relayer/src/ethereum_beacon_client/mod.rs b/relayer/src/ethereum_beacon_client/mod.rs index ade8b66a..0e1377f8 100644 --- a/relayer/src/ethereum_beacon_client/mod.rs +++ b/relayer/src/ethereum_beacon_client/mod.rs @@ -11,8 +11,8 @@ use ethereum_common::{ base_types::{BytesFixed, FixedArray}, beacon::{BLSPubKey, Block as BeaconBlock}, utils::{ - BeaconBlockHeaderResponse, BeaconBlockResponse, Bootstrap, BootstrapResponse, - FinalityUpdate, FinalityUpdateResponse, Update, UpdateResponse, + BeaconBlockHeaderResponse, BeaconBlockResponse, FinalityUpdate, FinalityUpdateResponse, + Update, UpdateResponse, }, MAX_REQUEST_LIGHT_CLIENT_UPDATES, }; diff --git a/relayer/src/main.rs b/relayer/src/main.rs index ac8cb313..c21582e0 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -324,7 +324,7 @@ async fn main() { .await .expect("Failed to fetch authority set state"); } - CliCommands::RelayErc20(args) => todo!(), + CliCommands::RelayErc20(_args) => todo!(), }; } diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index 2d07e79a..5f2602d1 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -1,14 +1,12 @@ use std::sync::mpsc::{channel, Receiver, Sender}; -use ethereum_client::{DepositEventEntry, EthApi}; +use ethereum_client::EthApi; use futures::executor::block_on; use prometheus::IntCounter; use sails_rs::H160; use utils_prometheus::{impl_metered_service, MeteredService}; -use crate::message_relayer::common::{ - ERC20Deposit, ERC20DepositData, ERC20DepositTx, EthereumBlockNumber, -}; +use crate::message_relayer::common::{ERC20DepositTx, EthereumBlockNumber}; pub struct DepositEventExtractor { eth_api: EthApi, @@ -70,35 +68,26 @@ impl DepositEventExtractor { async fn process_block_events( &self, block: EthereumBlockNumber, - sender: &Sender, + _sender: &Sender, ) -> anyhow::Result<()> { - let events = self + let _events = self .eth_api .fetch_deposit_events(self.erc20_treasury_address, block.0) .await?; - // TODO: fetch slot number by block number. - let slot_number = todo!(); - - self.metrics - .total_deposits_found - .inc_by(events.len() as u64); - - for DepositEventEntry { - from, - to, - token, - amount, - tx_hash, - } in events - { - sender.send( - ERC20DepositTx { - slot_number, - tx_hash, - } - )?; - } + // // TODO: fetch slot number by block number. + // let slot_number = todo!(); + + // self.metrics + // .total_deposits_found + // .inc_by(events.len() as u64); + + // for DepositEventEntry { tx_hash, .. } in events { + // sender.send(ERC20DepositTx { + // slot_number, + // tx_hash, + // })?; + // } Ok(()) } diff --git a/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs b/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs index 3909c3e6..09c188ee 100644 --- a/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs +++ b/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs @@ -101,7 +101,7 @@ impl CheckpointsExtractor { assert!(state.checkpoints.len() <= 1); - let latest_checkpoint = state.checkpoints.get(0); + let latest_checkpoint = state.checkpoints.first(); match (latest_checkpoint, self.latest_checkpoint) { (None, None) => {} diff --git a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs index 7fa1bf28..78da0297 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs @@ -1,4 +1,4 @@ -use crate::{ethereum_beacon_client, RelayErc20Args}; +use crate::ethereum_beacon_client; use alloy::{ network::primitives::BlockTransactionsKind, @@ -13,13 +13,9 @@ use checkpoint_light_client_io::ethereum_common::{ utils::{self as eth_utils, MerkleProof}, SLOTS_PER_EPOCH, }; -use erc20_relay_client::{ - traits::Erc20Relay as _, BlockInclusionProof, Erc20Relay, EthToVaraEvent, -}; -use futures::StreamExt; -use gclient::{GearApi, WSAddress}; +use erc20_relay_client::{BlockInclusionProof, EthToVaraEvent}; use reqwest::Client; -use sails_rs::{calls::*, events::*, gclient::calls::*, prelude::*}; +use sails_rs::prelude::*; use std::cmp::Ordering; // TODO: Don't create ethereum clients inside. @@ -164,10 +160,7 @@ async fn find_beacon_block( Ok(_) => (), Err(e) if e.downcast_ref::() - .is_some() => - { - () - } + .is_some() => {} Err(e) => return Err(e), } } diff --git a/relayer/src/message_relayer/common/gear/message_sender/mod.rs b/relayer/src/message_relayer/common/gear/message_sender/mod.rs index 02339093..1132ee8d 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/mod.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/mod.rs @@ -2,7 +2,6 @@ use std::sync::mpsc::Receiver; use futures::executor::block_on; use gclient::GearApi; -use gear_core::ids::MessageId; use primitive_types::H256; use prometheus::IntGauge; use sails_rs::{ @@ -89,7 +88,6 @@ impl MessageSender { checkpoints: &Receiver, ) -> anyhow::Result<()> { let mut waiting_checkpoint: Vec = vec![]; - let mut waiting_finality: Vec<(ERC20DepositTx, MessageId)> = vec![]; let mut latest_checkpoint_slot = None; diff --git a/relayer/src/message_relayer/common/mod.rs b/relayer/src/message_relayer/common/mod.rs index 165f6e35..5baef64f 100644 --- a/relayer/src/message_relayer/common/mod.rs +++ b/relayer/src/message_relayer/common/mod.rs @@ -1,6 +1,6 @@ use ethereum_client::TxHash; use gear_rpc_client::dto::Message; -use primitive_types::{H160, H256, U256}; +use primitive_types::H256; pub mod ethereum; pub mod gear; @@ -38,20 +38,6 @@ pub struct RelayedMerkleRoot { pub authority_set_id: AuthoritySetId, } -#[derive(Clone, Debug)] -pub struct ERC20Deposit { - pub data: ERC20DepositData, - pub tx: ERC20DepositTx, -} - -#[derive(Clone, Debug)] -pub struct ERC20DepositData { - pub from: H160, - pub to: H256, - pub token: H160, - pub amount: U256, -} - #[derive(Clone, Debug)] pub struct ERC20DepositTx { pub slot_number: EthereumSlotNumber, diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs index 068fc0e0..093d96f5 100644 --- a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -8,15 +8,13 @@ use gear_rpc_client::GearApi; use utils_prometheus::MeteredService; use crate::message_relayer::common::{ - self, ethereum::{ block_listener::BlockListener as EthereumBlockListener, - deposit_event_extractor::DepositEventExtractor, merkle_root_extractor::MerkleRootExtractor, + deposit_event_extractor::DepositEventExtractor, }, gear::{ block_listener::BlockListener as GearBlockListener, - checkpoints_extractor::CheckpointsExtractor, - message_queued_event_extractor::MessageQueuedEventExtractor, message_sender::MessageSender, + checkpoints_extractor::CheckpointsExtractor, message_sender::MessageSender, }, }; @@ -42,6 +40,7 @@ impl MeteredService for Relayer { } impl Relayer { + #[allow(clippy::too_many_arguments)] pub async fn new( gear_api: GearApi, gclient_gear_api: GclientGearApi, From aac57a7baddac7a2f97cf2a8d8e6f58140737fb2 Mon Sep 17 00:00:00 2001 From: mertwole Date: Fri, 11 Oct 2024 16:56:59 +0000 Subject: [PATCH 16/32] Move beacon client to a separate module --- relayer/src/ethereum_beacon_client/mod.rs | 263 +++++++++++------- relayer/src/ethereum_checkpoints/mod.rs | 15 +- .../src/ethereum_checkpoints/replay_back.rs | 57 ++-- .../src/ethereum_checkpoints/sync_update.rs | 19 +- relayer/src/ethereum_checkpoints/tests/mod.rs | 50 ++-- .../gear/message_sender/compose_payload.rs | 78 ++---- .../common/gear/message_sender/mod.rs | 17 +- 7 files changed, 228 insertions(+), 271 deletions(-) diff --git a/relayer/src/ethereum_beacon_client/mod.rs b/relayer/src/ethereum_beacon_client/mod.rs index 0e1377f8..5ffa9b90 100644 --- a/relayer/src/ethereum_beacon_client/mod.rs +++ b/relayer/src/ethereum_beacon_client/mod.rs @@ -1,8 +1,11 @@ -use std::{cmp, error::Error, fmt}; +use std::{ + cmp::{self, Ordering}, + error::Error, + fmt, +}; use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; use ark_serialize::CanonicalDeserialize; -// TODO: Fix this import use checkpoint_light_client_io::{ ArkScale, BeaconBlockHeader, G1TypeInfo, G2TypeInfo, Slot, SyncCommitteeKeys, SyncCommitteeUpdate, G1, G2, SYNC_COMMITTEE_SIZE, @@ -39,107 +42,160 @@ struct CodeResponse { message: String, } -pub async fn get(request_builder: RequestBuilder) -> AnyResult { - let bytes = request_builder - .send() - .await - .map_err(AnyError::from)? - .bytes() - .await - .map_err(AnyError::from)?; +#[derive(Clone)] +pub struct BeaconClient { + client: Client, + rpc_url: String, +} - match serde_json::from_slice::(&bytes) { - Ok(code_response) if code_response.code == 404 => Err(ErrorNotFound.into()), - _ => Ok(serde_json::from_slice::(&bytes).map_err(AnyError::from)?), +impl BeaconClient { + // TODO: Make a request to the node to check it's validity on construction. + pub fn new(rpc_url: String) -> Self { + // let client_http = ClientBuilder::new() + // .timeout(Duration::from_secs(beacon_timeout)) + // .build() + // .expect("Reqwest client should be created"); + + Self { + client: Client::new(), + rpc_url, + } } -} -#[cfg(test)] -pub async fn get_bootstrap( - client: &Client, - rpc_url: &str, - checkpoint: &str, -) -> AnyResult { - let checkpoint_no_prefix = match checkpoint.starts_with("0x") { - true => &checkpoint[2..], - false => checkpoint, - }; + pub async fn get_updates(&self, period: u64, count: u8) -> AnyResult { + let count = cmp::min(count, MAX_REQUEST_LIGHT_CLIENT_UPDATES); + let url = format!( + "{}/eth/v1/beacon/light_client/updates?start_period={}&count={}", + self.rpc_url, period, count + ); - let url = format!("{rpc_url}/eth/v1/beacon/light_client/bootstrap/0x{checkpoint_no_prefix}",); + get::(self.client.get(&url)).await + } - get::(client.get(&url)) - .await - .map(|response| response.data) -} + pub async fn get_block_header(&self, slot: u64) -> AnyResult { + let url = format!("{}/eth/v1/beacon/headers/{}", self.rpc_url, slot); -pub async fn get_updates( - client: &Client, - rpc_url: &str, - period: u64, - count: u8, -) -> AnyResult { - let count = cmp::min(count, MAX_REQUEST_LIGHT_CLIENT_UPDATES); - let url = format!( - "{rpc_url}/eth/v1/beacon/light_client/updates?start_period={period}&count={count}", - ); - - get::(client.get(&url)).await -} + get::(self.client.get(&url)) + .await + .map(|response| response.data.header.message) + } -pub async fn get_block_header( - client: &Client, - rpc_url: &str, - slot: u64, -) -> AnyResult { - let url = format!("{rpc_url}/eth/v1/beacon/headers/{slot}"); + pub async fn get_block_finalized(&self) -> AnyResult { + let url = format!("{}/eth/v2/beacon/blocks/finalized", self.rpc_url); - get::(client.get(&url)) - .await - .map(|response| response.data.header.message) -} + get::(self.client.get(&url)) + .await + .map(|response| response.data.message) + } -pub async fn get_block_finalized(client: &Client, rpc_url: &str) -> AnyResult { - let url = format!("{rpc_url}/eth/v2/beacon/blocks/finalized"); + pub async fn get_block(&self, slot: u64) -> AnyResult { + let url = format!("{}/eth/v2/beacon/blocks/{}", self.rpc_url, slot); - get::(client.get(&url)) - .await - .map(|response| response.data.message) -} + get::(self.client.get(&url)) + .await + .map(|response| response.data.message) + } -pub async fn get_block(client: &Client, rpc_url: &str, slot: u64) -> AnyResult { - let url = format!("{rpc_url}/eth/v2/beacon/blocks/{slot}"); + pub async fn get_block_by_hash(&self, hash: &[u8; 32]) -> AnyResult { + let mut hex_encoded = [0u8; 66]; + hex_encoded[0] = b'0'; + hex_encoded[1] = b'x'; + + hex::encode_to_slice(hash, &mut hex_encoded[2..]).expect("The buffer has the right size"); + let url = format!( + "{}/eth/v2/beacon/blocks/{}", + self.rpc_url, + String::from_utf8_lossy(&hex_encoded) + ); + + get::(self.client.get(&url)) + .await + .map(|response| response.data.message) + } - get::(client.get(&url)) - .await - .map(|response| response.data.message) -} + pub async fn get_finality_update(&self) -> AnyResult { + let url = format!( + "{}/eth/v1/beacon/light_client/finality_update", + self.rpc_url + ); -pub async fn get_block_by_hash( - client: &Client, - rpc_url: &str, - hash: &[u8; 32], -) -> AnyResult { - let mut hex_encoded = [0u8; 66]; - hex_encoded[0] = b'0'; - hex_encoded[1] = b'x'; - - hex::encode_to_slice(hash, &mut hex_encoded[2..]).expect("The buffer has the right size"); - let url = format!( - "{rpc_url}/eth/v2/beacon/blocks/{}", - String::from_utf8_lossy(&hex_encoded) - ); - - get::(client.get(&url)) - .await - .map(|response| response.data.message) -} + get::(self.client.get(&url)) + .await + .map(|response| response.data) + } -pub async fn get_finality_update(client: &Client, rpc_url: &str) -> AnyResult { - let url = format!("{rpc_url}/eth/v1/beacon/light_client/finality_update"); + pub async fn request_headers( + &self, + slot_start: Slot, + slot_end: Slot, + ) -> AnyResult> { + let batch_size = (slot_end - slot_start) as usize; + let mut requests_headers = Vec::with_capacity(batch_size); + for i in slot_start..slot_end { + requests_headers.push(self.get_block_header(i)); + } + + futures::future::join_all(requests_headers) + .await + .into_iter() + .filter(|maybe_header| !matches!(maybe_header, Err(e) if e.downcast_ref::().is_some())) + .collect::, _>>() + .map_err(|e| { + anyhow!("Failed to fetch block headers ([{slot_start}; {slot_end})): {e:?}") + }) + } - get::(client.get(&url)) - .await - .map(|response| response.data) + pub async fn find_beacon_block( + &self, + block_number: u64, + block_start: &BeaconBlock, + ) -> AnyResult { + match block_number.cmp(&block_start.body.execution_payload.block_number) { + Ordering::Less => { + return Err(anyhow!( + "Requested block number is behind the start beacon block" + )) + } + Ordering::Equal => return Ok(block_start.clone()), + Ordering::Greater => (), + } + + let block_finalized = self.get_block_finalized().await?; + + let slot_start = block_start.slot + 1; + for slot in slot_start..=block_finalized.slot { + match self.get_block(slot).await { + Ok(block) if block.body.execution_payload.block_number == block_number => { + return Ok(block) + } + Ok(_) => (), + Err(e) if e.downcast_ref::().is_some() => {} + Err(e) => return Err(e), + } + } + + Err(anyhow!("Block was not found")) + } + + #[cfg(test)] + pub async fn get_bootstrap( + &self, + checkpoint: &str, + ) -> AnyResult { + let checkpoint_no_prefix = match checkpoint.starts_with("0x") { + true => &checkpoint[2..], + false => checkpoint, + }; + + let url = format!( + "{}/eth/v1/beacon/light_client/bootstrap/0x{checkpoint_no_prefix}", + self.rpc_url + ); + + get::(self.client.get(&url)) + .await + .map(|response| response.data) + } } pub fn map_public_keys( @@ -223,24 +279,17 @@ pub fn try_from_hex_encoded>>(hex_encoded: &str) -> Option .and_then(|bytes| >>::try_from(bytes).ok()) } -pub async fn request_headers( - client_http: &Client, - beacon_endpoint: &str, - slot_start: Slot, - slot_end: Slot, -) -> AnyResult> { - let batch_size = (slot_end - slot_start) as usize; - let mut requests_headers = Vec::with_capacity(batch_size); - for i in slot_start..slot_end { - requests_headers.push(get_block_header(client_http, beacon_endpoint, i)); - } - - futures::future::join_all(requests_headers) +async fn get(request_builder: RequestBuilder) -> AnyResult { + let bytes = request_builder + .send() .await - .into_iter() - .filter(|maybe_header| !matches!(maybe_header, Err(e) if e.downcast_ref::().is_some())) - .collect::, _>>() - .map_err(|e| { - anyhow!("Failed to fetch block headers ([{slot_start}; {slot_end})): {e:?}") - }) + .map_err(AnyError::from)? + .bytes() + .await + .map_err(AnyError::from)?; + + match serde_json::from_slice::(&bytes) { + Ok(code_response) if code_response.code == 404 => Err(ErrorNotFound.into()), + _ => Ok(serde_json::from_slice::(&bytes).map_err(AnyError::from)?), + } } diff --git a/relayer/src/ethereum_checkpoints/mod.rs b/relayer/src/ethereum_checkpoints/mod.rs index d996518d..339e551a 100644 --- a/relayer/src/ethereum_checkpoints/mod.rs +++ b/relayer/src/ethereum_checkpoints/mod.rs @@ -6,14 +6,13 @@ use checkpoint_light_client_io::{ tree_hash::Hash256, Handle, HandleResult, Slot, SyncCommitteeUpdate, G2, }; -use ethereum_beacon_client::slots_batch::Iter as SlotsBatchIter; +use ethereum_beacon_client::{slots_batch::Iter as SlotsBatchIter, BeaconClient}; use futures::{ future::{self, Either}, pin_mut, }; use gclient::{EventProcessor, GearApi, WSAddress}; use parity_scale_codec::Decode; -use reqwest::{Client, ClientBuilder}; use tokio::{ signal::unix::{self, SignalKind}, sync::mpsc::{self, Sender}, @@ -40,7 +39,7 @@ pub async fn relay(args: RelayCheckpointsArgs) { let RelayCheckpointsArgs { program_id, beacon_endpoint, - beacon_timeout, + beacon_timeout: _, // TODO: Use this. vara_domain, vara_port, vara_suri, @@ -52,16 +51,13 @@ pub async fn relay(args: RelayCheckpointsArgs) { let program_id = ethereum_beacon_client::try_from_hex_encoded(&program_id) .expect("Expecting correct ProgramId"); - let client_http = ClientBuilder::new() - .timeout(Duration::from_secs(beacon_timeout)) - .build() - .expect("Reqwest client should be created"); + let beacon_client = BeaconClient::new(beacon_endpoint.clone()); let mut signal_interrupt = unix::signal(SignalKind::interrupt()).expect("Set SIGINT handler"); let (sender, mut receiver) = mpsc::channel(SIZE_CHANNEL); - sync_update::spawn_receiver(client_http.clone(), beacon_endpoint.clone(), sender); + sync_update::spawn_receiver(beacon_client.clone(), sender); let client = GearApi::init_with(WSAddress::new(vara_domain, vara_port), vara_suri) .await @@ -92,8 +88,7 @@ pub async fn relay(args: RelayCheckpointsArgs) { checkpoint, })) => { if let Err(e) = replay_back::execute( - &client_http, - &beacon_endpoint, + &beacon_client, &client, program_id, gas_limit, diff --git a/relayer/src/ethereum_checkpoints/replay_back.rs b/relayer/src/ethereum_checkpoints/replay_back.rs index 7febcb08..c0eeda79 100644 --- a/relayer/src/ethereum_checkpoints/replay_back.rs +++ b/relayer/src/ethereum_checkpoints/replay_back.rs @@ -1,10 +1,9 @@ use super::*; -use crate::ethereum_beacon_client; +use crate::ethereum_beacon_client::{self, BeaconClient}; #[allow(clippy::too_many_arguments)] pub async fn execute( - client_http: &Client, - beacon_endpoint: &str, + beacon_client: &BeaconClient, client: &GearApi, program_id: [u8; 32], gas_limit: u64, @@ -24,8 +23,7 @@ pub async fn execute( .ok_or(anyhow!("Failed to create slots_batch::Iter with slot_start = {slot_start}, slot_end = {slot_end}."))?; replay_back_slots( - client_http, - beacon_endpoint, + beacon_client, client, program_id, gas_limit, @@ -37,14 +35,10 @@ pub async fn execute( } let period_start = 1 + eth_utils::calculate_period(slot_start); - let updates = ethereum_beacon_client::get_updates( - client_http, - beacon_endpoint, - period_start, - MAX_REQUEST_LIGHT_CLIENT_UPDATES, - ) - .await - .map_err(|e| anyhow!("Failed to get updates for period {period_start}: {e:?}"))?; + let updates = beacon_client + .get_updates(period_start, MAX_REQUEST_LIGHT_CLIENT_UPDATES) + .await + .map_err(|e| anyhow!("Failed to get updates for period {period_start}: {e:?}"))?; let slot_last = sync_update.finalized_header.slot; for update in updates { @@ -61,8 +55,7 @@ pub async fn execute( let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update.data); replay_back_slots_start( - client_http, - beacon_endpoint, + beacon_client, client, program_id, gas_limit, @@ -72,8 +65,7 @@ pub async fn execute( .await?; replay_back_slots( - client_http, - beacon_endpoint, + beacon_client, client, program_id, gas_limit, @@ -91,8 +83,7 @@ pub async fn execute( .ok_or(anyhow!("Failed to create slots_batch::Iter with slot_start = {slot_start}, slot_last = {slot_last}."))?; replay_back_slots_start( - client_http, - beacon_endpoint, + beacon_client, client, program_id, gas_limit, @@ -102,8 +93,7 @@ pub async fn execute( .await?; replay_back_slots( - client_http, - beacon_endpoint, + beacon_client, client, program_id, gas_limit, @@ -117,8 +107,7 @@ pub async fn execute( } async fn replay_back_slots( - client_http: &Client, - beacon_endpoint: &str, + beacon_client: &BeaconClient, client: &GearApi, program_id: [u8; 32], gas_limit: u64, @@ -127,8 +116,7 @@ async fn replay_back_slots( for (slot_start, slot_end) in slots_batch_iter { log::debug!("slot_start = {slot_start}, slot_end = {slot_end}"); replay_back_slots_inner( - client_http, - beacon_endpoint, + beacon_client, client, program_id, slot_start, @@ -143,18 +131,14 @@ async fn replay_back_slots( #[allow(clippy::too_many_arguments)] async fn replay_back_slots_inner( - client_http: &Client, - beacon_endpoint: &str, + beacon_client: &BeaconClient, client: &GearApi, program_id: [u8; 32], slot_start: Slot, slot_end: Slot, gas_limit: u64, ) -> AnyResult<()> { - let payload = Handle::ReplayBack( - ethereum_beacon_client::request_headers(client_http, beacon_endpoint, slot_start, slot_end) - .await?, - ); + let payload = Handle::ReplayBack(beacon_client.request_headers(slot_start, slot_end).await?); let mut listener = client.subscribe().await?; @@ -183,8 +167,7 @@ async fn replay_back_slots_inner( #[allow(clippy::too_many_arguments)] async fn replay_back_slots_start( - client_http: &Client, - beacon_endpoint: &str, + beacon_client: &BeaconClient, client: &GearApi, program_id: [u8; 32], gas_limit: u64, @@ -197,13 +180,7 @@ async fn replay_back_slots_start( let payload = Handle::ReplayBackStart { sync_update, - headers: ethereum_beacon_client::request_headers( - client_http, - beacon_endpoint, - slot_start, - slot_end, - ) - .await?, + headers: beacon_client.request_headers(slot_start, slot_end).await?, }; let mut listener = client.subscribe().await?; diff --git a/relayer/src/ethereum_checkpoints/sync_update.rs b/relayer/src/ethereum_checkpoints/sync_update.rs index b17bbd4b..51f308fc 100644 --- a/relayer/src/ethereum_checkpoints/sync_update.rs +++ b/relayer/src/ethereum_checkpoints/sync_update.rs @@ -1,19 +1,15 @@ use super::*; -use crate::ethereum_beacon_client; +use crate::ethereum_beacon_client::{self, BeaconClient}; pub use checkpoint_light_client_io::sync_update::Error; use std::ops::ControlFlow::{self, *}; -pub fn spawn_receiver( - client_http: Client, - beacon_endpoint: String, - sender: Sender, -) { +pub fn spawn_receiver(beacon_client: BeaconClient, sender: Sender) { tokio::spawn(async move { log::info!("Update receiver spawned"); let mut failures = 0; loop { - match receive(&client_http, &beacon_endpoint, &sender).await { + match receive(&beacon_client, &sender).await { Ok(Break(_)) => break, Ok(Continue(_)) => (), Err(e) => { @@ -32,16 +28,17 @@ pub fn spawn_receiver( } async fn receive( - client_http: &Client, - beacon_endpoint: &str, + beacon_client: &BeaconClient, sender: &Sender, ) -> AnyResult> { - let finality_update = ethereum_beacon_client::get_finality_update(client_http, beacon_endpoint) + let finality_update = beacon_client + .get_finality_update() .await .map_err(|e| anyhow!("Unable to fetch FinalityUpdate: {e:?}"))?; let period = eth_utils::calculate_period(finality_update.finalized_header.slot); - let mut updates = ethereum_beacon_client::get_updates(client_http, beacon_endpoint, period, 1) + let mut updates = beacon_client + .get_updates(period, 1) .await .map_err(|e| anyhow!("Unable to fetch Updates: {e:?}"))?; diff --git a/relayer/src/ethereum_checkpoints/tests/mod.rs b/relayer/src/ethereum_checkpoints/tests/mod.rs index 1e4990fa..5feed583 100644 --- a/relayer/src/ethereum_checkpoints/tests/mod.rs +++ b/relayer/src/ethereum_checkpoints/tests/mod.rs @@ -1,4 +1,4 @@ -use crate::ethereum_beacon_client::{self, slots_batch}; +use crate::ethereum_beacon_client::{self, slots_batch, BeaconClient}; use checkpoint_light_client::WASM_BINARY; use checkpoint_light_client_io::{ ethereum_common::{ @@ -13,7 +13,6 @@ use checkpoint_light_client_io::{ }; use gclient::{EventListener, EventProcessor, GearApi, Result}; use parity_scale_codec::{Decode, Encode}; -use reqwest::Client; use tokio::time::{self, Duration}; const RPC_URL: &str = "http://127.0.0.1:5052"; @@ -66,15 +65,13 @@ async fn upload_program( } async fn init(network: Network) -> Result<()> { - let client_http = Client::new(); + let beacon_client = BeaconClient::new(RPC_URL.to_string()); // use the latest finality header as a checkpoint for bootstrapping - let finality_update = - ethereum_beacon_client::get_finality_update(&client_http, RPC_URL).await?; + let finality_update = beacon_client.get_finality_update().await?; let slot = finality_update.finalized_header.slot; let current_period = eth_utils::calculate_period(slot); - let mut updates = - ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period, 1).await?; + let mut updates = beacon_client.get_updates(current_period, 1).await?; println!( "finality_update slot = {}, period = {}", @@ -94,8 +91,7 @@ async fn init(network: Network) -> Result<()> { update.finalized_header.slot, checkpoint_hex ); - let bootstrap = - ethereum_beacon_client::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; + let bootstrap = beacon_client.get_bootstrap(&checkpoint_hex).await?; let signature = ::deserialize_compressed( &update.sync_aggregate.sync_committee_signature.0 .0[..], @@ -150,14 +146,12 @@ async fn init_mainnet() -> Result<()> { #[ignore] #[tokio::test] async fn init_and_updating() -> Result<()> { - let client_http = Client::new(); + let beacon_client = BeaconClient::new(RPC_URL.to_string()); // use the latest finality header as a checkpoint for bootstrapping - let finality_update = - ethereum_beacon_client::get_finality_update(&client_http, RPC_URL).await?; + let finality_update = beacon_client.get_finality_update().await?; let current_period = eth_utils::calculate_period(finality_update.finalized_header.slot); - let mut updates = - ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period, 1).await?; + let mut updates = beacon_client.get_updates(current_period, 1).await?; println!( "finality_update slot = {}, period = {}", @@ -177,8 +171,7 @@ async fn init_and_updating() -> Result<()> { update.finalized_header.slot, checkpoint_hex ); - let bootstrap = - ethereum_beacon_client::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; + let bootstrap = beacon_client.get_bootstrap(&checkpoint_hex).await?; let signature = ::deserialize_compressed( &update.sync_aggregate.sync_committee_signature.0 .0[..], @@ -213,12 +206,11 @@ async fn init_and_updating() -> Result<()> { println!(); for _ in 0..30 { - let update = ethereum_beacon_client::get_finality_update(&client_http, RPC_URL).await?; + let update = beacon_client.get_finality_update().await?; let slot: u64 = update.finalized_header.slot; let current_period = eth_utils::calculate_period(slot); - let mut updates = - ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period, 1).await?; + let mut updates = beacon_client.get_updates(current_period, 1).await?; match updates.pop() { Some(update) if updates.is_empty() && update.data.finalized_header.slot >= slot => { println!("update sync committee"); @@ -296,7 +288,7 @@ async fn init_and_updating() -> Result<()> { #[ignore] #[tokio::test] async fn replaying_back() -> Result<()> { - let client_http = Client::new(); + let beacon_client = BeaconClient::new(RPC_URL.to_string()); let finality_update: FinalityUpdateResponse = serde_json::from_slice(FINALITY_UPDATE_5_254_112).unwrap(); @@ -308,8 +300,7 @@ async fn replaying_back() -> Result<()> { // This SyncCommittee operated for about 13K slots, so we make adjustments let current_period = eth_utils::calculate_period(finality_update.finalized_header.slot); - let mut updates = - ethereum_beacon_client::get_updates(&client_http, RPC_URL, current_period - 1, 1).await?; + let mut updates = beacon_client.get_updates(current_period - 1, 1).await?; let update = match updates.pop() { Some(update) if updates.is_empty() => update.data, @@ -318,8 +309,7 @@ async fn replaying_back() -> Result<()> { let checkpoint = update.finalized_header.tree_hash_root(); let checkpoint_hex = hex::encode(checkpoint); - let bootstrap = - ethereum_beacon_client::get_bootstrap(&client_http, RPC_URL, &checkpoint_hex).await?; + let bootstrap = beacon_client.get_bootstrap(&checkpoint_hex).await?; println!("bootstrap slot = {}", bootstrap.header.slot); println!("update slot = {}", update.finalized_header.slot); @@ -365,11 +355,7 @@ async fn replaying_back() -> Result<()> { if let Some((slot_start, slot_end)) = slots_batch_iter.next() { let mut requests_headers = Vec::with_capacity(batch_size as usize); for i in slot_start..slot_end { - requests_headers.push(ethereum_beacon_client::get_block_header( - &client_http, - RPC_URL, - i, - )); + requests_headers.push(beacon_client.get_block_header(i)); } let headers = futures::future::join_all(requests_headers) @@ -413,11 +399,7 @@ async fn replaying_back() -> Result<()> { for (slot_start, slot_end) in slots_batch_iter { let mut requests_headers = Vec::with_capacity(batch_size as usize); for i in slot_start..slot_end { - requests_headers.push(ethereum_beacon_client::get_block_header( - &client_http, - RPC_URL, - i, - )); + requests_headers.push(beacon_client.get_block_header(i)); } let headers = futures::future::join_all(requests_headers) diff --git a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs index 78da0297..edde8e9c 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs @@ -1,4 +1,4 @@ -use crate::ethereum_beacon_client; +use crate::ethereum_beacon_client::BeaconClient; use alloy::{ network::primitives::BlockTransactionsKind, @@ -9,18 +9,16 @@ use alloy_eips::BlockNumberOrTag; use alloy_rlp::Encodable; use anyhow::{anyhow, Result as AnyResult}; use checkpoint_light_client_io::ethereum_common::{ - beacon::{light::Block as LightBeaconBlock, Block as BeaconBlock}, + beacon::light::Block as LightBeaconBlock, utils::{self as eth_utils, MerkleProof}, SLOTS_PER_EPOCH, }; use erc20_relay_client::{BlockInclusionProof, EthToVaraEvent}; -use reqwest::Client; use sails_rs::prelude::*; -use std::cmp::Ordering; // TODO: Don't create ethereum clients inside. pub async fn compose( - beacon_endpoint: String, + beacon_client: &BeaconClient, eth_endpoint: String, tx_hash: TxHash, ) -> AnyResult { @@ -54,14 +52,9 @@ pub async fn compose( .header .number .ok_or(anyhow!("Unable to determine Ethereum block number"))?; - let client_http = Client::new(); - let proof_block = build_inclusion_proof( - &client_http, - &beacon_endpoint, - &beacon_root_parent, - block_number, - ) - .await?; + + let proof_block = + build_inclusion_proof(beacon_client, &beacon_root_parent, block_number).await?; // receipt Merkle-proof let tx_index = receipt @@ -96,16 +89,16 @@ pub async fn compose( } async fn build_inclusion_proof( - client_http: &Client, - rpc_url: &str, + beacon_client: &BeaconClient, beacon_root_parent: &[u8; 32], block_number: u64, ) -> AnyResult { - let beacon_block_parent = - ethereum_beacon_client::get_block_by_hash(client_http, rpc_url, beacon_root_parent).await?; + let beacon_block_parent = beacon_client.get_block_by_hash(beacon_root_parent).await?; let beacon_block = LightBeaconBlock::from( - find_beacon_block(client_http, rpc_url, block_number, &beacon_block_parent).await?, + beacon_client + .find_beacon_block(block_number, &beacon_block_parent) + .await?, ); let slot = beacon_block.slot; @@ -121,49 +114,10 @@ async fn build_inclusion_proof( Ok(BlockInclusionProof { block: beacon_block, - headers: ethereum_beacon_client::request_headers( - client_http, - rpc_url, - slot + 1, - slot_checkpoint + 1, - ) - .await? - .into_iter() - .collect(), + headers: beacon_client + .request_headers(slot + 1, slot_checkpoint + 1) + .await? + .into_iter() + .collect(), }) } - -async fn find_beacon_block( - client_http: &Client, - rpc_url: &str, - block_number: u64, - block_start: &BeaconBlock, -) -> AnyResult { - match block_number.cmp(&block_start.body.execution_payload.block_number) { - Ordering::Less => { - return Err(anyhow!( - "Requested block number is behind the start beacon block" - )) - } - Ordering::Equal => return Ok(block_start.clone()), - Ordering::Greater => (), - } - - let block_finalized = ethereum_beacon_client::get_block_finalized(client_http, rpc_url).await?; - - let slot_start = block_start.slot + 1; - for slot in slot_start..=block_finalized.slot { - match ethereum_beacon_client::get_block(client_http, rpc_url, slot).await { - Ok(block) if block.body.execution_payload.block_number == block_number => { - return Ok(block) - } - Ok(_) => (), - Err(e) - if e.downcast_ref::() - .is_some() => {} - Err(e) => return Err(e), - } - } - - Err(anyhow!("Block was not found")) -} diff --git a/relayer/src/message_relayer/common/gear/message_sender/mod.rs b/relayer/src/message_relayer/common/gear/message_sender/mod.rs index 1132ee8d..27570e7b 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/mod.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/mod.rs @@ -12,7 +12,10 @@ use sails_rs::{ use erc20_relay_client::{traits::Erc20Relay as _, Erc20Relay}; use utils_prometheus::{impl_metered_service, MeteredService}; -use crate::message_relayer::common::{ERC20DepositTx, EthereumSlotNumber}; +use crate::{ + ethereum_beacon_client::BeaconClient, + message_relayer::common::{ERC20DepositTx, EthereumSlotNumber}, +}; mod compose_payload; @@ -125,12 +128,12 @@ impl MessageSender { } async fn submit_message(&self, message: &ERC20DepositTx) -> anyhow::Result<()> { - let message = compose_payload::compose( - self.beacon_endpoint.clone(), - self.eth_endpoint.clone(), - message.tx_hash, - ) - .await?; + // TODO: Don't create it here. + let beacon_client = BeaconClient::new(self.beacon_endpoint.clone()); + + let message = + compose_payload::compose(&beacon_client, self.eth_endpoint.clone(), message.tx_hash) + .await?; let gas_limit_block = self.gear_api.block_gas_limit()?; // Use 95% of block gas limit for all extrinsics. From 641e471c3b93ac22d22fb7b3547d16a11a5c9514 Mon Sep 17 00:00:00 2001 From: mertwole Date: Fri, 11 Oct 2024 18:27:41 +0000 Subject: [PATCH 17/32] Inject beacon client dependency --- .../common/gear/message_sender/mod.rs | 18 +++++++-------- .../eth_to_gear/all_token_transfers.rs | 23 +++++++++++-------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/relayer/src/message_relayer/common/gear/message_sender/mod.rs b/relayer/src/message_relayer/common/gear/message_sender/mod.rs index 27570e7b..cfb10a4c 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/mod.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/mod.rs @@ -21,8 +21,8 @@ mod compose_payload; pub struct MessageSender { gear_api: GearApi, + beacon_client: BeaconClient, // TODO: Don't store strings here. - beacon_endpoint: String, eth_endpoint: String, ethereum_event_client_address: H256, @@ -56,14 +56,14 @@ impl_metered_service! { impl MessageSender { pub fn new( gear_api: GearApi, - beacon_endpoint: String, + beacon_client: BeaconClient, eth_endpoint: String, ethereum_event_client_address: H256, ) -> Self { Self { gear_api, + beacon_client, - beacon_endpoint, eth_endpoint, ethereum_event_client_address, @@ -128,12 +128,12 @@ impl MessageSender { } async fn submit_message(&self, message: &ERC20DepositTx) -> anyhow::Result<()> { - // TODO: Don't create it here. - let beacon_client = BeaconClient::new(self.beacon_endpoint.clone()); - - let message = - compose_payload::compose(&beacon_client, self.eth_endpoint.clone(), message.tx_hash) - .await?; + let message = compose_payload::compose( + &self.beacon_client, + self.eth_endpoint.clone(), + message.tx_hash, + ) + .await?; let gas_limit_block = self.gear_api.block_gas_limit()?; // Use 95% of block gas limit for all extrinsics. diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs index 093d96f5..c1bfb66a 100644 --- a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -7,14 +7,17 @@ use ethereum_client::EthApi; use gear_rpc_client::GearApi; use utils_prometheus::MeteredService; -use crate::message_relayer::common::{ - ethereum::{ - block_listener::BlockListener as EthereumBlockListener, - deposit_event_extractor::DepositEventExtractor, - }, - gear::{ - block_listener::BlockListener as GearBlockListener, - checkpoints_extractor::CheckpointsExtractor, message_sender::MessageSender, +use crate::{ + ethereum_beacon_client::BeaconClient, + message_relayer::common::{ + ethereum::{ + block_listener::BlockListener as EthereumBlockListener, + deposit_event_extractor::DepositEventExtractor, + }, + gear::{ + block_listener::BlockListener as GearBlockListener, + checkpoints_extractor::CheckpointsExtractor, message_sender::MessageSender, + }, }, }; @@ -45,7 +48,7 @@ impl Relayer { gear_api: GearApi, gclient_gear_api: GclientGearApi, eth_api: EthApi, - beacon_endpoint: String, + beacon_client: BeaconClient, eth_endpoint: String, erc20_treasury_address: H160, checkpoint_light_client_address: H256, @@ -68,7 +71,7 @@ impl Relayer { let gear_message_sender = MessageSender::new( gclient_gear_api, - beacon_endpoint, + beacon_client, eth_endpoint, ethereum_event_client_address, ); From ff69924b41f7699667ec3caaaeb2f860b9e12cfd Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 14 Oct 2024 07:43:58 +0000 Subject: [PATCH 18/32] Finish deposit_event_extractor --- ethereum/client/src/lib.rs | 5 ++ .../ethereum/deposit_event_extractor.rs | 64 ++++++++++++++----- .../eth_to_gear/all_token_transfers.rs | 7 +- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/ethereum/client/src/lib.rs b/ethereum/client/src/lib.rs index bcef3775..836132f5 100644 --- a/ethereum/client/src/lib.rs +++ b/ethereum/client/src/lib.rs @@ -123,6 +123,11 @@ impl EthApi { }) } + // TODO: Don't expose provider here. + pub fn raw_provider(&self) -> &ProviderType { + &self.contracts.provider + } + pub async fn get_approx_balance(&self) -> Result { self.contracts.get_approx_balance(self.public_key).await } diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index 5f2602d1..009856fd 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -1,15 +1,24 @@ use std::sync::mpsc::{channel, Receiver, Sender}; -use ethereum_client::EthApi; +use alloy::providers::Provider; +use alloy_eips::BlockNumberOrTag; +use anyhow::anyhow; use futures::executor::block_on; use prometheus::IntCounter; use sails_rs::H160; + +use ethereum_client::{DepositEventEntry, EthApi}; use utils_prometheus::{impl_metered_service, MeteredService}; -use crate::message_relayer::common::{ERC20DepositTx, EthereumBlockNumber}; +use crate::{ + ethereum_beacon_client::BeaconClient, + message_relayer::common::{ERC20DepositTx, EthereumBlockNumber, EthereumSlotNumber}, +}; pub struct DepositEventExtractor { eth_api: EthApi, + beacon_client: BeaconClient, + erc20_treasury_address: H160, metrics: Metrics, @@ -31,9 +40,11 @@ impl_metered_service! { } impl DepositEventExtractor { - pub fn new(eth_api: EthApi, erc20_treasury_address: H160) -> Self { + pub fn new(eth_api: EthApi, beacon_client: BeaconClient, erc20_treasury_address: H160) -> Self { Self { eth_api, + beacon_client, + erc20_treasury_address, metrics: Metrics::new(), @@ -68,26 +79,47 @@ impl DepositEventExtractor { async fn process_block_events( &self, block: EthereumBlockNumber, - _sender: &Sender, + sender: &Sender, ) -> anyhow::Result<()> { - let _events = self + let events = self .eth_api .fetch_deposit_events(self.erc20_treasury_address, block.0) .await?; - // // TODO: fetch slot number by block number. - // let slot_number = todo!(); + let block_body = self + .eth_api + .raw_provider() + .get_block_by_number(BlockNumberOrTag::Number(block.0), false) + .await? + .ok_or(anyhow!("Ethereum block #{} is missing", block.0))?; + + let beacon_root_parent = block_body.header.parent_beacon_block_root.ok_or(anyhow!( + "Unable to determine root of parent beacon block for block #{}", + block.0 + ))?; + + let beacon_block_parent = self + .beacon_client + .get_block_by_hash(&beacon_root_parent.0) + .await?; + + let beacon_block = self + .beacon_client + .find_beacon_block(block.0, &beacon_block_parent) + .await?; - // self.metrics - // .total_deposits_found - // .inc_by(events.len() as u64); + let slot_number = EthereumSlotNumber(beacon_block.slot); - // for DepositEventEntry { tx_hash, .. } in events { - // sender.send(ERC20DepositTx { - // slot_number, - // tx_hash, - // })?; - // } + self.metrics + .total_deposits_found + .inc_by(events.len() as u64); + + for DepositEventEntry { tx_hash, .. } in events { + sender.send(ERC20DepositTx { + slot_number, + tx_hash, + })?; + } Ok(()) } diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs index c1bfb66a..dff568f5 100644 --- a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -63,8 +63,11 @@ impl Relayer { let ethereum_block_listener = EthereumBlockListener::new(eth_api.clone(), from_eth_block); - let deposit_event_extractor = - DepositEventExtractor::new(eth_api.clone(), erc20_treasury_address); + let deposit_event_extractor = DepositEventExtractor::new( + eth_api.clone(), + beacon_client.clone(), + erc20_treasury_address, + ); let checkpoints_extractor = CheckpointsExtractor::new(gear_api.clone(), checkpoint_light_client_address); From 0f5a7b8d99c18ff018bd8e518d9fdf2fdd22ef0b Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 14 Oct 2024 09:29:11 +0000 Subject: [PATCH 19/32] Finalize BeaconClient --- relayer/src/ethereum_beacon_client/mod.rs | 41 +++++++++++++------ relayer/src/ethereum_checkpoints/mod.rs | 7 +++- relayer/src/ethereum_checkpoints/tests/mod.rs | 12 ++++-- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/relayer/src/ethereum_beacon_client/mod.rs b/relayer/src/ethereum_beacon_client/mod.rs index 5ffa9b90..7f0f5dd3 100644 --- a/relayer/src/ethereum_beacon_client/mod.rs +++ b/relayer/src/ethereum_beacon_client/mod.rs @@ -2,9 +2,10 @@ use std::{ cmp::{self, Ordering}, error::Error, fmt, + time::Duration, }; -use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; +use anyhow::{anyhow, bail, Error as AnyError, Result as AnyResult}; use ark_serialize::CanonicalDeserialize; use checkpoint_light_client_io::{ ArkScale, BeaconBlockHeader, G1TypeInfo, G2TypeInfo, Slot, SyncCommitteeKeys, @@ -19,7 +20,7 @@ use ethereum_common::{ }, MAX_REQUEST_LIGHT_CLIENT_UPDATES, }; -use reqwest::{Client, RequestBuilder}; +use reqwest::{Client, ClientBuilder, RequestBuilder}; use serde::{de::DeserializeOwned, Deserialize}; pub mod slots_batch; @@ -49,17 +50,33 @@ pub struct BeaconClient { } impl BeaconClient { - // TODO: Make a request to the node to check it's validity on construction. - pub fn new(rpc_url: String) -> Self { - // let client_http = ClientBuilder::new() - // .timeout(Duration::from_secs(beacon_timeout)) - // .build() - // .expect("Reqwest client should be created"); - - Self { - client: Client::new(), - rpc_url, + pub async fn connect(rpc_url: String, timeout: Option) -> AnyResult { + let client = ClientBuilder::new(); + + let client = if let Some(timeout) = timeout { + client.timeout(timeout) + } else { + client + }; + + let client = client + .build() + .expect("Failed to create reqwest http client"); + + let health = client + .get(format!("{}/eth/v1/node/health", rpc_url)) + .send() + .await? + .status(); + + if !health.is_success() { + bail!( + "Tried to connect to unhealthy beacon node. Status code returned: {}", + health + ); } + + Ok(Self { client, rpc_url }) } pub async fn get_updates(&self, period: u64, count: u8) -> AnyResult { diff --git a/relayer/src/ethereum_checkpoints/mod.rs b/relayer/src/ethereum_checkpoints/mod.rs index 339e551a..51c5f021 100644 --- a/relayer/src/ethereum_checkpoints/mod.rs +++ b/relayer/src/ethereum_checkpoints/mod.rs @@ -39,7 +39,7 @@ pub async fn relay(args: RelayCheckpointsArgs) { let RelayCheckpointsArgs { program_id, beacon_endpoint, - beacon_timeout: _, // TODO: Use this. + beacon_timeout, vara_domain, vara_port, vara_suri, @@ -51,7 +51,10 @@ pub async fn relay(args: RelayCheckpointsArgs) { let program_id = ethereum_beacon_client::try_from_hex_encoded(&program_id) .expect("Expecting correct ProgramId"); - let beacon_client = BeaconClient::new(beacon_endpoint.clone()); + let timeout = Some(Duration::from_secs(beacon_timeout)); + let beacon_client = BeaconClient::connect(beacon_endpoint.clone(), timeout) + .await + .expect("Failed to connect to beacon node"); let mut signal_interrupt = unix::signal(SignalKind::interrupt()).expect("Set SIGINT handler"); diff --git a/relayer/src/ethereum_checkpoints/tests/mod.rs b/relayer/src/ethereum_checkpoints/tests/mod.rs index 5feed583..5a5c833c 100644 --- a/relayer/src/ethereum_checkpoints/tests/mod.rs +++ b/relayer/src/ethereum_checkpoints/tests/mod.rs @@ -65,7 +65,9 @@ async fn upload_program( } async fn init(network: Network) -> Result<()> { - let beacon_client = BeaconClient::new(RPC_URL.to_string()); + let beacon_client = BeaconClient::connect(RPC_URL.to_string(), None) + .await + .expect("Failed to connect to beacon node"); // use the latest finality header as a checkpoint for bootstrapping let finality_update = beacon_client.get_finality_update().await?; @@ -146,7 +148,9 @@ async fn init_mainnet() -> Result<()> { #[ignore] #[tokio::test] async fn init_and_updating() -> Result<()> { - let beacon_client = BeaconClient::new(RPC_URL.to_string()); + let beacon_client = BeaconClient::connect(RPC_URL.to_string(), None) + .await + .expect("Failed to connect to beacon node"); // use the latest finality header as a checkpoint for bootstrapping let finality_update = beacon_client.get_finality_update().await?; @@ -288,7 +292,9 @@ async fn init_and_updating() -> Result<()> { #[ignore] #[tokio::test] async fn replaying_back() -> Result<()> { - let beacon_client = BeaconClient::new(RPC_URL.to_string()); + let beacon_client = BeaconClient::connect(RPC_URL.to_string(), None) + .await + .expect("Failed to connect to beacon node"); let finality_update: FinalityUpdateResponse = serde_json::from_slice(FINALITY_UPDATE_5_254_112).unwrap(); From ad9afe619a2478f8a907205e0d03c8433cdcdfad Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 14 Oct 2024 09:35:13 +0000 Subject: [PATCH 20/32] Implement TODOs --- .../gear/message_sender/compose_payload.rs | 16 ++++++---------- .../common/gear/message_sender/mod.rs | 17 ++++++----------- .../eth_to_gear/all_token_transfers.rs | 3 +-- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs index edde8e9c..57416465 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/compose_payload.rs @@ -1,29 +1,25 @@ use crate::ethereum_beacon_client::BeaconClient; -use alloy::{ - network::primitives::BlockTransactionsKind, - primitives::TxHash, - providers::{Provider, ProviderBuilder}, -}; +use alloy::{network::primitives::BlockTransactionsKind, primitives::TxHash, providers::Provider}; use alloy_eips::BlockNumberOrTag; use alloy_rlp::Encodable; use anyhow::{anyhow, Result as AnyResult}; +use sails_rs::prelude::*; + use checkpoint_light_client_io::ethereum_common::{ beacon::light::Block as LightBeaconBlock, utils::{self as eth_utils, MerkleProof}, SLOTS_PER_EPOCH, }; use erc20_relay_client::{BlockInclusionProof, EthToVaraEvent}; -use sails_rs::prelude::*; +use ethereum_client::EthApi; -// TODO: Don't create ethereum clients inside. pub async fn compose( beacon_client: &BeaconClient, - eth_endpoint: String, + eth_client: &EthApi, tx_hash: TxHash, ) -> AnyResult { - let rpc_url = eth_endpoint.parse()?; - let provider = ProviderBuilder::new().on_http(rpc_url); + let provider = eth_client.raw_provider(); let receipt = provider .get_transaction_receipt(tx_hash) diff --git a/relayer/src/message_relayer/common/gear/message_sender/mod.rs b/relayer/src/message_relayer/common/gear/message_sender/mod.rs index cfb10a4c..153e57bc 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/mod.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/mod.rs @@ -1,5 +1,6 @@ use std::sync::mpsc::Receiver; +use ethereum_client::EthApi; use futures::executor::block_on; use gclient::GearApi; use primitive_types::H256; @@ -21,9 +22,8 @@ mod compose_payload; pub struct MessageSender { gear_api: GearApi, + eth_api: EthApi, beacon_client: BeaconClient, - // TODO: Don't store strings here. - eth_endpoint: String, ethereum_event_client_address: H256, @@ -56,16 +56,15 @@ impl_metered_service! { impl MessageSender { pub fn new( gear_api: GearApi, + eth_api: EthApi, beacon_client: BeaconClient, - eth_endpoint: String, ethereum_event_client_address: H256, ) -> Self { Self { gear_api, + eth_api, beacon_client, - eth_endpoint, - ethereum_event_client_address, metrics: Metrics::new(), @@ -128,12 +127,8 @@ impl MessageSender { } async fn submit_message(&self, message: &ERC20DepositTx) -> anyhow::Result<()> { - let message = compose_payload::compose( - &self.beacon_client, - self.eth_endpoint.clone(), - message.tx_hash, - ) - .await?; + let message = + compose_payload::compose(&self.beacon_client, &self.eth_api, message.tx_hash).await?; let gas_limit_block = self.gear_api.block_gas_limit()?; // Use 95% of block gas limit for all extrinsics. diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs index dff568f5..cfdb8515 100644 --- a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -49,7 +49,6 @@ impl Relayer { gclient_gear_api: GclientGearApi, eth_api: EthApi, beacon_client: BeaconClient, - eth_endpoint: String, erc20_treasury_address: H160, checkpoint_light_client_address: H256, ethereum_event_client_address: H256, @@ -74,8 +73,8 @@ impl Relayer { let gear_message_sender = MessageSender::new( gclient_gear_api, + eth_api, beacon_client, - eth_endpoint, ethereum_event_client_address, ); From 61b3461f662a81c019d61ed9da5a958fe96a29ac Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 14 Oct 2024 10:42:02 +0000 Subject: [PATCH 21/32] Compose cli args --- relayer/src/main.rs | 174 +++++++++++++++++++++++++++++++++----------- 1 file changed, 133 insertions(+), 41 deletions(-) diff --git a/relayer/src/main.rs b/relayer/src/main.rs index c21582e0..59480680 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -3,11 +3,14 @@ extern crate pretty_env_logger; use std::time::Duration; use clap::{Args, Parser, Subcommand}; -use message_relayer::gear_to_eth::{all_token_transfers, paid_token_transfers}; +use ethereum_beacon_client::BeaconClient; +use gclient::{GearApi as GclientGearApi, WSAddress}; use pretty_env_logger::env_logger::fmt::TimestampPrecision; +use primitive_types::{H160, H256}; use ethereum_client::EthApi; use gear_rpc_client::GearApi; +use message_relayer::{eth_to_gear, gear_to_eth}; use proof_storage::{FileSystemProofStorage, GearProofStorage, ProofStorage}; use relay_merkle_roots::MerkleRootRelayer; use utils_prometheus::MetricsBuilder; @@ -21,6 +24,7 @@ mod prover_interface; mod relay_merkle_roots; const DEFAULT_VARA_RPC: &str = "ws://localhost:8989"; +const DEFAULT_ETH_BEACON_RPC: &str = "http://localhost:50000"; const DEFAULT_ETH_RPC: &str = "http://localhost:8545"; const DEFAULT_PROMETHEUS_ENDPOINT: &str = "0.0.0.0:9090"; @@ -89,6 +93,7 @@ struct FetchAuthoritySetStateArgs { write_to_file: bool, } +// TODO: Separate domain and port. #[derive(Args)] struct VaraEndpointArg { /// Address of the VARA RPC endpoint @@ -120,6 +125,21 @@ struct EthereumArgs { mq_address: String, } +#[derive(Args)] +struct BeaconRpcArgs { + /// Address of the ethereum beacon RPC endpoint + #[arg( + long = "ethereum-beacon-rpc", + default_value = DEFAULT_ETH_BEACON_RPC, + env = "ETH_BEACON_RPC" + )] + endpoint: String, + + /// Timeout in seconds for requests to the ethereum beacon RPC + #[arg(long = "ethereum-beacon-rpc-timeout", env = "ETH_BEACON_RPC_TIMEOUT")] + timeout: Option, +} + #[derive(Args)] struct PrometheusArgs { /// Address of the prometheus endpoint @@ -173,40 +193,42 @@ struct RelayCheckpointsArgs { #[derive(Args)] struct RelayErc20Args { - /// Specify ProgramId of the program - #[arg(long, env = "ADDRESS")] - program_id: String, + /// Address of the ERC20Treasury contract on ethereum + #[arg(long = "erc20-treasury-address", env = "ERC20_TREASURY_ADDRESS")] + erc20_treasury_address: String, - /// Specify an endpoint providing Beacon API - #[arg(long, env = "BEACON_ENDPOINT")] - beacon_endpoint: String, + /// Address of the checkpoint-light-client program on gear + #[arg( + long = "checkpoint-light-client-address", + env = "CHECKPOINT_LIGHT_CLIENT_ADDRESS" + )] + checkpoint_light_client_address: String, - /// Domain of the VARA RPC endpoint - #[arg(long, default_value = "ws://127.0.0.1", env = "VARA_DOMAIN")] - vara_domain: String, + /// Address of the ethereum-event-client program on gear + #[arg( + long = "ethereum-event-client-address", + env = "ETHEREUM_EVENT_CLIENT_ADDRESS" + )] + ethereum_event_client_address: String, - /// Port of the VARA RPC endpoint - #[arg(long, default_value = "9944", env = "VARA_PORT")] - vara_port: u16, + #[clap(flatten)] + vara_endpoint: VaraEndpointArg, /// Substrate URI that identifies a user by a mnemonic phrase or /// provides default users from the keyring (e.g., "//Alice", "//Bob", /// etc.). The password for URI should be specified in the same `suri`, /// separated by the ':' char - #[arg(long, default_value = "//Alice", env = "VARA_SURI")] + #[arg(long, env = "VARA_SURI")] vara_suri: String, - /// Address of the ethereum endpoint - #[arg( - long = "ethereum-endpoint", - default_value = DEFAULT_ETH_RPC, - env = "ETH_RPC" - )] - eth_endpoint: String, + #[clap(flatten)] + ethereum_args: EthereumArgs, - /// Specify the hash of the ERC20-transaction to relay - #[arg(long, env = "TX_HASH")] - tx_hash: String, + #[clap(flatten)] + beacon_rpc: BeaconRpcArgs, + + #[clap(flatten)] + prometheus_args: PrometheusArgs, } #[tokio::main] @@ -269,20 +291,9 @@ async fn main() { let eth_api = create_eth_client(&args.ethereum_args); if let Some(bridging_payment_address) = args.bridging_payment_address { - let bridging_payment_address = if &bridging_payment_address[..2] == "0x" { - &bridging_payment_address[2..] - } else { - &bridging_payment_address - }; - - let bridging_payment_address: [u8; 32] = hex::decode(bridging_payment_address) - .expect("Wrong format of bridging-payment-address") - .try_into() - .expect("Wrong format of bridging-payment-address"); + let bridging_payment_address = decode_h256(&bridging_payment_address); - let bridging_payment_address = bridging_payment_address.into(); - - let relayer = paid_token_transfers::Relayer::new( + let relayer = gear_to_eth::paid_token_transfers::Relayer::new( gear_api, eth_api, args.from_block, @@ -299,9 +310,13 @@ async fn main() { relayer.run(); } else { - let relayer = all_token_transfers::Relayer::new(gear_api, eth_api, args.from_block) - .await - .unwrap(); + let relayer = gear_to_eth::all_token_transfers::Relayer::new( + gear_api, + eth_api, + args.from_block, + ) + .await + .unwrap(); MetricsBuilder::new() .register_service(&relayer) @@ -324,10 +339,60 @@ async fn main() { .await .expect("Failed to fetch authority set state"); } - CliCommands::RelayErc20(_args) => todo!(), + CliCommands::RelayErc20(args) => { + let eth_api = create_eth_client(&args.ethereum_args); + let beacon_client = create_beacon_client(&args.beacon_rpc).await; + + let gear_api = create_gear_client(&args.vara_endpoint).await; + let gclient_client = create_gclient_client(&args.vara_endpoint, &args.vara_suri).await; + + let erc20_treasury_address = decode_h160(&args.erc20_treasury_address); + let checkpoint_light_client_address = + decode_h256(&args.checkpoint_light_client_address); + let ethereum_event_client_address = decode_h256(&args.ethereum_event_client_address); + + let relayer = eth_to_gear::all_token_transfers::Relayer::new( + gear_api, + gclient_client, + eth_api, + beacon_client, + erc20_treasury_address, + checkpoint_light_client_address, + ethereum_event_client_address, + ) + .await + .expect("Failed to create relayer"); + + MetricsBuilder::new() + .register_service(&relayer) + .build() + .run(args.prometheus_args.endpoint) + .await; + + relayer.run(); + + loop { + // relayer.run() spawns thread and exits, so we need to add this loop after calling run. + std::thread::sleep(Duration::from_millis(100)); + } + } }; } +async fn create_gclient_client(args: &VaraEndpointArg, vara_suri: &str) -> GclientGearApi { + let endpoint_parts: Vec<_> = args.vara_endpoint.split(':').collect(); + let [domain_1, domain_2, port] = endpoint_parts + .try_into() + .expect("Invalid gear endpoint provided"); + + let domain = [domain_1, domain_2].join(":"); + let port: u16 = port.parse().expect("Invalid gear endpoint provided"); + + GclientGearApi::init_with(WSAddress::new(domain, Some(port)), vara_suri) + .await + .expect("Failed to create gclient client") +} + async fn create_gear_client(args: &VaraEndpointArg) -> GearApi { GearApi::new(&args.vara_endpoint) .await @@ -350,3 +415,30 @@ fn create_eth_client(args: &EthereumArgs) -> EthApi { ) .unwrap_or_else(|err| panic!("Error while creating ethereum client: {}", err)) } + +async fn create_beacon_client(args: &BeaconRpcArgs) -> BeaconClient { + let timeout = args.timeout.map(Duration::from_secs); + + BeaconClient::connect(args.endpoint.clone(), timeout) + .await + .expect("Failed to create beacon client") +} + +fn decode_h256(hex: &str) -> H256 { + let data: [u8; 32] = decode_byte_array(hex); + data.into() +} + +fn decode_h160(hex: &str) -> H160 { + let data: [u8; 20] = decode_byte_array(hex); + data.into() +} + +fn decode_byte_array(hex: &str) -> [u8; LEN] { + let address = if &hex[..2] == "0x" { &hex[2..] } else { hex }; + + hex::decode(address) + .unwrap_or_else(|_| panic!("Wrong address format: {}", hex)) + .try_into() + .unwrap_or_else(|_| panic!("Wrong address length: {}", hex)) +} From c2f0f3235012dc3ff75a6880cd8f8a07fe7ede3d Mon Sep 17 00:00:00 2001 From: mertwole Date: Tue, 15 Oct 2024 10:54:44 +0000 Subject: [PATCH 22/32] Rename endpoint to beacon_endpoint --- relayer/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/relayer/src/main.rs b/relayer/src/main.rs index 59480680..d5952623 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -133,11 +133,11 @@ struct BeaconRpcArgs { default_value = DEFAULT_ETH_BEACON_RPC, env = "ETH_BEACON_RPC" )] - endpoint: String, + beacon_endpoint: String, /// Timeout in seconds for requests to the ethereum beacon RPC #[arg(long = "ethereum-beacon-rpc-timeout", env = "ETH_BEACON_RPC_TIMEOUT")] - timeout: Option, + beacon_timeout: Option, } #[derive(Args)] @@ -417,9 +417,9 @@ fn create_eth_client(args: &EthereumArgs) -> EthApi { } async fn create_beacon_client(args: &BeaconRpcArgs) -> BeaconClient { - let timeout = args.timeout.map(Duration::from_secs); + let timeout = args.beacon_timeout.map(Duration::from_secs); - BeaconClient::connect(args.endpoint.clone(), timeout) + BeaconClient::connect(args.beacon_endpoint.clone(), timeout) .await .expect("Failed to create beacon client") } From ca56a35fc4269a06a83fa23c1b53e641d0c11143 Mon Sep 17 00:00:00 2001 From: mertwole Date: Fri, 18 Oct 2024 11:36:49 +0000 Subject: [PATCH 23/32] Small fixes --- ethereum/client/src/lib.rs | 15 ++++++++++++ .../common/ethereum/block_listener.rs | 2 +- .../ethereum/deposit_event_extractor.rs | 14 ++++++++++- .../common/gear/checkpoints_extractor.rs | 9 ++++--- .../common/gear/message_sender/mod.rs | 24 ++++++++++++++++--- .../eth_to_gear/all_token_transfers.rs | 2 +- .../gear_to_eth/all_token_transfers.rs | 2 +- .../gear_to_eth/paid_token_transfers.rs | 2 +- 8 files changed, 59 insertions(+), 11 deletions(-) diff --git a/ethereum/client/src/lib.rs b/ethereum/client/src/lib.rs index 836132f5..875c27fc 100644 --- a/ethereum/client/src/lib.rs +++ b/ethereum/client/src/lib.rs @@ -199,6 +199,10 @@ impl EthApi { self.contracts.block_number().await } + pub async fn finalized_block_number(&self) -> Result { + self.contracts.finalized_block_number().await + } + #[allow(clippy::too_many_arguments)] pub async fn provide_content_message( &self, @@ -295,6 +299,17 @@ where self.provider.get_block_number().await.map_err(|e| e.into()) } + pub async fn finalized_block_number(&self) -> Result { + self.provider + .get_block_by_number(BlockNumberOrTag::Finalized, false) + .await + .map_err(|e| Error::ErrorInHTTPTransport(e))? + .ok_or(Error::ErrorFetchingBlock)? + .header + .number + .ok_or(Error::ErrorFetchingBlock) + } + pub async fn fetch_merkle_roots(&self, depth: u64) -> Result, Error> { let current_block: u64 = self.provider.get_block_number().await?; diff --git a/relayer/src/message_relayer/common/ethereum/block_listener.rs b/relayer/src/message_relayer/common/ethereum/block_listener.rs index 07499201..acfc51b4 100644 --- a/relayer/src/message_relayer/common/ethereum/block_listener.rs +++ b/relayer/src/message_relayer/common/ethereum/block_listener.rs @@ -64,7 +64,7 @@ impl BlockListener { self.metrics.latest_block.set(current_block as i64); loop { - let latest = self.eth_api.block_number().await?; + let latest = self.eth_api.finalized_block_number().await?; if latest >= current_block { for block in current_block..=latest { sender.send(EthereumBlockNumber(block))?; diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index 009856fd..c0b6c924 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -57,7 +57,7 @@ impl DepositEventExtractor { tokio::task::spawn_blocking(move || loop { let res = block_on(self.run_inner(&sender, &blocks)); if let Err(err) = res { - log::error!("Message queued extractor failed: {}", err); + log::error!("Deposit event extractor failed: {}", err); } }); @@ -114,6 +114,18 @@ impl DepositEventExtractor { .total_deposits_found .inc_by(events.len() as u64); + for ev in &events { + log::info!( + "Found deposit event: tx_hash={}, from={}, to={}, token={}, amount={}, slot_number={}", + hex::encode(ev.tx_hash.0), + hex::encode(ev.from.0), + hex::encode(ev.to.0), + hex::encode(ev.token.0), + ev.amount, + slot_number.0, + ); + } + for DepositEventEntry { tx_hash, .. } in events { sender.send(ERC20DepositTx { slot_number, diff --git a/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs b/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs index 09c188ee..50ffefad 100644 --- a/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs +++ b/relayer/src/message_relayer/common/gear/checkpoints_extractor.rs @@ -52,7 +52,7 @@ impl CheckpointsExtractor { tokio::task::spawn_blocking(move || loop { let res = block_on(self.run_inner(&sender, &blocks)); if let Err(err) = res { - log::error!("Message paid event extractor failed: {}", err); + log::error!("Checkpoints extractor failed: {}", err); } }); @@ -95,8 +95,7 @@ impl CheckpointsExtractor { ) .await?; - let state = hex::decode(state)?; - + let state = hex::decode(&state[2..])?; let state = State::decode(&mut &state[..])?; assert!(state.checkpoints.len() <= 1); @@ -116,6 +115,8 @@ impl CheckpointsExtractor { self.metrics.latest_checkpoint_slot.set(checkpoint.0 as i64); + log::info!("First checkpoint discovered: {}", checkpoint.0); + sender.send(EthereumSlotNumber(checkpoint.0))?; } (Some(latest), Some(stored)) => { @@ -126,6 +127,8 @@ impl CheckpointsExtractor { self.latest_checkpoint = Some(latest); + log::info!("New checkpoint discovered: {}", latest.0); + sender.send(latest)?; } } diff --git a/relayer/src/message_relayer/common/gear/message_sender/mod.rs b/relayer/src/message_relayer/common/gear/message_sender/mod.rs index 153e57bc..861ce1da 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/mod.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/mod.rs @@ -76,10 +76,17 @@ impl MessageSender { messages: Receiver, checkpoints: Receiver, ) { + let mut error_count = 0; + tokio::task::spawn_blocking(move || loop { let res = block_on(self.run_inner(&messages, &checkpoints)); if let Err(err) = res { - log::error!("Ethereum message sender failed: {}", err); + log::error!("Gear message sender failed: {}", err); + // TODO: Fix an issue with node droppping connection + error_count += 1; + if error_count > 10 { + break; + } } }); } @@ -89,13 +96,13 @@ impl MessageSender { messages: &Receiver, checkpoints: &Receiver, ) -> anyhow::Result<()> { + self.update_balance_metric().await?; + let mut waiting_checkpoint: Vec = vec![]; let mut latest_checkpoint_slot = None; loop { - self.update_balance_metric().await?; - for checkpoint in checkpoints.try_iter() { if latest_checkpoint_slot.unwrap_or_default() < checkpoint { latest_checkpoint_slot = Some(checkpoint); @@ -113,6 +120,9 @@ impl MessageSender { waiting_checkpoint.push(message); } + if waiting_checkpoint.is_empty() { + continue; + } for i in (0..waiting_checkpoint.len()).rev() { if waiting_checkpoint[i].slot_number <= latest_checkpoint_slot.unwrap_or_default() { self.submit_message(&waiting_checkpoint[i]).await?; @@ -120,6 +130,8 @@ impl MessageSender { } } + self.update_balance_metric().await?; + self.metrics .messages_waiting_checkpoint .set(waiting_checkpoint.len() as i64); @@ -130,6 +142,12 @@ impl MessageSender { let message = compose_payload::compose(&self.beacon_client, &self.eth_api, message.tx_hash).await?; + log::info!( + "Sending message in gear_message_sender: tx_index={}, slot={}", + message.transaction_index, + message.proof_block.block.slot + ); + let gas_limit_block = self.gear_api.block_gas_limit()?; // Use 95% of block gas limit for all extrinsics. let gas_limit = gas_limit_block / 100 * 95; diff --git a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs index cfdb8515..60e51a57 100644 --- a/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs +++ b/relayer/src/message_relayer/eth_to_gear/all_token_transfers.rs @@ -53,7 +53,7 @@ impl Relayer { checkpoint_light_client_address: H256, ethereum_event_client_address: H256, ) -> anyhow::Result { - let from_eth_block = eth_api.block_number().await?; + let from_eth_block = eth_api.finalized_block_number().await?; let from_gear_block = gear_api.latest_finalized_block().await?; let from_gear_block = gear_api.block_hash_to_number(from_gear_block).await?; diff --git a/relayer/src/message_relayer/gear_to_eth/all_token_transfers.rs b/relayer/src/message_relayer/gear_to_eth/all_token_transfers.rs index 9fc7d818..9204e1a4 100644 --- a/relayer/src/message_relayer/gear_to_eth/all_token_transfers.rs +++ b/relayer/src/message_relayer/gear_to_eth/all_token_transfers.rs @@ -49,7 +49,7 @@ impl Relayer { gear_api.block_hash_to_number(block).await? }; - let from_eth_block = eth_api.block_number().await?; + let from_eth_block = eth_api.finalized_block_number().await?; let gear_block_listener = GearBlockListener::new(gear_api.clone(), from_gear_block); diff --git a/relayer/src/message_relayer/gear_to_eth/paid_token_transfers.rs b/relayer/src/message_relayer/gear_to_eth/paid_token_transfers.rs index 82cf4cff..e9b4c424 100644 --- a/relayer/src/message_relayer/gear_to_eth/paid_token_transfers.rs +++ b/relayer/src/message_relayer/gear_to_eth/paid_token_transfers.rs @@ -58,7 +58,7 @@ impl Relayer { gear_api.block_hash_to_number(block).await? }; - let from_eth_block = eth_api.block_number().await?; + let from_eth_block = eth_api.finalized_block_number().await?; log::info!( "Starting gear event processing from block #{}", From 3a93c5850da5b2a3a39d805dd8a90f560b03d398 Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 21 Oct 2024 07:35:17 +0000 Subject: [PATCH 24/32] Move some code to utils in beacon client --- relayer/src/ethereum_beacon_client/mod.rs | 93 +------------------ relayer/src/ethereum_beacon_client/utils.rs | 91 ++++++++++++++++++ relayer/src/ethereum_checkpoints/mod.rs | 2 +- .../src/ethereum_checkpoints/replay_back.rs | 3 +- .../src/ethereum_checkpoints/sync_update.rs | 4 +- relayer/src/ethereum_checkpoints/tests/mod.rs | 29 +++--- 6 files changed, 114 insertions(+), 108 deletions(-) create mode 100644 relayer/src/ethereum_beacon_client/utils.rs diff --git a/relayer/src/ethereum_beacon_client/mod.rs b/relayer/src/ethereum_beacon_client/mod.rs index 7f0f5dd3..34704977 100644 --- a/relayer/src/ethereum_beacon_client/mod.rs +++ b/relayer/src/ethereum_beacon_client/mod.rs @@ -6,17 +6,12 @@ use std::{ }; use anyhow::{anyhow, bail, Error as AnyError, Result as AnyResult}; -use ark_serialize::CanonicalDeserialize; -use checkpoint_light_client_io::{ - ArkScale, BeaconBlockHeader, G1TypeInfo, G2TypeInfo, Slot, SyncCommitteeKeys, - SyncCommitteeUpdate, G1, G2, SYNC_COMMITTEE_SIZE, -}; +use checkpoint_light_client_io::{BeaconBlockHeader, Slot}; use ethereum_common::{ - base_types::{BytesFixed, FixedArray}, - beacon::{BLSPubKey, Block as BeaconBlock}, + beacon::Block as BeaconBlock, utils::{ BeaconBlockHeaderResponse, BeaconBlockResponse, FinalityUpdate, FinalityUpdateResponse, - Update, UpdateResponse, + UpdateResponse, }, MAX_REQUEST_LIGHT_CLIENT_UPDATES, }; @@ -24,6 +19,7 @@ use reqwest::{Client, ClientBuilder, RequestBuilder}; use serde::{de::DeserializeOwned, Deserialize}; pub mod slots_batch; +pub mod utils; #[derive(Clone, Debug)] pub struct ErrorNotFound; @@ -215,87 +211,6 @@ impl BeaconClient { } } -pub fn map_public_keys( - compressed_public_keys: &FixedArray, -) -> Box { - let keys = compressed_public_keys - .0 - .iter() - .map(|BytesFixed(pub_key_compressed)| { - let pub_key = ::deserialize_compressed_unchecked( - &pub_key_compressed.0[..], - ) - .expect("Public keys have the required size"); - - let ark_scale: ArkScale = G1TypeInfo(pub_key).into(); - - ark_scale - }) - .collect::>(); - - Box::new(FixedArray(keys.try_into().expect( - "The size of keys array is guaranteed on the type level", - ))) -} - -pub fn sync_update_from_finality( - signature: G2, - finality_update: FinalityUpdate, -) -> SyncCommitteeUpdate { - SyncCommitteeUpdate { - signature_slot: finality_update.signature_slot, - attested_header: finality_update.attested_header, - finalized_header: finality_update.finalized_header, - sync_aggregate: finality_update.sync_aggregate, - sync_committee_next_aggregate_pubkey: None, - sync_committee_signature: G2TypeInfo(signature).into(), - sync_committee_next_pub_keys: None, - sync_committee_next_branch: None, - finality_branch: finality_update - .finality_branch - .into_iter() - .map(|BytesFixed(array)| array.0) - .collect::<_>(), - } -} - -pub fn sync_update_from_update(signature: G2, update: Update) -> SyncCommitteeUpdate { - let next_sync_committee_keys = map_public_keys(&update.next_sync_committee.pubkeys); - - SyncCommitteeUpdate { - signature_slot: update.signature_slot, - attested_header: update.attested_header, - finalized_header: update.finalized_header, - sync_aggregate: update.sync_aggregate, - sync_committee_next_aggregate_pubkey: Some(update.next_sync_committee.aggregate_pubkey), - sync_committee_signature: G2TypeInfo(signature).into(), - sync_committee_next_pub_keys: Some(next_sync_committee_keys), - sync_committee_next_branch: Some( - update - .next_sync_committee_branch - .into_iter() - .map(|BytesFixed(array)| array.0) - .collect::<_>(), - ), - finality_branch: update - .finality_branch - .into_iter() - .map(|BytesFixed(array)| array.0) - .collect::<_>(), - } -} - -pub fn try_from_hex_encoded>>(hex_encoded: &str) -> Option { - let data = match hex_encoded.starts_with("0x") { - true => &hex_encoded[2..], - false => hex_encoded, - }; - - hex::decode(data) - .ok() - .and_then(|bytes| >>::try_from(bytes).ok()) -} - async fn get(request_builder: RequestBuilder) -> AnyResult { let bytes = request_builder .send() diff --git a/relayer/src/ethereum_beacon_client/utils.rs b/relayer/src/ethereum_beacon_client/utils.rs new file mode 100644 index 00000000..281c812c --- /dev/null +++ b/relayer/src/ethereum_beacon_client/utils.rs @@ -0,0 +1,91 @@ +use ark_serialize::CanonicalDeserialize; +use checkpoint_light_client_io::{ + ArkScale, G1TypeInfo, G2TypeInfo, SyncCommitteeKeys, SyncCommitteeUpdate, G1, G2, + SYNC_COMMITTEE_SIZE, +}; +use ethereum_common::{ + base_types::{BytesFixed, FixedArray}, + beacon::BLSPubKey, + utils::{FinalityUpdate, Update}, +}; + +pub fn sync_update_from_finality( + signature: G2, + finality_update: FinalityUpdate, +) -> SyncCommitteeUpdate { + SyncCommitteeUpdate { + signature_slot: finality_update.signature_slot, + attested_header: finality_update.attested_header, + finalized_header: finality_update.finalized_header, + sync_aggregate: finality_update.sync_aggregate, + sync_committee_next_aggregate_pubkey: None, + sync_committee_signature: G2TypeInfo(signature).into(), + sync_committee_next_pub_keys: None, + sync_committee_next_branch: None, + finality_branch: finality_update + .finality_branch + .into_iter() + .map(|BytesFixed(array)| array.0) + .collect::<_>(), + } +} + +pub fn map_public_keys( + compressed_public_keys: &FixedArray, +) -> Box { + let keys = compressed_public_keys + .0 + .iter() + .map(|BytesFixed(pub_key_compressed)| { + let pub_key = ::deserialize_compressed_unchecked( + &pub_key_compressed.0[..], + ) + .expect("Public keys have the required size"); + + let ark_scale: ArkScale = G1TypeInfo(pub_key).into(); + + ark_scale + }) + .collect::>(); + + Box::new(FixedArray(keys.try_into().expect( + "The size of keys array is guaranteed on the type level", + ))) +} + +pub fn sync_update_from_update(signature: G2, update: Update) -> SyncCommitteeUpdate { + let next_sync_committee_keys = map_public_keys(&update.next_sync_committee.pubkeys); + + SyncCommitteeUpdate { + signature_slot: update.signature_slot, + attested_header: update.attested_header, + finalized_header: update.finalized_header, + sync_aggregate: update.sync_aggregate, + sync_committee_next_aggregate_pubkey: Some(update.next_sync_committee.aggregate_pubkey), + sync_committee_signature: G2TypeInfo(signature).into(), + sync_committee_next_pub_keys: Some(next_sync_committee_keys), + sync_committee_next_branch: Some( + update + .next_sync_committee_branch + .into_iter() + .map(|BytesFixed(array)| array.0) + .collect::<_>(), + ), + finality_branch: update + .finality_branch + .into_iter() + .map(|BytesFixed(array)| array.0) + .collect::<_>(), + } +} + +pub fn try_from_hex_encoded>>(hex_encoded: &str) -> Option { + let data = match hex_encoded.starts_with("0x") { + true => &hex_encoded[2..], + false => hex_encoded, + }; + + hex::decode(data) + .ok() + .and_then(|bytes| >>::try_from(bytes).ok()) +} diff --git a/relayer/src/ethereum_checkpoints/mod.rs b/relayer/src/ethereum_checkpoints/mod.rs index 51c5f021..52a76c8a 100644 --- a/relayer/src/ethereum_checkpoints/mod.rs +++ b/relayer/src/ethereum_checkpoints/mod.rs @@ -48,7 +48,7 @@ pub async fn relay(args: RelayCheckpointsArgs) { }, } = args; - let program_id = ethereum_beacon_client::try_from_hex_encoded(&program_id) + let program_id = ethereum_beacon_client::utils::try_from_hex_encoded(&program_id) .expect("Expecting correct ProgramId"); let timeout = Some(Duration::from_secs(beacon_timeout)); diff --git a/relayer/src/ethereum_checkpoints/replay_back.rs b/relayer/src/ethereum_checkpoints/replay_back.rs index c0eeda79..4f75d7e3 100644 --- a/relayer/src/ethereum_checkpoints/replay_back.rs +++ b/relayer/src/ethereum_checkpoints/replay_back.rs @@ -53,7 +53,8 @@ pub async fn execute( ) .map_err(|e| anyhow!("Failed to deserialize point on G2 (replay back): {e:?}"))?; - let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update.data); + let sync_update = + ethereum_beacon_client::utils::sync_update_from_update(signature, update.data); replay_back_slots_start( beacon_client, client, diff --git a/relayer/src/ethereum_checkpoints/sync_update.rs b/relayer/src/ethereum_checkpoints/sync_update.rs index 51f308fc..c5ed2a8b 100644 --- a/relayer/src/ethereum_checkpoints/sync_update.rs +++ b/relayer/src/ethereum_checkpoints/sync_update.rs @@ -59,9 +59,9 @@ async fn receive( .map_err(|e| anyhow!("Failed to deserialize point on G2: {e:?}"))?; let sync_update = if update.finalized_header.slot >= finality_update.finalized_header.slot { - ethereum_beacon_client::sync_update_from_update(signature, update) + ethereum_beacon_client::utils::sync_update_from_update(signature, update) } else { - ethereum_beacon_client::sync_update_from_finality(signature, finality_update) + ethereum_beacon_client::utils::sync_update_from_finality(signature, finality_update) }; if sender.send(sync_update).await.is_err() { diff --git a/relayer/src/ethereum_checkpoints/tests/mod.rs b/relayer/src/ethereum_checkpoints/tests/mod.rs index 5a5c833c..47e67127 100644 --- a/relayer/src/ethereum_checkpoints/tests/mod.rs +++ b/relayer/src/ethereum_checkpoints/tests/mod.rs @@ -99,12 +99,12 @@ async fn init(network: Network) -> Result<()> { &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::utils::sync_update_from_update(signature, update); println!("bootstrap slot = {}", bootstrap.header.slot); let pub_keys = - ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + ethereum_beacon_client::utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network, sync_committee_current_pub_keys: pub_keys, @@ -181,12 +181,12 @@ async fn init_and_updating() -> Result<()> { &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::utils::sync_update_from_update(signature, update); println!("bootstrap slot = {}", bootstrap.header.slot); let pub_keys = - ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + ethereum_beacon_client::utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network: Network::Holesky, sync_committee_current_pub_keys: pub_keys, @@ -223,10 +223,9 @@ async fn init_and_updating() -> Result<()> { &update.data.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let payload = Handle::SyncUpdate(ethereum_beacon_client::sync_update_from_update( - signature, - update.data, - )); + let payload = Handle::SyncUpdate( + ethereum_beacon_client::utils::sync_update_from_update(signature, update.data), + ); let gas_limit = client .calculate_handle_gas(None, program_id.into(), payload.encode(), 0, true) .await? @@ -259,7 +258,7 @@ async fn init_and_updating() -> Result<()> { }; let payload = Handle::SyncUpdate( - ethereum_beacon_client::sync_update_from_finality(signature, update), + ethereum_beacon_client::utils::sync_update_from_finality(signature, update), ); let gas_limit = client @@ -323,7 +322,7 @@ async fn replaying_back() -> Result<()> { &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::utils::sync_update_from_update(signature, update); let slot_start = sync_update.finalized_header.slot; let slot_end = finality_update.finalized_header.slot; println!( @@ -332,7 +331,7 @@ async fn replaying_back() -> Result<()> { ); let pub_keys = - ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + ethereum_beacon_client::utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network: Network::Sepolia, sync_committee_current_pub_keys: pub_keys, @@ -376,7 +375,7 @@ async fn replaying_back() -> Result<()> { .unwrap(); let payload = Handle::ReplayBackStart { - sync_update: ethereum_beacon_client::sync_update_from_finality( + sync_update: ethereum_beacon_client::utils::sync_update_from_finality( signature, finality_update, ), @@ -474,10 +473,10 @@ async fn sync_update_requires_replaying_back() -> Result<()> { &update.sync_aggregate.sync_committee_signature.0 .0[..], ) .unwrap(); - let sync_update = ethereum_beacon_client::sync_update_from_update(signature, update); + let sync_update = ethereum_beacon_client::utils::sync_update_from_update(signature, update); let pub_keys = - ethereum_beacon_client::map_public_keys(&bootstrap.current_sync_committee.pubkeys); + ethereum_beacon_client::utils::map_public_keys(&bootstrap.current_sync_committee.pubkeys); let init = Init { network: Network::Sepolia, sync_committee_current_pub_keys: pub_keys, @@ -509,7 +508,7 @@ async fn sync_update_requires_replaying_back() -> Result<()> { ) .unwrap(); - let payload = Handle::SyncUpdate(ethereum_beacon_client::sync_update_from_finality( + let payload = Handle::SyncUpdate(ethereum_beacon_client::utils::sync_update_from_finality( signature, finality_update, )); From 750bc1ef4c716b151f4c38b62383bace5b6c095f Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 21 Oct 2024 07:57:52 +0000 Subject: [PATCH 25/32] Finalize --- .../src/message_relayer/common/gear/message_sender/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/relayer/src/message_relayer/common/gear/message_sender/mod.rs b/relayer/src/message_relayer/common/gear/message_sender/mod.rs index 861ce1da..1971c9ee 100644 --- a/relayer/src/message_relayer/common/gear/message_sender/mod.rs +++ b/relayer/src/message_relayer/common/gear/message_sender/mod.rs @@ -76,17 +76,10 @@ impl MessageSender { messages: Receiver, checkpoints: Receiver, ) { - let mut error_count = 0; - tokio::task::spawn_blocking(move || loop { let res = block_on(self.run_inner(&messages, &checkpoints)); if let Err(err) = res { log::error!("Gear message sender failed: {}", err); - // TODO: Fix an issue with node droppping connection - error_count += 1; - if error_count > 10 { - break; - } } }); } From 70ddf581cc4665a078094559aac681de76977317 Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 21 Oct 2024 08:01:36 +0000 Subject: [PATCH 26/32] Fix clippy --- ethereum/client/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/client/src/lib.rs b/ethereum/client/src/lib.rs index 875c27fc..d24f4af1 100644 --- a/ethereum/client/src/lib.rs +++ b/ethereum/client/src/lib.rs @@ -303,7 +303,7 @@ where self.provider .get_block_by_number(BlockNumberOrTag::Finalized, false) .await - .map_err(|e| Error::ErrorInHTTPTransport(e))? + .map_err(Error::ErrorInHTTPTransport)? .ok_or(Error::ErrorFetchingBlock)? .header .number From 34c9e7a15f1908fa5589a512a28891fde9c46f25 Mon Sep 17 00:00:00 2001 From: mertwole Date: Mon, 21 Oct 2024 09:13:57 +0000 Subject: [PATCH 27/32] Add temporary fix for error Block not found --- .../ethereum/deposit_event_extractor.rs | 82 +++++++++++++------ 1 file changed, 59 insertions(+), 23 deletions(-) diff --git a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs index c0b6c924..4f863f38 100644 --- a/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs +++ b/relayer/src/message_relayer/common/ethereum/deposit_event_extractor.rs @@ -1,4 +1,7 @@ -use std::sync::mpsc::{channel, Receiver, Sender}; +use std::{ + sync::mpsc::{channel, Receiver, Sender}, + time::Duration, +}; use alloy::providers::Provider; use alloy_eips::BlockNumberOrTag; @@ -86,29 +89,11 @@ impl DepositEventExtractor { .fetch_deposit_events(self.erc20_treasury_address, block.0) .await?; - let block_body = self - .eth_api - .raw_provider() - .get_block_by_number(BlockNumberOrTag::Number(block.0), false) - .await? - .ok_or(anyhow!("Ethereum block #{} is missing", block.0))?; - - let beacon_root_parent = block_body.header.parent_beacon_block_root.ok_or(anyhow!( - "Unable to determine root of parent beacon block for block #{}", - block.0 - ))?; - - let beacon_block_parent = self - .beacon_client - .get_block_by_hash(&beacon_root_parent.0) - .await?; - - let beacon_block = self - .beacon_client - .find_beacon_block(block.0, &beacon_block_parent) - .await?; + if events.is_empty() { + return Ok(()); + } - let slot_number = EthereumSlotNumber(beacon_block.slot); + let slot_number = self.find_slot_by_block_number(block).await?; self.metrics .total_deposits_found @@ -135,4 +120,55 @@ impl DepositEventExtractor { Ok(()) } + + async fn find_slot_by_block_number( + &self, + block: EthereumBlockNumber, + ) -> anyhow::Result { + let block_body = self + .eth_api + .raw_provider() + .get_block_by_number(BlockNumberOrTag::Number(block.0), false) + .await? + .ok_or(anyhow!("Ethereum block #{} is missing", block.0))?; + + let beacon_root_parent = block_body.header.parent_beacon_block_root.ok_or(anyhow!( + "Unable to determine root of parent beacon block for block #{}", + block.0 + ))?; + + let beacon_block_parent = self + .beacon_client + .get_block_by_hash(&beacon_root_parent.0) + .await?; + + // TODO: It's a temporary solution of a problem that we're connecting to a different + // nodes, so if we're observing finalized block on one node, the finalized slot might still be not + // available on other. + for _ in 0..10 { + let beacon_block_result = self + .beacon_client + .find_beacon_block(block.0, &beacon_block_parent) + .await; + + match beacon_block_result { + Ok(beacon_block) => { + return Ok(EthereumSlotNumber(beacon_block.slot)); + } + Err(err) => { + log::warn!( + "Failed to find beacon block for ethereum block #{}: {}. Waiting for 1 second before next attempt...", + block.0, + err + ); + tokio::time::sleep(Duration::from_secs(1)).await; + } + } + } + + anyhow::bail!( + "Failed to find beacon block for Ethereum block #{} after 5 attempts", + block.0 + ); + } } From dcc738c75be8fab8d1d459991d36bed8caa62b55 Mon Sep 17 00:00:00 2001 From: mertwole Date: Wed, 30 Oct 2024 08:38:34 +0000 Subject: [PATCH 28/32] Add hex_utils module --- relayer/src/ethereum_beacon_client/utils.rs | 11 ------- relayer/src/ethereum_checkpoints/mod.rs | 4 +-- relayer/src/hex_utils.rs | 18 +++++++++++ relayer/src/main.rs | 34 ++++++--------------- 4 files changed, 30 insertions(+), 37 deletions(-) create mode 100644 relayer/src/hex_utils.rs diff --git a/relayer/src/ethereum_beacon_client/utils.rs b/relayer/src/ethereum_beacon_client/utils.rs index 281c812c..30ef8408 100644 --- a/relayer/src/ethereum_beacon_client/utils.rs +++ b/relayer/src/ethereum_beacon_client/utils.rs @@ -78,14 +78,3 @@ pub fn sync_update_from_update(signature: G2, update: Update) -> SyncCommitteeUp .collect::<_>(), } } - -pub fn try_from_hex_encoded>>(hex_encoded: &str) -> Option { - let data = match hex_encoded.starts_with("0x") { - true => &hex_encoded[2..], - false => hex_encoded, - }; - - hex::decode(data) - .ok() - .and_then(|bytes| >>::try_from(bytes).ok()) -} diff --git a/relayer/src/ethereum_checkpoints/mod.rs b/relayer/src/ethereum_checkpoints/mod.rs index 52a76c8a..9ccc1dfb 100644 --- a/relayer/src/ethereum_checkpoints/mod.rs +++ b/relayer/src/ethereum_checkpoints/mod.rs @@ -48,8 +48,8 @@ pub async fn relay(args: RelayCheckpointsArgs) { }, } = args; - let program_id = ethereum_beacon_client::utils::try_from_hex_encoded(&program_id) - .expect("Expecting correct ProgramId"); + let program_id = + crate::hex_utils::decode_byte_array(&program_id).expect("Failed to parse ProgramId"); let timeout = Some(Duration::from_secs(beacon_timeout)); let beacon_client = BeaconClient::connect(beacon_endpoint.clone(), timeout) diff --git a/relayer/src/hex_utils.rs b/relayer/src/hex_utils.rs new file mode 100644 index 00000000..521d3791 --- /dev/null +++ b/relayer/src/hex_utils.rs @@ -0,0 +1,18 @@ +use primitive_types::{H160, H256}; + +pub fn decode_h256(hex: &str) -> anyhow::Result { + let data: [u8; 32] = decode_byte_array(hex)?; + Ok(data.into()) +} + +pub fn decode_h160(hex: &str) -> anyhow::Result { + let data: [u8; 20] = decode_byte_array(hex)?; + Ok(data.into()) +} + +pub fn decode_byte_array(hex: &str) -> anyhow::Result<[u8; LEN]> { + let address = if &hex[..2] == "0x" { &hex[2..] } else { hex }; + Ok(hex::decode(address)? + .try_into() + .map_err(|_| anyhow::anyhow!("Invalid length"))?) +} diff --git a/relayer/src/main.rs b/relayer/src/main.rs index 14a91cf8..af79df88 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -3,7 +3,6 @@ use std::time::Duration; use clap::{Args, Parser, Subcommand}; use ethereum_beacon_client::BeaconClient; use gclient::{GearApi as GclientGearApi, WSAddress}; -use primitive_types::{H160, H256}; use ethereum_client::EthApi; use gear_rpc_client::GearApi; @@ -15,6 +14,7 @@ use utils_prometheus::MetricsBuilder; mod ethereum_beacon_client; mod ethereum_checkpoints; +mod hex_utils; mod message_relayer; mod proof_storage; mod prover_interface; @@ -295,7 +295,8 @@ async fn main() { let eth_api = create_eth_client(&args.ethereum_args); if let Some(bridging_payment_address) = args.bridging_payment_address { - let bridging_payment_address = decode_h256(&bridging_payment_address); + let bridging_payment_address = hex_utils::decode_h256(&bridging_payment_address) + .expect("Failed to parse address"); let relayer = gear_to_eth::paid_token_transfers::Relayer::new( gear_api, @@ -344,10 +345,14 @@ async fn main() { let gear_api = create_gear_client(&args.vara_endpoint).await; let gclient_client = create_gclient_client(&args.vara_endpoint, &args.vara_suri).await; - let erc20_treasury_address = decode_h160(&args.erc20_treasury_address); + let erc20_treasury_address = hex_utils::decode_h160(&args.erc20_treasury_address) + .expect("Failed to parse address"); let checkpoint_light_client_address = - decode_h256(&args.checkpoint_light_client_address); - let ethereum_event_client_address = decode_h256(&args.ethereum_event_client_address); + hex_utils::decode_h256(&args.checkpoint_light_client_address) + .expect("Failed to parse address"); + let ethereum_event_client_address = + hex_utils::decode_h256(&args.ethereum_event_client_address) + .expect("Failed to parse address"); let relayer = eth_to_gear::all_token_transfers::Relayer::new( gear_api, @@ -421,22 +426,3 @@ async fn create_beacon_client(args: &BeaconRpcArgs) -> BeaconClient { .await .expect("Failed to create beacon client") } - -fn decode_h256(hex: &str) -> H256 { - let data: [u8; 32] = decode_byte_array(hex); - data.into() -} - -fn decode_h160(hex: &str) -> H160 { - let data: [u8; 20] = decode_byte_array(hex); - data.into() -} - -fn decode_byte_array(hex: &str) -> [u8; LEN] { - let address = if &hex[..2] == "0x" { &hex[2..] } else { hex }; - - hex::decode(address) - .unwrap_or_else(|_| panic!("Wrong address format: {}", hex)) - .try_into() - .unwrap_or_else(|_| panic!("Wrong address length: {}", hex)) -} From 3e8be22bfa1697890c7abd1fd986fede985b3031 Mon Sep 17 00:00:00 2001 From: mertwole Date: Wed, 30 Oct 2024 08:41:28 +0000 Subject: [PATCH 29/32] Gclient -> GClient --- relayer/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/relayer/src/main.rs b/relayer/src/main.rs index af79df88..c177b414 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -2,7 +2,7 @@ use std::time::Duration; use clap::{Args, Parser, Subcommand}; use ethereum_beacon_client::BeaconClient; -use gclient::{GearApi as GclientGearApi, WSAddress}; +use gclient::{GearApi as GClientGearApi, WSAddress}; use ethereum_client::EthApi; use gear_rpc_client::GearApi; @@ -382,7 +382,7 @@ async fn main() { }; } -async fn create_gclient_client(args: &VaraEndpointArg, vara_suri: &str) -> GclientGearApi { +async fn create_gclient_client(args: &VaraEndpointArg, vara_suri: &str) -> GClientGearApi { let endpoint_parts: Vec<_> = args.vara_endpoint.split(':').collect(); let [domain_1, domain_2, port] = endpoint_parts .try_into() @@ -391,7 +391,7 @@ async fn create_gclient_client(args: &VaraEndpointArg, vara_suri: &str) -> Gclie let domain = [domain_1, domain_2].join(":"); let port: u16 = port.parse().expect("Invalid gear endpoint provided"); - GclientGearApi::init_with(WSAddress::new(domain, Some(port)), vara_suri) + GClientGearApi::init_with(WSAddress::new(domain, Some(port)), vara_suri) .await .expect("Failed to create gclient client") } From 9bccb00ad9bc39b2c4283e65e9dd5ae458542111 Mon Sep 17 00:00:00 2001 From: mertwole Date: Wed, 30 Oct 2024 08:45:58 +0000 Subject: [PATCH 30/32] BeaconClient::connect -> new --- relayer/src/ethereum_beacon_client/mod.rs | 23 ++++--------------- relayer/src/ethereum_checkpoints/mod.rs | 2 +- relayer/src/ethereum_checkpoints/tests/mod.rs | 6 ++--- relayer/src/main.rs | 2 +- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/relayer/src/ethereum_beacon_client/mod.rs b/relayer/src/ethereum_beacon_client/mod.rs index 34704977..73a6bc4c 100644 --- a/relayer/src/ethereum_beacon_client/mod.rs +++ b/relayer/src/ethereum_beacon_client/mod.rs @@ -46,32 +46,17 @@ pub struct BeaconClient { } impl BeaconClient { - pub async fn connect(rpc_url: String, timeout: Option) -> AnyResult { + pub async fn new(rpc_url: String, timeout: Option) -> AnyResult { let client = ClientBuilder::new(); - - let client = if let Some(timeout) = timeout { - client.timeout(timeout) - } else { - client + let client = match timeout { + Some(timeout) => client.timeout(timeout), + None => client, }; let client = client .build() .expect("Failed to create reqwest http client"); - let health = client - .get(format!("{}/eth/v1/node/health", rpc_url)) - .send() - .await? - .status(); - - if !health.is_success() { - bail!( - "Tried to connect to unhealthy beacon node. Status code returned: {}", - health - ); - } - Ok(Self { client, rpc_url }) } diff --git a/relayer/src/ethereum_checkpoints/mod.rs b/relayer/src/ethereum_checkpoints/mod.rs index 9ccc1dfb..bd18ccdc 100644 --- a/relayer/src/ethereum_checkpoints/mod.rs +++ b/relayer/src/ethereum_checkpoints/mod.rs @@ -52,7 +52,7 @@ pub async fn relay(args: RelayCheckpointsArgs) { crate::hex_utils::decode_byte_array(&program_id).expect("Failed to parse ProgramId"); let timeout = Some(Duration::from_secs(beacon_timeout)); - let beacon_client = BeaconClient::connect(beacon_endpoint.clone(), timeout) + let beacon_client = BeaconClient::new(beacon_endpoint.clone(), timeout) .await .expect("Failed to connect to beacon node"); diff --git a/relayer/src/ethereum_checkpoints/tests/mod.rs b/relayer/src/ethereum_checkpoints/tests/mod.rs index 47e67127..6d0704f7 100644 --- a/relayer/src/ethereum_checkpoints/tests/mod.rs +++ b/relayer/src/ethereum_checkpoints/tests/mod.rs @@ -65,7 +65,7 @@ async fn upload_program( } async fn init(network: Network) -> Result<()> { - let beacon_client = BeaconClient::connect(RPC_URL.to_string(), None) + let beacon_client = BeaconClient::new(RPC_URL.to_string(), None) .await .expect("Failed to connect to beacon node"); @@ -148,7 +148,7 @@ async fn init_mainnet() -> Result<()> { #[ignore] #[tokio::test] async fn init_and_updating() -> Result<()> { - let beacon_client = BeaconClient::connect(RPC_URL.to_string(), None) + let beacon_client = BeaconClient::new(RPC_URL.to_string(), None) .await .expect("Failed to connect to beacon node"); @@ -291,7 +291,7 @@ async fn init_and_updating() -> Result<()> { #[ignore] #[tokio::test] async fn replaying_back() -> Result<()> { - let beacon_client = BeaconClient::connect(RPC_URL.to_string(), None) + let beacon_client = BeaconClient::new(RPC_URL.to_string(), None) .await .expect("Failed to connect to beacon node"); diff --git a/relayer/src/main.rs b/relayer/src/main.rs index c177b414..cf027740 100644 --- a/relayer/src/main.rs +++ b/relayer/src/main.rs @@ -422,7 +422,7 @@ fn create_eth_client(args: &EthereumArgs) -> EthApi { async fn create_beacon_client(args: &BeaconRpcArgs) -> BeaconClient { let timeout = args.beacon_timeout.map(Duration::from_secs); - BeaconClient::connect(args.beacon_endpoint.clone(), timeout) + BeaconClient::new(args.beacon_endpoint.clone(), timeout) .await .expect("Failed to create beacon client") } From a837a5e410613317cbcf6ef43476d27b9369d26a Mon Sep 17 00:00:00 2001 From: mertwole Date: Wed, 30 Oct 2024 09:04:41 +0000 Subject: [PATCH 31/32] Fix warn --- relayer/src/ethereum_beacon_client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/src/ethereum_beacon_client/mod.rs b/relayer/src/ethereum_beacon_client/mod.rs index 73a6bc4c..5f3346af 100644 --- a/relayer/src/ethereum_beacon_client/mod.rs +++ b/relayer/src/ethereum_beacon_client/mod.rs @@ -5,7 +5,7 @@ use std::{ time::Duration, }; -use anyhow::{anyhow, bail, Error as AnyError, Result as AnyResult}; +use anyhow::{anyhow, Error as AnyError, Result as AnyResult}; use checkpoint_light_client_io::{BeaconBlockHeader, Slot}; use ethereum_common::{ beacon::Block as BeaconBlock, From afee900e8a2d70990e201fe593a0452f16544730 Mon Sep 17 00:00:00 2001 From: mertwole Date: Wed, 30 Oct 2024 09:15:44 +0000 Subject: [PATCH 32/32] Fix clippy --- relayer/src/hex_utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/relayer/src/hex_utils.rs b/relayer/src/hex_utils.rs index 521d3791..8c6ffd0b 100644 --- a/relayer/src/hex_utils.rs +++ b/relayer/src/hex_utils.rs @@ -12,7 +12,7 @@ pub fn decode_h160(hex: &str) -> anyhow::Result { pub fn decode_byte_array(hex: &str) -> anyhow::Result<[u8; LEN]> { let address = if &hex[..2] == "0x" { &hex[2..] } else { hex }; - Ok(hex::decode(address)? + hex::decode(address)? .try_into() - .map_err(|_| anyhow::anyhow!("Invalid length"))?) + .map_err(|_| anyhow::anyhow!("Invalid length")) }