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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

### Added

- [#6061](https://github.com/ChainSafe/forest/pull/6061) Added `forest-cli state actor-cids` command for listing all actor CIDs in the state tree for the current tipset.

Comment thread
LesnyRumcajs marked this conversation as resolved.
### Changed

### Removed
Expand Down
8 changes: 8 additions & 0 deletions scripts/tests/calibnet_other_check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ $FOREST_CLI_PATH healthcheck healthy --wait
echo "Test subcommand: healthcheck ready"
$FOREST_CLI_PATH healthcheck ready --wait

echo "Test subcommand: state actor-cids"
bundle_cid=$($FOREST_CLI_PATH state actor-cids --format json | jq -r '.Bundle["/"]')
manifest_path="./build/manifest.json"
if ! grep -q "$bundle_cid" "$manifest_path"; then
echo "Bundle CID $bundle_cid not found in $manifest_path"
exit 1
fi

Comment thread
LesnyRumcajs marked this conversation as resolved.
echo "Regression testing mempool select"
gem install http --user-install
$FOREST_CLI_PATH chain head --format json -n 1000 | scripts/mpool_select_killer.rb
Expand Down
22 changes: 22 additions & 0 deletions src/cli/subcommands/state_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::time::Duration;

#[derive(Debug, Clone, clap::ValueEnum)]
pub enum Format {
Json,
Text,
}

#[derive(Debug, Subcommand)]
pub enum StateCommands {
Fetch {
Expand All @@ -37,6 +43,12 @@ pub enum StateCommands {
/// Actor address to read the state of
actor_address: StrictAddress,
},
/// Returns the built-in actor bundle CIDs for the current network
ActorCids {
/// Format output
#[arg(long, default_value = "text")]
format: Format,
},
}

impl StateCommands {
Expand Down Expand Up @@ -83,6 +95,16 @@ impl StateCommands {
.await?;
println!("{}", ret.state.into_lotus_json_string_pretty()?);
}
Self::ActorCids { format } => {
let info = client.call(StateActorInfo::request(())?).await?;

match format {
Format::Json => {
println!("{}", serde_json::to_string_pretty(&info)?);
}
Format::Text => println!("{info}"),
}
}
}
Ok(())
}
Expand Down
100 changes: 97 additions & 3 deletions src/rpc/methods/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ use crate::cid_collections::CidHashSet;
use crate::eth::EthChainId;
use crate::interpreter::{MessageCallbackCtx, VMTrace};
use crate::libp2p::NetworkMessage;
use crate::lotus_json::lotus_json_with_self;
use crate::lotus_json::{LotusJson, lotus_json_with_self};
use crate::networks::ChainConfig;
use crate::rpc::registry::actors_reg::load_and_serialize_actor_state;
use crate::shim::actors::init;
use crate::shim::actors::market::DealState;
use crate::shim::actors::market::ext::MarketStateExt as _;
use crate::shim::actors::miner::ext::DeadlineExt;
use crate::shim::actors::state_load::*;
use crate::shim::actors::verifreg::ext::VerifiedRegistryStateExt as _;
use crate::shim::actors::verifreg::{Allocation, AllocationID, Claim};
use crate::shim::actors::{init, system};
use crate::shim::actors::{
market, miner,
miner::{MinerInfo, MinerPower},
Expand All @@ -32,6 +32,7 @@ use crate::shim::actors::{
power::ext::PowerStateExt as _,
};
use crate::shim::address::Payload;
use crate::shim::machine::BuiltinActorManifest;
use crate::shim::message::{Message, MethodNum};
use crate::shim::piece::PaddedPieceSize;
use crate::shim::sector::{SectorNumber, SectorSize};
Expand All @@ -49,7 +50,7 @@ use crate::{
rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError, types::*},
};
use ahash::{HashMap, HashMapExt, HashSet};
use anyhow::Context as _;
use anyhow::Context;
use anyhow::Result;
use cid::Cid;
use enumflags2::{BitFlags, make_bitflags};
Expand Down Expand Up @@ -3164,3 +3165,96 @@ fn get_pledge_ramp_params(
Ok((0, 0))
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
#[serde(rename_all = "PascalCase")]
pub struct StateActorCodeCidsOutput {
pub network_version: NetworkVersion,
pub network_version_revision: i64,
pub actor_version: String,
#[serde(with = "crate::lotus_json")]
#[schemars(with = "LotusJson<Cid>")]
pub manifest: Cid,
#[serde(with = "crate::lotus_json")]
#[schemars(with = "LotusJson<Cid>")]
pub bundle: Cid,
#[serde(with = "crate::lotus_json")]
#[schemars(with = "LotusJson<HashMap<String, Cid>>")]
pub actor_cids: HashMap<String, Cid>,
}
lotus_json_with_self!(StateActorCodeCidsOutput);

impl std::fmt::Display for StateActorCodeCidsOutput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Network Version: {}", self.network_version)?;
writeln!(
f,
"Network Version Revision: {}",
self.network_version_revision
)?;
writeln!(f, "Actor Version: {}", self.actor_version)?;
writeln!(f, "Manifest CID: {}", self.manifest)?;
writeln!(f, "Bundle CID: {}", self.bundle)?;
writeln!(f, "Actor CIDs:")?;
let longest_name = self
.actor_cids
.keys()
.map(|name| name.len())
.max()
.unwrap_or(0);
for (name, cid) in &self.actor_cids {
writeln!(f, " {:width$} : {}", name, cid, width = longest_name)?;
}
Ok(())
}
}

