Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions src/commands/start/eth_acc_funding/eth_acc_funding_step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::key_operations::import_faucet_key;
use super::lotus_checks::{check_lotus_running, get_global_faucet_address};
use crate::commands::init::keys::load_keys;
use crate::commands::start::eth_acc_funding::constants::FEVM_ACCOUNTS_PREFUNDED;
use crate::commands::start::lotus_utils::{get_lotus_rpc_url, wait_for_account_nonce};
use crate::commands::start::step::{SetupContext, Step};
use crate::docker::command_logger::log_command;
use crate::docker::containers::lotus_container_name;
Expand Down Expand Up @@ -266,20 +267,22 @@ impl ETHAccFundingStep {
Ok(())
}

/// Verify account balances in parallel by querying the Lotus node
fn verify_balances_parallel(
/// Verify balances and message pool readiness for each funded account in parallel
fn verify_accounts_parallel(
&self,
accounts: Vec<(String, String, u64)>,
accounts: Vec<(String, String, String, u64)>,
context: &SetupContext,
) -> Result<(), Box<dyn Error>> {
let lotus_rpc_url = get_lotus_rpc_url(context)?;
let run_id = context.run_id();
let container_name = lotus_container_name(run_id);

// Shared error collection
let errors: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));
let mut handles = vec![];

for (account_name, address, expected_amount) in accounts {
for (account_name, address, eth_address, expected_amount) in accounts {
let lotus_rpc_url = lotus_rpc_url.clone();
let container = container_name.clone();
let errors_clone = Arc::clone(&errors);
let context_clone = context.clone();
Expand Down Expand Up @@ -368,7 +371,11 @@ impl ETHAccFundingStep {
&format!("Balance verification for {}", account_name),
);

// Handle retry result
let verify_result = verify_result.and_then(|()| {
wait_for_account_nonce(&eth_address, &lotus_rpc_url, &context_clone)
});

// Handle verification result
if let Err(e) = verify_result {
let error_msg = format!("{}: {}", account_name, e);
tracing::error!(" {}", error_msg);
Expand All @@ -379,18 +386,18 @@ impl ETHAccFundingStep {
handles.push(handle);
}

// Wait for all balance checks to complete
// Wait for all account verification checks to complete
for handle in handles {
handle
.join()
.map_err(|_| "Thread panicked during balance verification")?;
.map_err(|_| "Thread panicked during account verification")?;
}

// Check if any errors occurred
let errors_vec = errors.lock().unwrap();
if !errors_vec.is_empty() {
let combined_error = errors_vec.join("\n");
return Err(format!("Balance verification failed:\n{}", combined_error).into());
return Err(format!("Account verification failed:\n{}", combined_error).into());
}

Ok(())
Expand Down Expand Up @@ -461,12 +468,17 @@ impl Step for ETHAccFundingStep {

info!("{}: {} (ETH: {})", account_name, addr, eth_addr);

accounts_to_verify.push((account_name.to_string(), addr.to_string(), *expected_amount));
accounts_to_verify.push((
account_name.to_string(),
addr.to_string(),
eth_addr.to_string(),
*expected_amount,
));
}

// Verify balances in parallel
info!("Verifying account balances with Lotus node...");
self.verify_balances_parallel(accounts_to_verify, context)?;
// Verify each account balance and message pool readiness in parallel
info!("Verifying account balances and message pool readiness with Lotus node...");
self.verify_accounts_parallel(accounts_to_verify, context)?;

info!("Ethereum account funding verified successfully!");

Expand Down
65 changes: 65 additions & 0 deletions src/commands/start/lotus_utils/account_readiness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! Read-only checks for account readiness in the Lotus message pool.

use super::super::step::SetupContext;
use crate::docker::command_logger::run_and_log_command_strings;
use crate::utils::retry::{retry_with_fixed_delay, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY_SECS};
use std::error::Error;
use tracing::info;

/// Wait until the message pool can resolve an account's nonce.
///
/// A funded balance at the chain head does not mean the message pool has caught up.
/// `--block pending` queries the pool's state view, also used when broadcasting;
/// other block parameters can return zero for a missing actor and hide this race.
/// This checks actor visibility, not every condition for transaction acceptance.
pub fn wait_for_account_nonce(
eth_address: &str,
lotus_rpc_url: &str,
context: &SetupContext,
) -> Result<(), Box<dyn Error>> {
let run_id = context.run_id();
let mut attempt = 0;

retry_with_fixed_delay(
|| {
attempt += 1;
let args: Vec<String> = vec![
"run".to_string(),
"--rm".to_string(),
"--name".to_string(),
format!("foc-{}-nonce-{}-{}", run_id, eth_address, attempt),
"-u".to_string(),
"foc-user".to_string(),
"--network".to_string(),
"host".to_string(),
crate::constants::BUILDER_DOCKER_IMAGE.to_string(),
"bash".to_string(),
"-c".to_string(),
format!(
"cast nonce {} --block pending --rpc-url {}",
eth_address, lotus_rpc_url
),
];

let key = format!("account_nonce_{}_{}_{}", run_id, eth_address, attempt);
let output = run_and_log_command_strings("docker", &args, context, &key)?;

if output.status.success() {
Ok(())
} else {
Err(format!(
"Pending nonce lookup failed for {}: {}",
eth_address,
String::from_utf8_lossy(&output.stderr).trim()
)
.into())
}
},
DEFAULT_MAX_RETRIES,
DEFAULT_RETRY_DELAY_SECS,
&format!("Account nonce lookup for {}", eth_address),
)?;

info!("✓ Message pool resolves the nonce for {}", eth_address);
Ok(())
}
4 changes: 4 additions & 0 deletions src/commands/start/lotus_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
//!
//! This module provides shared utilities for working with Lotus daemon.

mod account_readiness;

pub use account_readiness::wait_for_account_nonce;

use std::error::Error;
use std::fs;

Expand Down
Loading