Skip to main content

forest/state_manager/
address_resolution.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use super::*;
5use crate::prelude::*;
6use crate::shim::address::Payload;
7use bls_signatures::{PublicKey as BlsPublicKey, Serialize as _};
8
9impl StateManager {
10    /// Returns a BLS public key from provided address
11    pub fn get_bls_public_key(
12        db: &(impl Blockstore + ShallowClone),
13        addr: Address,
14        state_cid: Cid,
15    ) -> Result<BlsPublicKey, Error> {
16        let state =
17            StateTree::new_from_root(db, &state_cid).map_err(|e| Error::Other(e.to_string()))?;
18        let kaddr = state
19            .resolve_to_deterministic_address(db, addr)
20            .context("Failed to resolve key address")?;
21
22        match kaddr.into_payload() {
23            Payload::BLS(key) => BlsPublicKey::from_bytes(&key)
24                .context("Failed to construct bls public key")
25                .map_err(Error::from),
26            _ => Err(Error::state(
27                "Address must be BLS address to load bls public key",
28            )),
29        }
30    }
31
32    /// Looks up ID [Address] from the state at the given [Tipset].
33    pub fn lookup_id(&self, addr: &Address, ts: &Tipset) -> Result<Option<Address>, Error> {
34        let state_tree =
35            StateTree::new_from_root(self.db(), ts.parent_state()).map_err(|e| format!("{e:?}"))?;
36        Ok(state_tree
37            .lookup_id(addr)
38            .map_err(|e| Error::Other(e.to_string()))?
39            .map(Address::new_id))
40    }
41
42    /// Looks up required ID [Address] from the state at the given [Tipset].
43    pub fn lookup_required_id(&self, addr: &Address, ts: &Tipset) -> Result<Address, Error> {
44        self.lookup_id(addr, ts)?
45            .ok_or_else(|| Error::Other(format!("Failed to lookup the id address {addr}")))
46    }
47
48    /// Similar to [`StateTree::resolve_to_deterministic_addr`] but does not allow [`crate::shim::address::Protocol::Actor`] type of addresses.
49    /// Uses the [`Tipset`] `ts` to generate the VM state.
50    pub async fn resolve_to_deterministic_address(
51        &self,
52        address: Address,
53        ts: &Tipset,
54    ) -> anyhow::Result<Address> {
55        use crate::shim::address::Protocol::*;
56        match address.protocol() {
57            BLS | Secp256k1 | Delegated => Ok(address),
58            Actor => anyhow::bail!("cannot resolve actor address to key address"),
59            ID => {
60                let id = address.id()?;
61                let resolve = async {
62                    // First try to resolve the actor in the parent state, so we don't have to compute anything.
63                    let resolved = if let Ok(state) =
64                        StateTree::new_from_root(self.db(), ts.parent_state())
65                        && let Ok(address) =
66                            state.resolve_to_deterministic_address(self.db(), address)
67                    {
68                        address
69                    } else {
70                        // If that fails, compute the tip-set and try again.
71                        let TipsetState { state_root, .. } = self.load_tipset_state(ts).await?;
72                        let state = StateTree::new_from_root(self.db(), &state_root)?;
73                        state.resolve_to_deterministic_address(self.db(), address)?
74                    };
75                    anyhow::Ok(resolved)
76                };
77                // Memoize unless the cache is disabled (test-snapshot generation
78                // and replay, see the field docs on `StateManager`).
79                match &self.id_to_deterministic_address_cache {
80                    Some(cache) => cache.get_or_insert_async(&id, resolve).await,
81                    None => resolve.await,
82                }
83            }
84        }
85    }
86}