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 _, anyhow, 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
215 .get_actor(&addr.into())
216 .map_err(|e| anyhow!("{e}"))?
217 .map(Into::into))
218 }
219 StateTree::FvmV3(st) => {
220 let id = st.lookup_id(&addr.into())?;
221 if let Some(id) = id {
222 Ok(st
223 .get_actor(id)
224 .map_err(|e| anyhow!("{e}"))?
225 .map(Into::into))
226 } else {
227 Ok(None)
228 }
229 }
230 StateTree::FvmV4(st) => {
231 let id = st.lookup_id(addr)?;
232 if let Some(id) = id {
233 Ok(st
234 .get_actor(id)
235 .map_err(|e| anyhow!("{e}"))?
236 .map(Into::into))
237 } else {
238 Ok(None)
239 }
240 }
241 StateTree::V0(st) => {
242 let id = st.lookup_id(addr)?;
243 if let Some(id) = id {
244 Ok(st
245 .get_actor(&id)
246 .map_err(|e| anyhow!("{e}"))?
247 .map(Into::into))
248 } else {
249 Ok(None)
250 }
251 }
252 }
253 }
254
255 pub fn get_actor_state<STATE: LoadActorStateFromBlockstore>(&self) -> anyhow::Result<STATE> {
257 let address = STATE::ACTOR.with_context(|| {
258 format!(
259 "No associated actor address for {}, use `get_actor_state_from_address` instead.",
260 std::any::type_name::<STATE>()
261 )
262 })?;
263 let actor = self.get_required_actor(&address)?;
264 STATE::load_from_blockstore(self.store(), &actor)
265 }
266
267 pub fn get_actor_state_from_address<STATE: LoadActorStateFromBlockstore>(
269 &self,
270 actor_address: &Address,
271 ) -> anyhow::Result<STATE> {
272 let actor = self.get_required_actor(actor_address)?;
273 STATE::load_from_blockstore(self.store(), &actor)
274 }
275
276 pub fn store(&self) -> &S {
278 delegate_state_tree!(self.store())
279 }
280
281 pub fn lookup_id(&self, addr: &Address) -> anyhow::Result<Option<ActorID>> {
283 match self {
284 StateTree::FvmV2(st) => st.lookup_id(&addr.into()).map_err(|e| anyhow!("{e}")),
285 StateTree::FvmV3(st) => Ok(st.lookup_id(&addr.into())?),
286 StateTree::FvmV4(st) => Ok(st.lookup_id(&addr.into())?),
287 StateTree::V0(_) => bail!("StateTree::lookup_id not supported on old state trees"),
288 }
289 }
290
291 pub fn lookup_required_id(&self, addr: &Address) -> anyhow::Result<ActorID> {
293 self.lookup_id(addr)?
294 .with_context(|| format!("actor id not found for address {addr}"))
295 }
296
297 pub fn for_each<F>(&self, mut f: F) -> anyhow::Result<()>
298 where
299 F: FnMut(Address, &ActorState) -> anyhow::Result<()>,
300 {
301 match self {
302 StateTree::FvmV2(st) => {
303 st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
304 }
305 StateTree::FvmV3(st) => {
306 st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
307 }
308 StateTree::FvmV4(st) => {
309 st.for_each(|address, actor_state| f(address.into(), &actor_state.into()))
310 }
311 StateTree::V0(_) => bail!("StateTree::for_each not supported on old state trees"),
312 }
313 }
314
315 pub fn flush(&mut self) -> anyhow::Result<Cid> {
317 match self {
318 StateTree::FvmV2(st) => st.flush().map_err(|e| anyhow!("{e}")),
319 StateTree::FvmV3(st) => Ok(st.flush()?),
320 StateTree::FvmV4(st) => Ok(st.flush()?),
321 StateTree::V0(_) => bail!("StateTree::flush not supported on old state trees"),
322 }
323 }
324
325 pub fn set_actor(&mut self, addr: &Address, actor: ActorState) -> anyhow::Result<()> {
327 match self {
328 StateTree::FvmV2(st) => st
329 .set_actor(&addr.into(), actor.into())
330 .map_err(|e| anyhow!("{e}")),
331 StateTree::FvmV3(st) => {
332 let id = st
333 .lookup_id(&addr.into())?
334 .context("couldn't find actor id")?;
335 st.set_actor(id, actor.into());
336 Ok(())
337 }
338 StateTree::FvmV4(st) => {
339 let id = st
340 .lookup_id(&addr.into())?
341 .context("couldn't find actor id")?;
342 st.set_actor(id, actor.into());
343 Ok(())
344 }
345 StateTree::V0(_) => bail!("StateTree::set_actor not supported on old state trees"),
346 }
347 }
348
349 pub fn resolve_to_deterministic_addr(
353 &self,
354 store: &impl Blockstore,
355 addr: Address,
356 ) -> anyhow::Result<Address> {
357 use crate::shim::address::Protocol::*;
358 match addr.protocol() {
359 BLS | Secp256k1 | Delegated => Ok(addr),
360 _ => {
361 let actor = self
362 .get_actor(&addr)?
363 .with_context(|| format!("failed to find actor: {addr}"))?;
364
365 if !matches!(self, Self::FvmV2(_) | Self::V0(_))
368 && let Some(address) = actor.delegated_address
369 {
370 return Ok(address.into());
371 }
372
373 let account_state = account::State::load(store, actor.code, actor.state)?;
374 Ok(account_state.pubkey_address())
375 }
376 }
377 }
378}
379
380#[derive(
406 PartialEq, Eq, Clone, Debug, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut,
407)]
408#[serde(transparent)]
409#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
410pub struct ActorState(ActorState_latest);
411
412impl ActorState {
413 pub fn new(
414 code: Cid,
415 state: Cid,
416 balance: TokenAmount,
417 sequence: u64,
418 address: Option<Address>,
419 ) -> Self {
420 Self(ActorState_latest::new(
421 code,
422 state,
423 balance.into(),
424 sequence,
425 address.map(Into::into),
426 ))
427 }
428 pub fn new_empty(code: Cid, delegated_address: Option<Address>) -> Self {
430 Self(ActorState_latest::new_empty(
431 code,
432 delegated_address.map(Into::into),
433 ))
434 }
435}
436
437impl From<&ActorStateV2> for ActorState {
438 fn from(value: &ActorStateV2) -> Self {
439 Self(ActorState_latest {
440 code: value.code,
441 state: value.state,
442 sequence: value.sequence,
443 balance: TokenAmount::from(&value.balance).into(),
444 delegated_address: None,
445 })
446 }
447}
448
449impl From<ActorStateV2> for ActorState {
450 fn from(value: ActorStateV2) -> Self {
451 (&value).into()
452 }
453}
454
455impl From<ActorStateV3> for ActorState {
456 fn from(value: ActorStateV3) -> Self {
457 Self(ActorState_latest {
458 code: value.code,
459 state: value.state,
460 sequence: value.sequence,
461 balance: TokenAmount::from(value.balance).into(),
462 delegated_address: value
463 .delegated_address
464 .map(|addr| Address::from(addr).into()),
465 })
466 }
467}
468
469impl From<&ActorStateV3> for ActorState {
470 fn from(value: &ActorStateV3) -> Self {
471 value.clone().into()
472 }
473}
474
475impl From<ActorStateV4> for ActorState {
476 fn from(value: ActorStateV4) -> Self {
477 ActorState(value)
478 }
479}
480
481impl From<&ActorStateV4> for ActorState {
482 fn from(value: &ActorStateV4) -> Self {
483 value.clone().into()
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 ActorStateV2 {
499 fn from(other: &ActorState) -> ActorStateV2 {
500 Self {
501 code: other.code,
502 state: other.state,
503 sequence: other.sequence,
504 balance: TokenAmount::from(&other.balance).into(),
505 }
506 }
507}
508
509impl From<ActorState> for ActorStateV3 {
510 fn from(other: ActorState) -> Self {
511 Self {
512 code: other.code,
513 state: other.state,
514 sequence: other.sequence,
515 balance: TokenAmount::from(&other.balance).into(),
516 delegated_address: other
517 .delegated_address
518 .map(|addr| Address::from(addr).into()),
519 }
520 }
521}
522
523impl From<ActorState> for ActorStateV4 {
524 fn from(other: ActorState) -> Self {
525 other.0
526 }
527}
528
529#[cfg(test)]
530mod tests {
531 use super::StateTree;
532 use crate::blocks::CachingBlockHeader;
533 use crate::db::car::AnyCar;
534 use crate::networks::{calibnet, mainnet};
535 use crate::shim::actors::init;
536 use cid::Cid;
537 use std::sync::Arc;
538
539 fn get_network_name(car: &'static [u8], genesis_cid: Cid) -> String {
541 let forest_car = AnyCar::new(car).unwrap();
542 let genesis_block = CachingBlockHeader::load(&forest_car, genesis_cid)
543 .unwrap()
544 .unwrap();
545 let state_tree =
546 StateTree::new_from_root(Arc::new(&forest_car), &genesis_block.state_root).unwrap();
547 let state: init::State = state_tree.get_actor_state().unwrap();
548 state.into_network_name()
549 }
550
551 #[test]
552 fn calibnet_network_name() {
553 assert_eq!(
554 get_network_name(calibnet::DEFAULT_GENESIS, *calibnet::GENESIS_CID),
555 "calibrationnet"
556 );
557 }
558
559 #[test]
560 fn mainnet_network_name() {
561 assert_eq!(
563 get_network_name(mainnet::DEFAULT_GENESIS, *mainnet::GENESIS_CID),
564 "testnetnet"
565 );
566 }
567}