pub enum StateActorInfo {}

impl RpcMethod<0> for StateActorInfo {
const NAME: &'static str = "Forest.StateActorInfo";
const PARAM_NAMES: [&'static str; 0] = [];
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
const PERMISSION: Permission = Permission::Read;
const DESCRIPTION: Option<&'static str> =
Some("Returns the builtin actor information for the current network.");

type Params = ();
type Ok = StateActorCodeCidsOutput;

async fn handle(
ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
(): Self::Params,
) -> Result<Self::Ok, ServerError> {
let ts = ctx.chain_store().load_required_tipset_or_heaviest(None)?;
let state_tree = StateTree::new_from_tipset(ctx.store_owned(), &ts)?;
let bundle = state_tree.get_actor_bundle_metadata()?;
Comment thread
LesnyRumcajs marked this conversation as resolved.
let system_state: system::State = state_tree.get_actor_state()?;
let actors = system_state.builtin_actors_cid();

let current_manifest = BuiltinActorManifest::load_v1_actor_list(ctx.store(), actors)?;

// Sanity check: the command would normally be used only for diagnostics, so we want to be
// sure the data is consistent.
if current_manifest != bundle.manifest {
return Err(anyhow::anyhow!("Actor bundle manifest does not match the manifest in the state tree. This indicates that the node is misconfigured or is running an unsupported network.")
.into());
}

let network_version = ctx.chain_config().network_version(ts.epoch() - 1);
let network_version_revision = ctx.chain_config().network_version_revision(ts.epoch() - 1);
let result = StateActorCodeCidsOutput {
network_version,
network_version_revision,
actor_version: bundle.version.to_owned(),
manifest: current_manifest.actor_list_cid,
bundle: bundle.bundle_cid,
actor_cids: current_manifest
.builtin_actors()
.map(|(a, c)| (a.name().to_string(), c))
.collect(),
};

Ok(result)
}
}
1 change: 1 addition & 0 deletions src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ macro_rules! for_each_rpc_method {
$callback!($crate::rpc::state::StateMinerSectors);
$callback!($crate::rpc::state::StateNetworkName);
$callback!($crate::rpc::state::StateNetworkVersion);
$callback!($crate::rpc::state::StateActorInfo);
$callback!($crate::rpc::state::StateReadState);
$callback!($crate::rpc::state::StateDecodeParams);
$callback!($crate::rpc::state::StateReplay);
Expand Down
19 changes: 19 additions & 0 deletions src/shim/actors/builtin/system/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2019-2025 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use cid::Cid;
use fvm_shared2::address::Address;
use serde::Serialize;

Expand All @@ -25,3 +26,21 @@ pub enum State {
V16(fil_actor_system_state::v16::State),
V17(fil_actor_system_state::v17::State),
}

impl State {
/// Returns the builtin actors Cid.
pub fn builtin_actors_cid(&self) -> &Cid {
match self {
State::V8(s) => &s.builtin_actors,
State::V9(s) => &s.builtin_actors,
State::V10(s) => &s.builtin_actors,
State::V11(s) => &s.builtin_actors,
State::V12(s) => &s.builtin_actors,
State::V13(s) => &s.builtin_actors,
State::V14(s) => &s.builtin_actors,
State::V15(s) => &s.builtin_actors,
State::V16(s) => &s.builtin_actors,
State::V17(s) => &s.builtin_actors,
}
}
}
2 changes: 1 addition & 1 deletion src/shim/machine/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub use fil_actors_shared::v11::runtime::builtins::Type as BuiltinActor;
pub struct BuiltinActorManifest {
builtin2cid: BTreeMap<BuiltinActor, Cid>,
/// The CID that this manifest was built from
actor_list_cid: Cid,
pub actor_list_cid: Cid,
}

// We need to implement Serialize and Deserialize manually because `BuiltinActor` is not `Serialize` or `Deserialize`,
Expand Down
1 change: 1 addition & 0 deletions src/tool/subcommands/api_cmd/test_snapshots_ignored.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Forest.ChainExport
Forest.ChainGetMinBaseFee
Forest.NetInfo
Forest.SnapshotGC
Forest.StateActorInfo
Forest.StateCompute
Forest.StateFetchRoot
Forest.SyncSnapshotProgress
Expand Down
Loading