forest/shim/
state_tree_v0.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3// ported from commit hash b622af
4
5// The FVM crates only support state tree versions 3,4 and 5. This module
6// contains read-only support for state tree version 0. This version is required
7// to parse genesis states. Ideally, we would have a library that supports _all_
8// state tree versions.
9
10use cid::Cid;
11use fil_actors_shared::fvm_ipld_hamt::Hamtv0 as Hamt;
12use fvm_ipld_blockstore::Blockstore;
13use fvm_ipld_encoding::CborStore;
14
15use super::state_tree::StateRoot;
16use super::state_tree::StateTreeVersion;
17use crate::shim::address::Address;
18pub use fvm2::state_tree::ActorState as ActorStateV2;
19
20const HAMTV0_BIT_WIDTH: u32 = 5;
21
22// This is a read-only version of the earliest state trees.
23/// State tree implementation using HAMT. This structure is not thread safe and should only be used
24/// in sync contexts.
25pub struct StateTreeV0<S> {
26    hamt: Hamt<S, ActorStateV2>,
27}
28
29impl<S> StateTreeV0<S>
30where
31    S: Blockstore,
32{
33    /// Constructor for a HAMT state tree given an IPLD store
34    pub fn new_from_root(store: S, c: &Cid) -> anyhow::Result<Self> {
35        // Try to load state root, if versioned
36        let (version, actors) = if let Ok(Some(StateRoot {
37            version, actors, ..
38        })) = store.get_cbor(c)
39        {
40            (StateTreeVersion::from(version), actors)
41        } else {
42            // Fallback to v0 state tree if retrieval fails
43            (StateTreeVersion::V0, *c)
44        };
45
46        match version {
47            StateTreeVersion::V0 => {
48                let hamt = Hamt::load_with_bit_width(&actors, store, HAMTV0_BIT_WIDTH)?;
49                Ok(Self { hamt })
50            }
51            _ => anyhow::bail!("unsupported state tree version: {:?}", version),
52        }
53    }
54
55    /// Retrieve store reference to modify db.
56    pub fn store(&self) -> &S {
57        self.hamt.store()
58    }
59
60    /// Get actor state from an address. Will be resolved to ID address.
61    pub fn get_actor(&self, addr: &Address) -> anyhow::Result<Option<ActorStateV2>> {
62        let addr = match self.lookup_id(addr)? {
63            Some(addr) => addr,
64            None => return Ok(None),
65        };
66
67        // if state doesn't exist, find using hamt
68        let act = self.hamt.get(&addr.to_bytes())?.cloned();
69
70        Ok(act)
71    }
72
73    /// Get an ID address from any Address
74    pub fn lookup_id(&self, addr: &Address) -> anyhow::Result<Option<Address>> {
75        if addr.protocol() == fvm_shared4::address::Protocol::ID {
76            return Ok(Some(*addr));
77        }
78        anyhow::bail!("StateTreeV0::lookup_id is only defined for ID addresses")
79    }
80}