forest/shim/
state_tree.rs

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