1use super::actors::LoadActorStateFromBlockstore;
4pub use super::fvm_shared_latest::{ActorID, state::StateRoot};
5use crate::{
6 blocks::Tipset,
7 shim::{actors::AccountActorStateLoad as _, address::Address, econ::TokenAmount},
8};
9use crate::{
10 networks::{ACTOR_BUNDLES_METADATA, ActorBundleMetadata},
11 shim::actors::account,
12};
13use anyhow::{Context as _, bail};
14use cid::Cid;
15use fvm_ipld_blockstore::Blockstore;
16use fvm_ipld_encoding::{
17 CborStore as _,
18 repr::{Deserialize_repr, Serialize_repr},
19};
20use fvm_shared2::state::StateTreeVersion as StateTreeVersionV2;
21use fvm_shared3::state::StateTreeVersion as StateTreeVersionV3;
22use fvm_shared4::state::StateTreeVersion as StateTreeVersionV4;
23pub use fvm2::state_tree::{ActorState as ActorStateV2, StateTree as StateTreeV2};
24pub use fvm3::state_tree::{ActorState as ActorStateV3, StateTree as StateTreeV3};
25pub use fvm4::state_tree::{
26 ActorState as ActorStateV4, ActorState as ActorState_latest, StateTree as StateTreeV4,
27};
28use num::FromPrimitive;
29use num_derive::FromPrimitive;
30use serde::{Deserialize, Serialize};
31use spire_enum::prelude::delegated_enum;
32use std::sync::Arc;
33
34#[derive(
35 Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Serialize_repr, Deserialize_repr, FromPrimitive,
36)]
37#[repr(u64)]
38pub enum StateTreeVersion {
39 V0,
40 V1,
41 V2,
42 V3,
43 V4,
44 V5,
45}
46
47impl From<StateTreeVersionV4> for StateTreeVersion {
48 fn from(value: StateTreeVersionV4) -> Self {
49 match value {
50 StateTreeVersionV4::V0 => Self::V0,
51 StateTreeVersionV4::V1 => Self::V1,
52 StateTreeVersionV4::V2 => Self::V2,
53 StateTreeVersionV4::V3 => Self::V3,
54 StateTreeVersionV4::V4 => Self::V4,
55 StateTreeVersionV4::V5 => Self::V5,
56 }
57 }
58}
59
60impl From<StateTreeVersionV3> for StateTreeVersion {
61 fn from(value: StateTreeVersionV3) -> Self {
62 match value {
63 StateTreeVersionV3::V0 => Self::V0,
64 StateTreeVersionV3::V1 => Self::V1,
65 StateTreeVersionV3::V2 => Self::V2,
66 StateTreeVersionV3::V3 => Self::V3,
67 StateTreeVersionV3::V4 => Self::V4,
68 StateTreeVersionV3::V5 => Self::V5,
69 }
70 }
71}
72
73impl TryFrom<StateTreeVersionV2> for StateTreeVersion {
74 type Error = anyhow::Error;
75 fn try_from(value: StateTreeVersionV2) -> anyhow::Result<Self> {
76 if let Some(v) = FromPrimitive::from_u32(value as u32) {
77 Ok(v)
78 } else {
79 bail!("Invalid conversion");
80 }
81 }
82}
83
84impl TryFrom<StateTreeVersion> for StateTreeVersionV2 {
85 type Error = anyhow::Error;
86
87 fn try_from(value: StateTreeVersion) -> anyhow::Result<Self> {
88 Ok(match value {
89 StateTreeVersion::V0 => Self::V0,
90 StateTreeVersion::V1 => Self::V1,
91 StateTreeVersion::V2 => Self::V2,
92 StateTreeVersion::V3 => Self::V3,
93 StateTreeVersion::V4 => Self::V4,
94 StateTreeVersion::V5 => bail!("Impossible conversion"),
95 })
96 }
97}
98
99impl TryFrom<StateTreeVersion> for StateTreeVersionV3 {
100 type Error = anyhow::Error;
101
102 fn try_from(value: StateTreeVersion) -> anyhow::Result<Self> {
103 Ok(match value {
104 StateTreeVersion::V0 => Self::V0,
105 StateTreeVersion::V1 => Self::V1,
106 StateTreeVersion::V2 => Self::V2,
107 StateTreeVersion::V3 => Self::V3,
108 StateTreeVersion::V4 => Self::V4,
109 StateTreeVersion::V5 => Self::V5,
110 })
111 }
112}
113
114impl TryFrom<StateTreeVersion> for StateTreeVersionV4 {
115 type Error = anyhow::Error;
116
117 fn try_from(value: StateTreeVersion) -> anyhow::Result<Self> {
118 Ok(match value {
119 StateTreeVersion::V0 => Self::V0,
120 StateTreeVersion::V1 => Self::V1,
121 StateTreeVersion::V2 => Self::V2,
122 StateTreeVersion::V3 => Self::V3,
123 StateTreeVersion::V4 => Self::V4,
124 StateTreeVersion::V5 => Self::V5,
125 })
126 }
127}
128
129#[delegated_enum(impl_conversions)]
137pub enum StateTree<S> {
138 V0(super::state_tree_v0::StateTreeV0<Arc<S>>),
140 FvmV2(StateTreeV2<Arc<S>>),
142 FvmV3(StateTreeV3<Arc<S>>),
144 FvmV4(StateTreeV4<Arc<S>>),
146}
147
148impl<S> StateTree<S>
149where
150 S: Blockstore,
151{
152 pub fn new(store: Arc<S>, version: StateTreeVersion) -> anyhow::Result<Self> {
154 if let Ok(st) = StateTreeV4::new(store.clone(), version.try_into()?) {
155 Ok(StateTree::FvmV4(st))
156 } else if let Ok(st) = StateTreeV3::new(store.clone(), version.try_into()?) {
157 Ok(StateTree::FvmV3(st))
158 } else if let Ok(st) = StateTreeV2::new(store, version.try_into()?) {
159 Ok(StateTree::FvmV2(st))
160 } else {
161 bail!("Can't create a valid state tree for the given version.");
162 }
163 }
164
165 pub fn new_from_root(store: Arc<S>, c: &Cid) -> anyhow::Result<Self> {
166 if let Ok(st) = StateTreeV4::new_from_root(store.clone(), c) {
167 Ok(StateTree::FvmV4(st))
168 } else if let Ok(st) = StateTreeV3::new_from_root(store.clone(), c) {
169 Ok(StateTree::FvmV3(st))
170 } else if let Ok(st) = StateTreeV2::new_from_root(store.clone(), c) {
171 Ok(StateTree::FvmV2(st))
172 } else if let Ok(st) = super::state_tree_v0::StateTreeV0::new_from_root(store.clone(), c) {
173 Ok(StateTree::V0(st))
174 } else if !store.has(c)? {
175 bail!("No state tree exists for the root {c}.")
176 } else {
177 let state_root = store.get_cbor::<StateRoot>(c).ok().flatten();
178 let state_root_version = state_root
179 .map(|sr| format!("{:?}", sr.version))
180 .unwrap_or_else(|| "unknown".into());
181 bail!(
182 "Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid={c}, state_root_version={state_root_version}"
183 )
184 }
185 }
186
187 pub fn new_from_tipset(store: Arc<S>, ts: &Tipset) -> anyhow::Result<Self> {
188 Self::new_from_root(store, ts.parent_state())
189 }
190
191 pub fn get_required_actor(&self, addr: &Address) -> anyhow::Result<ActorState> {
193 self.get_actor(addr)?
194 .with_context(|| format!("Actor not found: addr={addr}"))
195 }
196
197 pub fn get_actor_bundle_metadata(&self) -> anyhow::Result<&ActorBundleMetadata> {
199 let system_actor_code = self.get_required_actor(&Address::SYSTEM_ACTOR)?.code;
200 ACTOR_BUNDLES_METADATA
201 .values()
202 .find(|v| v.manifest.get_system() == system_actor_code)
203 .with_context(|| format!("actor bundle not found for system actor {system_actor_code}"))
204 }
205
206 pub fn get_actor(&self, addr: &Address) -> anyhow::Result<Option<ActorState>> {
208 match self {
209 StateTree::FvmV2(st) => {
210 anyhow::ensure!(
211 addr.protocol() != crate::shim::address::Protocol::Delegated,
212 "Delegated addresses are not supported in FVMv2 state trees"
213 );
214 Ok(st.get_actor(&addr.into())?.map(Into::into))
215 }
216 StateTree::FvmV3(st) => {
217 let id = st.lookup_id(&addr.into())?;
218 if let Some(id) = id {
219 Ok(st.get_actor(id)?.map(Into::into))
220 } else {
221 Ok(None)
222 }
223 }
224 StateTree::FvmV4(st) => {
225 let id = st.lookup_id(addr)?;
226 if let Some(id) = id {
227 Ok(st.get_actor(id)?.map(Into::into))
228 } else {
229 Ok(None)
230 }
231 }
232 StateTree::V0(st) => {
233 let id = st.lookup_id(addr)?;
234 if let Some(id) = id {
235 Ok(st.get_actor(&id)?.map(Into::into))
236 } else {
237 Ok(None)
238 }
239 }
240 }
241 }
242
243 pub fn get_actor_state<STATE: LoadActorStateFromBlockstore>(&self) -> anyhow::Result<STATE> {
245 let address = STATE::ACTOR.with_context(|| {
246 format!(
247 "No associated actor address for {}, use `get_actor_state_from_address` instead.",
248 std::any::type_name::<STATE>()
249 )
250 })?;
251 let actor = self.get_required_actor(&address)?;
252 STATE::load_from_blockstore(self.store(), &actor)
253 }
254
255 pub fn get_actor_state_from_address<STATE: LoadActorStateFromBlockstore>(
257 &self,
258 actor_address: &Address,
259 ) -> anyhow::Result<STATE> {
260 let actor = self.get_required_actor(actor_address)?;
261 STATE::load_from_blockstore(self.store(), &actor)
262 }
263
264 pub fn store(&self) -> &S {
266 delegate_state_tree!(self.store())
267 }
268
269 pub fn lookup_id(&self, addr: &Address) -> anyhow::Result<Option<ActorID>> {
271 match self {
272 StateTree::FvmV2(st) => Ok(st.lookup_id(&addr.into())?),
273 StateTree::FvmV3(st) => Ok(st.lookup_id(&addr.into())?),
274 StateTree::FvmV4(st) => Ok(st.lookup_id(&addr.into())?),
275 StateTree::V0(_) => bail!("StateTree::lookup_id not supported on old state trees"),
276 }
277 }
278
279 pub fn lookup_required_id(&self, addr: &Address) -> anyhow::Result<ActorID> {
281 self.lookup_id(addr)?
282 .with_context(|| format!("actor id not found for address {addr}"))
283 }
284
285 pub fn for_each<F>(&self, mut f: F) -> anyhow::Result<()>
286 where
287 F: FnMut(Address, &ActorState) -> anyhow::Result<()>,
288 {
289 match self {
290 StateTree::FvmV2(st) => {
291 st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
292 }
293 StateTree::FvmV3(st) => {
294 st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
295 }
296 StateTree::FvmV4(st) => {
297 st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
298 }
299 StateTree::V0(_) => bail!("StateTree::for_each not supported on old state trees"),
300 }
301 }
302
303 pub fn flush(&mut self) -> anyhow::Result<Cid> {
305 match self {
306 StateTree::FvmV2(st) => Ok(st.flush()?),
307 StateTree::FvmV3(st) => Ok(st.flush()?),
308 StateTree::FvmV4(st) => Ok(st.flush()?),
309 StateTree::V0(_) => bail!("StateTree::flush not supported on old state trees"),
310 }
311 }
312
313 pub fn set_actor(&mut self, addr: &Address, actor: ActorState) -> anyhow::Result<()> {
315 match self {
316 StateTree::FvmV2(st) => {
317 st.set_actor(&addr.into(), actor.into())?;
318 Ok(())
319 }
320 StateTree::FvmV3(st) => {
321 let id = st
322 .lookup_id(&addr.into())?
323 .context("couldn't find actor id")?;
324 st.set_actor(id, actor.into());
325 Ok(())
326 }
327 StateTree::FvmV4(st) => {
328 let id = st
329 .lookup_id(&addr.into())?
330 .context("couldn't find actor id")?;
331 st.set_actor(id, actor.into());
332 Ok(())
333 }
334 StateTree::V0(_) => bail!("StateTree::set_actor not supported on old state trees"),
335 }
336 }
337
338 pub fn resolve_to_deterministic_addr(
342 &self,
343 store: &impl Blockstore,
344 addr: Address,
345 ) -> anyhow::Result<Address> {
346 use crate::shim::address::Protocol::*;
347 match addr.protocol() {
348 BLS | Secp256k1 | Delegated => Ok(addr),
349 _ => {
350 let actor = self
351 .get_actor(&addr)?
352 .with_context(|| format!("failed to find actor: {addr}"))?;
353
354 if !matches!(self, Self::FvmV2(_) | Self::V0(_))
357 && let Some(address) = actor.delegated_address
358 {
359 return Ok(address.into());
360 }
361
362 let account_state = account::State::load(store, actor.code, actor.state)?;
363 Ok(account_state.pubkey_address())
364 }
365 }
366 }
367}
368
369#[derive(
395 PartialEq, Eq, Clone, Debug, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut,
396)]
397#[serde(transparent)]
398#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
399pub struct ActorState(ActorState_latest);
400
401impl ActorState {
402 pub fn new(
403 code: Cid,
404 state: Cid,
405 balance: TokenAmount,
406 sequence: u64,
407 address: Option<Address>,
408 ) -> Self {
409 Self(ActorState_latest::new(
410 code,
411 state,
412 balance.into(),
413 sequence,
414 address.map(Into::into),
415 ))
416 }
417 pub fn new_empty(code: Cid, delegated_address: Option<Address>) -> Self {
419 Self(ActorState_latest::new_empty(
420 code,
421 delegated_address.map(Into::into),
422 ))
423 }
424}
425
426impl From<&ActorStateV2> for ActorState {
427 fn from(value: &ActorStateV2) -> Self {
428 Self(ActorState_latest {
429 code: value.code,
430 state: value.state,
431 sequence: value.sequence,
432 balance: TokenAmount::from(&value.balance).into(),
433 delegated_address: None,
434 })
435 }
436}
437
438impl From<ActorStateV2> for ActorState {
439 fn from(value: ActorStateV2) -> Self {
440 (&value).into()
441 }
442}
443
444impl From<ActorStateV3> for ActorState {
445 fn from(value: ActorStateV3) -> Self {
446 Self(ActorState_latest {
447 code: value.code,
448 state: value.state,
449 sequence: value.sequence,
450 balance: TokenAmount::from(value.balance).into(),
451 delegated_address: value
452 .delegated_address
453 .map(|addr| Address::from(addr).into()),
454 })
455 }
456}
457
458impl From<&ActorStateV3> for ActorState {
459 fn from(value: &ActorStateV3) -> Self {
460 value.clone().into()
461 }
462}
463
464impl From<ActorStateV4> for ActorState {
465 fn from(value: ActorStateV4) -> Self {
466 ActorState(value)
467 }
468}
469
470impl From<&ActorStateV4> for ActorState {
471 fn from(value: &ActorStateV4) -> Self {
472 value.clone().into()
473 }
474}
475
476impl From<ActorState> for ActorStateV2 {
477 fn from(other: ActorState) -> ActorStateV2 {
478 Self {
479 code: other.code,
480 state: other.state,
481 sequence: other.sequence,
482 balance: TokenAmount::from(&other.balance).into(),
483 }
484 }
485}
486
487impl From<&ActorState> for ActorStateV2 {
488 fn from(other: &ActorState) -> ActorStateV2 {
489 Self {
490 code: other.code,
491 state: other.state,
492 sequence: other.sequence,
493 balance: TokenAmount::from(&other.balance).into(),
494 }
495 }
496}
497
498impl From<ActorState> for ActorStateV3 {
499 fn from(other: ActorState) -> Self {
500 Self {
501 code: other.code,
502 state: other.state,
503 sequence: other.sequence,
504 balance: TokenAmount::from(&other.balance).into(),
505 delegated_address: other
506 .delegated_address
507 .map(|addr| Address::from(addr).into()),
508 }
509 }
510}
511
512impl From<ActorState> for ActorStateV4 {
513 fn from(other: ActorState) -> Self {
514 other.0
515 }
516}
517
518#[cfg(test)]
519mod tests {
520 use super::StateTree;
521 use crate::blocks::CachingBlockHeader;
522 use crate::db::car::AnyCar;
523 use crate::networks::{calibnet, mainnet};
524 use crate::shim::actors::init;
525 use cid::Cid;
526 use std::sync::Arc;
527
528 fn get_network_name(car: &'static [u8], genesis_cid: Cid) -> String {
530 let forest_car = AnyCar::new(car).unwrap();
531 let genesis_block = CachingBlockHeader::load(&forest_car, genesis_cid)
532 .unwrap()
533 .unwrap();
534 let state_tree =
535 StateTree::new_from_root(Arc::new(&forest_car), &genesis_block.state_root).unwrap();
536 let state: init::State = state_tree.get_actor_state().unwrap();
537 state.into_network_name()
538 }
539
540 #[test]
541 fn calibnet_network_name() {
542 assert_eq!(
543 get_network_name(calibnet::DEFAULT_GENESIS, *calibnet::GENESIS_CID),
544 "calibrationnet"
545 );
546 }
547
548 #[test]
549 fn mainnet_network_name() {
550 assert_eq!(
552 get_network_name(mainnet::DEFAULT_GENESIS, *mainnet::GENESIS_CID),
553 "testnetnet"
554 );
555 }
556}