diff --git a/CHANGELOG.md b/CHANGELOG.md index cda01cbd8..4b670e912 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- feat(fgw): added `add_transaction` for gateway client - fix(fgw): include `l1_to_l2_consumed_message` in L1 handler receipt - build: up starknet-rs, starknet-types, blockifier(v0.8.0), cairo - feat(rpc): added `getCompiledCasm` method diff --git a/Cargo.lock b/Cargo.lock index 32df88d57..b6e69d68b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5389,6 +5389,7 @@ dependencies = [ "fdlimit", "futures", "governor", + "http 1.1.0", "hyper 0.14.30", "jsonrpsee", "mc-analytics", @@ -5396,14 +5397,14 @@ dependencies = [ "mc-db", "mc-devnet", "mc-eth", - "mc-gateway", + "mc-gateway-client", + "mc-gateway-server", "mc-mempool", "mc-rpc", "mc-sync", "mc-telemetry", "mp-block", "mp-chain-config", - "mp-convert", "mp-utils", "opentelemetry", "opentelemetry-appender-tracing", @@ -5687,7 +5688,7 @@ dependencies = [ ] [[package]] -name = "mc-gateway" +name = "mc-gateway-client" version = "0.7.0" dependencies = [ "anyhow", @@ -5699,6 +5700,30 @@ dependencies = [ "hyper 1.5.0", "hyper-tls", "hyper-util", + "mp-block", + "mp-class", + "mp-gateway", + "rstest 0.18.2", + "serde", + "serde_json", + "starknet-core", + "starknet-types-core", + "tokio", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "mc-gateway-server" +version = "0.7.0" +dependencies = [ + "anyhow", + "bytes", + "flate2", + "http-body-util", + "hyper 1.5.0", + "hyper-util", "mc-db", "mc-rpc", "mp-block", @@ -5712,9 +5737,7 @@ dependencies = [ "starknet-types-core", "thiserror", "tokio", - "tower 0.4.13", "tracing", - "url", ] [[package]] @@ -5771,11 +5794,13 @@ dependencies = [ "m-proc-macros", "mc-db", "mc-exec", + "mc-gateway-client", "mc-mempool", "mp-block", "mp-chain-config", "mp-class", "mp-convert", + "mp-gateway", "mp-receipt", "mp-state-update", "mp-transactions", @@ -5783,7 +5808,6 @@ dependencies = [ "serde", "serde_json", "starknet-core", - "starknet-providers", "starknet-types-core", "starknet-types-rpc", "starknet_api", @@ -5804,7 +5828,7 @@ dependencies = [ "mc-analytics", "mc-block-import", "mc-db", - "mc-gateway", + "mc-gateway-client", "mc-telemetry", "mp-block", "mp-chain-config", @@ -6018,6 +6042,8 @@ name = "mp-gateway" version = "0.7.0" dependencies = [ "anyhow", + "http 1.1.0", + "hyper 1.5.0", "mc-block-import", "mp-block", "mp-chain-config", @@ -6031,6 +6057,8 @@ dependencies = [ "serde_with", "starknet-core", "starknet-types-core", + "thiserror", + "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 80d2c9d2a..72e206804 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,8 @@ members = [ "crates/client/sync", "crates/client/eth", "crates/client/rpc", - "crates/client/gateway", + "crates/client/gateway/client", + "crates/client/gateway/server", "crates/client/analytics", "crates/client/telemetry", "crates/client/devnet", @@ -32,7 +33,8 @@ default-members = [ "crates/client/exec", "crates/client/sync", "crates/client/eth", - "crates/client/gateway", + "crates/client/gateway/client", + "crates/client/gateway/server", "crates/client/rpc", "crates/client/telemetry", "crates/client/devnet", @@ -114,7 +116,8 @@ mc-telemetry = { path = "crates/client/telemetry" } mc-db = { path = "crates/client/db" } mc-exec = { path = "crates/client/exec" } mc-rpc = { path = "crates/client/rpc" } -mc-gateway = { path = "crates/client/gateway" } +mc-gateway-client = { path = "crates/client/gateway/client" } +mc-gateway-server = { path = "crates/client/gateway/server" } mc-sync = { path = "crates/client/sync" } mc-eth = { path = "crates/client/eth" } mc-mempool = { path = "crates/client/mempool" } diff --git a/crates/client/gateway/Cargo.toml b/crates/client/gateway/client/Cargo.toml similarity index 86% rename from crates/client/gateway/Cargo.toml rename to crates/client/gateway/client/Cargo.toml index 19b159568..bbfb40ddf 100644 --- a/crates/client/gateway/Cargo.toml +++ b/crates/client/gateway/client/Cargo.toml @@ -1,6 +1,6 @@ [package] -description = "Madara client rpc service" -name = "mc-gateway" +description = "Madara gateway client provider" +name = "mc-gateway-client" authors.workspace = true edition.workspace = true license.workspace = true @@ -17,12 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Madara -mc-db.workspace = true -mc-rpc.workspace = true mp-block.workspace = true mp-class.workspace = true mp-gateway.workspace = true -mp-utils.workspace = true # Starknet starknet-core.workspace = true @@ -39,7 +36,6 @@ hyper-tls.workspace = true hyper-util.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true -thiserror.workspace = true tokio.workspace = true tower = { version = "0.4", features = ["timeout", "retry", "util", "limit"] } tracing.workspace = true diff --git a/crates/client/gateway/src/client/builder.rs b/crates/client/gateway/client/src/builder.rs similarity index 93% rename from crates/client/gateway/src/client/builder.rs rename to crates/client/gateway/client/src/builder.rs index 8b176c200..2d2a0af96 100644 --- a/crates/client/gateway/src/client/builder.rs +++ b/crates/client/gateway/client/src/builder.rs @@ -23,15 +23,14 @@ type HttpsClient = Client, String>; type TimeoutRetryClient = Retry>; pub type PausedClient = PauseLayerMiddleware; #[derive(Debug, Clone)] -pub struct FeederClient { +pub struct GatewayProvider { pub(crate) client: PausedClient, - #[allow(dead_code)] pub(crate) gateway_url: Url, pub(crate) feeder_gateway_url: Url, pub(crate) headers: HeaderMap, } -impl FeederClient { +impl GatewayProvider { pub fn new(gateway_url: Url, feeder_gateway_url: Url) -> Self { let pause_until = Arc::new(RwLock::new(None)); let connector = HttpsConnector::new(); @@ -77,6 +76,15 @@ impl FeederClient { .expect("Failed to parse Starknet Alpha Sepolia feeder gateway url. This should not fail in prod."), ) } + pub fn starknet_integration_sepolia() -> Self { + Self::new( + Url::parse("https://integration-sepolia.starknet.io/gateway/") + .expect("Failed to parse Starknet Integration Sepolia gateway url. This should not fail in prod."), + Url::parse("https://integration-sepolia.starknet.io/feeder_gateway/").expect( + "Failed to parse Starknet Integration Sepolia feeder gateway url. This should not fail in prod.", + ), + ) + } } #[derive(Clone, Debug)] diff --git a/crates/client/gateway/client/src/lib.rs b/crates/client/gateway/client/src/lib.rs new file mode 100644 index 000000000..7f10cfe36 --- /dev/null +++ b/crates/client/gateway/client/src/lib.rs @@ -0,0 +1,5 @@ +mod builder; +mod methods; +mod request_builder; + +pub use builder::GatewayProvider; diff --git a/crates/client/gateway/src/client/methods.rs b/crates/client/gateway/client/src/methods.rs similarity index 83% rename from crates/client/gateway/src/client/methods.rs rename to crates/client/gateway/client/src/methods.rs index 5805a1367..525644786 100644 --- a/crates/client/gateway/src/client/methods.rs +++ b/crates/client/gateway/client/src/methods.rs @@ -1,19 +1,28 @@ -use super::{builder::FeederClient, request_builder::RequestBuilder}; -use crate::error::{SequencerError, StarknetError}; +use std::{borrow::Cow, sync::Arc}; + use mp_block::{BlockId, BlockTag}; use mp_class::{ContractClass, FlattenedSierraClass}; +use mp_gateway::error::{SequencerError, StarknetError}; use mp_gateway::{ block::{ProviderBlock, ProviderBlockPending, ProviderBlockPendingMaybe, ProviderBlockSignature}, state_update::{ ProviderStateUpdate, ProviderStateUpdatePending, ProviderStateUpdatePendingMaybe, ProviderStateUpdateWithBlock, ProviderStateUpdateWithBlockPending, ProviderStateUpdateWithBlockPendingMaybe, }, + user_transaction::{ + UserDeclareTransaction, UserDeployAccountTransaction, UserInvokeFunctionTransaction, UserTransaction, + }, }; +use serde::de::DeserializeOwned; use serde_json::Value; -use starknet_core::types::{contract::legacy::LegacyContractClass, Felt}; -use std::{borrow::Cow, sync::Arc}; +use starknet_core::types::{ + contract::legacy::LegacyContractClass, DeclareTransactionResult, DeployAccountTransactionResult, Felt, + InvokeTransactionResult, +}; + +use super::{builder::GatewayProvider, request_builder::RequestBuilder}; -impl FeederClient { +impl GatewayProvider { pub async fn get_block(&self, block_id: BlockId) -> Result { let request = RequestBuilder::new(&self.client, self.feeder_gateway_url.clone(), self.headers.clone()) .add_uri_segment("get_block") @@ -99,6 +108,38 @@ impl FeederClient { Err(SequencerError::DeserializeBody { serde_error: err }) } } + + async fn add_transaction(&self, transaction: UserTransaction) -> Result + where + T: DeserializeOwned, + { + let request = RequestBuilder::new(&self.client, self.gateway_url.clone(), self.headers.clone()) + .add_uri_segment("add_transaction") + .expect("Failed to add URI segment. This should not fail in prod."); + + request.send_post(transaction).await + } + + pub async fn add_invoke_transaction( + &self, + transaction: UserInvokeFunctionTransaction, + ) -> Result { + self.add_transaction(UserTransaction::InvokeFunction(transaction)).await + } + + pub async fn add_declare_transaction( + &self, + transaction: UserDeclareTransaction, + ) -> Result { + self.add_transaction(UserTransaction::Declare(transaction)).await + } + + pub async fn add_deploy_account_transaction( + &self, + transaction: UserDeployAccountTransaction, + ) -> Result { + self.add_transaction(UserTransaction::DeployAccount(transaction)).await + } } #[cfg(test)] @@ -110,6 +151,7 @@ mod tests { }; use mp_block::BlockTag; use mp_class::CompressedLegacyContractClass; + use mp_gateway::error::{SequencerError, StarknetError, StarknetErrorCode}; use rstest::*; use serde::de::DeserializeOwned; use starknet_core::types::Felt; @@ -118,8 +160,6 @@ mod tests { use std::ops::Drop; use std::path::PathBuf; - use crate::error::StarknetErrorCode; - use super::*; const CLASS_BLOCK_0: &str = "0x010455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8"; @@ -211,7 +251,7 @@ mod tests { #[test] #[ignore] fn compress() { - // file_compress("src/client/mocks/.json").unwrap(); + // file_compress("src/mocks/.json").unwrap(); } /// Converts a crate-relative path to an absolute system path. @@ -225,13 +265,13 @@ mod tests { } #[fixture] - fn client_mainnet_fixture() -> FeederClient { - FeederClient::starknet_alpha_mainnet() + fn client_mainnet_fixture() -> GatewayProvider { + GatewayProvider::starknet_alpha_mainnet() } #[rstest] #[tokio::test] - async fn get_block(client_mainnet_fixture: FeederClient) { + async fn get_block(client_mainnet_fixture: GatewayProvider) { let block = client_mainnet_fixture.get_block(BlockId::Number(0)).await.unwrap(); println!("parent_block_hash: 0x{:x}", block.parent_block_hash()); assert!(matches!(block, ProviderBlockPendingMaybe::NonPending(_))); @@ -253,7 +293,7 @@ mod tests { #[rstest] #[tokio::test] - async fn get_state_update(client_mainnet_fixture: FeederClient) { + async fn get_state_update(client_mainnet_fixture: GatewayProvider) { let state_update = client_mainnet_fixture.get_state_update(BlockId::Number(0)).await.unwrap(); assert!(matches!(state_update, ProviderStateUpdatePendingMaybe::NonPending(_))); assert_eq!( @@ -284,7 +324,7 @@ mod tests { #[rstest] #[tokio::test] - async fn get_state_update_with_block_first_few_blocks(client_mainnet_fixture: FeederClient) { + async fn get_state_update_with_block_first_few_blocks(client_mainnet_fixture: GatewayProvider) { let let_binding = client_mainnet_fixture .get_state_update_with_block(BlockId::Number(0)) .await @@ -294,7 +334,7 @@ mod tests { state_update_0.non_pending_ownded().expect("State update at block number 0 should not be pending"); let block_0 = block_0.non_pending_owned().expect("Block at block number 0 should not be pending"); let ProviderStateUpdateWithBlock { state_update: state_update_0_reference, block: block_0_reference } = - load_from_file_compressed::("src/client/mocks/state_update_and_block_0.gz"); + load_from_file_compressed::("src/mocks/state_update_and_block_0.gz"); assert_eq!(state_update_0, state_update_0_reference); assert_eq!(block_0, block_0_reference); @@ -308,7 +348,7 @@ mod tests { state_update_1.non_pending_ownded().expect("State update at block number 1 should not be pending"); let block_1 = block_1.non_pending_owned().expect("Block at block number 1 should not be pending"); let ProviderStateUpdateWithBlock { state_update: state_update_1_reference, block: block_1_reference } = - load_from_file_compressed::("src/client/mocks/state_update_and_block_1.gz"); + load_from_file_compressed::("src/mocks/state_update_and_block_1.gz"); assert_eq!(state_update_1, state_update_1_reference); assert_eq!(block_1, block_1_reference); @@ -322,7 +362,7 @@ mod tests { state_update_2.non_pending_ownded().expect("State update at block number 0 should not be pending"); let block_2 = block_2.non_pending_owned().expect("Block at block number 0 should not be pending"); let ProviderStateUpdateWithBlock { state_update: state_update_2_reference, block: block_2_reference } = - load_from_file_compressed::("src/client/mocks/state_update_and_block_2.gz"); + load_from_file_compressed::("src/mocks/state_update_and_block_2.gz"); assert_eq!(state_update_2, state_update_2_reference); assert_eq!(block_2, block_2_reference); @@ -330,7 +370,7 @@ mod tests { #[rstest] #[tokio::test] - async fn get_state_update_with_block_latest(client_mainnet_fixture: FeederClient) { + async fn get_state_update_with_block_latest(client_mainnet_fixture: GatewayProvider) { let let_binding = client_mainnet_fixture .get_state_update_with_block(BlockId::Tag(BlockTag::Latest)) .await @@ -343,7 +383,7 @@ mod tests { #[rstest] #[tokio::test] - async fn get_state_update_with_block_pending(client_mainnet_fixture: FeederClient) { + async fn get_state_update_with_block_pending(client_mainnet_fixture: GatewayProvider) { let let_binding = client_mainnet_fixture .get_state_update_with_block(BlockId::Tag(BlockTag::Pending)) .await @@ -356,14 +396,13 @@ mod tests { #[rstest] #[tokio::test] - async fn get_class_by_hash_block_0(client_mainnet_fixture: FeederClient) { + async fn get_class_by_hash_block_0(client_mainnet_fixture: GatewayProvider) { let class = client_mainnet_fixture .get_class_by_hash(Felt::from_hex_unchecked(CLASS_BLOCK_0), BlockId::Number(0)) .await .unwrap_or_else(|_| panic!("Getting class {CLASS_BLOCK_0} at block number 0")); - let class_reference = load_from_file_compressed::(&format!( - "src/client/mocks/class_block_0_{CLASS_BLOCK_0}.gz" - )); + let class_reference = + load_from_file_compressed::(&format!("src/mocks/class_block_0_{CLASS_BLOCK_0}.gz")); let class_compressed_reference: CompressedLegacyContractClass = class_reference.compress().expect("Compressing legacy contract class").into(); @@ -372,13 +411,13 @@ mod tests { #[rstest] #[tokio::test] - async fn get_class_by_hash_account(client_mainnet_fixture: FeederClient) { + async fn get_class_by_hash_account(client_mainnet_fixture: GatewayProvider) { let class_account = client_mainnet_fixture .get_class_by_hash(Felt::from_hex_unchecked(CLASS_ACCOUNT), BlockId::Number(CLASS_ACCOUNT_BLOCK)) .await .unwrap_or_else(|_| panic!("Getting account class {CLASS_ACCOUNT} at block number {CLASS_ACCOUNT_BLOCK}")); let class_reference = load_from_file_compressed::(&format!( - "src/client/mocks/class_block_{CLASS_ACCOUNT_BLOCK}_account_{CLASS_ACCOUNT}.gz" + "src/mocks/class_block_{CLASS_ACCOUNT_BLOCK}_account_{CLASS_ACCOUNT}.gz" )); let class_compressed_reference: CompressedLegacyContractClass = class_reference.compress().expect("Compressing legacy contract class").into(); @@ -388,13 +427,13 @@ mod tests { #[rstest] #[tokio::test] - async fn get_class_by_hash_proxy(client_mainnet_fixture: FeederClient) { + async fn get_class_by_hash_proxy(client_mainnet_fixture: GatewayProvider) { let class_proxy = client_mainnet_fixture .get_class_by_hash(Felt::from_hex_unchecked(CLASS_PROXY), BlockId::Number(CLASS_PROXY_BLOCK)) .await .unwrap_or_else(|_| panic!("Getting proxy class {CLASS_PROXY} at block number {CLASS_PROXY_BLOCK}")); let class_reference = load_from_file_compressed::(&format!( - "src/client/mocks/class_block_{CLASS_PROXY_BLOCK}_proxy_{CLASS_PROXY}.gz" + "src/mocks/class_block_{CLASS_PROXY_BLOCK}_proxy_{CLASS_PROXY}.gz" )); let class_compressed_reference: CompressedLegacyContractClass = class_reference.compress().expect("Compressing legacy contract class").into(); @@ -404,13 +443,13 @@ mod tests { #[rstest] #[tokio::test] - async fn get_class_by_hash_erc20(client_mainnet_fixture: FeederClient) { + async fn get_class_by_hash_erc20(client_mainnet_fixture: GatewayProvider) { let class_erc20 = client_mainnet_fixture .get_class_by_hash(Felt::from_hex_unchecked(CLASS_ERC20), BlockId::Number(CLASS_ERC20_BLOCK)) .await .unwrap_or_else(|_| panic!("Getting proxy class {CLASS_ERC20} at block number {CLASS_ERC20_BLOCK}")); let class_reference = load_from_file_compressed::(&format!( - "src/client/mocks/class_block_{CLASS_ERC20_BLOCK}_erc20_{CLASS_ERC20}.gz" + "src/mocks/class_block_{CLASS_ERC20_BLOCK}_erc20_{CLASS_ERC20}.gz" )); let class_compressed_reference: CompressedLegacyContractClass = class_reference.compress().expect("Compressing legacy contract class").into(); @@ -420,13 +459,13 @@ mod tests { #[rstest] #[tokio::test] - async fn get_class_by_hash_erc721(client_mainnet_fixture: FeederClient) { + async fn get_class_by_hash_erc721(client_mainnet_fixture: GatewayProvider) { let class_erc721 = client_mainnet_fixture .get_class_by_hash(Felt::from_hex_unchecked(CLASS_ERC721), BlockId::Number(CLASS_ERC721_BLOCK)) .await .unwrap_or_else(|_| panic!("Getting proxy class {CLASS_ERC721} at block number {CLASS_ERC721_BLOCK}")); let class_reference = load_from_file_compressed::(&format!( - "src/client/mocks/class_block_{CLASS_ERC721_BLOCK}_erc721_{CLASS_ERC721}.gz" + "src/mocks/class_block_{CLASS_ERC721_BLOCK}_erc721_{CLASS_ERC721}.gz" )); let class_compressed_reference: CompressedLegacyContractClass = class_reference.compress().expect("Compressing legacy contract class").into(); @@ -436,13 +475,13 @@ mod tests { #[rstest] #[tokio::test] - async fn get_class_by_hash_erc1155(client_mainnet_fixture: FeederClient) { + async fn get_class_by_hash_erc1155(client_mainnet_fixture: GatewayProvider) { let class_erc1155 = client_mainnet_fixture .get_class_by_hash(Felt::from_hex_unchecked(CLASS_ERC1155), BlockId::Number(CLASS_ERC1155_BLOCK)) .await .unwrap_or_else(|_| panic!("Getting proxy class {CLASS_ERC1155} at block number {CLASS_ERC1155_BLOCK}")); let class_reference = load_from_file_compressed::(&format!( - "src/client/mocks/class_block_{CLASS_ERC1155_BLOCK}_erc1155_{CLASS_ERC1155}.gz" + "src/mocks/class_block_{CLASS_ERC1155_BLOCK}_erc1155_{CLASS_ERC1155}.gz" )); let class_compressed_reference: CompressedLegacyContractClass = class_reference.compress().expect("Compressing legacy contract class").into(); @@ -452,13 +491,12 @@ mod tests { #[rstest] #[tokio::test] - async fn get_signature_first_few_blocks(client_mainnet_fixture: FeederClient) { + async fn get_signature_first_few_blocks(client_mainnet_fixture: GatewayProvider) { let signature_block_0 = client_mainnet_fixture .get_signature(BlockId::Number(0)) .await .expect("Failed to get signature for block number 0"); - let signature_reference = - load_from_file_compressed::("src/client/mocks/signature_block_0.gz"); + let signature_reference = load_from_file_compressed::("src/mocks/signature_block_0.gz"); assert_eq!(signature_block_0, signature_reference); @@ -466,8 +504,7 @@ mod tests { .get_signature(BlockId::Number(1)) .await .expect("Failed to get signature for block number 1"); - let signature_reference = - load_from_file_compressed::("src/client/mocks/signature_block_1.gz"); + let signature_reference = load_from_file_compressed::("src/mocks/signature_block_1.gz"); assert_eq!(signature_block_1, signature_reference); @@ -475,15 +512,14 @@ mod tests { .get_signature(BlockId::Number(2)) .await .expect("Failed to get signature for block number 2"); - let signature_reference = - load_from_file_compressed::("src/client/mocks/signature_block_2.gz"); + let signature_reference = load_from_file_compressed::("src/mocks/signature_block_2.gz"); assert_eq!(signature_block_2, signature_reference); } #[rstest] #[tokio::test] - async fn get_signature_latest(client_mainnet_fixture: FeederClient) { + async fn get_signature_latest(client_mainnet_fixture: GatewayProvider) { let signature_block_latest = client_mainnet_fixture.get_signature(BlockId::Tag(BlockTag::Latest)).await; assert!(matches!(signature_block_latest, Ok(ProviderBlockSignature { .. }))) @@ -491,7 +527,7 @@ mod tests { #[rstest] #[tokio::test] - async fn get_signature_pending(client_mainnet_fixture: FeederClient) { + async fn get_signature_pending(client_mainnet_fixture: GatewayProvider) { let signature_block_pending = client_mainnet_fixture.get_signature(BlockId::Tag(BlockTag::Pending)).await; assert!(matches!( diff --git a/crates/client/gateway/src/client/mocks/class_block_0_0x010455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8.gz b/crates/client/gateway/client/src/mocks/class_block_0_0x010455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/class_block_0_0x010455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8.gz rename to crates/client/gateway/client/src/mocks/class_block_0_0x010455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8.gz diff --git a/crates/client/gateway/src/client/mocks/class_block_1342_account_0x07595b4f7d50010ceb00230d8b5656e3c3dd201b6df35d805d3f2988c69a1432.gz b/crates/client/gateway/client/src/mocks/class_block_1342_account_0x07595b4f7d50010ceb00230d8b5656e3c3dd201b6df35d805d3f2988c69a1432.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/class_block_1342_account_0x07595b4f7d50010ceb00230d8b5656e3c3dd201b6df35d805d3f2988c69a1432.gz rename to crates/client/gateway/client/src/mocks/class_block_1342_account_0x07595b4f7d50010ceb00230d8b5656e3c3dd201b6df35d805d3f2988c69a1432.gz diff --git a/crates/client/gateway/src/client/mocks/class_block_1343_proxy_0x071c3c99f5cf76fc19945d4b8b7d34c7c5528f22730d56192b50c6bbfd338a64.gz b/crates/client/gateway/client/src/mocks/class_block_1343_proxy_0x071c3c99f5cf76fc19945d4b8b7d34c7c5528f22730d56192b50c6bbfd338a64.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/class_block_1343_proxy_0x071c3c99f5cf76fc19945d4b8b7d34c7c5528f22730d56192b50c6bbfd338a64.gz rename to crates/client/gateway/client/src/mocks/class_block_1343_proxy_0x071c3c99f5cf76fc19945d4b8b7d34c7c5528f22730d56192b50c6bbfd338a64.gz diff --git a/crates/client/gateway/src/client/mocks/class_block_18507_erc1155_0x04be7f1bace6f593abd8e56947c11151f45498030748a950fdaf0b79ac3dc03f.gz b/crates/client/gateway/client/src/mocks/class_block_18507_erc1155_0x04be7f1bace6f593abd8e56947c11151f45498030748a950fdaf0b79ac3dc03f.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/class_block_18507_erc1155_0x04be7f1bace6f593abd8e56947c11151f45498030748a950fdaf0b79ac3dc03f.gz rename to crates/client/gateway/client/src/mocks/class_block_18507_erc1155_0x04be7f1bace6f593abd8e56947c11151f45498030748a950fdaf0b79ac3dc03f.gz diff --git a/crates/client/gateway/src/client/mocks/class_block_1981_erc20_0x07543f8eb21f10b1827a495084697a519274ac9c1a1fbf931bac40133a6b9c15.gz b/crates/client/gateway/client/src/mocks/class_block_1981_erc20_0x07543f8eb21f10b1827a495084697a519274ac9c1a1fbf931bac40133a6b9c15.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/class_block_1981_erc20_0x07543f8eb21f10b1827a495084697a519274ac9c1a1fbf931bac40133a6b9c15.gz rename to crates/client/gateway/client/src/mocks/class_block_1981_erc20_0x07543f8eb21f10b1827a495084697a519274ac9c1a1fbf931bac40133a6b9c15.gz diff --git a/crates/client/gateway/src/client/mocks/class_block_3125_erc721_0x074a7ed7f1236225600f355efe70812129658c82c295ff0f8307b3fad4bf09a9.gz b/crates/client/gateway/client/src/mocks/class_block_3125_erc721_0x074a7ed7f1236225600f355efe70812129658c82c295ff0f8307b3fad4bf09a9.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/class_block_3125_erc721_0x074a7ed7f1236225600f355efe70812129658c82c295ff0f8307b3fad4bf09a9.gz rename to crates/client/gateway/client/src/mocks/class_block_3125_erc721_0x074a7ed7f1236225600f355efe70812129658c82c295ff0f8307b3fad4bf09a9.gz diff --git a/crates/client/gateway/src/client/mocks/signature_block_0.gz b/crates/client/gateway/client/src/mocks/signature_block_0.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/signature_block_0.gz rename to crates/client/gateway/client/src/mocks/signature_block_0.gz diff --git a/crates/client/gateway/src/client/mocks/signature_block_1.gz b/crates/client/gateway/client/src/mocks/signature_block_1.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/signature_block_1.gz rename to crates/client/gateway/client/src/mocks/signature_block_1.gz diff --git a/crates/client/gateway/src/client/mocks/signature_block_2.gz b/crates/client/gateway/client/src/mocks/signature_block_2.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/signature_block_2.gz rename to crates/client/gateway/client/src/mocks/signature_block_2.gz diff --git a/crates/client/gateway/src/client/mocks/state_update_and_block_0.gz b/crates/client/gateway/client/src/mocks/state_update_and_block_0.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/state_update_and_block_0.gz rename to crates/client/gateway/client/src/mocks/state_update_and_block_0.gz diff --git a/crates/client/gateway/src/client/mocks/state_update_and_block_1.gz b/crates/client/gateway/client/src/mocks/state_update_and_block_1.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/state_update_and_block_1.gz rename to crates/client/gateway/client/src/mocks/state_update_and_block_1.gz diff --git a/crates/client/gateway/src/client/mocks/state_update_and_block_2.gz b/crates/client/gateway/client/src/mocks/state_update_and_block_2.gz similarity index 100% rename from crates/client/gateway/src/client/mocks/state_update_and_block_2.gz rename to crates/client/gateway/client/src/mocks/state_update_and_block_2.gz diff --git a/crates/client/gateway/src/client/request_builder.rs b/crates/client/gateway/client/src/request_builder.rs similarity index 94% rename from crates/client/gateway/src/client/request_builder.rs rename to crates/client/gateway/client/src/request_builder.rs index cc0a7db58..26f48a4f2 100644 --- a/crates/client/gateway/src/client/request_builder.rs +++ b/crates/client/gateway/client/src/request_builder.rs @@ -7,13 +7,13 @@ use hyper::body::Incoming; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use hyper::{HeaderMap, Request, Response, StatusCode, Uri}; use mp_block::{BlockId, BlockTag}; +use mp_gateway::error::{SequencerError, StarknetError}; use serde::de::DeserializeOwned; +use serde::Serialize; use starknet_types_core::felt::Felt; use tower::Service; use url::Url; -use crate::error::{SequencerError, StarknetError}; - use super::builder::PausedClient; #[derive(Debug)] @@ -90,10 +90,10 @@ impl<'a> RequestBuilder<'a> { Ok(response) } - #[allow(dead_code)] - pub async fn send_post(self) -> Result + pub async fn send_post(self, body: D) -> Result where T: DeserializeOwned, + D: Serialize, { let uri = self.build_uri()?; @@ -101,7 +101,7 @@ impl<'a> RequestBuilder<'a> { req_builder.headers_mut().expect("Failed to get mutable reference to request headers").extend(self.headers); - let body = serde_json::to_string(&self.params)?; + let body = serde_json::to_string(&body).map_err(SequencerError::SerializeRequest)?; let req = req_builder.header(CONTENT_TYPE, "application/json").body(body)?; diff --git a/crates/client/gateway/server/Cargo.toml b/crates/client/gateway/server/Cargo.toml new file mode 100644 index 000000000..082bb5190 --- /dev/null +++ b/crates/client/gateway/server/Cargo.toml @@ -0,0 +1,46 @@ +[package] +description = "Madara gateway server service" +name = "mc-gateway-server" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true +homepage.workspace = true + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] + +# Madara +mc-db.workspace = true +mc-rpc.workspace = true +mp-block.workspace = true +mp-class.workspace = true +mp-gateway.workspace = true +mp-utils.workspace = true + +# Starknet +starknet-core.workspace = true +starknet-types-core.workspace = true + +# Other +anyhow.workspace = true +bytes.workspace = true +http-body-util.workspace = true +hyper = { workspace = true, features = ["full"] } +hyper-util.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +thiserror.workspace = true +tokio.workspace = true +tracing.workspace = true + +[dev-dependencies] +tokio.workspace = true +rstest.workspace = true +flate2.workspace = true diff --git a/crates/client/gateway/src/server/error.rs b/crates/client/gateway/server/src/error.rs similarity index 96% rename from crates/client/gateway/src/server/error.rs rename to crates/client/gateway/server/src/error.rs index f1708e18f..77e09eed9 100644 --- a/crates/client/gateway/src/server/error.rs +++ b/crates/client/gateway/server/src/error.rs @@ -3,8 +3,9 @@ use std::fmt::{self, Display}; use hyper::Response; use mc_db::MadaraStorageError; use mc_rpc::StarknetRpcApiError; +use mp_gateway::error::{StarknetError, StarknetErrorCode}; -use crate::error::{StarknetError, StarknetErrorCode}; +use crate::helpers::create_json_response; use super::helpers::internal_error_response; @@ -26,7 +27,7 @@ impl From for GatewayError { impl From for Response { fn from(e: GatewayError) -> Response { match e { - GatewayError::StarknetError(e) => e.into(), + GatewayError::StarknetError(e) => create_json_response(hyper::StatusCode::BAD_REQUEST, &e), GatewayError::InternalServerError(msg) => internal_error_response(&msg), } } diff --git a/crates/client/gateway/src/server/handler.rs b/crates/client/gateway/server/src/handler.rs similarity index 99% rename from crates/client/gateway/src/server/handler.rs rename to crates/client/gateway/server/src/handler.rs index 091a16d1e..ccdaf44a3 100644 --- a/crates/client/gateway/src/server/handler.rs +++ b/crates/client/gateway/server/src/handler.rs @@ -11,6 +11,7 @@ use mc_rpc::{ }; use mp_block::{BlockId, BlockTag, MadaraBlock, MadaraMaybePendingBlockInfo, MadaraPendingBlock}; use mp_class::{ClassInfo, ContractClass}; +use mp_gateway::error::StarknetError; use mp_gateway::{ block::{BlockStatus, ProviderBlock, ProviderBlockPending, ProviderBlockSignature}, state_update::{ProviderStateUpdate, ProviderStateUpdatePending}, @@ -23,8 +24,6 @@ use starknet_core::types::{ }; use starknet_types_core::felt::Felt; -use crate::error::StarknetError; - use super::{ error::{GatewayError, OptionExt, ResultExt}, helpers::{ diff --git a/crates/client/gateway/src/server/helpers.rs b/crates/client/gateway/server/src/helpers.rs similarity index 95% rename from crates/client/gateway/src/server/helpers.rs rename to crates/client/gateway/server/src/helpers.rs index 36ca94176..9e380c98b 100644 --- a/crates/client/gateway/src/server/helpers.rs +++ b/crates/client/gateway/server/src/helpers.rs @@ -2,11 +2,10 @@ use std::collections::HashMap; use hyper::{body::Incoming, header, Request, Response, StatusCode}; use mp_block::{BlockId, BlockTag}; +use mp_gateway::error::{StarknetError, StarknetErrorCode}; use serde::Serialize; use starknet_types_core::felt::Felt; -use crate::error::{StarknetError, StarknetErrorCode}; - pub(crate) fn service_unavailable_response(service_name: &str) -> Response { Response::builder() .status(StatusCode::SERVICE_UNAVAILABLE) @@ -117,9 +116,3 @@ pub(crate) fn block_id_from_params(params: &HashMap) -> Result) -> bool { params.get("includeBlock").map_or(false, |v| v == "true") } - -impl From for Response { - fn from(error: StarknetError) -> Self { - create_json_response(hyper::StatusCode::BAD_REQUEST, &error) - } -} diff --git a/crates/client/gateway/src/server/mod.rs b/crates/client/gateway/server/src/lib.rs similarity index 100% rename from crates/client/gateway/src/server/mod.rs rename to crates/client/gateway/server/src/lib.rs diff --git a/crates/client/gateway/src/server/router.rs b/crates/client/gateway/server/src/router.rs similarity index 100% rename from crates/client/gateway/src/server/router.rs rename to crates/client/gateway/server/src/router.rs diff --git a/crates/client/gateway/src/server/service.rs b/crates/client/gateway/server/src/service.rs similarity index 100% rename from crates/client/gateway/src/server/service.rs rename to crates/client/gateway/server/src/service.rs diff --git a/crates/client/gateway/src/client/mod.rs b/crates/client/gateway/src/client/mod.rs deleted file mode 100644 index 1724cd844..000000000 --- a/crates/client/gateway/src/client/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod builder; -mod methods; -mod request_builder; diff --git a/crates/client/gateway/src/lib.rs b/crates/client/gateway/src/lib.rs deleted file mode 100644 index a79a04cfd..000000000 --- a/crates/client/gateway/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod client; -pub mod error; -pub mod server; diff --git a/crates/client/rpc/Cargo.toml b/crates/client/rpc/Cargo.toml index c361bce91..531a7dae2 100644 --- a/crates/client/rpc/Cargo.toml +++ b/crates/client/rpc/Cargo.toml @@ -25,11 +25,13 @@ mc-db = { workspace = true, features = ["testing"] } m-proc-macros = { workspace = true } mc-db = { workspace = true } mc-exec = { workspace = true } +mc-gateway-client = { workspace = true } mc-mempool = { workspace = true } mp-block = { workspace = true, default-features = true } mp-chain-config = { workspace = true } mp-class = { workspace = true } mp-convert = { workspace = true, default-features = true } +mp-gateway = { workspace = true } mp-receipt = { workspace = true } mp-state-update = { workspace = true } mp-transactions = { workspace = true } @@ -37,7 +39,6 @@ mp-transactions = { workspace = true } # Starknet blockifier = { workspace = true, default-features = true } starknet-core = { workspace = true } -starknet-providers = { workspace = true } starknet-types-core = { workspace = true } starknet-types-rpc = { workspace = true } starknet_api = { workspace = true, default-features = true } diff --git a/crates/client/rpc/src/errors.rs b/crates/client/rpc/src/errors.rs index f5e589e94..7994cbf00 100644 --- a/crates/client/rpc/src/errors.rs +++ b/crates/client/rpc/src/errors.rs @@ -1,9 +1,9 @@ use std::fmt::Display; use mc_db::MadaraStorageError; +use mp_gateway::error::{StarknetError, StarknetErrorCode}; use serde_json::json; use starknet_api::StarknetApiError; -use starknet_core::types::StarknetError; use crate::utils::display_internal_server_error; @@ -167,36 +167,26 @@ impl From for jsonrpsee::types::ErrorObjectOwned { impl From for StarknetRpcApiError { fn from(err: StarknetError) -> Self { - match err { - StarknetError::FailedToReceiveTransaction => StarknetRpcApiError::FailedToReceiveTxn, - StarknetError::ContractNotFound => StarknetRpcApiError::ContractNotFound, - StarknetError::BlockNotFound => StarknetRpcApiError::BlockNotFound, - StarknetError::InvalidTransactionIndex => StarknetRpcApiError::InvalidTxnIndex, - StarknetError::ClassHashNotFound => StarknetRpcApiError::ClassHashNotFound, - StarknetError::TransactionHashNotFound => StarknetRpcApiError::TxnHashNotFound, - StarknetError::PageSizeTooBig => StarknetRpcApiError::PageSizeTooBig, - StarknetError::NoBlocks => StarknetRpcApiError::NoBlocks, - StarknetError::InvalidContinuationToken => StarknetRpcApiError::InvalidContinuationToken, - StarknetError::TooManyKeysInFilter => StarknetRpcApiError::TooManyKeysInFilter, - StarknetError::ContractError(_) => StarknetRpcApiError::ContractError, - StarknetError::ClassAlreadyDeclared => StarknetRpcApiError::ClassAlreadyDeclared, - StarknetError::InvalidTransactionNonce => StarknetRpcApiError::InvalidTxnNonce, - StarknetError::InsufficientMaxFee => StarknetRpcApiError::InsufficientMaxFee, - StarknetError::InsufficientAccountBalance => StarknetRpcApiError::InsufficientAccountBalance, - StarknetError::ValidationFailure(error) => StarknetRpcApiError::ValidationFailure { error }, - StarknetError::CompilationFailed => StarknetRpcApiError::CompilationFailed, - StarknetError::ContractClassSizeIsTooLarge => StarknetRpcApiError::ContractClassSizeTooLarge, - StarknetError::NonAccount => StarknetRpcApiError::NonAccount, - StarknetError::DuplicateTx => StarknetRpcApiError::DuplicateTxn, - StarknetError::CompiledClassHashMismatch => StarknetRpcApiError::CompiledClassHashMismatch, - StarknetError::UnsupportedTxVersion => StarknetRpcApiError::UnsupportedTxnVersion, - StarknetError::UnsupportedContractClassVersion => StarknetRpcApiError::UnsupportedContractClassVersion, - StarknetError::UnexpectedError(data) => StarknetRpcApiError::ErrUnexpectedError { data }, - StarknetError::NoTraceAvailable(_) => StarknetRpcApiError::InternalServerError, - StarknetError::TransactionExecutionError(error) => StarknetRpcApiError::TxnExecutionError { - tx_index: error.transaction_index as usize, - error: error.execution_error.to_string(), - }, + match err.code { + StarknetErrorCode::BlockNotFound => StarknetRpcApiError::BlockNotFound, + StarknetErrorCode::TransactionFailed | StarknetErrorCode::ValidateFailure => { + StarknetRpcApiError::ValidationFailure { error: err.message } + } + StarknetErrorCode::UninitializedContract => StarknetRpcApiError::ContractNotFound, + StarknetErrorCode::UndeclaredClass => StarknetRpcApiError::ClassHashNotFound, + StarknetErrorCode::InvalidTransactionNonce => StarknetRpcApiError::InvalidTxnNonce, + StarknetErrorCode::ClassAlreadyDeclared => StarknetRpcApiError::ClassAlreadyDeclared, + StarknetErrorCode::CompilationFailed => StarknetRpcApiError::CompilationFailed, + StarknetErrorCode::InvalidCompiledClassHash => StarknetRpcApiError::CompiledClassHashMismatch, + StarknetErrorCode::DuplicatedTransaction => StarknetRpcApiError::DuplicateTxn, + StarknetErrorCode::ContractBytecodeSizeTooLarge => StarknetRpcApiError::ContractClassSizeTooLarge, + StarknetErrorCode::InvalidContractClassVersion => StarknetRpcApiError::UnsupportedContractClassVersion, + StarknetErrorCode::InvalidContractClass => StarknetRpcApiError::InvalidContractClass, + StarknetErrorCode::InvalidContractDefinition => StarknetRpcApiError::InvalidContractClass, + StarknetErrorCode::OutOfRangeBlockHash => StarknetRpcApiError::InvalidBlockHash, + StarknetErrorCode::OutOfRangeTransactionHash => StarknetRpcApiError::InvalidTxnHash, + StarknetErrorCode::InvalidTransactionVersion => StarknetRpcApiError::UnsupportedTxnVersion, + _ => StarknetRpcApiError::ErrUnexpectedError { data: err.message }, } } } diff --git a/crates/client/rpc/src/providers/forward_to_provider.rs b/crates/client/rpc/src/providers/forward_to_provider.rs index 9bead7924..0fd9a124b 100644 --- a/crates/client/rpc/src/providers/forward_to_provider.rs +++ b/crates/client/rpc/src/providers/forward_to_provider.rs @@ -1,26 +1,27 @@ use crate::{bail_internal_server_error, errors::StarknetRpcApiError}; use jsonrpsee::core::{async_trait, RpcResult}; +use mc_gateway_client::GatewayProvider; +use mp_gateway::error::SequencerError; use mp_transactions::BroadcastedDeclareTransactionV0; use starknet_core::types::{ BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, DeclareTransactionResult, DeployAccountTransactionResult, InvokeTransactionResult, }; -use starknet_providers::{Provider, ProviderError}; use super::AddTransactionProvider; -pub struct ForwardToProvider { - provider: P, +pub struct ForwardToProvider { + provider: GatewayProvider, } -impl ForwardToProvider

{ - pub fn new(provider: P) -> Self { +impl ForwardToProvider { + pub fn new(provider: GatewayProvider) -> Self { Self { provider } } } #[async_trait] -impl AddTransactionProvider for ForwardToProvider

{ +impl AddTransactionProvider for ForwardToProvider { async fn add_declare_v0_transaction( &self, _declare_v0_transaction: BroadcastedDeclareTransactionV0, @@ -31,9 +32,9 @@ impl AddTransactionProvider for ForwardToProvider

&self, declare_transaction: BroadcastedDeclareTransaction, ) -> RpcResult { - let sequencer_response = match self.provider.add_declare_transaction(declare_transaction).await { + let sequencer_response = match self.provider.add_declare_transaction(declare_transaction.into()).await { Ok(response) => response, - Err(ProviderError::StarknetError(e)) => { + Err(SequencerError::StarknetError(e)) => { return Err(StarknetRpcApiError::from(e).into()); } Err(e) => bail_internal_server_error!("Failed to add declare transaction to sequencer: {e}"), @@ -45,13 +46,14 @@ impl AddTransactionProvider for ForwardToProvider

&self, deploy_account_transaction: BroadcastedDeployAccountTransaction, ) -> RpcResult { - let sequencer_response = match self.provider.add_deploy_account_transaction(deploy_account_transaction).await { - Ok(response) => response, - Err(ProviderError::StarknetError(e)) => { - return Err(StarknetRpcApiError::from(e).into()); - } - Err(e) => bail_internal_server_error!("Failed to add deploy account transaction to sequencer: {e}"), - }; + let sequencer_response = + match self.provider.add_deploy_account_transaction(deploy_account_transaction.into()).await { + Ok(response) => response, + Err(SequencerError::StarknetError(e)) => { + return Err(StarknetRpcApiError::from(e).into()); + } + Err(e) => bail_internal_server_error!("Failed to add deploy account transaction to sequencer: {e}"), + }; Ok(sequencer_response) } @@ -60,9 +62,9 @@ impl AddTransactionProvider for ForwardToProvider

&self, invoke_transaction: BroadcastedInvokeTransaction, ) -> RpcResult { - let sequencer_response = match self.provider.add_invoke_transaction(invoke_transaction).await { + let sequencer_response = match self.provider.add_invoke_transaction(invoke_transaction.into()).await { Ok(response) => response, - Err(ProviderError::StarknetError(e)) => { + Err(SequencerError::StarknetError(e)) => { return Err(StarknetRpcApiError::from(e).into()); } Err(e) => bail_internal_server_error!("Failed to add invoke transaction to sequencer: {e}"), diff --git a/crates/client/sync/Cargo.toml b/crates/client/sync/Cargo.toml index 239d8ccac..da9276f52 100644 --- a/crates/client/sync/Cargo.toml +++ b/crates/client/sync/Cargo.toml @@ -33,7 +33,7 @@ m-cairo-test-contracts.workspace = true mc-analytics.workspace = true mc-block-import.workspace = true mc-db.workspace = true -mc-gateway.workspace = true +mc-gateway-client.workspace = true mc-telemetry.workspace = true mp-block.workspace = true diff --git a/crates/client/sync/src/fetch/fetchers.rs b/crates/client/sync/src/fetch/fetchers.rs index 3f2e26d6a..a793ff6bc 100644 --- a/crates/client/sync/src/fetch/fetchers.rs +++ b/crates/client/sync/src/fetch/fetchers.rs @@ -6,12 +6,12 @@ use core::fmt; use core::time::Duration; use futures::FutureExt; use mc_block_import::{UnverifiedCommitments, UnverifiedFullBlock, UnverifiedPendingFullBlock}; -use mc_gateway::client::builder::FeederClient; -use mc_gateway::error::{SequencerError, StarknetError, StarknetErrorCode}; +use mc_gateway_client::GatewayProvider; use mp_class::class_update::{ClassUpdate, LegacyClassUpdate, SierraClassUpdate}; use mp_class::{ContractClass, MISSED_CLASS_HASHES}; use mp_convert::ToFelt; use mp_gateway::block::{ProviderBlock, ProviderBlockPending}; +use mp_gateway::error::{SequencerError, StarknetError, StarknetErrorCode}; use mp_gateway::state_update::ProviderStateUpdateWithBlockPendingMaybe::{self}; use mp_gateway::state_update::{ProviderStateUpdate, ProviderStateUpdatePending, StateDiff}; use mp_transactions::MAIN_CHAIN_ID; @@ -88,7 +88,7 @@ impl From for starknet_core::types::BlockId { pub async fn fetch_pending_block_and_updates( parent_block_hash: Felt, chain_id: &ChainId, - provider: &FeederClient, + provider: &GatewayProvider, ) -> Result, FetchError> { let block_id = FetchBlockId::Pending; let sw = PerfStopwatch::new(); @@ -138,7 +138,7 @@ pub async fn fetch_pending_block_and_updates( pub async fn fetch_block_and_updates( chain_id: &ChainId, block_n: u64, - provider: &FeederClient, + provider: &GatewayProvider, ) -> Result { let block_id = FetchBlockId::BlockN(block_n); @@ -205,7 +205,7 @@ async fn fetch_class_updates( chain_id: &ChainId, state_diff: &StateDiff, block_id: FetchBlockId, - provider: &FeederClient, + provider: &GatewayProvider, ) -> anyhow::Result> { let chain_id: Felt = chain_id.to_felt(); @@ -268,7 +268,7 @@ async fn fetch_class_updates( async fn fetch_class( class_hash: Felt, block_id: FetchBlockId, - provider: &FeederClient, + provider: &GatewayProvider, ) -> Result<(Felt, ContractClass), SequencerError> { let contract_class = provider.get_class_by_hash(class_hash, block_id.into()).await?; tracing::debug!("Got the contract class {:?}", class_hash); diff --git a/crates/client/sync/src/fetch/fetchers_real_fgw_test.rs b/crates/client/sync/src/fetch/fetchers_real_fgw_test.rs index 0a3dd266f..ddfd5fb14 100644 --- a/crates/client/sync/src/fetch/fetchers_real_fgw_test.rs +++ b/crates/client/sync/src/fetch/fetchers_real_fgw_test.rs @@ -4,13 +4,13 @@ use super::*; use rstest::{fixture, rstest}; #[fixture] -fn client_mainnet_fixture() -> FeederClient { - FeederClient::starknet_alpha_mainnet() +fn client_mainnet_fixture() -> GatewayProvider { + GatewayProvider::starknet_alpha_mainnet() } #[rstest] #[tokio::test] -async fn test_can_fetch_pending_block(client_mainnet_fixture: FeederClient) { +async fn test_can_fetch_pending_block(client_mainnet_fixture: GatewayProvider) { let block = fetch_pending_block_and_updates(Felt::ZERO, &ChainId::Mainnet, &client_mainnet_fixture).await.unwrap(); // ignore as we can't check much here :/ drop(block); @@ -21,7 +21,7 @@ async fn test_can_fetch_pending_block(client_mainnet_fixture: FeederClient) { #[rstest] #[case(0)] #[case(724_130)] -async fn test_can_fetch_and_convert_block(client_mainnet_fixture: FeederClient, #[case] block_n: u64) { +async fn test_can_fetch_and_convert_block(client_mainnet_fixture: GatewayProvider, #[case] block_n: u64) { // Sorting is necessary since we store storage diffs and nonces in a // hashmap in the fgw types before converting them to a Vec in the mp // types, resulting in unpredictable ordering diff --git a/crates/client/sync/src/fetch/mod.rs b/crates/client/sync/src/fetch/mod.rs index 709ed63e8..e850e98a6 100644 --- a/crates/client/sync/src/fetch/mod.rs +++ b/crates/client/sync/src/fetch/mod.rs @@ -4,10 +4,8 @@ use std::time::Duration; use futures::prelude::*; use mc_block_import::UnverifiedFullBlock; use mc_db::MadaraBackend; -use mc_gateway::{ - client::builder::FeederClient, - error::{SequencerError, StarknetError, StarknetErrorCode}, -}; +use mc_gateway_client::GatewayProvider; +use mp_gateway::error::{SequencerError, StarknetError, StarknetErrorCode}; use mp_utils::{channel_wait_or_graceful_shutdown, wait_or_graceful_shutdown}; use tokio::sync::{mpsc, oneshot}; @@ -21,7 +19,7 @@ pub async fn l2_fetch_task( first_block: u64, n_blocks_to_sync: Option, fetch_stream_sender: mpsc::Sender, - provider: Arc, + provider: Arc, sync_polling_interval: Option, once_caught_up_callback: oneshot::Sender<()>, ) -> anyhow::Result<()> { diff --git a/crates/client/sync/src/l2.rs b/crates/client/sync/src/l2.rs index 12ba64e62..66b2ba4a1 100644 --- a/crates/client/sync/src/l2.rs +++ b/crates/client/sync/src/l2.rs @@ -9,11 +9,11 @@ use mc_block_import::{ }; use mc_db::MadaraBackend; use mc_db::MadaraStorageError; -use mc_gateway::client::builder::FeederClient; -use mc_gateway::error::SequencerError; +use mc_gateway_client::GatewayProvider; use mc_telemetry::{TelemetryHandle, VerbosityLevel}; use mp_block::BlockId; use mp_block::BlockTag; +use mp_gateway::error::SequencerError; use mp_utils::{channel_wait_or_graceful_shutdown, wait_or_graceful_shutdown, PerfStopwatch}; use starknet_api::core::ChainId; use starknet_types_core::felt::Felt; @@ -128,7 +128,7 @@ async fn l2_pending_block_task( block_import: Arc, validation: BlockValidationContext, sync_finished_cb: oneshot::Receiver<()>, - provider: Arc, + provider: Arc, pending_block_poll_interval: Duration, ) -> anyhow::Result<()> { // clear pending status @@ -193,7 +193,7 @@ pub struct L2SyncConfig { #[tracing::instrument(skip(backend, provider, config, chain_id, telemetry, block_importer), fields(module = "Sync"))] pub async fn sync( backend: &Arc, - provider: FeederClient, + provider: GatewayProvider, config: L2SyncConfig, chain_id: ChainId, telemetry: TelemetryHandle, diff --git a/crates/client/sync/src/lib.rs b/crates/client/sync/src/lib.rs index a40f3b886..221731e64 100644 --- a/crates/client/sync/src/lib.rs +++ b/crates/client/sync/src/lib.rs @@ -4,7 +4,7 @@ use fetch::fetchers::FetchConfig; use hyper::header::{HeaderName, HeaderValue}; use mc_block_import::BlockImporter; use mc_db::MadaraBackend; -use mc_gateway::client::builder::FeederClient; +use mc_gateway_client::GatewayProvider; use mc_telemetry::TelemetryHandle; use std::{sync::Arc, time::Duration}; @@ -42,7 +42,7 @@ pub async fn sync( tracing::info!("⛓️ Starting L2 sync from block {}", starting_block); - let mut provider = FeederClient::new(fetch_config.gateway, fetch_config.feeder_gateway); + let mut provider = GatewayProvider::new(fetch_config.gateway, fetch_config.feeder_gateway); if let Some(api_key) = fetch_config.api_key { provider.add_header( HeaderName::from_static("x-throttling-bypass"), diff --git a/crates/client/sync/src/tests/utils/gateway.rs b/crates/client/sync/src/tests/utils/gateway.rs index 55a832916..c55e13973 100644 --- a/crates/client/sync/src/tests/utils/gateway.rs +++ b/crates/client/sync/src/tests/utils/gateway.rs @@ -1,7 +1,7 @@ use httpmock::MockServer; use mc_block_import::UnverifiedFullBlock; use mc_db::MadaraBackend; -use mc_gateway::client::builder::FeederClient; +use mc_gateway_client::GatewayProvider; use mp_chain_config::ChainConfig; use rstest::*; use serde_json::{json, Value}; @@ -11,7 +11,7 @@ use url::Url; pub struct TestContext { pub mock_server: MockServer, - pub provider: Arc, + pub provider: Arc, pub backend: Arc, pub fetch_stream_sender: mpsc::Sender, pub fetch_stream_receiver: mpsc::Receiver, @@ -33,7 +33,7 @@ pub fn test_setup() -> Arc { impl TestContext { pub fn new(backend: Arc) -> Self { let mock_server = MockServer::start(); - let provider = Arc::new(FeederClient::new( + let provider = Arc::new(GatewayProvider::new( Url::parse(&format!("{}/gateway/", mock_server.base_url())).unwrap(), Url::parse(&format!("{}/feeder_gateway/", mock_server.base_url())).unwrap(), )); diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index 9a8cfd977..6fd56cf41 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -26,14 +26,14 @@ mc-block-import = { workspace = true } mc-db = { workspace = true } mc-devnet = { workspace = true } mc-eth = { workspace = true } -mc-gateway = { workspace = true } +mc-gateway-client = { workspace = true } +mc-gateway-server = { workspace = true } mc-mempool = { workspace = true } mc-rpc = { workspace = true } mc-sync = { workspace = true } mc-telemetry = { workspace = true } mp-block = { workspace = true } mp-chain-config = { workspace = true } -mp-convert = { workspace = true } mp-utils = { workspace = true } # Starknet @@ -50,6 +50,7 @@ clap = { workspace = true, features = ["derive", "env"] } fdlimit.workspace = true futures = { workspace = true, features = ["thread-pool"] } governor.workspace = true +http.workspace = true hyper = { version = "0.14", features = ["server"] } jsonrpsee.workspace = true rand.workspace = true diff --git a/crates/node/src/main.rs b/crates/node/src/main.rs index dd23c0e56..7721525bf 100644 --- a/crates/node/src/main.rs +++ b/crates/node/src/main.rs @@ -10,16 +10,16 @@ use std::sync::Arc; use anyhow::Context; use clap::Parser; use cli::{NetworkType, RunCmd}; +use http::{HeaderName, HeaderValue}; use mc_analytics::Analytics; use mc_block_import::BlockImporter; use mc_db::DatabaseService; +use mc_gateway_client::GatewayProvider; use mc_mempool::{GasPriceProvider, L1DataProvider, Mempool}; use mc_rpc::providers::{AddTransactionProvider, ForwardToProvider, MempoolAddTxProvider}; use mc_telemetry::{SysInfo, TelemetryService}; -use mp_convert::ToFelt; use mp_utils::service::{Service, ServiceGroup}; use service::{BlockProductionService, GatewayService, L1SyncService, RpcService, SyncService}; -use starknet_providers::SequencerGatewayProvider; const GREET_IMPL_NAME: &str = "Madara"; const GREET_SUPPORT_URL: &str = "https://github.com/madara-alliance/madara/issues"; @@ -157,14 +157,17 @@ async fn main() -> anyhow::Result<()> { .await .context("Initializing sync service")?; - ( - ServiceGroup::default().with(sync_service), - Arc::new(ForwardToProvider::new(SequencerGatewayProvider::new( - chain_config.gateway_url.clone(), - chain_config.feeder_gateway_url.clone(), - chain_config.chain_id.to_felt(), - ))), - ) + let mut provider = + GatewayProvider::new(chain_config.gateway_url.clone(), chain_config.feeder_gateway_url.clone()); + // gateway api key is needed for declare transactions on mainnet + if let Some(api_key) = run_cmd.sync_params.gateway_key { + provider.add_header( + HeaderName::from_static("x-throttling-bypass"), + HeaderValue::from_str(&api_key).with_context(|| "Invalid API key format")?, + ) + } + + (ServiceGroup::default().with(sync_service), Arc::new(ForwardToProvider::new(provider))) } }; diff --git a/crates/node/src/service/gateway.rs b/crates/node/src/service/gateway.rs index 54d55fbeb..52aa889c4 100644 --- a/crates/node/src/service/gateway.rs +++ b/crates/node/src/service/gateway.rs @@ -29,7 +29,7 @@ impl Service for GatewayService { let GatewayService { db_backend, add_transaction_provider, config } = self.clone(); join_set.spawn(async move { - mc_gateway::server::service::start_server( + mc_gateway_server::service::start_server( db_backend, add_transaction_provider, config.feeder_gateway_enable, diff --git a/crates/primitives/gateway/Cargo.toml b/crates/primitives/gateway/Cargo.toml index 187743fbe..035ad97c6 100644 --- a/crates/primitives/gateway/Cargo.toml +++ b/crates/primitives/gateway/Cargo.toml @@ -32,6 +32,10 @@ starknet-types-core.workspace = true # Other anyhow.workspace = true +http.workspace = true +hyper.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true serde_with.workspace = true +thiserror.workspace = true +url.workspace = true diff --git a/crates/client/gateway/src/error.rs b/crates/primitives/gateway/src/error.rs similarity index 100% rename from crates/client/gateway/src/error.rs rename to crates/primitives/gateway/src/error.rs diff --git a/crates/primitives/gateway/src/lib.rs b/crates/primitives/gateway/src/lib.rs index 265d3e94a..bd933cca8 100644 --- a/crates/primitives/gateway/src/lib.rs +++ b/crates/primitives/gateway/src/lib.rs @@ -1,4 +1,5 @@ pub mod block; +pub mod error; pub mod receipt; pub mod state_update; pub mod transaction; diff --git a/crates/primitives/gateway/src/user_transaction.rs b/crates/primitives/gateway/src/user_transaction.rs index 621b8f382..dfc7ae3f6 100644 --- a/crates/primitives/gateway/src/user_transaction.rs +++ b/crates/primitives/gateway/src/user_transaction.rs @@ -15,7 +15,7 @@ use starknet_types_core::felt::Felt; #[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")] #[serde(deny_unknown_fields)] pub enum UserTransaction { - DeclareV1(UserDeclareTransaction), + Declare(UserDeclareTransaction), InvokeFunction(UserInvokeFunctionTransaction), DeployAccount(UserDeployAccountTransaction), } @@ -23,13 +23,23 @@ pub enum UserTransaction { impl From for BroadcastedTransaction { fn from(transaction: UserTransaction) -> Self { match transaction { - UserTransaction::DeclareV1(v1) => BroadcastedTransaction::Declare(v1.into()), + UserTransaction::Declare(v1) => BroadcastedTransaction::Declare(v1.into()), UserTransaction::InvokeFunction(v1) => BroadcastedTransaction::Invoke(v1.into()), UserTransaction::DeployAccount(v1) => BroadcastedTransaction::DeployAccount(v1.into()), } } } +impl From for UserTransaction { + fn from(transaction: BroadcastedTransaction) -> Self { + match transaction { + BroadcastedTransaction::Declare(v1) => UserTransaction::Declare(v1.into()), + BroadcastedTransaction::Invoke(v1) => UserTransaction::InvokeFunction(v1.into()), + BroadcastedTransaction::DeployAccount(v1) => UserTransaction::DeployAccount(v1.into()), + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "version")] pub enum UserDeclareTransaction { @@ -51,6 +61,16 @@ impl From for BroadcastedDeclareTransaction { } } +impl From for UserDeclareTransaction { + fn from(transaction: BroadcastedDeclareTransaction) -> Self { + match transaction { + BroadcastedDeclareTransaction::V1(v1) => UserDeclareTransaction::V1(v1.into()), + BroadcastedDeclareTransaction::V2(v2) => UserDeclareTransaction::V2(v2.into()), + BroadcastedDeclareTransaction::V3(v3) => UserDeclareTransaction::V3(v3.into()), + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct UserDeclareV1Transaction { pub contract_class: CompressedLegacyContractClass, @@ -74,6 +94,19 @@ impl From for BroadcastedDeclareTransactionV1 { } } +impl From for UserDeclareV1Transaction { + fn from(transaction: BroadcastedDeclareTransactionV1) -> Self { + Self { + sender_address: transaction.sender_address, + max_fee: transaction.max_fee, + signature: transaction.signature, + nonce: transaction.nonce, + contract_class: transaction.contract_class.as_ref().to_owned().into(), + is_query: transaction.is_query, + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct UserDeclareV2Transaction { pub contract_class: FlattenedSierraClass, @@ -99,6 +132,20 @@ impl From for BroadcastedDeclareTransactionV2 { } } +impl From for UserDeclareV2Transaction { + fn from(transaction: BroadcastedDeclareTransactionV2) -> Self { + Self { + sender_address: transaction.sender_address, + compiled_class_hash: transaction.compiled_class_hash, + signature: transaction.signature, + nonce: transaction.nonce, + contract_class: transaction.contract_class.as_ref().to_owned().into(), + max_fee: transaction.max_fee, + is_query: transaction.is_query, + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct UserDeclareV3Transaction { pub contract_class: FlattenedSierraClass, @@ -134,6 +181,25 @@ impl From for BroadcastedDeclareTransactionV3 { } } +impl From for UserDeclareV3Transaction { + fn from(transaction: BroadcastedDeclareTransactionV3) -> Self { + Self { + sender_address: transaction.sender_address, + compiled_class_hash: transaction.compiled_class_hash, + signature: transaction.signature, + nonce: transaction.nonce, + nonce_data_availability_mode: transaction.nonce_data_availability_mode.into(), + fee_data_availability_mode: transaction.fee_data_availability_mode.into(), + resource_bounds: transaction.resource_bounds.into(), + tip: transaction.tip, + contract_class: transaction.contract_class.as_ref().to_owned().into(), + paymaster_data: transaction.paymaster_data, + account_deployment_data: transaction.account_deployment_data, + is_query: transaction.is_query, + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "version")] pub enum UserInvokeFunctionTransaction { @@ -152,6 +218,15 @@ impl From for BroadcastedInvokeTransaction { } } +impl From for UserInvokeFunctionTransaction { + fn from(transaction: BroadcastedInvokeTransaction) -> Self { + match transaction { + BroadcastedInvokeTransaction::V1(v1) => UserInvokeFunctionTransaction::V1(v1.into()), + BroadcastedInvokeTransaction::V3(v3) => UserInvokeFunctionTransaction::V3(v3.into()), + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct UserInvokeFunctionV1Transaction { pub sender_address: Felt, @@ -175,6 +250,19 @@ impl From for BroadcastedInvokeTransactionV1 { } } +impl From for UserInvokeFunctionV1Transaction { + fn from(transaction: BroadcastedInvokeTransactionV1) -> Self { + Self { + sender_address: transaction.sender_address, + calldata: transaction.calldata, + signature: transaction.signature, + max_fee: transaction.max_fee, + nonce: transaction.nonce, + is_query: transaction.is_query, + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct UserInvokeFunctionV3Transaction { pub sender_address: Felt, @@ -208,6 +296,24 @@ impl From for BroadcastedInvokeTransactionV3 { } } +impl From for UserInvokeFunctionV3Transaction { + fn from(transaction: BroadcastedInvokeTransactionV3) -> Self { + Self { + sender_address: transaction.sender_address, + calldata: transaction.calldata, + signature: transaction.signature, + nonce: transaction.nonce, + nonce_data_availability_mode: transaction.nonce_data_availability_mode.into(), + fee_data_availability_mode: transaction.fee_data_availability_mode.into(), + resource_bounds: transaction.resource_bounds.into(), + tip: transaction.tip, + paymaster_data: transaction.paymaster_data, + account_deployment_data: transaction.account_deployment_data, + is_query: transaction.is_query, + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "version")] pub enum UserDeployAccountTransaction { @@ -226,6 +332,15 @@ impl From for BroadcastedDeployAccountTransaction } } +impl From for UserDeployAccountTransaction { + fn from(transaction: BroadcastedDeployAccountTransaction) -> Self { + match transaction { + BroadcastedDeployAccountTransaction::V1(v1) => UserDeployAccountTransaction::V1(v1.into()), + BroadcastedDeployAccountTransaction::V3(v3) => UserDeployAccountTransaction::V3(v3.into()), + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct UserDeployAccountV1Transaction { pub class_hash: Felt, @@ -251,6 +366,20 @@ impl From for BroadcastedDeployAccountTransactio } } +impl From for UserDeployAccountV1Transaction { + fn from(transaction: BroadcastedDeployAccountTransactionV1) -> Self { + Self { + class_hash: transaction.class_hash, + contract_address_salt: transaction.contract_address_salt, + constructor_calldata: transaction.constructor_calldata, + max_fee: transaction.max_fee, + signature: transaction.signature, + nonce: transaction.nonce, + is_query: transaction.is_query, + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct UserDeployAccountV3Transaction { pub class_hash: Felt, @@ -283,3 +412,21 @@ impl From for BroadcastedDeployAccountTransactio } } } + +impl From for UserDeployAccountV3Transaction { + fn from(transaction: BroadcastedDeployAccountTransactionV3) -> Self { + Self { + class_hash: transaction.class_hash, + contract_address_salt: transaction.contract_address_salt, + constructor_calldata: transaction.constructor_calldata, + signature: transaction.signature, + nonce: transaction.nonce, + nonce_data_availability_mode: transaction.nonce_data_availability_mode.into(), + fee_data_availability_mode: transaction.fee_data_availability_mode.into(), + resource_bounds: transaction.resource_bounds.into(), + tip: transaction.tip, + paymaster_data: transaction.paymaster_data, + is_query: transaction.is_query, + } + } +}