Skip to content

Commit ee97b62

Browse files
Added fetch_add_nonce method for NodeInteraction trait. Added extra logging. (#25)
* added logging * added fetch_add_nonce method * Added nonce for legacy transaction also * Addressed PR comments
1 parent e9b5a06 commit ee97b62

File tree

7 files changed

+213
-19
lines changed

7 files changed

+213
-19
lines changed

crates/core/src/driver/mod.rs

Lines changed: 99 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,28 @@ where
8484
task.json_output = Some(output.output.clone());
8585
task.error = output.error;
8686
self.contracts.insert(output.input, output.output);
87+
88+
if let Some(last_output) = self.contracts.values().last() {
89+
if let Some(contracts) = &last_output.contracts {
90+
for (file, contracts_map) in contracts {
91+
for contract_name in contracts_map.keys() {
92+
log::debug!(
93+
"Compiled contract: {} from file: {}",
94+
contract_name,
95+
file
96+
);
97+
}
98+
}
99+
} else {
100+
log::warn!("Compiled contracts field is None");
101+
}
102+
}
103+
87104
Report::compilation(span, T::config_id(), task);
88105
Ok(())
89106
}
90107
Err(error) => {
108+
log::error!("Failed to compile contract: {:?}", error.to_string());
91109
task.error = Some(error.to_string());
92110
Err(error)
93111
}
@@ -99,13 +117,40 @@ where
99117
input: &Input,
100118
node: &T::Blockchain,
101119
) -> anyhow::Result<(GethTrace, DiffMode)> {
102-
let receipt = node.execute_transaction(input.legacy_transaction(
103-
self.config.network_id,
104-
0,
105-
&self.deployed_contracts,
106-
)?)?;
120+
log::trace!("Calling execute_input for input: {:?}", input);
121+
122+
let nonce = node.fetch_add_nonce(input.caller)?;
123+
124+
log::debug!(
125+
"Nonce calculated on the execute contract, calculated nonce {}, for contract {}, having address {} on node: {}",
126+
&nonce,
127+
&input.instance,
128+
&input.caller,
129+
std::any::type_name::<T>()
130+
);
131+
132+
let tx =
133+
match input.legacy_transaction(self.config.network_id, nonce, &self.deployed_contracts)
134+
{
135+
Ok(tx) => tx,
136+
Err(err) => {
137+
log::error!("Failed to construct legacy transaction: {:?}", err);
138+
return Err(err);
139+
}
140+
};
141+
142+
log::trace!("Executing transaction for input: {:?}", input);
143+
144+
let receipt = match node.execute_transaction(tx) {
145+
Ok(receipt) => receipt,
146+
Err(err) => {
147+
log::error!("Failed to execute transaction: {:?}", err);
148+
return Err(err);
149+
}
150+
};
107151

108152
log::trace!("Transaction receipt: {:?}", receipt);
153+
109154
let trace = node.trace_transaction(receipt.clone())?;
110155
log::trace!("Trace result: {:?}", trace);
111156

@@ -115,14 +160,28 @@ where
115160
}
116161

