run each etherscan test at least 200ms

This commit is contained in:
Alexey Shekhirin 2021-11-25 11:10:41 +03:00
parent 20948d9fe5
commit 7e453722db
No known key found for this signature in database
GPG Key ID: AF9A26AA133B5B98
5 changed files with 132 additions and 79 deletions

View File

@ -22,7 +22,7 @@ serde-aux = { version = "3.0.1", default-features = false }
thiserror = "1.0.29" thiserror = "1.0.29"
[dev-dependencies] [dev-dependencies]
tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.5", features = ["macros", "rt-multi-thread", "time"] }
serial_test = "0.5.1" serial_test = "0.5.1"
[package.metadata.docs.rs] [package.metadata.docs.rs]

View File

@ -1,8 +1,11 @@
use crate::{Client, Response, Result};
use ethers_core::abi::{Abi, Address};
use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use ethers_core::abi::{Abi, Address};
use crate::{Client, Response, Result};
/// Arguments for verifying contracts /// Arguments for verifying contracts
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct VerifyContract { pub struct VerifyContract {
@ -251,55 +254,66 @@ impl Client {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{contract::VerifyContract, Client}; use std::time::Duration;
use ethers_core::types::Chain;
use serial_test::serial; use serial_test::serial;
use ethers_core::types::Chain;
use crate::{contract::VerifyContract, tests::run_at_least_duration, Client};
#[tokio::test] #[tokio::test]
#[serial] #[serial]
#[ignore] #[ignore]
async fn can_fetch_contract_abi() { async fn can_fetch_contract_abi() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let _abi = client let _abi = client
.contract_abi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap()) .contract_abi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap())
.await .await
.unwrap(); .unwrap();
})
.await;
} }
#[tokio::test] #[tokio::test]
#[serial] #[serial]
#[ignore] #[ignore]
async fn can_fetch_contract_source_code() { async fn can_fetch_contract_source_code() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let _meta = client let _meta = client
.contract_source_code("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap()) .contract_source_code("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap())
.await .await
.unwrap(); .unwrap();
})
.await
} }
#[tokio::test] #[tokio::test]
#[serial] #[serial]
#[ignore] #[ignore]
async fn can_verify_contract() { async fn can_verify_contract() {
// TODO this needs further investigation run_at_least_duration(Duration::from_millis(200), async {
// TODO this needs further investigation
// https://etherscan.io/address/0x9e744c9115b74834c0f33f4097f40c02a9ac5c33#code // https://etherscan.io/address/0x9e744c9115b74834c0f33f4097f40c02a9ac5c33#code
let contract = include_str!("../resources/UniswapExchange.sol"); let contract = include_str!("../resources/UniswapExchange.sol");
let address = "0x9e744c9115b74834c0f33f4097f40c02a9ac5c33".parse().unwrap(); let address = "0x9e744c9115b74834c0f33f4097f40c02a9ac5c33".parse().unwrap();
let compiler_version = "v0.5.17+commit.d19bba13"; let compiler_version = "v0.5.17+commit.d19bba13";
let constructor_args = "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000007596179537761700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035941590000000000000000000000000000000000000000000000000000000000"; let constructor_args = "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000007596179537761700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035941590000000000000000000000000000000000000000000000000000000000";
let client = Client::new_from_env(Chain::Mainnet).unwrap(); let client = Client::new_from_env(Chain::Mainnet).unwrap();
let contract = let contract =
VerifyContract::new(address, contract.to_string(), compiler_version.to_string()) VerifyContract::new(address, contract.to_string(), compiler_version.to_string())
.constructor_arguments(Some(constructor_args)) .constructor_arguments(Some(constructor_args))
.optimization(true) .optimization(true)
.runs(200); .runs(200);
let _resp = client.submit_contract_verification(&contract).await; let _resp = client.submit_contract_verification(&contract).await;
}).await
} }
} }

View File

@ -70,48 +70,61 @@ impl Client {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::time::Duration;
use serial_test::serial; use serial_test::serial;
use ethers_core::types::Chain; use ethers_core::types::Chain;
use crate::tests::run_at_least_duration;
use super::*; use super::*;
#[tokio::test] #[tokio::test]
#[serial] #[serial]
async fn gas_estimate_success() { async fn gas_estimate_success() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let result = client.gas_estimate(2000000000u32.into()).await; let result = client.gas_estimate(2000000000u32.into()).await;
assert!(result.is_ok()); assert!(result.is_ok());
})
.await
} }
#[tokio::test] #[tokio::test]
#[serial] #[serial]
async fn gas_estimate_error() { async fn gas_estimate_error() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let err = client.gas_estimate(7123189371829732819379218u128.into()).await.unwrap_err(); let err = client.gas_estimate(7123189371829732819379218u128.into()).await.unwrap_err();
assert!(matches!(err, EtherscanError::GasEstimationFailed)); assert!(matches!(err, EtherscanError::GasEstimationFailed));
})
.await
} }
#[tokio::test] #[tokio::test]
#[serial] #[serial]
async fn gas_oracle_success() { async fn gas_oracle_success() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let result = client.gas_oracle().await; let result = client.gas_oracle().await;
assert!(result.is_ok()); assert!(result.is_ok());
let oracle = result.unwrap(); let oracle = result.unwrap();
assert!(oracle.safe_gas_price > 0); assert!(oracle.safe_gas_price > 0);
assert!(oracle.propose_gas_price > 0); assert!(oracle.propose_gas_price > 0);
assert!(oracle.fast_gas_price > 0); assert!(oracle.fast_gas_price > 0);
assert!(oracle.last_block > 0); assert!(oracle.last_block > 0);
assert!(oracle.suggested_base_fee > 0.0); assert!(oracle.suggested_base_fee > 0.0);
assert!(oracle.gas_used_ratio.len() > 0); assert!(oracle.gas_used_ratio.len() > 0);
})
.await
} }
} }

