1use 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
133pub enum StateTree<S> {
141 V0(super::state_tree_v0::StateTreeV0<Arc<S>>),
143 FvmV2(StateTreeV2<Arc<S>>),
145 FvmV3(StateTreeV3<Arc<S>>),
147 FvmV4(StateTreeV4<Arc<S>>),
149}
150
151impl<S> StateTree<S>
152where
153 S: Blockstore,
154{
155 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 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 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 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 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 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 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 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 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 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 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 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 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#[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 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 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 assert_eq!(
586 get_network_name(mainnet::DEFAULT_GENESIS, *mainnet::GENESIS_CID),
587 "testnetnet"
588 );
589 }
590}