117162
pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> {
163+
log::debug!(
164+
"Deploying contracts {}, having address {} on node: {}",
165+
&input.instance,
166+
&input.caller,
167+
std::any::type_name::<T>()
168+
);
118169
for output in self.contracts.values() {
119170
let Some(contract_map) = &output.contracts else {
120-
log::debug!("No contracts in output — skipping deployment for this input.");
171+
log::debug!(
172+
"No contracts in output — skipping deployment for this input {}",
173+
&input.instance
174+
);
121175
continue;
122176
};
123177

124178
for contracts in contract_map.values() {
125179
for (contract_name, contract) in contracts {
180+
log::debug!(
181+
"Contract name is: {:?} and the input name is: {:?}",
182+
&contract_name,
183+
&input.instance
184+
);
126185
if contract_name != &input.instance {
127186
continue;
128187
}
@@ -134,24 +193,47 @@ where
134193
.map(|b| b.object.clone());
135194

136195
let Some(code) = bytecode else {
137-
anyhow::bail!("no bytecode for contract `{}`", contract_name);
196+
log::error!("no bytecode for contract {}", contract_name);
197+
continue;
138198
};
139199

200+
let nonce = node.fetch_add_nonce(input.caller)?;
201+
202+
log::debug!(
203+
"Calculated nonce {}, for contract {}, having address {} on node: {}",
204+
&nonce,
205+
&input.instance,
206+
&input.caller,
207+
std::any::type_name::<T>()
208+
);
209+
140210
let tx = TransactionRequest::default()
141211
.with_from(input.caller)
142212
.with_to(Address::ZERO)
143213
.with_input(Bytes::from(code.clone()))
144-
.with_gas_price(20_000_000_000)
145-
.with_gas_limit(20_000_000_000)
214+
.with_gas_price(5_000_000)
215+
.with_gas_limit(5_000_000)
146216
.with_chain_id(self.config.network_id)
147-
.with_nonce(0);
217+
.with_nonce(nonce);
218+
219+
let receipt = match node.execute_transaction(tx) {
220+
Ok(receipt) => receipt,
221+
Err(err) => {
222+
log::error!(
223+
"Failed to execute transaction when deploying the contract: {:?}, {:?}",
224+
&contract_name,
225+
err
226+
);
227+
return Err(err);
228+
}
229+
};
148230

149-
let receipt = node.execute_transaction(tx)?;
150231
let Some(address) = receipt.contract_address else {
151-
anyhow::bail!(
152-
"contract `{}` deployment did not return an address",
232+
log::error!(
233+
"contract {} deployment did not return an address",
153234
contract_name
154235
);
236+
continue;
155237
};
156238

157239
self.deployed_contracts
@@ -161,6 +243,8 @@ where
161243
}
162244
}
163245

246+
log::debug!("Available contracts: {:?}", self.deployed_contracts.keys());
247+
164248
Ok(())
165249
}
166250
}
@@ -227,9 +311,11 @@ where
227311

228312
for case in &self.metadata.cases {
229313
for input in &case.inputs {
314+
log::debug!("Starting deploying contract {}", &input.instance);
230315
leader_state.deploy_contracts(input, self.leader_node)?;
231316
follower_state.deploy_contracts(input, self.follower_node)?;
232317

318+
log::debug!("Starting executing contract {}", &input.instance);
233319
let (_, leader_diff) = leader_state.execute_input(input, self.leader_node)?;
234320
let (_, follower_diff) =
235321
follower_state.execute_input(input, self.follower_node)?;

crates/format/src/input.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ impl Input {
118118
.with_to(to)
119119
.with_nonce(nonce)
120120
.with_chain_id(chain_id)
121-
.with_gas_price(20_000_000_000)
122-
.with_gas_limit(20_000_000_000))
121+
.with_gas_price(5_000_000)
122+
.with_gas_limit(5_000_000))
123123
}
124124
}
125125

crates/node-interaction/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//! This crate implements all node interactions.
22
3+
use alloy::primitives::Address;
34
use alloy::rpc::types::trace::geth::{DiffMode, GethTrace};
45
use alloy::rpc::types::{TransactionReceipt, TransactionRequest};
56
use tokio_runtime::TO_TOKIO;
67

