Skip to content

Commit

Permalink
chore: add e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Romsters committed Dec 13, 2024
1 parent f620ac4 commit 9b2df93
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 19 deletions.
2 changes: 1 addition & 1 deletion e2e-tests-rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ mod provider;
mod utils;

pub use ext::{ReceiptExt, ZksyncWalletProviderExt};
pub use provider::{init_testing_provider, AnvilZKsyncApi, TestingProvider, DEFAULT_TX_VALUE};
pub use provider::{init_testing_provider, init_testing_provider_with_http_headers, AnvilZKsyncApi, TestingProvider, DEFAULT_TX_VALUE};
2 changes: 1 addition & 1 deletion e2e-tests-rust/src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ mod anvil_zksync;
mod testing;

pub use anvil_zksync::AnvilZKsyncApi;
pub use testing::{init_testing_provider, TestingProvider, DEFAULT_TX_VALUE};
pub use testing::{init_testing_provider, init_testing_provider_with_http_headers, TestingProvider, DEFAULT_TX_VALUE};
100 changes: 84 additions & 16 deletions e2e-tests-rust/src/provider/testing.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
use crate::utils::LockedPort;
use crate::utils::{LockedPort,get_node_binary_path};
use crate::ReceiptExt;
use alloy::network::primitives::{BlockTransactionsKind, HeaderResponse as _};
use alloy::network::{Network, ReceiptResponse as _, TransactionBuilder};
use alloy::primitives::{Address, U256};
use alloy::signers::local::LocalSigner;
use alloy::providers::{
PendingTransaction, PendingTransactionBuilder, PendingTransactionError, Provider, RootProvider,
SendableTx, WalletProvider,
};
use alloy::rpc::types::{Block, TransactionRequest};
use alloy::transports::http::{reqwest, Http};
use alloy::rpc::{
types::{Block, TransactionRequest},
client::RpcClient,
};
use alloy::transports::http::{
reqwest,
reqwest::{
header::HeaderMap,
Client,
},
Http
};
use alloy::transports::{RpcError, Transport, TransportErrorKind, TransportResult};
use alloy_zksync::network::header_response::HeaderResponse;
use alloy_zksync::network::receipt_response::ReceiptResponse;
use alloy_zksync::network::transaction_response::TransactionResponse;
use alloy_zksync::network::Zksync;
use alloy_zksync::node_bindings::EraTestNode;
use alloy_zksync::provider::{zksync_provider, ProviderBuilderExt};
use alloy_zksync::node_bindings::{EraTestNode,EraTestNodeError::NoKeysAvailable};
use alloy_zksync::provider::{zksync_provider, ProviderBuilderExt, layers::era_test_node::EraTestNodeLayer};
use alloy_zksync::wallet::ZksyncWallet;
use anyhow::Context as _;
use itertools::Itertools;
Expand Down Expand Up @@ -71,10 +82,7 @@ pub async fn init_testing_provider(
.with_recommended_fillers()
.on_era_test_node_with_wallet_and_config(|node| {
f(node
.path(
std::env::var("ANVIL_ZKSYNC_BINARY_PATH")
.unwrap_or("../target/release/anvil-zksync".to_string()),
)
.path(get_node_binary_path())
.port(locked_port.port))
});

Expand All @@ -93,6 +101,66 @@ pub async fn init_testing_provider(
})
}

// Init testing provider which sends specified HTTP headers e.g. for authentication
// Outside of `TestingProvider` to avoid specifying `P`
pub async fn init_testing_provider_with_http_headers(
headers: HeaderMap,
f: impl FnOnce(EraTestNode) -> EraTestNode,
) -> anyhow::Result<
TestingProvider<impl FullZksyncProvider<Http<reqwest::Client>>, Http<reqwest::Client>>,
> {
use alloy::signers::Signer;

let locked_port = LockedPort::acquire_unused().await?;
let node_layer = EraTestNodeLayer::from(
f(
EraTestNode::new()
.path(get_node_binary_path())
.port(locked_port.port)
)
);

let client_with_headers = Client::builder().default_headers(headers).build()?;
let rpc_url = node_layer.endpoint_url();
let http = Http::with_client(client_with_headers, rpc_url);
let rpc_client = RpcClient::new(http, true);

let default_keys = node_layer.instance().keys().to_vec();
let (default_key, remaining_keys) = default_keys
.split_first()
.ok_or(NoKeysAvailable)?;

let default_signer = LocalSigner::from(default_key.clone())
.with_chain_id(Some(node_layer.instance().chain_id()));
let mut wallet = ZksyncWallet::from(default_signer);

for key in remaining_keys {
let signer = LocalSigner::from(key.clone());
wallet.register_signer(signer)
}

let provider = zksync_provider()
.with_recommended_fillers()
.wallet(wallet)
.layer(node_layer)
.on_client(rpc_client);

// Grab default rich accounts right after init. Note that subsequent calls to this method
// might return different value as wallet's signers are dynamic and can be changed by the user.
let rich_accounts = provider.signer_addresses().collect::<Vec<_>>();
// Wait for anvil-zksync to get up and be able to respond
// Ignore error response (should not fail here if provider is used with intentionally wrong origin for testing purposes)
let _ = provider.get_chain_id().await;
// Explicitly unlock the port to showcase why we waited above
drop(locked_port);

Ok(TestingProvider {
inner: provider,
rich_accounts,
_pd: Default::default(),
})
}