View File

@ -78,8 +78,7 @@ impl Client {
Chain::Mainnet | Chain::Ropsten | Chain::Kovan | Chain::Rinkeby | Chain::Goerli => { Chain::Mainnet | Chain::Ropsten | Chain::Kovan | Chain::Rinkeby | Chain::Goerli => {
std::env::var("ETHERSCAN_API_KEY")? std::env::var("ETHERSCAN_API_KEY")?
} }
Chain::XDai => String::default(), _ => String::default(),
chain => return Err(EtherscanError::ChainNotSupported(chain)),
}; };
Self::new(chain, api_key) Self::new(chain, api_key)
} }
@ -176,6 +175,11 @@ struct Query<'a, T: Serialize> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{
future::Future,
time::{Duration, SystemTime},
};
use ethers_core::types::Chain; use ethers_core::types::Chain;
use crate::{Client, EtherscanError}; use crate::{Client, EtherscanError};
@ -187,4 +191,12 @@ mod tests {
assert!(matches!(err, EtherscanError::ChainNotSupported(_))); assert!(matches!(err, EtherscanError::ChainNotSupported(_)));
assert_eq!(err.to_string(), "chain XDai not supported"); assert_eq!(err.to_string(), "chain XDai not supported");
} }
pub async fn run_at_least_duration(duration: Duration, block: impl Future) {
let start = SystemTime::now();
block.await;
if let Some(sleep) = duration.checked_sub(start.elapsed().unwrap()) {
tokio::time::sleep(sleep).await;
}
}
} }

View File

@ -52,68 +52,82 @@ impl Client {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::time::Duration;
use serial_test::serial; use serial_test::serial;
use crate::Chain; use crate::{tests::run_at_least_duration, Chain};
use super::*; use super::*;
#[tokio::test] #[tokio::test]
#[serial] #[serial]
async fn check_contract_execution_status_success() { async fn check_contract_execution_status_success() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let status = client let status = client
.check_contract_execution_status( .check_contract_execution_status(
"0x16197e2a0eacc44c1ebdfddcfcfcafb3538de557c759a66e0ba95263b23d9007", "0x16197e2a0eacc44c1ebdfddcfcfcafb3538de557c759a66e0ba95263b23d9007",
) )
.await; .await;
assert!(status.is_ok()); assert!(status.is_ok());
})
.await
} }
#[tokio::test] #[tokio::test]
#[serial] #[serial]
async fn check_contract_execution_status_error() { async fn check_contract_execution_status_error() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let err = client let err = client
.check_contract_execution_status( .check_contract_execution_status(
"0x15f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a", "0x15f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a",
) )
.await .await
.unwrap_err(); .unwrap_err();
assert!(matches!(err, EtherscanError::ExecutionFailed(_))); assert!(matches!(err, EtherscanError::ExecutionFailed(_)));
assert_eq!(err.to_string(), "contract execution call failed: Bad jump destination"); assert_eq!(err.to_string(), "contract execution call failed: Bad jump destination");
})
.await
} }
#[tokio::test] #[tokio::test]
#[serial] #[serial]
async fn check_transaction_receipt_status_success() { async fn check_transaction_receipt_status_success() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let success = client let success = client
.check_transaction_receipt_status( .check_transaction_receipt_status(
"0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76", "0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76",
) )
.await; .await;
assert!(success.is_ok()); assert!(success.is_ok());
})
.await
} }
#[tokio::test] #[tokio::test]
#[serial] #[serial]
async fn check_transaction_receipt_status_failed() { async fn check_transaction_receipt_status_failed() {
let client = Client::new_from_env(Chain::Mainnet).unwrap(); run_at_least_duration(Duration::from_millis(200), async {
let client = Client::new_from_env(Chain::Mainnet).unwrap();
let err = client let err = client
.check_transaction_receipt_status( .check_transaction_receipt_status(
"0x21a29a497cb5d4bf514c0cca8d9235844bd0215c8fab8607217546a892fd0758", "0x21a29a497cb5d4bf514c0cca8d9235844bd0215c8fab8607217546a892fd0758",
) )
.await .await
.unwrap_err(); .unwrap_err();
assert!(matches!(err, EtherscanError::TransactionReceiptFailed)); assert!(matches!(err, EtherscanError::TransactionReceiptFailed));
})
.await
} }
} }