Skip to main content

forest/shim/
state_tree.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3use super::actors::LoadActorStateFromBlockstore;
4pub use super::fvm_shared_latest::{ActorID, state::StateRoot};
5use crate::{
6    blocks::Tipset,
7    networks::{ACTOR_BUNDLES_METADATA, ActorBundleMetadata},
8    prelude::*,
9    shim::{
10        actors::{AccountActorStateLoad as _, account},
11        address::Address,
12        econ::TokenAmount,
13    },
14    utils::get_size::big_int_heap_size_helper,
15};
16use anyhow::bail;
17use fvm_ipld_encoding::{
18    CborStore as _,
19    repr::{Deserialize_repr, Serialize_repr},
20};
21use fvm_shared2::state::StateTreeVersion as StateTreeVersionV2;
22use fvm_shared3::state::StateTreeVersion as StateTreeVersionV3;
23use fvm_shared4::state::StateTreeVersion as StateTreeVersionV4;
24pub use fvm2::state_tree::{ActorState as ActorStateV2, StateTree as StateTreeV2};
25pub use fvm3::state_tree::{ActorState as ActorStateV3, StateTree as StateTreeV3};
26pub use fvm4::state_tree::{
27    ActorState as ActorStateV4, ActorState as ActorState_latest, StateTree as StateTreeV4,
28};
29use get_size2::GetSize;
30use num::FromPrimitive;
31use num_derive::FromPrimitive;
32use serde::{Deserialize, Serialize};
33use spire_enum::prelude::delegated_enum;
34
35#[derive(
36    Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Serialize_repr, Deserialize_repr, FromPrimitive,
37)]
38#[repr(u64)]
39pub enum StateTreeVersion {
40    V0,
41    V1,
42    V2,
43    V3,
44    V4,
45    V5,
46}
47
48impl From<StateTreeVersionV4> for StateTreeVersion {
49    fn from(value: StateTreeVersionV4) -> Self {
50        match value {
51            StateTreeVersionV4::V0 => Self::V0,
52            StateTreeVersionV4::V1 => Self::V1,
53            StateTreeVersionV4::V2 => Self::V2,
54            StateTreeVersionV4::V3 => Self::V3,
55            StateTreeVersionV4::V4 => Self::V4,
56            StateTreeVersionV4::V5 => Self::V5,
57        }
58    }
59}
60
61impl From<StateTreeVersionV3> for StateTreeVersion {
62    fn from(value: StateTreeVersionV3) -> Self {
63        match value {
64            StateTreeVersionV3::V0 => Self::V0,
65            StateTreeVersionV3::V1 => Self::V1,
66            StateTreeVersionV3::V2 => Self::V2,
67            StateTreeVersionV3::V3 => Self::V3,
68            StateTreeVersionV3::V4 => Self::V4,
69            StateTreeVersionV3::V5 => Self::V5,
70        }
71    }
72}
73
74impl TryFrom<StateTreeVersionV2> for StateTreeVersion {
75    type Error = anyhow::Error;
76    fn try_from(value: StateTreeVersionV2) -> anyhow::Result<Self> {
77        if let Some(v) = FromPrimitive::from_u32(value as u32) {
78            Ok(v)
79        } else {
80            bail!("Invalid conversion");
81        }
82    }
83}
84
85impl TryFrom<StateTreeVersion> for StateTreeVersionV2 {
86    type Error = anyhow::Error;
87
88    fn try_from(value: StateTreeVersion) -> anyhow::Result<Self> {
89        Ok(match value {
90            StateTreeVersion::V0 => Self::V0,
91            StateTreeVersion::V1 => Self::V1,
92            StateTreeVersion::V2 => Self::V2,
93            StateTreeVersion::V3 => Self::V3,
94            StateTreeVersion::V4 => Self::V4,
95            StateTreeVersion::V5 => bail!("Impossible conversion"),
96        })
97    }
98}
99
100impl TryFrom<StateTreeVersion> for StateTreeVersionV3 {
101    type Error = anyhow::Error;
102
103    fn try_from(value: StateTreeVersion) -> anyhow::Result<Self> {
104        Ok(match value {
105            StateTreeVersion::V0 => Self::V0,
106            StateTreeVersion::V1 => Self::V1,
107            StateTreeVersion::V2 => Self::V2,
108            StateTreeVersion::V3 => Self::V3,
109            StateTreeVersion::V4 => Self::V4,
110            StateTreeVersion::V5 => Self::V5,
111        })
112    }
113}
114
115impl TryFrom<StateTreeVersion> for StateTreeVersionV4 {
116    type Error = anyhow::Error;
117
118    fn try_from(value: StateTreeVersion) -> anyhow::Result<Self> {
119        Ok(match value {
120            StateTreeVersion::V0 => Self::V0,
121            StateTreeVersion::V1 => Self::V1,
122            StateTreeVersion::V2 => Self::V2,
123            StateTreeVersion::V3 => Self::V3,
124            StateTreeVersion::V4 => Self::V4,
125            StateTreeVersion::V5 => Self::V5,
126        })
127    }
128}
129
130/// FVM `StateTree` variant. The `new_from_root` constructor will try to resolve
131/// to a valid `StateTree` version or fail if we don't support it at the moment.
132/// Other methods usage should be transparent (using shimmed versions of
133/// structures introduced in this crate::shim.
134///
135/// Not all the inner methods are implemented, only those that are needed. Feel
136/// free to add those when necessary.
137#[delegated_enum(impl_conversions)]
138pub enum StateTree<S> {
139    // Version 0 is used to parse the genesis block.
140    V0(super::state_tree_v0::StateTreeV0<S>),
141    // fvm-2 support state tree versions 3 and 4.
142    FvmV2(StateTreeV2<S>),
143    // fvm-3 support state tree versions 5.
144    FvmV3(StateTreeV3<S>),
145    // fvm-4 support state tree versions *.
146    FvmV4(StateTreeV4<S>),
147}
148
149impl<S> StateTree<S>
150where
151    S: Blockstore + ShallowClone,
152{
153    /// Constructor for a HAMT state tree given an IPLD store
154    pub fn new(store: &S, version: StateTreeVersion) -> anyhow::Result<Self> {
155        if let Ok(st) = StateTreeV4::new(store.shallow_clone(), version.try_into()?) {
156            Ok(StateTree::FvmV4(st))
157        } else if let Ok(st) = StateTreeV3::new(store.shallow_clone(), version.try_into()?) {
158            Ok(StateTree::FvmV3(st))
159        } else if let Ok(st) = StateTreeV2::new(store.shallow_clone(), version.try_into()?) {
160            Ok(StateTree::FvmV2(st))
161        } else {
162            bail!("Can't create a valid state tree for the given version.");
163        }
164    }
165
166    pub fn new_from_root(store: &S, c: &Cid) -> anyhow::Result<Self> {
167        if let Ok(st) = StateTreeV4::new_from_root(store.shallow_clone(), c) {
168            Ok(StateTree::FvmV4(st))
169        } else if let Ok(st) = StateTreeV3::new_from_root(store.shallow_clone(), c) {
170            Ok(StateTree::FvmV3(st))
171        } else if let Ok(st) = StateTreeV2::new_from_root(store.shallow_clone(), c) {
172            Ok(StateTree::FvmV2(st))
173        } else if let Ok(st) =
174            super::state_tree_v0::StateTreeV0::new_from_root(store.shallow_clone(), c)
175        {
176            Ok(StateTree::V0(st))
177        } else if !store.has(c)? {
178            bail!("No state tree exists for the root {c}.")
179        } else {
180            let state_root = store.get_cbor::<StateRoot>(c).ok().flatten();
181            let state_root_version = state_root
182                .map(|sr| format!("{:?}", sr.version))
183                .unwrap_or_else(|| "unknown".into());
184            bail!(
185                "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}"
186            )
187        }
188    }
189
190    pub fn new_from_tipset(store: &S, ts: &Tipset) -> anyhow::Result<Self> {
191        Self::new_from_root(store, ts.parent_state())
192    }
193}
194
195impl<S> StateTree<S>
196where
197    S: Blockstore,
198{
199    /// Get required actor state from an address. Will be resolved to ID address.
200    pub fn get_required_actor(&self, addr: &Address) -> anyhow::Result<ActorState> {
201        self.get_actor(addr)?
202            .with_context(|| format!("Actor not found: addr={addr}"))
203    }
204
205    /// Get the actor bundle metadata
206    pub fn get_actor_bundle_metadata(&self) -> anyhow::Result<&ActorBundleMetadata> {
207        let system_actor_code = self.get_required_actor(&Address::SYSTEM_ACTOR)?.code;
208        ACTOR_BUNDLES_METADATA
209            .values()
210            .find(|v| v.manifest.get_system() == system_actor_code)
211            .with_context(|| format!("actor bundle not found for system actor {system_actor_code}"))
212    }
213
214    /// Get actor state from an address. Will be resolved to ID address.
215    pub fn get_actor(&self, addr: &Address) -> anyhow::Result<Option<ActorState>> {
216        match self {
217            StateTree::FvmV2(st) => {
218                anyhow::ensure!(
219                    addr.protocol() != crate::shim::address::Protocol::Delegated,
220                    "Delegated addresses are not supported in FVMv2 state trees"
221                );
222                Ok(st.get_actor(&addr.into())?.map(Into::into))
223            }
224            StateTree::FvmV3(st) => {
225                let id = st.lookup_id(&addr.into())?;
226                if let Some(id) = id {
227                    Ok(st.get_actor(id)?.map(Into::into))
228                } else {
229                    Ok(None)
230                }
231            }
232            StateTree::FvmV4(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            StateTree::V0(st) => {
241                let id = st.lookup_id(addr)?;
242                if let Some(id) = id {
243                    Ok(st.get_actor(&id)?.map(Into::into))
244                } else {
245                    Ok(None)
246                }
247            }
248        }
249    }
250
251    /// Gets actor state from implicit actor address
252    pub fn get_actor_state<STATE: LoadActorStateFromBlockstore>(&self) -> anyhow::Result<STATE> {
253        let address = STATE::ACTOR.with_context(|| {
254            format!(
255                "No associated actor address for {}, use `get_actor_state_from_address` instead.",
256                std::any::type_name::<STATE>()
257            )
258        })?;
259        let actor = self.get_required_actor(&address)?;
260        STATE::load_from_blockstore(self.store(), &actor)
261    }
262
263    /// Gets actor state from explicit actor address
264    pub fn get_actor_state_from_address<STATE: LoadActorStateFromBlockstore>(
265        &self,
266        actor_address: &Address,
267    ) -> anyhow::Result<STATE> {
268        let actor = self.get_required_actor(actor_address)?;
269        STATE::load_from_blockstore(self.store(), &actor)
270    }
271
272    /// Retrieve store reference to modify db.
273    pub fn store(&self) -> &S {
274        delegate_state_tree!(self.store())
275    }
276
277    /// Get an ID address from any Address
278    pub fn lookup_id(&self, addr: &Address) -> anyhow::Result<Option<ActorID>> {
279        match self {
280            StateTree::FvmV2(st) => Ok(st.lookup_id(&addr.into())?),
281            StateTree::FvmV3(st) => Ok(st.lookup_id(&addr.into())?),
282            StateTree::FvmV4(st) => Ok(st.lookup_id(&addr.into())?),
283            StateTree::V0(_) => bail!("StateTree::lookup_id not supported on old state trees"),
284        }
285    }
286
287    /// Get an required ID address from any Address
288    pub fn lookup_required_id(&self, addr: &Address) -> anyhow::Result<ActorID> {
289        self.lookup_id(addr)?
290            .with_context(|| format!("actor id not found for address {addr}"))
291    }
292
293    /// Use [`Self::for_each_cacheless`] instead unless cache is really needed.
294    /// Note that this method caches all HAMT nodes and can be memory-intensive.
295    pub fn for_each<F>(&self, mut f: F) -> anyhow::Result<()>
296    where
297        F: FnMut(Address, &ActorState) -> anyhow::Result<()>,
298    {
299        match self {
300            StateTree::FvmV2(st) => {
301                st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
302            }
303            StateTree::FvmV3(st) => {
304                st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
305            }
306            StateTree::FvmV4(st) => {
307                st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
308            }
309            StateTree::V0(_) => bail!("StateTree::for_each not supported on old state trees"),
310        }
311    }
312
313    /// Iterate on all actors
314    pub fn for_each_cacheless<F>(&self, mut f: F) -> anyhow::Result<()>
315    where
316        F: FnMut(Address, &ActorState) -> anyhow::Result<()>,
317    {
318        match self {
319            StateTree::FvmV2(st) => {
320                st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
321            }
322            StateTree::FvmV3(st) => {
323                st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
324            }
325            StateTree::FvmV4(st) => {
326                st.for_each_cacheless(|address, actor_state| f(address.into(), &actor_state.into()))
327            }
328            StateTree::V0(_) => {
329                bail!("StateTree::for_each_cacheless not supported on old state trees")
330            }
331        }
332    }
333
334    /// Flush state tree and return Cid root.
335    pub fn flush(&mut self) -> anyhow::Result<Cid> {
336        match self {
337            StateTree::FvmV2(st) => Ok(st.flush()?),
338            StateTree::FvmV3(st) => Ok(st.flush()?),
339            StateTree::FvmV4(st) => Ok(st.flush()?),
340            StateTree::V0(_) => bail!("StateTree::flush not supported on old state trees"),
341        }
342    }
343
344    /// Set actor state with an actor ID.
345    pub fn set_actor(&mut self, addr: &Address, actor: ActorState) -> anyhow::Result<()> {
346        match self {
347            StateTree::FvmV2(st) => {
348                st.set_actor(&addr.into(), actor.into())?;
349                Ok(())
350            }
351            StateTree::FvmV3(st) => {
352                let id = st
353                    .lookup_id(&addr.into())?
354                    .context("couldn't find actor id")?;
355                st.set_actor(id, actor.into());
356                Ok(())
357            }
358            StateTree::FvmV4(st) => {
359                let id = st
360                    .lookup_id(&addr.into())?
361                    .context("couldn't find actor id")?;
362                st.set_actor(id, actor.into());
363                Ok(())
364            }
365            StateTree::V0(_) => bail!("StateTree::set_actor not supported on old state trees"),
366        }
367    }
368
369    /// Returns the public key type of
370    /// address(`BLS`/`SECP256K1`) of an actor identified by `addr`,
371    /// or its delegated address.
372    pub fn resolve_to_deterministic_address(
373        &self,
374        store: &impl Blockstore,
375        addr: Address,
376    ) -> anyhow::Result<Address> {
377        use crate::shim::address::Protocol::*;
378        match addr.protocol() {
379            BLS | Secp256k1 | Delegated => Ok(addr),
380            _ => {
381                let actor = self
382                    .get_actor(&addr)?
383                    .with_context(|| format!("failed to find actor: {addr}"))?;
384                if let Some(address) = actor.delegated_address {
385                    Ok(address.into())
386                } else {
387                    let account_state = account::State::load(store, actor.code, actor.state)?;
388                    Ok(account_state.pubkey_address())
389                }
390            }
391        }
392    }
393}
394
395/// `Newtype` to wrap different versions of `fvm::state_tree::ActorState`
396///
397/// # Examples
398/// ```
399/// # use forest::doctest_private::ActorState;
400/// use cid::Cid;
401///
402/// // Create FVM2 ActorState normally
403/// let fvm2_actor_state = fvm2::state_tree::ActorState::new(Cid::default(), Cid::default(),
404/// fvm_shared2::econ::TokenAmount::from_atto(42), 0);
405///
406/// // Create a correspndoning FVM3 ActorState
407/// let fvm3_actor_state = fvm3::state_tree::ActorState::new(Cid::default(), Cid::default(),
408/// fvm_shared3::econ::TokenAmount::from_atto(42), 0, None);
409///
410/// // Create a correspndoning FVM4 ActorState
411/// let fvm4_actor_state = fvm4::state_tree::ActorState::new(Cid::default(), Cid::default(),
412/// fvm_shared4::econ::TokenAmount::from_atto(42), 0, None);
413///
414/// // Create a shim out of fvm2 state, ensure conversions are correct
415/// let state_shim = ActorState::from(fvm2_actor_state.clone());
416/// assert_eq!(fvm4_actor_state, *state_shim);
417/// assert_eq!(fvm3_actor_state, state_shim.clone().into());
418/// assert_eq!(fvm2_actor_state, state_shim.into());
419/// ```
420#[derive(
421    PartialEq, Eq, Clone, Debug, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut,
422)]
423#[serde(transparent)]
424#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
425pub struct ActorState(ActorState_latest);
426
427impl ActorState {
428    pub fn new(
429        code: Cid,
430        state: Cid,
431        balance: TokenAmount,
432        sequence: u64,
433        address: Option<Address>,
434    ) -> Self {
435        Self(ActorState_latest::new(
436            code,
437            state,
438            balance.into(),
439            sequence,
440            address.map(Into::into),
441        ))
442    }
443    /// Construct a new empty actor with the specified code.
444    pub fn new_empty(code: Cid, delegated_address: Option<Address>) -> Self {
445        Self(ActorState_latest::new_empty(
446            code,
447            delegated_address.map(Into::into),
448        ))
449    }
450}
451
452impl GetSize for ActorState {
453    fn get_heap_size_with_tracker<T: get_size2::GetSizeTracker>(&self, tracker: T) -> (usize, T) {
454        (big_int_heap_size_helper(self.balance.atto()), tracker)
455    }
456}
457
458impl From<&ActorStateV2> for ActorState {
459    fn from(value: &ActorStateV2) -> Self {
460        Self(ActorState_latest {
461            code: value.code,
462            state: value.state,
463            sequence: value.sequence,
464            balance: TokenAmount::from(&value.balance).into(),
465            delegated_address: None,
466        })
467    }
468}
469
470impl From<ActorStateV2> for ActorState {
471    fn from(value: ActorStateV2) -> Self {
472        (&value).into()
473    }
474}
475
476impl From<ActorStateV3> for ActorState {
477    fn from(value: ActorStateV3) -> Self {
478        Self(ActorState_latest {
479            code: value.code,
480            state: value.state,
481            sequence: value.sequence,
482            balance: TokenAmount::from(value.balance).into(),
483            delegated_address: value
484                .delegated_address
485                .map(|addr| Address::from(addr).into()),
486        })
487    }
488}
489
490impl From<&ActorStateV3> for ActorState {
491    fn from(value: &ActorStateV3) -> Self {
492        value.clone().into()
493    }
494}
495
496impl From<ActorStateV4> for ActorState {
497    fn from(value: ActorStateV4) -> Self {
498        ActorState(value)
499    }
500}
501
502impl From<&ActorStateV4> for ActorState {
503    fn from(value: &ActorStateV4) -> Self {
504        value.clone().into()
505    }
506}
507
508impl From<ActorState> for ActorStateV2 {
509    fn from(other: ActorState) -> ActorStateV2 {
510        Self {
511            code: other.code,
512            state: other.state,
513            sequence: other.sequence,
514            balance: TokenAmount::from(&other.balance).into(),
515        }
516    }
517}
518
519impl From<&ActorState> for ActorStateV2 {
520    fn from(other: &ActorState) -> ActorStateV2 {
521        Self {
522            code: other.code,
523            state: other.state,
524            sequence: other.sequence,
525            balance: TokenAmount::from(&other.balance).into(),
526        }
527    }
528}
529
530impl From<ActorState> for ActorStateV3 {
531    fn from(other: ActorState) -> Self {
532        Self {
533            code: other.code,
534            state: other.state,
535            sequence: other.sequence,
536            balance: TokenAmount::from(&other.balance).into(),
537            delegated_address: other
538                .delegated_address
539                .map(|addr| Address::from(addr).into()),
540        }
541    }
542}
543
544impl From<ActorState> for ActorStateV4 {
545    fn from(other: ActorState) -> Self {
546        other.0
547    }
548}
549
550#[cfg(test)]
551mod tests {
552    use super::StateTree;
553    use crate::blocks::CachingBlockHeader;
554    use crate::db::car::AnyCar;
555    use crate::networks::{calibnet, mainnet};
556    use crate::shim::actors::init;
557    use cid::Cid;
558    use std::sync::Arc;
559
560    // refactored from `StateManager::get_network_name`
561    fn get_network_name(car: &'static [u8], genesis_cid: Cid) -> String {
562        let forest_car = Arc::new(AnyCar::new(car).unwrap());
563        let genesis_block = CachingBlockHeader::load(&forest_car, genesis_cid)
564            .unwrap()
565            .unwrap();
566        let state_tree = StateTree::new_from_root(&forest_car, &genesis_block.state_root).unwrap();
567        let state: init::State = state_tree.get_actor_state().unwrap();
568        state.into_network_name()
569    }
570
571    #[test]
572    fn calibnet_network_name() {
573        assert_eq!(
574            get_network_name(calibnet::DEFAULT_GENESIS, *calibnet::GENESIS_CID),
575            "calibrationnet"
576        );
577    }
578
579    #[test]
580    fn mainnet_network_name() {
581        // Yes, the name of `mainnet` in the genesis block really is `testnetnet`.
582        assert_eq!(
583            get_network_name(mainnet::DEFAULT_GENESIS, *mainnet::GENESIS_CID),
584            "testnetnet"
585        );
586    }
587}