use crate::clique::{CliqueGethInstance, CliqueMiddleware}; use ethers_core::{ types::{transaction::eip2718::TypedTransaction, Address, Eip1559TransactionRequest}, utils::Geth, }; use ethers_providers::Middleware; use reth_network::{ test_utils::{unused_tcp_and_udp_port, unused_tcp_udp, NetworkEventStream}, NetworkConfig, NetworkManager, }; use reth_network_api::Peers; use reth_primitives::{ChainSpec, Genesis, PeerId, SealedHeader}; use reth_provider::test_utils::NoopProvider; use secp256k1::SecretKey; use std::{net::SocketAddr, sync::Arc}; #[tokio::test(flavor = "multi_thread")] #[cfg_attr(not(feature = "geth-tests"), ignore)] async fn can_peer_with_geth() { reth_tracing::init_test_tracing(); let (clique, chainspec) = init_geth().await; let geth_p2p_port = clique.instance.p2p_port().unwrap(); // === initialize reth networking stack === let secret_key = SecretKey::new(&mut rand::thread_rng()); let (reth_p2p, reth_disc) = unused_tcp_udp(); tracing::info!( %reth_p2p, %reth_disc, "setting up reth networking stack in keepalive test" ); let config = NetworkConfig::builder(secret_key) .listener_addr(reth_p2p) .discovery_addr(reth_disc) .chain_spec(chainspec) .build(Arc::new(NoopProvider::default())); let network = NetworkManager::new(config).await.unwrap(); let handle = network.handle().clone(); tokio::task::spawn(network); // create networkeventstream to get the next session established event easily let mut events = NetworkEventStream::new(handle.event_listener()); let geth_socket = SocketAddr::new([127, 0, 0, 1].into(), geth_p2p_port); // get the peer id we should be expecting let geth_peer_id: PeerId = clique.provider.peer_id().await.unwrap(); // add geth as a peer then wait for `PeerAdded` and `SessionEstablished` events. handle.add_peer(geth_peer_id, geth_socket); // wait for the session to be established let peer_id = events.peer_added_and_established().await.unwrap(); assert_eq!(geth_peer_id, peer_id); } async fn init_geth() -> (CliqueGethInstance, Arc) { // first create a signer that we will fund so we can make transactions let chain_id = 13337u64; let data_dir = tempfile::tempdir().expect("should be able to create temp geth datadir"); let dir_path = data_dir.path(); tracing::info!( data_dir=?dir_path, "initializing geth instance" ); // this creates a funded geth let clique_geth = Geth::new() .chain_id(chain_id) .p2p_port(unused_tcp_and_udp_port()) .data_dir(dir_path.to_str().unwrap()); // build the funded geth let mut clique = CliqueGethInstance::new(clique_geth, None).await; let geth_p2p_port = clique.instance.p2p_port().expect("geth should be configured with a p2p port"); tracing::info!( p2p_port=%geth_p2p_port, rpc_port=%clique.instance.port(), "configured clique geth instance in keepalive test" ); // don't print logs, but drain the stderr clique.prevent_blocking().await; // get geth to start producing blocks - use a blank password let clique_private_key = clique .instance .clique_private_key() .clone() .expect("clique should be configured with a private key"); clique.provider.enable_mining(clique_private_key, "".into()).await.unwrap(); // === check that we have the same genesis hash === // get the chainspec from the genesis we configured for geth let chainspec = ChainSpec::from(Genesis::from( clique.instance.genesis().clone().expect("clique should be configured with a genesis"), )); let remote_genesis = SealedHeader::from(&clique.provider.remote_genesis_block().await.unwrap()); let local_genesis = chainspec.genesis_header().seal(chainspec.genesis_hash()); assert_eq!(local_genesis, remote_genesis, "genesis blocks should match, we computed {local_genesis:#?} but geth computed {remote_genesis:#?}"); // === create many blocks === let nonces = 0..1000u64; let txs = nonces.map(|nonce| { // create a tx that just sends to the zero addr TypedTransaction::Eip1559( Eip1559TransactionRequest::new().to(Address::zero()).value(1u64).nonce(nonce), ) }); tracing::info!("generated transactions for blocks"); // finally send the txs to geth clique.provider.send_requests(txs).await.unwrap(); let block = clique.provider.get_block_number().await.unwrap(); assert!(block.as_u64() > 0); (clique, Arc::new(chainspec)) }