1use 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#[delegated_enum(impl_conversions)]
138pub enum StateTree<S> {
139 V0(super::state_tree_v0::StateTreeV0<S>),
141 FvmV2(StateTreeV2<S>),
143 FvmV3(StateTreeV3<S>),
145 FvmV4(StateTreeV4<S>),
147}
148
149impl<S> StateTree<S>
150where
151 S: Blockstore + ShallowClone,
152{
153 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 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 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 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 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 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 pub fn store(&self) -> &S {
274 delegate_state_tree!(self.store())
275 }
276
277 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 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 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 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 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 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 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#[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 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 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 assert_eq!(
583 get_network_name(mainnet::DEFAULT_GENESIS, *mainnet::GENESIS_CID),
584 "testnetnet"
585 );
586 }
587}