diff --git a/src/benchmark_private/tipset_validation.rs b/src/benchmark_private/tipset_validation.rs index e1957393bad0..1fa208a495f9 100644 --- a/src/benchmark_private/tipset_validation.rs +++ b/src/benchmark_private/tipset_validation.rs @@ -2,76 +2,13 @@ // SPDX-License-Identifier: Apache-2.0, MIT use crate::{ - blocks::Tipset, - chain::store::ChainStore, - db::{ - MemoryDB, - car::{AnyCar, ManyCar}, + networks::NetworkChain, + state_manager::utils::state_compute::{ + get_state_compute_snapshot, prepare_state_compute, state_compute, }, - genesis::read_genesis_header, - interpreter::VMTrace, - networks::{ChainConfig, NetworkChain}, - state_manager::StateManager, - utils::net::{DownloadFileOption, download_file_with_cache}, }; use criterion::Criterion; -use directories::ProjectDirs; -use std::{ - hint::black_box, - path::{Path, PathBuf}, - sync::{Arc, LazyLock}, -}; -use url::Url; - -pub static CACHE_DIR: LazyLock = LazyLock::new(|| { - let project_dir = ProjectDirs::from("com", "ChainSafe", "Forest"); - project_dir - .map(|d| d.cache_dir().to_path_buf()) - .unwrap_or_else(std::env::temp_dir) - .join("state_compute_snapshots") -}); - -async fn get_snapshot(chain: &NetworkChain, epoch: i64) -> anyhow::Result { - let url = Url::parse(&format!( - "https://forest-snapshots.fra1.cdn.digitaloceanspaces.com/state_compute/{chain}_{epoch}.forest.car.zst" - ))?; - Ok( - download_file_with_cache(&url, &CACHE_DIR, DownloadFileOption::NonResumable) - .await? - .path, - ) -} - -async fn prepare_validation( - chain: &NetworkChain, - snapshot: &Path, -) -> anyhow::Result<(Arc>, Tipset)> { - let snap_car = AnyCar::try_from(snapshot)?; - let ts = snap_car.heaviest_tipset()?; - let db = Arc::new(ManyCar::new(MemoryDB::default()).with_read_only(snap_car)?); - let chain_config = Arc::new(ChainConfig::from_chain(chain)); - let genesis_header = - read_genesis_header(None, chain_config.genesis_bytes(&db).await?.as_deref(), &db).await?; - let chain_store = Arc::new(ChainStore::new( - db.clone(), - db.clone(), - db.clone(), - db.clone(), - chain_config, - genesis_header, - )?); - let state_manager = Arc::new(StateManager::new(chain_store.clone())?); - // warmup - validate(state_manager.clone(), ts.clone()).await; - Ok((state_manager, ts)) -} - -async fn validate(state_manager: Arc>, ts: Tipset) { - state_manager - .compute_tipset_state(ts, crate::state_manager::NO_CALLBACK, VMTrace::NotTraced) - .await - .unwrap(); -} +use std::hint::black_box; pub fn bench_tipset_validation(c: &mut Criterion) { let rt = tokio::runtime::Builder::new_multi_thread() @@ -87,24 +24,24 @@ pub fn bench_tipset_validation(c: &mut Criterion) { let epoch = 3111900; let (state_manager, ts) = rt .block_on(async { - let snapshot = get_snapshot(&chain, epoch).await?; - prepare_validation(&chain, &snapshot).await + let snapshot = get_state_compute_snapshot(&chain, epoch).await?; + prepare_state_compute(&chain, &snapshot, true).await }) .unwrap(); b.to_async(&rt) - .iter(|| validate(black_box(state_manager.clone()), black_box(ts.clone()))) + .iter(|| state_compute(black_box(state_manager.clone()), black_box(ts.clone()))) }) .bench_function("mainnet@5427431", |b| { let chain = NetworkChain::Mainnet; let epoch = 5427431; let (state_manager, ts) = rt .block_on(async { - let snapshot = get_snapshot(&chain, epoch).await?; - prepare_validation(&chain, &snapshot).await + let snapshot = get_state_compute_snapshot(&chain, epoch).await?; + prepare_state_compute(&chain, &snapshot, true).await }) .unwrap(); b.to_async(&rt) - .iter(|| validate(black_box(state_manager.clone()), black_box(ts.clone()))) + .iter(|| state_compute(black_box(state_manager.clone()), black_box(ts.clone()))) }); group.finish(); diff --git a/src/chain_sync/tipset_syncer.rs b/src/chain_sync/tipset_syncer.rs index 162d8b5376d6..ff7208ddc708 100644 --- a/src/chain_sync/tipset_syncer.rs +++ b/src/chain_sync/tipset_syncer.rs @@ -11,7 +11,7 @@ use crate::shim::{ address::Address, crypto::verify_bls_aggregate, econ::BLOCK_GAS_LIMIT, gas::price_list_by_network_version, message::Message, state_tree::StateTree, }; -use crate::state_manager::{Error as StateManagerError, StateManager, is_valid_for_sending}; +use crate::state_manager::{Error as StateManagerError, StateManager, utils::is_valid_for_sending}; use crate::{ blocks::{Block, CachingBlockHeader, Error as ForestBlockError, FullTipset, Tipset}, fil_cns::{self, FilecoinConsensus, FilecoinConsensusError}, diff --git a/src/message_pool/msgpool/msg_pool.rs b/src/message_pool/msgpool/msg_pool.rs index c2fdc0987bb7..6b6a497ba66f 100644 --- a/src/message_pool/msgpool/msg_pool.rs +++ b/src/message_pool/msgpool/msg_pool.rs @@ -22,7 +22,7 @@ use crate::shim::{ econ::TokenAmount, gas::{Gas, price_list_by_network_version}, }; -use crate::state_manager::is_valid_for_sending; +use crate::state_manager::utils::is_valid_for_sending; use crate::utils::cache::SizeTrackingLruCache; use crate::utils::get_size::CidWrapper; use ahash::{HashMap, HashMapExt, HashSet, HashSetExt}; diff --git a/src/state_manager/mod.rs b/src/state_manager/mod.rs index d61bdefc237a..0cb6230f7c30 100644 --- a/src/state_manager/mod.rs +++ b/src/state_manager/mod.rs @@ -88,7 +88,6 @@ use std::time::Duration; use std::{num::NonZeroUsize, sync::Arc}; use tokio::sync::{RwLock, broadcast::error::RecvError}; use tracing::{error, info, instrument, trace, warn}; -pub use utils::is_valid_for_sending; const DEFAULT_TIPSET_CACHE_SIZE: NonZeroUsize = nonzero!(1024usize); diff --git a/src/state_manager/utils.rs b/src/state_manager/utils.rs index ea0681e5164b..9d5f50e619ff 100644 --- a/src/state_manager/utils.rs +++ b/src/state_manager/utils.rs @@ -1,6 +1,7 @@ // Copyright 2019-2025 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT +use super::MinerActorStateLoad as _; use crate::shim::actors::miner; use crate::shim::{ actors::{is_account_actor, is_ethaccount_actor, is_placeholder_actor}, @@ -10,6 +11,7 @@ use crate::shim::{ state_tree::ActorState, version::NetworkVersion, }; +use crate::state_manager::{StateManager, errors::*}; use crate::utils::encoding::prover_id_from_u64; use cid::Cid; use fil_actors_shared::filecoin_proofs_api::post; @@ -17,10 +19,6 @@ use fil_actors_shared::fvm_ipld_bitfield::BitField; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::bytes_32; -use crate::state_manager::{StateManager, errors::*}; - -use super::MinerActorStateLoad as _; - impl StateManager where DB: Blockstore, @@ -180,6 +178,110 @@ fn generate_winning_post_sector_challenge( ) } +#[cfg(any(test, feature = "benchmark-private"))] +pub mod state_compute { + use crate::{ + blocks::Tipset, + chain::store::ChainStore, + db::{ + MemoryDB, + car::{AnyCar, ManyCar}, + }, + genesis::read_genesis_header, + interpreter::VMTrace, + networks::{ChainConfig, NetworkChain}, + state_manager::StateManager, + utils::net::{DownloadFileOption, download_file_with_cache}, + }; + use directories::ProjectDirs; + use std::{ + path::{Path, PathBuf}, + sync::{Arc, LazyLock}, + }; + use url::Url; + + static SNAPSHOT_CACHE_DIR: LazyLock = LazyLock::new(|| { + let project_dir = ProjectDirs::from("com", "ChainSafe", "Forest"); + project_dir + .map(|d| d.cache_dir().to_path_buf()) + .unwrap_or_else(std::env::temp_dir) + .join("state_compute_snapshots") + }); + + pub async fn get_state_compute_snapshot( + chain: &NetworkChain, + epoch: i64, + ) -> anyhow::Result { + let url = Url::parse(&format!( + "https://forest-snapshots.fra1.cdn.digitaloceanspaces.com/state_compute/{chain}_{epoch}.forest.car.zst" + ))?; + Ok( + download_file_with_cache(&url, &SNAPSHOT_CACHE_DIR, DownloadFileOption::NonResumable) + .await? + .path, + ) + } + + pub async fn prepare_state_compute( + chain: &NetworkChain, + snapshot: &Path, + warmup: bool, + ) -> anyhow::Result<(Arc>, Tipset)> { + let snap_car = AnyCar::try_from(snapshot)?; + let ts = snap_car.heaviest_tipset()?; + let db = Arc::new(ManyCar::new(MemoryDB::default()).with_read_only(snap_car)?); + let chain_config = Arc::new(ChainConfig::from_chain(chain)); + let genesis_header = + read_genesis_header(None, chain_config.genesis_bytes(&db).await?.as_deref(), &db) + .await?; + let chain_store = Arc::new(ChainStore::new( + db.clone(), + db.clone(), + db.clone(), + db.clone(), + chain_config, + genesis_header, + )?); + let state_manager = Arc::new(StateManager::new(chain_store.clone())?); + if warmup { + state_compute(state_manager.clone(), ts.clone()).await; + } + Ok((state_manager, ts)) + } + + pub async fn state_compute(state_manager: Arc>, ts: Tipset) { + state_manager + .compute_tipset_state(ts, crate::state_manager::NO_CALLBACK, VMTrace::NotTraced) + .await + .unwrap(); + } + + #[cfg(test)] + mod tests { + use super::*; + + #[tokio::test(flavor = "multi_thread")] + async fn state_compute_calibnet() { + let chain = NetworkChain::Calibnet; + let snapshot = get_state_compute_snapshot(&chain, 3111900).await.unwrap(); + let (sm, ts) = prepare_state_compute(&chain, &snapshot, false) + .await + .unwrap(); + state_compute(sm, ts).await; + } + + #[tokio::test(flavor = "multi_thread")] + async fn state_compute_mainnet() { + let chain = NetworkChain::Mainnet; + let snapshot = get_state_compute_snapshot(&chain, 5427431).await.unwrap(); + let (sm, ts) = prepare_state_compute(&chain, &snapshot, false) + .await + .unwrap(); + state_compute(sm, ts).await; + } + } +} + #[cfg(test)] mod test { use crate::shim::{address::Address, econ::TokenAmount, state_tree::ActorState};