8+
pub mod nonce;
79
mod tokio_runtime;
810
pub mod trace;
911
pub mod transaction;
@@ -21,4 +23,7 @@ pub trait EthereumNode {
2123

2224
/// Returns the state diff of the transaction hash in the [TransactionReceipt].
2325
fn state_diff(&self, transaction: TransactionReceipt) -> anyhow::Result<DiffMode>;
26+
27+
/// Returns the next available nonce for the given [Address].
28+
fn fetch_add_nonce(&self, address: Address) -> anyhow::Result<u64>;
2429
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use std::pin::Pin;
2+
3+
use alloy::{
4+
primitives::Address,
5+
providers::{Provider, ProviderBuilder},
6+
};
7+
use tokio::sync::oneshot;
8+
9+
use crate::{TO_TOKIO, tokio_runtime::AsyncNodeInteraction};
10+
11+
pub type Task = Pin<Box<dyn Future<Output = anyhow::Result<u64>> + Send>>;
12+
13+
pub(crate) struct Nonce {
14+
sender: oneshot::Sender<anyhow::Result<u64>>,
15+
task: Task,
16+
}
17+
18+
impl AsyncNodeInteraction for Nonce {
19+
type Output = anyhow::Result<u64>;
20+
21+
fn split(
22+
self,
23+
) -> (
24+
std::pin::Pin<Box<dyn Future<Output = Self::Output> + Send>>,
25+
oneshot::Sender<Self::Output>,
26+
) {
27+
(self.task, self.sender)
28+
}
29+
}
30+
31+
/// This is like `trace_transaction`, just for nonces.
32+
pub fn fetch_onchain_nonce(
33+
connection: String,
34+
wallet: alloy::network::EthereumWallet,
35+
address: Address,
36+
) -> anyhow::Result<u64> {
37+
let sender = TO_TOKIO.lock().unwrap().nonce_sender.clone();
38+
39+
let (tx, rx) = oneshot::channel();
40+
let task: Task = Box::pin(async move {
41+
let provider = ProviderBuilder::new()
42+
.wallet(wallet)
43+
.connect(&connection)
44+
.await?;
45+
let onchain = provider.get_transaction_count(address).await?;
46+
Ok(onchain)
47+
});
48+
49+
sender
50+
.blocking_send(Nonce { task, sender: tx })
51+
.expect("not in async context");
52+
53+
rx.blocking_recv()
54+
.unwrap_or_else(|err| anyhow::bail!("nonce fetch failed: {err}"))
55+
}

crates/node-interaction/src/tokio_runtime.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use tokio::spawn;
1010
use tokio::sync::{mpsc, oneshot};
1111
use tokio::task::JoinError;
1212

13+
use crate::nonce::Nonce;
1314
use crate::trace::Trace;
1415
use crate::transaction::Transaction;
1516

@@ -33,31 +34,38 @@ pub(crate) trait AsyncNodeInteraction: Send + 'static {
3334
pub(crate) struct TokioRuntime {
3435
pub(crate) transaction_sender: mpsc::Sender<Transaction>,
3536
pub(crate) trace_sender: mpsc::Sender<Trace>,
37+
pub(crate) nonce_sender: mpsc::Sender<Nonce>,
3638
}
3739

3840
impl TokioRuntime {
3941
fn spawn() -> Self {
4042
let rt = Runtime::new().expect("should be able to create the tokio runtime");
4143
let (transaction_sender, transaction_receiver) = mpsc::channel::<Transaction>(1024);
4244
let (trace_sender, trace_receiver) = mpsc::channel::<Trace>(1024);
45+
let (nonce_sender, nonce_receiver) = mpsc::channel::<Nonce>(1024);
4346

4447
thread::spawn(move || {
4548
rt.block_on(async move {
4649
let transaction_task = spawn(interaction::<Transaction>(transaction_receiver));
4750
let trace_task = spawn(interaction::<Trace>(trace_receiver));
51+
let nonce_task = spawn(interaction::<Nonce>(nonce_receiver));
4852

4953
if let Err(error) = transaction_task.await {
5054
log::error!("tokio transaction task failed: {error}");
5155
}
5256
if let Err(error) = trace_task.await {
5357
log::error!("tokio trace transaction task failed: {error}");
5458
}
59+
if let Err(error) = nonce_task.await {
60+
log::error!("tokio nonce task failed: {error}");
61+
}
5562
});
5663
});
5764

5865
Self {
5966
transaction_sender,
6067
trace_sender,
68+
nonce_sender,
6169
}
6270
}
6371
}

crates/node/src/geth.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ use std::{
55
io::{BufRead, BufReader, Read, Write},
66
path::PathBuf,
77
process::{Child, Command, Stdio},
8-
sync::atomic::{AtomicU32, Ordering},
8+
sync::{
9+
Mutex,
10+
atomic::{AtomicU32, Ordering},
11+
},
912
thread,
1013
time::{Duration, Instant},
1114
};
1215

1316
use alloy::{
1417
network::EthereumWallet,
18+
primitives::{Address, map::HashMap},
1519
providers::{Provider, ProviderBuilder, ext::DebugApi},
1620
rpc::types::{
1721
TransactionReceipt, TransactionRequest,
@@ -20,7 +24,8 @@ use alloy::{
2024
};
2125
use revive_dt_config::Arguments;
2226
use revive_dt_node_interaction::{
23-
EthereumNode, trace::trace_transaction, transaction::execute_transaction,
27+
EthereumNode, nonce::fetch_onchain_nonce, trace::trace_transaction,
28+
transaction::execute_transaction,
2429
};
2530

2631
use crate::Node;
@@ -45,6 +50,7 @@ pub struct Instance {
4550
network_id: u64,
4651
start_timeout: u64,
4752
wallet: EthereumWallet,
53+
nonces: Mutex<HashMap<Address, u64>>,
4854
}
4955

5056
impl Instance {
@@ -198,6 +204,19 @@ impl EthereumNode for Instance {
198204
_ => anyhow::bail!("expected a diff mode trace"),
199205
}
200206
}
207+
208+
fn fetch_add_nonce(&self, address: Address) -> anyhow::Result<u64> {
209+
let connection_string = self.connection_string.clone();
210+
let wallet = self.wallet.clone();
211+
212+
let onchain_nonce = fetch_onchain_nonce(connection_string, wallet, address)?;
213+
214+
let mut nonces = self.nonces.lock().unwrap();
215+
let current = nonces.entry(address).or_insert(onchain_nonce);
216+
let value = *current;
217+
*current += 1;
218+
Ok(value)
219+
}
201220
}
202221

203222
impl Node for Instance {
@@ -216,6 +235,7 @@ impl Node for Instance {
216235
network_id: config.network_id,
217236
start_timeout: config.geth_start_timeout,
218237
wallet: config.wallet(),
238+
nonces: Mutex::new(HashMap::new()),
219239
}
220240
}
221241

0 commit comments

Comments
 (0)