impl<P, T> TestingProvider<P, T>
where
P: FullZksyncProvider<T>,
Expand Down Expand Up @@ -383,13 +451,7 @@ where
self
}

/// Builder-pattern method for setting the chain id.
pub fn with_chain_id(mut self, id: u64) -> Self {
self.inner = self.inner.with_chain_id(id);
self
}

/// Builder-pattern method for setting the recipient.
/// Builder-pattern method for setting the receiver.
pub fn with_to(mut self, to: Address) -> Self {
self.inner = self.inner.with_to(to);
self
Expand All @@ -401,6 +463,12 @@ where
self
}

/// Builder-pattern method for setting the chain id.
pub fn with_chain_id(mut self, id: u64) -> Self {
self.inner = self.inner.with_chain_id(id);
self
}

/// Submits transaction to the node.
///
/// This does not wait for the transaction to be confirmed, but returns a [`PendingTransactionFinalizable`]
Expand Down
5 changes: 5 additions & 0 deletions e2e-tests-rust/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,8 @@ impl Drop for LockedPort {
.unwrap();
}
}

pub fn get_node_binary_path() -> String {
std::env::var("ANVIL_ZKSYNC_BINARY_PATH")
.unwrap_or("../target/release/anvil-zksync".to_string())
}
37 changes: 36 additions & 1 deletion e2e-tests-rust/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use alloy::network::ReceiptResponse;
use alloy::providers::ext::AnvilApi;
use alloy::providers::Provider;
use anvil_zksync_e2e_tests::{
init_testing_provider, AnvilZKsyncApi, ReceiptExt, ZksyncWalletProviderExt, DEFAULT_TX_VALUE,
init_testing_provider, init_testing_provider_with_http_headers, AnvilZKsyncApi, ReceiptExt, ZksyncWalletProviderExt, DEFAULT_TX_VALUE,
};
use alloy::{
primitives::U256,
signers::local::PrivateKeySigner,
};
use alloy::transports::http::reqwest::header::{HeaderMap, HeaderValue, ORIGIN};
use std::convert::identity;
use std::time::Duration;

Expand Down Expand Up @@ -363,3 +364,37 @@ async fn set_chain_id() -> anyhow::Result<()> {

Ok(())
}

#[tokio::test]
async fn cli_no_cors() -> anyhow::Result<()> {
let mut headers = HeaderMap::new();
headers.insert(ORIGIN, HeaderValue::from_static("http://some.origin"));

// Verify all origins are allowed by default
let provider = init_testing_provider_with_http_headers(headers.clone(), identity).await?;
provider.get_chain_id().await?;

// Verify no origins are allowed with --no-cors
let provider_with_no_cors = init_testing_provider_with_http_headers(headers.clone(), |node| node.arg("--no-cors=true")).await?;
let error_resp = provider_with_no_cors.get_chain_id().await.unwrap_err();
assert_eq!(error_resp.to_string().contains("Origin of the request is not whitelisted"), true);

Ok(())
}

#[tokio::test]
async fn cli_allow_origin() -> anyhow::Result<()> {
let mut headers = HeaderMap::new();
headers.insert(ORIGIN, HeaderValue::from_static("http://some.origin"));

// Verify allowed origin can make requests
let provider_with_allowed_origin = init_testing_provider_with_http_headers(headers.clone(), |node| node.arg("--allow-origin=http://some.origin")).await?;
provider_with_allowed_origin.get_chain_id().await?;

// Verify different origin is not allowed
let provider_with_not_allowed_origin = init_testing_provider_with_http_headers(headers.clone(), |node| node.arg("--allow-origin=http://other.origin")).await?;
let error_resp = provider_with_not_allowed_origin.get_chain_id().await.unwrap_err();
assert_eq!(error_resp.to_string().contains("Origin of the request is not whitelisted"), true);

Ok(())
}

0 comments on commit 9b2df93

Please sign in to comment.