mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-20 12:41:04 +00:00
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
This commit is contained in:
@@ -84,10 +84,28 @@ where
|
|||||||
task.json_output = Some(output.output.clone());
|
task.json_output = Some(output.output.clone());
|
||||||
task.error = output.error;
|
task.error = output.error;
|
||||||
self.contracts.insert(output.input, output.output);
|
self.contracts.insert(output.input, output.output);
|
||||||
|
|
||||||
|
if let Some(last_output) = self.contracts.values().last() {
|
||||||
|
if let Some(contracts) = &last_output.contracts {
|
||||||
|
for (file, contracts_map) in contracts {
|
||||||
|
for contract_name in contracts_map.keys() {
|
||||||
|
log::debug!(
|
||||||
|
"Compiled contract: {} from file: {}",
|
||||||
|
contract_name,
|
||||||
|
file
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Compiled contracts field is None");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Report::compilation(span, T::config_id(), task);
|
Report::compilation(span, T::config_id(), task);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
log::error!("Failed to compile contract: {:?}", error.to_string());
|
||||||
task.error = Some(error.to_string());
|
task.error = Some(error.to_string());
|
||||||
Err(error)
|
Err(error)
|
||||||
}
|
}
|
||||||
@@ -99,13 +117,40 @@ where
|
|||||||
input: &Input,
|
input: &Input,
|
||||||
node: &T::Blockchain,
|
node: &T::Blockchain,
|
||||||
) -> anyhow::Result<(GethTrace, DiffMode)> {
|
) -> anyhow::Result<(GethTrace, DiffMode)> {
|
||||||
let receipt = node.execute_transaction(input.legacy_transaction(
|
log::trace!("Calling execute_input for input: {:?}", input);
|
||||||
self.config.network_id,
|
|
||||||
0,
|
let nonce = node.fetch_add_nonce(input.caller)?;
|
||||||
&self.deployed_contracts,
|
|
||||||
)?)?;
|
log::debug!(
|
||||||
|
"Nonce calculated on the execute contract, calculated nonce {}, for contract {}, having address {} on node: {}",
|
||||||
|
&nonce,
|
||||||
|
&input.instance,
|
||||||
|
&input.caller,
|
||||||
|
std::any::type_name::<T>()
|
||||||
|
);
|
||||||
|
|
||||||
|
let tx =
|
||||||
|
match input.legacy_transaction(self.config.network_id, nonce, &self.deployed_contracts)
|
||||||
|
{
|
||||||
|
Ok(tx) => tx,
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to construct legacy transaction: {:?}", err);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
log::trace!("Executing transaction for input: {:?}", input);
|
||||||
|
|
||||||
|
let receipt = match node.execute_transaction(tx) {
|
||||||
|
Ok(receipt) => receipt,
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to execute transaction: {:?}", err);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
log::trace!("Transaction receipt: {:?}", receipt);
|
log::trace!("Transaction receipt: {:?}", receipt);
|
||||||
|
|
||||||
let trace = node.trace_transaction(receipt.clone())?;
|
let trace = node.trace_transaction(receipt.clone())?;
|
||||||
log::trace!("Trace result: {:?}", trace);
|
log::trace!("Trace result: {:?}", trace);
|
||||||
|
|
||||||
@@ -115,14 +160,28 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> {
|
pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> {
|
||||||
|
log::debug!(
|
||||||
|
"Deploying contracts {}, having address {} on node: {}",
|
||||||
|
&input.instance,
|
||||||
|
&input.caller,
|
||||||
|
std::any::type_name::<T>()
|
||||||
|
);
|
||||||
for output in self.contracts.values() {
|
for output in self.contracts.values() {
|
||||||
let Some(contract_map) = &output.contracts else {
|
let Some(contract_map) = &output.contracts else {
|
||||||
log::debug!("No contracts in output — skipping deployment for this input.");
|
log::debug!(
|
||||||
|
"No contracts in output — skipping deployment for this input {}",
|
||||||
|
&input.instance
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
for contracts in contract_map.values() {
|
for contracts in contract_map.values() {
|
||||||
for (contract_name, contract) in contracts {
|
for (contract_name, contract) in contracts {
|
||||||
|
log::debug!(
|
||||||
|
"Contract name is: {:?} and the input name is: {:?}",
|
||||||
|
&contract_name,
|
||||||
|
&input.instance
|
||||||
|
);
|
||||||
if contract_name != &input.instance {
|
if contract_name != &input.instance {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -134,24 +193,47 @@ where
|
|||||||
.map(|b| b.object.clone());
|
.map(|b| b.object.clone());
|
||||||
|
|
||||||
let Some(code) = bytecode else {
|
let Some(code) = bytecode else {
|
||||||
anyhow::bail!("no bytecode for contract `{}`", contract_name);
|
log::error!("no bytecode for contract {}", contract_name);
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let nonce = node.fetch_add_nonce(input.caller)?;
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"Calculated nonce {}, for contract {}, having address {} on node: {}",
|
||||||
|
&nonce,
|
||||||
|
&input.instance,
|
||||||
|
&input.caller,
|
||||||
|
std::any::type_name::<T>()
|
||||||
|
);
|
||||||
|
|
||||||
let tx = TransactionRequest::default()
|
let tx = TransactionRequest::default()
|
||||||
.with_from(input.caller)
|
.with_from(input.caller)
|
||||||
.with_to(Address::ZERO)
|
.with_to(Address::ZERO)
|
||||||
.with_input(Bytes::from(code.clone()))
|
.with_input(Bytes::from(code.clone()))
|
||||||
.with_gas_price(20_000_000_000)
|
.with_gas_price(5_000_000)
|
||||||
.with_gas_limit(20_000_000_000)
|
.with_gas_limit(5_000_000)
|
||||||
.with_chain_id(self.config.network_id)
|
.with_chain_id(self.config.network_id)
|
||||||
.with_nonce(0);
|
.with_nonce(nonce);
|
||||||
|
|
||||||
|
let receipt = match node.execute_transaction(tx) {
|
||||||
|
Ok(receipt) => receipt,
|
||||||
|
Err(err) => {
|
||||||
|
log::error!(
|
||||||
|
"Failed to execute transaction when deploying the contract: {:?}, {:?}",
|
||||||
|
&contract_name,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let receipt = node.execute_transaction(tx)?;
|
|
||||||
let Some(address) = receipt.contract_address else {
|
let Some(address) = receipt.contract_address else {
|
||||||
anyhow::bail!(
|
log::error!(
|
||||||
"contract `{}` deployment did not return an address",
|
"contract {} deployment did not return an address",
|
||||||
contract_name
|
contract_name
|
||||||
);
|
);
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.deployed_contracts
|
self.deployed_contracts
|
||||||
@@ -161,6 +243,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::debug!("Available contracts: {:?}", self.deployed_contracts.keys());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,9 +311,11 @@ where
|
|||||||
|
|
||||||
for case in &self.metadata.cases {
|
for case in &self.metadata.cases {
|
||||||
for input in &case.inputs {
|
for input in &case.inputs {
|
||||||
|
log::debug!("Starting deploying contract {}", &input.instance);
|
||||||
leader_state.deploy_contracts(input, self.leader_node)?;
|
leader_state.deploy_contracts(input, self.leader_node)?;
|
||||||
follower_state.deploy_contracts(input, self.follower_node)?;
|
follower_state.deploy_contracts(input, self.follower_node)?;
|
||||||
|
|
||||||
|
log::debug!("Starting executing contract {}", &input.instance);
|
||||||
let (_, leader_diff) = leader_state.execute_input(input, self.leader_node)?;
|
let (_, leader_diff) = leader_state.execute_input(input, self.leader_node)?;
|
||||||
let (_, follower_diff) =
|
let (_, follower_diff) =
|
||||||
follower_state.execute_input(input, self.follower_node)?;
|
follower_state.execute_input(input, self.follower_node)?;
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ impl Input {
|
|||||||
.with_to(to)
|
.with_to(to)
|
||||||
.with_nonce(nonce)
|
.with_nonce(nonce)
|
||||||
.with_chain_id(chain_id)
|
.with_chain_id(chain_id)
|
||||||
.with_gas_price(20_000_000_000)
|
.with_gas_price(5_000_000)
|
||||||
.with_gas_limit(20_000_000_000))
|
.with_gas_limit(5_000_000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
//! This crate implements all node interactions.
|
//! This crate implements all node interactions.
|
||||||
|
|
||||||
|
use alloy::primitives::Address;
|
||||||
use alloy::rpc::types::trace::geth::{DiffMode, GethTrace};
|
use alloy::rpc::types::trace::geth::{DiffMode, GethTrace};
|
||||||
use alloy::rpc::types::{TransactionReceipt, TransactionRequest};
|
use alloy::rpc::types::{TransactionReceipt, TransactionRequest};
|
||||||
use tokio_runtime::TO_TOKIO;
|
use tokio_runtime::TO_TOKIO;
|
||||||
|
|
||||||
|
pub mod nonce;
|
||||||
mod tokio_runtime;
|
mod tokio_runtime;
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
@@ -21,4 +23,7 @@ pub trait EthereumNode {
|
|||||||
|
|
||||||
/// Returns the state diff of the transaction hash in the [TransactionReceipt].
|
/// Returns the state diff of the transaction hash in the [TransactionReceipt].
|
||||||
fn state_diff(&self, transaction: TransactionReceipt) -> anyhow::Result<DiffMode>;
|
fn state_diff(&self, transaction: TransactionReceipt) -> anyhow::Result<DiffMode>;
|
||||||
|
|
||||||
|
/// Returns the next available nonce for the given [Address].
|
||||||
|
fn fetch_add_nonce(&self, address: Address) -> anyhow::Result<u64>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use alloy::{
|
||||||
|
primitives::Address,
|
||||||
|
providers::{Provider, ProviderBuilder},
|
||||||
|
};
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
|
use crate::{TO_TOKIO, tokio_runtime::AsyncNodeInteraction};
|
||||||
|
|
||||||
|
pub type Task = Pin<Box<dyn Future<Output = anyhow::Result<u64>> + Send>>;
|
||||||
|
|
||||||
|
pub(crate) struct Nonce {
|
||||||
|
sender: oneshot::Sender<anyhow::Result<u64>>,
|
||||||
|
task: Task,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncNodeInteraction for Nonce {
|
||||||
|
type Output = anyhow::Result<u64>;
|
||||||
|
|
||||||
|
fn split(
|
||||||
|
self,
|
||||||
|
) -> (
|
||||||
|
std::pin::Pin<Box<dyn Future<Output = Self::Output> + Send>>,
|
||||||
|
oneshot::Sender<Self::Output>,
|
||||||
|
) {
|
||||||
|
(self.task, self.sender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is like `trace_transaction`, just for nonces.
|
||||||
|
pub fn fetch_onchain_nonce(
|
||||||
|
connection: String,
|
||||||
|
wallet: alloy::network::EthereumWallet,
|
||||||
|
address: Address,
|
||||||
|
) -> anyhow::Result<u64> {
|
||||||
|
let sender = TO_TOKIO.lock().unwrap().nonce_sender.clone();
|
||||||
|
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let task: Task = Box::pin(async move {
|
||||||
|
let provider = ProviderBuilder::new()
|
||||||
|
.wallet(wallet)
|
||||||
|
.connect(&connection)
|
||||||
|
.await?;
|
||||||
|
let onchain = provider.get_transaction_count(address).await?;
|
||||||
|
Ok(onchain)
|
||||||
|
});
|
||||||
|
|
||||||
|
sender
|
||||||
|
.blocking_send(Nonce { task, sender: tx })
|
||||||
|
.expect("not in async context");
|
||||||
|
|
||||||
|
rx.blocking_recv()
|
||||||
|
.unwrap_or_else(|err| anyhow::bail!("nonce fetch failed: {err}"))
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ use tokio::spawn;
|
|||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use tokio::task::JoinError;
|
use tokio::task::JoinError;
|
||||||
|
|
||||||
|
use crate::nonce::Nonce;
|
||||||
use crate::trace::Trace;
|
use crate::trace::Trace;
|
||||||
use crate::transaction::Transaction;
|
use crate::transaction::Transaction;
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ pub(crate) trait AsyncNodeInteraction: Send + 'static {
|
|||||||
pub(crate) struct TokioRuntime {
|
pub(crate) struct TokioRuntime {
|
||||||
pub(crate) transaction_sender: mpsc::Sender<Transaction>,
|
pub(crate) transaction_sender: mpsc::Sender<Transaction>,
|
||||||
pub(crate) trace_sender: mpsc::Sender<Trace>,
|
pub(crate) trace_sender: mpsc::Sender<Trace>,
|
||||||
|
pub(crate) nonce_sender: mpsc::Sender<Nonce>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokioRuntime {
|
impl TokioRuntime {
|
||||||
@@ -40,11 +42,13 @@ impl TokioRuntime {
|
|||||||
let rt = Runtime::new().expect("should be able to create the tokio runtime");
|
let rt = Runtime::new().expect("should be able to create the tokio runtime");
|
||||||
let (transaction_sender, transaction_receiver) = mpsc::channel::<Transaction>(1024);
|
let (transaction_sender, transaction_receiver) = mpsc::channel::<Transaction>(1024);
|
||||||
let (trace_sender, trace_receiver) = mpsc::channel::<Trace>(1024);
|
let (trace_sender, trace_receiver) = mpsc::channel::<Trace>(1024);
|
||||||
|
let (nonce_sender, nonce_receiver) = mpsc::channel::<Nonce>(1024);
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
rt.block_on(async move {
|
rt.block_on(async move {
|
||||||
let transaction_task = spawn(interaction::<Transaction>(transaction_receiver));
|
let transaction_task = spawn(interaction::<Transaction>(transaction_receiver));
|
||||||
let trace_task = spawn(interaction::<Trace>(trace_receiver));
|
let trace_task = spawn(interaction::<Trace>(trace_receiver));
|
||||||
|
let nonce_task = spawn(interaction::<Nonce>(nonce_receiver));
|
||||||
|
|
||||||
if let Err(error) = transaction_task.await {
|
if let Err(error) = transaction_task.await {
|
||||||
log::error!("tokio transaction task failed: {error}");
|
log::error!("tokio transaction task failed: {error}");
|
||||||
@@ -52,12 +56,16 @@ impl TokioRuntime {
|
|||||||
if let Err(error) = trace_task.await {
|
if let Err(error) = trace_task.await {
|
||||||
log::error!("tokio trace transaction task failed: {error}");
|
log::error!("tokio trace transaction task failed: {error}");
|
||||||
}
|
}
|
||||||
|
if let Err(error) = nonce_task.await {
|
||||||
|
log::error!("tokio nonce task failed: {error}");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
transaction_sender,
|
transaction_sender,
|
||||||
trace_sender,
|
trace_sender,
|
||||||
|
nonce_sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-2
@@ -5,13 +5,17 @@ use std::{
|
|||||||
io::{BufRead, BufReader, Read, Write},
|
io::{BufRead, BufReader, Read, Write},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::{Child, Command, Stdio},
|
process::{Child, Command, Stdio},
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
sync::{
|
||||||
|
Mutex,
|
||||||
|
atomic::{AtomicU32, Ordering},
|
||||||
|
},
|
||||||
thread,
|
thread,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloy::{
|
use alloy::{
|
||||||
network::EthereumWallet,
|
network::EthereumWallet,
|
||||||
|
primitives::{Address, map::HashMap},
|
||||||
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
||||||
rpc::types::{
|
rpc::types::{
|
||||||
TransactionReceipt, TransactionRequest,
|
TransactionReceipt, TransactionRequest,
|
||||||
@@ -20,7 +24,8 @@ use alloy::{
|
|||||||
};
|
};
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_node_interaction::{
|
use revive_dt_node_interaction::{
|
||||||
EthereumNode, trace::trace_transaction, transaction::execute_transaction,
|
EthereumNode, nonce::fetch_onchain_nonce, trace::trace_transaction,
|
||||||
|
transaction::execute_transaction,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
@@ -45,6 +50,7 @@ pub struct Instance {
|
|||||||
network_id: u64,
|
network_id: u64,
|
||||||
start_timeout: u64,
|
start_timeout: u64,
|
||||||
wallet: EthereumWallet,
|
wallet: EthereumWallet,
|
||||||
|
nonces: Mutex<HashMap<Address, u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
@@ -198,6 +204,19 @@ impl EthereumNode for Instance {
|
|||||||
_ => anyhow::bail!("expected a diff mode trace"),
|
_ => anyhow::bail!("expected a diff mode trace"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch_add_nonce(&self, address: Address) -> anyhow::Result<u64> {
|
||||||
|
let connection_string = self.connection_string.clone();
|
||||||
|
let wallet = self.wallet.clone();
|
||||||
|
|
||||||
|
let onchain_nonce = fetch_onchain_nonce(connection_string, wallet, address)?;
|
||||||
|
|
||||||
|
let mut nonces = self.nonces.lock().unwrap();
|
||||||
|
let current = nonces.entry(address).or_insert(onchain_nonce);
|
||||||
|
let value = *current;
|
||||||
|
*current += 1;
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Instance {
|
impl Node for Instance {
|
||||||
@@ -216,6 +235,7 @@ impl Node for Instance {
|
|||||||
network_id: config.network_id,
|
network_id: config.network_id,
|
||||||
start_timeout: config.geth_start_timeout,
|
start_timeout: config.geth_start_timeout,
|
||||||
wallet: config.wallet(),
|
wallet: config.wallet(),
|
||||||
|
nonces: Mutex::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ use std::{
|
|||||||
io::BufRead,
|
io::BufRead,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::{Child, Command, Stdio},
|
process::{Child, Command, Stdio},
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
sync::{
|
||||||
|
Mutex,
|
||||||
|
atomic::{AtomicU32, Ordering},
|
||||||
|
},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloy::{
|
use alloy::{
|
||||||
hex,
|
hex,
|
||||||
network::EthereumWallet,
|
network::EthereumWallet,
|
||||||
|
primitives::{Address, map::HashMap},
|
||||||
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
||||||
rpc::types::{
|
rpc::types::{
|
||||||
TransactionReceipt,
|
TransactionReceipt,
|
||||||
@@ -22,7 +26,8 @@ use sp_runtime::AccountId32;
|
|||||||
|
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_node_interaction::{
|
use revive_dt_node_interaction::{
|
||||||
EthereumNode, trace::trace_transaction, transaction::execute_transaction,
|
EthereumNode, nonce::fetch_onchain_nonce, trace::trace_transaction,
|
||||||
|
transaction::execute_transaction,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
@@ -39,6 +44,7 @@ pub struct KitchensinkNode {
|
|||||||
base_directory: PathBuf,
|
base_directory: PathBuf,
|
||||||
process_substrate: Option<Child>,
|
process_substrate: Option<Child>,
|
||||||
process_proxy: Option<Child>,
|
process_proxy: Option<Child>,
|
||||||
|
nonces: Mutex<HashMap<Address, u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KitchensinkNode {
|
impl KitchensinkNode {
|
||||||
@@ -289,6 +295,19 @@ impl EthereumNode for KitchensinkNode {
|
|||||||
_ => anyhow::bail!("expected a diff mode trace"),
|
_ => anyhow::bail!("expected a diff mode trace"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch_add_nonce(&self, address: Address) -> anyhow::Result<u64> {
|
||||||
|
let url = self.rpc_url.clone();
|
||||||
|
let wallet = self.wallet.clone();
|
||||||
|
|
||||||
|
let onchain_nonce = fetch_onchain_nonce(url, wallet, address)?;
|
||||||
|
|
||||||
|
let mut nonces = self.nonces.lock().unwrap();
|
||||||
|
let current = nonces.entry(address).or_insert(onchain_nonce);
|
||||||
|
let value = *current;
|
||||||
|
*current += 1;
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for KitchensinkNode {
|
impl Node for KitchensinkNode {
|
||||||
@@ -306,6 +325,7 @@ impl Node for KitchensinkNode {
|
|||||||
base_directory,
|
base_directory,
|
||||||
process_substrate: None,
|
process_substrate: None,
|
||||||
process_proxy: None,
|
process_proxy: None,
|
||||||
|
nonces: Mutex::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user