use super::*;
use crate::db::EthMappingsStore;
use crate::shim::address::{Payload, Protocol};
use anyhow::Context as _;
use bls_signatures::{PublicKey as BlsPublicKey, Serialize as _};
impl<DB> StateManager<DB>
where
DB: Blockstore + Send + Sync + 'static,
{
pub fn get_bls_public_key(
db: &Arc<DB>,
addr: &Address,
state_cid: Cid,
) -> Result<BlsPublicKey, Error> {
let state = StateTree::new_from_root(Arc::clone(db), &state_cid)
.map_err(|e| Error::Other(e.to_string()))?;
let kaddr =
resolve_to_key_addr(&state, db, addr).context("Failed to resolve key address")?;
match kaddr.into_payload() {
Payload::BLS(key) => BlsPublicKey::from_bytes(&key)
.context("Failed to construct bls public key")
.map_err(Error::from),
_ => Err(Error::state(
"Address must be BLS address to load bls public key",
)),
}
}
pub fn lookup_id(&self, addr: &Address, ts: &Tipset) -> Result<Option<Address>, Error> {
let state_tree = StateTree::new_from_root(self.blockstore_owned(), ts.parent_state())
.map_err(|e| format!("{e:?}"))?;
Ok(state_tree
.lookup_id(addr)
.map_err(|e| Error::Other(e.to_string()))?
.map(Address::new_id))
}
pub fn lookup_required_id(&self, addr: &Address, ts: &Tipset) -> Result<Address, Error> {
self.lookup_id(addr, ts)?
.ok_or_else(|| Error::Other(format!("Failed to lookup the id address {addr}")))
}
pub async fn resolve_to_key_addr(
self: &Arc<Self>,
addr: &Address,
ts: &Tipset,
) -> anyhow::Result<Address>
where
DB: EthMappingsStore,
{
match addr.protocol() {
Protocol::BLS | Protocol::Secp256k1 | Protocol::Delegated => return Ok(*addr),
Protocol::Actor => {
return Err(Error::Other(
"cannot resolve actor address to key address".to_string(),
)
.into());
}
_ => {}
};
let state = StateTree::new_from_root(self.blockstore_owned(), ts.parent_state())?;
if let Ok(addr) = resolve_to_key_addr(&state, self.blockstore(), addr) {
return Ok(addr);
}
let TipsetState { state_root, .. } = self.load_tipset_state(ts).await?;
let state = StateTree::new_from_root(self.blockstore_owned(), &state_root)?;
resolve_to_key_addr(&state, self.blockstore(), addr)
}
pub async fn resolve_to_deterministic_address(
self: &Arc<Self>,
address: Address,
ts: &Tipset,
) -> anyhow::Result<Address>
where
DB: EthMappingsStore,
{
use crate::shim::address::Protocol::*;
match address.protocol() {
BLS | Secp256k1 | Delegated => Ok(address),
Actor => anyhow::bail!("cannot resolve actor address to key address"),
ID => {
let id = address.id()?;
if let Some(cached) = self.id_to_deterministic_address_cache.get_cloned(&id) {
return Ok(cached);
}
let resolved = if let Ok(state) =
StateTree::new_from_root(self.blockstore_owned(), ts.parent_state())
&& let Ok(address) = state
.resolve_to_deterministic_addr(self.chain_store().blockstore(), address)
{
address
} else {
let TipsetState { state_root, .. } = self.load_tipset_state(ts).await?;
let state = StateTree::new_from_root(self.blockstore_owned(), &state_root)?;
state.resolve_to_deterministic_addr(self.chain_store().blockstore(), address)?
};
self.id_to_deterministic_address_cache.push(id, resolved);
Ok(resolved)
}
}
}
}