Skip to content

Instantly share code, notes, and snippets.

@flarocca
Last active July 22, 2024 12:55
Show Gist options
  • Save flarocca/6116abe2748157218c72827431906cc4 to your computer and use it in GitHub Desktop.
Save flarocca/6116abe2748157218c72827431906cc4 to your computer and use it in GitHub Desktop.
revm EthersDB failure on single threaded test
#[tokio::test]
async fn demo_test() {
// Problem:
// This test works fine with revm 8.0.0, but at latest version (12.1.0) it fails.
// There is a new at EthersDB::new() that checks that current tokio::runtime is
// not single-threaded (https://github.com/bluealloy/revm/blob/8eaff99234aca42955345e2775ef11e24e2c0339/crates/revm/src/db/ethersdb.rs#L24).
// Context:
// Our main application runs using tokio::main macro, which works pretty well with
// both versions of the library. However, as you can appreciate in the code snippet,
// all our integration tests run using tokio::test.
// These tests are integration tests meant to execute logic as close as possible to
// the real environment, that's why we use EthersDB directly.
// Challenge:
// Even though there is an alternative to create a EthersDB from a tokio::runtime
// (EthersDB::with_runtime(...)), that implies using different building mechanisms
// depending whether it is a test or the real application, which will require quite a
// significant amount of refactoring.
// Additionally, since we also use some Channels to send events between different parts
// of the application, it would also force us to refactor parts of the application not
// strictly related to EthersDB usage just for testing purposes.
// Open questions:
// 1. What is the reason behind the validation to prevent single-threaded scenarios?
// 2. What is the best way to use EthersDB to simulate transactions?
// 3. What is the best way to use EthersDB for integration testing like mine?
let provider = "https://eth-mainnet.g.alchemy.com/v2/{API_KEY}";
let client = Arc::new(Provider::<Http>::try_from(provider).unwrap());
let mut set = JoinSet::new();
// This process simulates how a transaction is executed. For each transaction
// we spawn a new task that executes the transaction against a fresh EthersDB.
for _transaction in 1..4 {
let cloned_client = client.clone();
set.spawn(async move {
// Select a specific block for simulation
let block_id = Some(BlockId::Number(
ethers_core::types::BlockNumber::from_str("latest").unwrap(),
));
let db = EthersDB::new(cloned_client, block_id);
assert!(db.is_some(), "Failed to create EthersDB");
});
}
while let Some(res) = set.join_next().await {
assert!(res.is_ok());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment