From 882ecfdc23f59a091f94ac2a2cc51d57da5e86b4 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 5 Oct 2024 20:24:35 +0200 Subject: [PATCH 1/2] Make changes required by gmp api. - mnemonic instead of keyfile - balance takes an address - static lifetime finalized block stream --- Cargo.lock | 2 + rosetta-client/Cargo.toml | 2 + rosetta-client/src/client.rs | 10 ++-- rosetta-client/src/lib.rs | 3 +- rosetta-client/src/wallet.rs | 94 +++++++++++++++++++++++++++--------- 5 files changed, 81 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 035b00ee..fe927421 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5602,6 +5602,7 @@ dependencies = [ "js-sys", "log", "num-traits", + "rosetta-config-ethereum", "rosetta-core", "rosetta-server-astar", "rosetta-server-ethereum", @@ -5610,6 +5611,7 @@ dependencies = [ "rosetta-tx-polkadot", "serde", "serde_json", + "tokio", "wasm-bindgen", "web-sys", ] diff --git a/rosetta-client/Cargo.toml b/rosetta-client/Cargo.toml index dcdbfc2b..2eec482b 100644 --- a/rosetta-client/Cargo.toml +++ b/rosetta-client/Cargo.toml @@ -19,6 +19,7 @@ hex = "0.4" log = "0.4" num-traits = "0.2" rosetta-core.workspace = true +rosetta-config-ethereum.workspace = true rosetta-server-astar.workspace = true rosetta-server-ethereum.workspace = true rosetta-server-polkadot.workspace = true @@ -26,6 +27,7 @@ rosetta-tx-ethereum.workspace = true rosetta-tx-polkadot.workspace = true serde.workspace = true serde_json.workspace = true +tokio.workspace = true [target.'cfg(target_family = "wasm")'.dependencies] getrandom = { version = "0.2", features = ["js"] } diff --git a/rosetta-client/src/client.rs b/rosetta-client/src/client.rs index 94adb73c..3ff4696e 100644 --- a/rosetta-client/src/client.rs +++ b/rosetta-client/src/client.rs @@ -83,11 +83,11 @@ impl GenericClient { ) -> Result { let blockchain = Blockchain::from_str(config.blockchain)?; Ok(match blockchain { - Blockchain::Ethereum | - Blockchain::Polygon | - Blockchain::Arbitrum | - Blockchain::Binance | - Blockchain::Avalanche => { + Blockchain::Ethereum + | Blockchain::Polygon + | Blockchain::Arbitrum + | Blockchain::Binance + | Blockchain::Avalanche => { let client = EthereumClient::from_config(config, url, private_key).await?; Self::Ethereum(client) }, diff --git a/rosetta-client/src/lib.rs b/rosetta-client/src/lib.rs index 9a44d678..c79ee4f1 100644 --- a/rosetta-client/src/lib.rs +++ b/rosetta-client/src/lib.rs @@ -3,7 +3,8 @@ use anyhow::Result; pub use crate::wallet::Wallet; -pub use rosetta_core::{crypto, types, BlockchainConfig}; +pub use rosetta_config_ethereum::*; +pub use rosetta_core::{crypto, types, BlockOrIdentifier, BlockchainConfig, ClientEvent}; /// Clients that communicates to different blockchains pub mod client; diff --git a/rosetta-client/src/wallet.rs b/rosetta-client/src/wallet.rs index 94f0604f..123bfd1e 100644 --- a/rosetta-client/src/wallet.rs +++ b/rosetta-client/src/wallet.rs @@ -1,14 +1,18 @@ use crate::{ client::{GenericClient, GenericMetadata, GenericMetadataParams}, crypto::{address::Address, bip32::DerivedSecretKey, bip44::ChildNumber}, - mnemonic::MnemonicStore, signer::{RosettaAccount, RosettaPublicKey, Signer}, tx_builder::GenericTransactionBuilder, types::{AccountIdentifier, BlockIdentifier, PublicKey}, Blockchain, BlockchainConfig, }; use anyhow::Result; -use rosetta_core::{types::PartialBlockIdentifier, BlockchainClient, RosettaAlgorithm}; +use futures::channel::mpsc; +use futures::{SinkExt, Stream, StreamExt}; +use rosetta_core::{ + types::PartialBlockIdentifier, BlockOrIdentifier, BlockchainClient, ClientEvent, + RosettaAlgorithm, +}; use rosetta_server_ethereum::{ config::{ ext::types::{self as ethereum_types, Address as EthAddress, H256, U256}, @@ -18,12 +22,13 @@ use rosetta_server_ethereum::{ }, SubmitResult, }; -use std::path::Path; +use std::pin::Pin; +use std::sync::Arc; /// The wallet provides the main entry point to this crate. pub struct Wallet { /// `GenericClient` instance - pub client: GenericClient, + pub client: Arc, account: AccountIdentifier, secret_key: DerivedSecretKey, public_key: PublicKey, @@ -37,11 +42,11 @@ impl Wallet { blockchain: Blockchain, network: &str, url: &str, - keyfile: Option<&Path>, + mnemonic: &str, private_key: Option<[u8; 32]>, ) -> Result { let client = GenericClient::new(blockchain, network, url, private_key).await?; - Self::from_client(client, keyfile) + Self::from_client(client, mnemonic) } /// Creates a new wallet from a config, url and keyfile. @@ -49,22 +54,22 @@ impl Wallet { pub async fn from_config( config: BlockchainConfig, url: &str, - keyfile: Option<&Path>, + mnemonic: &str, private_key: Option<[u8; 32]>, ) -> Result { let client = GenericClient::from_config(config, url, private_key).await?; - Self::from_client(client, keyfile) + Self::from_client(client, mnemonic) } /// Creates a new wallet from a client, url and keyfile. #[allow(clippy::missing_errors_doc)] - pub fn from_client(client: GenericClient, keyfile: Option<&Path>) -> Result { - let store = MnemonicStore::new(keyfile)?; + pub fn from_client(client: GenericClient, mnemonic: &str) -> Result { + /*let store = MnemonicStore::new(keyfile)?; let mnemonic = match keyfile { Some(_) => store.get_or_generate_mnemonic()?, None => store.generate()?, - }; - let signer = Signer::new(&mnemonic, "")?; + };*/ + let signer = Signer::new(&mnemonic.parse()?, "")?; let tx = GenericTransactionBuilder::new(client.config())?; let secret_key = if client.config().bip44 { signer @@ -81,7 +86,7 @@ impl Wallet { anyhow::bail!("The signer and client curve type aren't compatible.") } - Ok(Self { client, account, secret_key, public_key, tx }) + Ok(Self { client: Arc::new(client), account, secret_key, public_key, tx }) } /// Returns the blockchain config. @@ -103,7 +108,7 @@ impl Wallet { #[allow(clippy::missing_errors_doc)] pub async fn status(&self) -> Result { // self.client.finalized_block().await - match &self.client { + match &*self.client { GenericClient::Astar(client) => client.finalized_block().await, GenericClient::Ethereum(client) => client.finalized_block().await, GenericClient::Polkadot(client) => client.finalized_block().await, @@ -112,11 +117,10 @@ impl Wallet { /// Returns the balance of the wallet. #[allow(clippy::missing_errors_doc)] - pub async fn balance(&self) -> Result { + pub async fn balance(&self, address: String) -> Result { let block = self.client.current_block().await?; - let address = - Address::new(self.client.config().address_format, self.account.address.clone()); - let balance = match &self.client { + let address = Address::new(self.client.config().address_format, address); + let balance = match &*self.client { GenericClient::Astar(client) => { client.balance(&address, &PartialBlockIdentifier::from(block)).await? }, @@ -138,6 +142,48 @@ impl Wallet { self.client.listen().await } + /// Returns a stream of finalized blocks. + pub fn block_stream(&self) -> Pin + Send>> { + let (mut tx, rx) = mpsc::channel(1); + let client = self.client.clone(); + // spawn a task to avoid lifetime issue + tokio::task::spawn(async move { + loop { + let mut stream = match client.listen().await { + Ok(Some(stream)) => stream, + Ok(None) => { + log::debug!("error opening listener"); + continue; + }, + Err(err) => { + log::debug!("error opening listener {}", err); + continue; + }, + }; + while let Some(event) = stream.next().await { + match event { + ClientEvent::NewFinalized(BlockOrIdentifier::Identifier(identifier)) => { + if tx.send(identifier.index).await.is_err() { + return; + } + }, + ClientEvent::NewFinalized(BlockOrIdentifier::Block(block)) => { + if tx.send(block.block_identifier.index).await.is_err() { + return; + } + }, + ClientEvent::NewHead(_) => {}, + ClientEvent::Event(_) => {}, + ClientEvent::Close(reason) => { + log::warn!("block stream closed {}", reason); + }, + } + } + } + }); + Box::pin(rx) + } + /// Returns the on chain metadata. /// Parameters: /// - `metadata_params`: the metadata parameters which we got from transaction builder. @@ -263,7 +309,7 @@ impl Wallet { data, block: block_identifier, }; - let result = match &self.client { + let result = match &*self.client { GenericClient::Ethereum(client) => client.call(&EthQuery::CallContract(call)).await?, GenericClient::Astar(client) => client.call(&EthQuery::CallContract(call)).await?, GenericClient::Polkadot(_) => anyhow::bail!("polkadot doesn't support eth_view_call"), @@ -283,7 +329,7 @@ impl Wallet { query: Q, ) -> Result<::Result> { let query = ::into_query(query); - let result = match &self.client { + let result = match &*self.client { GenericClient::Ethereum(client) => client.call(&query).await?, GenericClient::Astar(client) => client.call(&query).await?, GenericClient::Polkadot(_) => anyhow::bail!("polkadot doesn't support eth_view_call"), @@ -304,7 +350,7 @@ impl Wallet { let storage_slot = H256(storage_slot); let get_storage = GetStorageAt { address: contract_address, at: storage_slot, block: block_identifier }; - let result = match &self.client { + let result = match &*self.client { GenericClient::Ethereum(client) => { client.call(&EthQuery::GetStorageAt(get_storage)).await? }, @@ -334,7 +380,7 @@ impl Wallet { storage_keys: storage_keys.collect(), block: block_identifier, }; - let result = match &self.client { + let result = match &*self.client { GenericClient::Ethereum(client) => client.call(&EthQuery::GetProof(get_proof)).await?, GenericClient::Astar(client) => client.call(&EthQuery::GetProof(get_proof)).await?, GenericClient::Polkadot(_) => anyhow::bail!("polkadot doesn't support eth_storage"), @@ -353,7 +399,7 @@ impl Wallet { ) -> Result> { let tx_hash = H256(tx_hash); let get_tx_receipt = GetTransactionReceipt { tx_hash }; - let result = match &self.client { + let result = match &*self.client { GenericClient::Ethereum(client) => { client.call(&EthQuery::GetTransactionReceipt(get_tx_receipt)).await? }, @@ -374,7 +420,7 @@ impl Wallet { /// Returns `Err` if the blockchain doesn't support `eth_chainId` or the client connection /// failed. pub async fn eth_chain_id(&self) -> Result { - let result = match &self.client { + let result = match &*self.client { GenericClient::Ethereum(client) => client.call(&EthQuery::ChainId).await?, GenericClient::Astar(client) => client.call(&EthQuery::ChainId).await?, GenericClient::Polkadot(_) => anyhow::bail!("polkadot doesn't support eth_chainId"), From 8f7395f57f2ffd5d00b9d7ce06f140db564052bc Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS Date: Mon, 28 Oct 2024 14:12:49 +0500 Subject: [PATCH 2/2] make EthereumRpcExt Public --- chains/ethereum/server/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chains/ethereum/server/src/lib.rs b/chains/ethereum/server/src/lib.rs index 71832655..c8254a8c 100644 --- a/chains/ethereum/server/src/lib.rs +++ b/chains/ethereum/server/src/lib.rs @@ -23,7 +23,7 @@ mod new_heads; mod proof; mod shared_stream; mod state; -mod utils; +pub mod utils; pub use event_stream::EthereumEventStream;