init node interaction crate

Signed-off-by: xermicus <bigcyrill@hotmail.com>
This commit is contained in:
xermicus
2025-03-20 12:48:04 +01:00
parent 67f068ca12
commit cf83a8e34b
9 changed files with 1715 additions and 41 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ rust-version.workspace = true
[[bin]]
name = "retester"
path = "src/bin/main.rs"
path = "src/main.rs"
[dependencies]
anyhow = { workspace = true }
+1 -5
View File
@@ -8,11 +8,7 @@ repository.workspace = true
rust-version.workspace = true
[dependencies]
alloy-json-abi = { workspace = true }
alloy-genesis = { workspace = true }
alloy-serde = { workspace = true }
alloy-primitives = { workspace = true }
alloy-sol-types = { workspace = true }
alloy = { workspace = true }
anyhow = { workspace = true }
log = { workspace = true }
semver = { workspace = true }
+12 -12
View File
@@ -1,7 +1,17 @@
use alloy_json_abi::Function;
use alloy_primitives::U256;
use alloy::json_abi::Function;
use alloy::primitives::U256;
use serde::{Deserialize, de::Deserializer};
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
pub struct Input {
instance: String,
#[serde(deserialize_with = "deserialize_method")]
method: Method,
#[serde(deserialize_with = "deserialize_calldata")]
calldata: Vec<u8>,
expected: Option<Vec<String>>,
}
/// Specify how the contract is called.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub enum Method {
@@ -20,16 +30,6 @@ pub enum Method {
Function([u8; 4]),
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
pub struct Input {
instance: String,
#[serde(deserialize_with = "deserialize_method")]
method: Method,
#[serde(deserialize_with = "deserialize_calldata")]
calldata: Vec<u8>,
expected: Option<Vec<String>>,
}
fn deserialize_calldata<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "revive-differential-testing-node-interaction"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
rust-version.workspace = true
[dependencies]
alloy = { workspace = true }
anyhow = { workspace = true }
hex = { workspace = true }
log = { workspace = true }
once_cell = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
+45
View File
@@ -0,0 +1,45 @@
//! Implements helpers for node interactions using transactions.
//!
//! The alloy crate is convenient but requires running in a tokio runtime.
//! We contain any async rust right here.
use once_cell::sync::Lazy;
use std::sync::Mutex;
use std::thread;
use tokio::runtime::Runtime;
use tokio::sync::mpsc;
use transaction::Transaction;
pub mod transaction;
pub(crate) static TO_TOKIO: Lazy<Mutex<TokioRuntime>> =
Lazy::new(|| Mutex::new(TokioRuntime::spawn()));
pub struct TokioRuntime {
pub transaction_sender: mpsc::Sender<Transaction>,
}
impl TokioRuntime {
pub fn spawn() -> Self {
let rt = Runtime::new().expect("should be able to create the tokio runtime");
let (transaction_sender, mut transaction_receiver) = mpsc::channel::<Transaction>(1024);
thread::spawn(move || {
rt.block_on(async move {
while let Some(transaction) = transaction_receiver.recv().await {
tokio::task::spawn(async move {
let sender = transaction.receipt_sender.clone();
let result = transaction.execute().await;
if let Err(error) = sender.send(result).await {
log::error!("failed to send transaction receipt: {error}");
}
})
.await
.expect("should alaways be able to spawn the tokio tasks");
}
});
});
Self { transaction_sender }
}
}
@@ -0,0 +1,43 @@
use alloy::providers::{Provider, ProviderBuilder};
use alloy::rpc::types::{TransactionReceipt, TransactionRequest};
use tokio::sync::mpsc;
use crate::TO_TOKIO;
pub struct Transaction {
pub transaction_request: TransactionRequest,
pub receipt_sender: mpsc::Sender<anyhow::Result<TransactionReceipt>>,
pub connection_string: String,
}
impl Transaction {
pub async fn execute(self) -> anyhow::Result<TransactionReceipt> {
let provider = ProviderBuilder::new()
.connect(&self.connection_string)
.await?;
Ok(provider
.send_transaction(self.transaction_request)
.await?
.get_receipt()
.await?)
}
}
pub fn execute_transaction(
transaction_request: TransactionRequest,
connection_string: String,
) -> anyhow::Result<TransactionReceipt> {
let request_sender = TO_TOKIO.lock().unwrap().transaction_sender.clone();
let (receipt_sender, mut receipt_receiver) = mpsc::channel(1);
request_sender.blocking_send(Transaction {
transaction_request,
receipt_sender,
connection_string,
})?;
match receipt_receiver.blocking_recv() {
Some(receipt) => receipt,
None => anyhow::bail!("no receipt received"),
}
}