1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2019-2026 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT
use crate::lotus_json::HasLotusJson;
use crate::rpc::state::{ForestComputeStateOutput, ForestStateCompute};
use crate::rpc::{self, prelude::*};
use crate::shim::address::StrictAddress;
use crate::shim::clock::ChainEpoch;
use cid::Cid;
use clap::Subcommand;
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 {
root: Cid,
/// The `.car` file path to save the state root
#[arg(short, long)]
save_to_file: Option<PathBuf>,
},
/// Compute state trees for epochs
Compute {
/// Which epoch to compute the state transition for
#[arg(long)]
epoch: ChainEpoch,
/// Number of tipset epochs to compute state for. Default is 1
#[arg(short, long)]
n_epochs: Option<NonZeroUsize>,
/// Force recomputing the state trees regardless whether the results are cached
#[arg(long)]
force: bool,
/// Print epoch and tipset key along with state root
#[arg(short, long)]
verbose: bool,
},
/// Read the state of an actor
ReadState {
/// 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 {
pub async fn run(self, client: rpc::Client) -> anyhow::Result<()> {
match self {
Self::Fetch { root, save_to_file } => {
let ret = client
.call(
StateFetchRoot::request((root, save_to_file))?.with_timeout(Duration::MAX),
)
.await?;
println!("{ret}");
}
StateCommands::Compute {
epoch,
n_epochs,
force,
verbose,
} => {
let results = client
.call(
ForestStateCompute::request((epoch, n_epochs, Some(force)))?
.with_timeout(Duration::MAX),
)
.await?;
for ForestComputeStateOutput {
state_root,
epoch,
tipset_key,
} in results
{
if verbose {
println!("{state_root} (epoch: {epoch}, tipset key: {tipset_key})");
} else {
println!("{state_root}");
}
}
}
Self::ReadState { actor_address } => {
let tipset = ChainHead::call(&client, ()).await?;
let ret = client
.call(
StateReadState::request((actor_address.into(), tipset.key().into()))?
.with_timeout(Duration::MAX),
)
.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(())
}
}