Skip to main content

tempo_bench/cmd/
signer_providers.rs

1use std::sync::Arc;
2
3use alloy::{
4    providers::{
5        DynProvider, Provider, ProviderBuilder, RootProvider,
6        fillers::{CachedNonceManager, FillProvider, TxFiller},
7    },
8    signers::local::{MnemonicBuilder, Secp256k1Signer},
9    transports::http::reqwest::Url,
10};
11use indicatif::ProgressIterator;
12use rand::seq::IndexedRandom;
13use tempo_alloy::TempoNetwork;
14
15type BenchProvider<F> = FillProvider<F, RootProvider<TempoNetwork>, TempoNetwork>;
16type UnsignedProviderFactory<F> =
17    Box<dyn Fn(Url, CachedNonceManager) -> BenchProvider<F> + Send + Sync>;
18type SignedProviderFactory = Box<
19    dyn Fn(Secp256k1Signer, Url, CachedNonceManager) -> DynProvider<TempoNetwork> + Send + Sync,
20>;
21
22/// Manages signers and target URLs for creating providers.
23#[derive(Debug, Clone)]
24pub(crate) struct SignerProviderManager<F: TxFiller<TempoNetwork>>(
25    Arc<SignerProviderManagerInner<F>>,
26);
27
28#[derive(Debug)]
29struct SignerProviderManagerInner<F: TxFiller<TempoNetwork>> {
30    /// List of secp256k1 signers (faster than k256-based PrivateKeySigner).
31    signers: Vec<Secp256k1Signer>,
32    /// List of target URLs.
33    target_urls: Vec<Url>,
34    /// Providers without signing capabilities.
35    unsigned_providers: Vec<BenchProvider<F>>,
36    /// List of providers (one per signer) with random target URLs.
37    signer_providers: Vec<(Secp256k1Signer, DynProvider<TempoNetwork>)>,
38}
39
40impl<F: TxFiller<TempoNetwork> + 'static> SignerProviderManager<F> {
41    /// Create a new instance of [`SignerProviderManager`].
42    ///
43    /// 1. Creates `accounts` signers from the `mnemonic` starting with `from_mnemonic_index` index.
44    /// 2. Creates `target_urls` providers without signing capabilities using `unsigned_provider_factory`.
45    /// 3. Creates `accounts` providers with signing capabilities, one per signer,
46    ///    with random target URLs using `signed_provider_factory`.
47    pub fn new(
48        mnemonic: String,
49        from_mnemonic_index: u32,
50        accounts: u64,
51        target_urls: Vec<Url>,
52        unsigned_provider_factory: UnsignedProviderFactory<F>,
53        signed_provider_factory: SignedProviderFactory,
54    ) -> Self {
55        let cached_nonce_manager = CachedNonceManager::default();
56        // Use Secp256k1Signer for better performance (libsecp256k1 bindings vs pure-Rust k256)
57        let signers: Vec<Secp256k1Signer> = (from_mnemonic_index..)
58            .take(accounts as usize)
59            .progress_count(accounts)
60            .map(|i| MnemonicBuilder::from_phrase_nth(&mnemonic, i).into_secp256k1())
61            .collect();
62        let unsigned_providers = target_urls
63            .iter()
64            .cloned()
65            .map(|target_url| (unsigned_provider_factory)(target_url, cached_nonce_manager.clone()))
66            .collect();
67        let signer_providers = signers
68            .iter()
69            .progress()
70            .cloned()
71            .map(|signer| {
72                let target_url = target_urls.choose(&mut rand::rng()).unwrap().clone();
73                let provider = (signed_provider_factory)(
74                    signer.clone(),
75                    target_url,
76                    cached_nonce_manager.clone(),
77                );
78                (signer, provider)
79            })
80            .collect();
81        Self(Arc::new(SignerProviderManagerInner {
82            signers,
83            target_urls,
84            unsigned_providers,
85            signer_providers,
86        }))
87    }
88
89    /// Returns a list of providers (one per target URL) with no signers and fillers set.
90    pub fn target_url_providers(&self) -> Vec<(&Url, DynProvider<TempoNetwork>)> {
91        self.0
92            .target_urls
93            .iter()
94            .map(|target_url| {
95                let provider = ProviderBuilder::default()
96                    .connect_http(target_url.clone())
97                    .erased();
98                (target_url, provider)
99            })
100            .collect()
101    }
102
103    /// Returns a list of providers (one per signer) with random target URLs.
104    pub fn signer_providers(&self) -> &[(Secp256k1Signer, DynProvider<TempoNetwork>)] {
105        &self.0.signer_providers
106    }
107
108    /// Returns a random signer without signing capabilities.
109    pub fn random_unsigned_provider(&self) -> BenchProvider<F> {
110        self.0
111            .unsigned_providers
112            .choose(&mut rand::rng())
113            .unwrap()
114            .clone()
115    }
116
117    /// Returns a random signer.
118    pub fn random_signer(&self) -> &Secp256k1Signer {
119        self.0.signers.choose(&mut rand::rng()).unwrap()
120    }
121}