Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
feat: rotating infura keys (#1017)
Browse files Browse the repository at this point in the history
* feat: add providers which rotate api keys

* test: use rotating key in provider instead of hardcoded

* chore: fmt
  • Loading branch information
gakonst authored Mar 13, 2022
1 parent 367f344 commit ae125bc
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 33 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 3 additions & 6 deletions ethers-middleware/tests/nonce_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
async fn nonce_manager() {
use ethers_core::types::*;
use ethers_middleware::{nonce_manager::NonceManagerMiddleware, signer::SignerMiddleware};
use ethers_providers::{Http, Middleware, Provider};
use ethers_providers::Middleware;
use ethers_signers::{LocalWallet, Signer};
use std::{convert::TryFrom, time::Duration};
use std::time::Duration;

let provider =
Provider::<Http>::try_from("https://rinkeby.infura.io/v3/fd8b88b56aa84f6da87b60f5441d6778")
.unwrap()
.interval(Duration::from_millis(2000u64));
let provider = ethers_providers::RINKEBY.provider().interval(Duration::from_millis(2000u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64();

let wallet = std::env::var("RINKEBY_PRIVATE_KEY")
Expand Down
13 changes: 4 additions & 9 deletions ethers-middleware/tests/signer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(unused)]
use ethers_providers::{Http, JsonRpcClient, Middleware, Provider};
use ethers_providers::{Http, JsonRpcClient, Middleware, Provider, RINKEBY};

use ethers_core::{
types::{BlockNumber, TransactionRequest},
Expand All @@ -8,7 +8,7 @@ use ethers_core::{
use ethers_middleware::signer::SignerMiddleware;
use ethers_signers::{coins_bip39::English, LocalWallet, MnemonicBuilder, Signer};
use once_cell::sync::Lazy;
use std::{convert::TryFrom, sync::atomic::AtomicU8, time::Duration};
use std::{convert::TryFrom, iter::Cycle, sync::atomic::AtomicU8, time::Duration};

static WALLETS: Lazy<TestWallets> = Lazy::new(|| {
TestWallets {
Expand Down Expand Up @@ -54,10 +54,7 @@ async fn send_eth() {
#[tokio::test]
#[cfg(not(feature = "celo"))]
async fn pending_txs_with_confirmations_testnet() {
let provider =
Provider::<Http>::try_from("https://rinkeby.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27")
.unwrap()
.interval(Duration::from_millis(3000));
let provider = RINKEBY.provider().interval(Duration::from_millis(3000));
let chain_id = provider.get_chainid().await.unwrap();
let wallet = WALLETS.next().with_chain_id(chain_id.as_u64());
let address = wallet.address();
Expand Down Expand Up @@ -97,9 +94,7 @@ async fn generic_pending_txs_test<M: Middleware>(provider: M, who: Address) {
#[tokio::test]
#[cfg(not(feature = "celo"))]
async fn typed_txs() {
let provider =
Provider::<Http>::try_from("https://rinkeby.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27")
.unwrap();
let provider = RINKEBY.provider();

let chain_id = provider.get_chainid().await.unwrap();
let wallet = WALLETS.next().with_chain_id(chain_id.as_u64());
Expand Down
1 change: 1 addition & 0 deletions ethers-providers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ tracing = { version = "0.1.32", default-features = false }
tracing-futures = { version = "0.2.5", default-features = false, features = ["std-future"] }

bytes = { version = "1.1.0", default-features = false, optional = true }
once_cell = "1.10.0"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
# tokio
Expand Down
50 changes: 50 additions & 0 deletions ethers-providers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,3 +657,53 @@ pub trait CeloMiddleware: Middleware {
self.provider().get_validators_bls_public_keys(block_id).await.map_err(FromErr::from)
}
}

pub use test_provider::{GOERLI, MAINNET, RINKEBY, ROPSTEN};

/// Pre-instantiated Infura HTTP clients which rotate through multiple API keys
/// to prevent rate limits
pub mod test_provider {
use super::*;
use crate::Http;
use once_cell::sync::Lazy;
use std::{convert::TryFrom, iter::Cycle, slice::Iter, sync::Mutex};

// List of infura keys to rotate through so we don't get rate limited
const INFURA_KEYS: &[&str] = &[
"6770454bc6ea42c58aac12978531b93f",
"7a8769b798b642f6933f2ed52042bd70",
"631fd9a6539644088297dc605d35fff3",
"16a8be88795540b9b3903d8de0f7baa5",
"f4a0bdad42674adab5fc0ac077ffab2b",
"5c812e02193c4ba793f8c214317582bd",
];

pub static RINKEBY: Lazy<TestProvider> =
Lazy::new(|| TestProvider::new(INFURA_KEYS, "rinkeby"));
pub static MAINNET: Lazy<TestProvider> =
Lazy::new(|| TestProvider::new(INFURA_KEYS, "mainnet"));
pub static GOERLI: Lazy<TestProvider> = Lazy::new(|| TestProvider::new(INFURA_KEYS, "goerli"));
pub static ROPSTEN: Lazy<TestProvider> =
Lazy::new(|| TestProvider::new(INFURA_KEYS, "ropsten"));

#[derive(Debug)]
pub struct TestProvider {
network: String,
keys: Mutex<Cycle<Iter<'static, &'static str>>>,
}

impl TestProvider {
pub fn new(keys: &'static [&'static str], network: &str) -> Self {
Self { keys: Mutex::new(keys.iter().cycle()), network: network.to_owned() }
}

pub fn provider(&self) -> Provider<Http> {
let url = format!(
"https://{}.infura.io/v3/{}",
self.network,
self.keys.lock().unwrap().next().unwrap()
);
Provider::try_from(url.as_str()).unwrap()
}
}
}
8 changes: 3 additions & 5 deletions ethers-providers/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1488,12 +1488,10 @@ mod tests {
};
use futures_util::StreamExt;

const INFURA: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";

#[tokio::test]
// Test vector from: https://docs.ethers.io/ethers.js/v5-beta/api-providers.html#id2
async fn mainnet_resolve_name() {
let provider = Provider::<HttpProvider>::try_from(INFURA).unwrap();
let provider = crate::test_provider::MAINNET.provider();

let addr = provider.resolve_name("registrar.firefly.eth").await.unwrap();
assert_eq!(addr, "6fC21092DA55B392b045eD78F4732bff3C580e2c".parse().unwrap());
Expand All @@ -1508,7 +1506,7 @@ mod tests {
#[tokio::test]
// Test vector from: https://docs.ethers.io/ethers.js/v5-beta/api-providers.html#id2
async fn mainnet_lookup_address() {
let provider = Provider::<HttpProvider>::try_from(INFURA).unwrap();
let provider = crate::MAINNET.provider();

let name = provider
.lookup_address("6fC21092DA55B392b045eD78F4732bff3C580e2c".parse().unwrap())
Expand All @@ -1525,7 +1523,7 @@ mod tests {

#[tokio::test]
async fn mainnet_resolve_avatar() {
let provider = Provider::<HttpProvider>::try_from(INFURA).unwrap();
let provider = crate::MAINNET.provider();

for (ens_name, res) in &[
// HTTPS
Expand Down
17 changes: 4 additions & 13 deletions ethers-providers/tests/provider.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![cfg(not(target_arch = "wasm32"))]
use ethers_providers::{Http, Middleware, Provider};
use ethers_providers::{Http, Middleware, Provider, RINKEBY};
use std::{convert::TryFrom, time::Duration};

#[cfg(not(feature = "celo"))]
Expand All @@ -12,10 +12,7 @@ mod eth_tests {

#[tokio::test]
async fn non_existing_data_works() {
let provider = Provider::<Http>::try_from(
"https://rinkeby.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27",
)
.unwrap();
let provider = RINKEBY.provider();

assert!(provider.get_transaction(H256::zero()).await.unwrap().is_none());
assert!(provider.get_transaction_receipt(H256::zero()).await.unwrap().is_none());
Expand All @@ -25,10 +22,7 @@ mod eth_tests {

#[tokio::test]
async fn client_version() {
let provider = Provider::<Http>::try_from(
"https://rinkeby.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27",
)
.unwrap();
let provider = RINKEBY.provider();

// e.g., Geth/v1.10.6-omnibus-1af33248/linux-amd64/go1.16.6
assert!(provider
Expand Down Expand Up @@ -95,10 +89,7 @@ mod eth_tests {

#[tokio::test]
async fn eip1559_fee_estimation() {
let provider = Provider::<Http>::try_from(
"https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27",
)
.unwrap();
let provider = ethers_providers::MAINNET.provider();

let (_max_fee_per_gas, _max_priority_fee_per_gas) =
provider.estimate_eip1559_fees(None).await.unwrap();
Expand Down

0 comments on commit ae125bc

Please sign in to comment.