-
Notifications
You must be signed in to change notification settings - Fork 123
Description
As it came up in #2456, we need a way for components to read from an account's storage, no matter what form it comes in, i.e. AccountStorage, PartialStorage or AccountReader (defined in the client).
The general goal is:
impl NetworkFungibleFaucet {
pub async fn try_from_interface(
interface: AccountInterface,
storage: &impl AccountStorageInterface,
) -> Result<Self, AccountError> {
todo!("interface compatibility check; see https://github.com/0xMiden/protocol/issues/2621");
let metadata = TokenMetadata::try_from_storage(storage).await?;
Ok(Self { metadata })
}
}For this, the easiest way is to add a trait that abstracts over account storage, including the AccountReader which is async. Consequently, the trait methods must be async as well. I don't think this is problem, at least in the protocol repo we don't need to reconstruct components in sync code from what I can tell.
We would have to remove impl TryFrom<&Account> for BasicFungibleFaucet and similar wrappers, but these could be replaced with direct calls to try_from_interface.
The trait could look like this:
pub trait AccountStorageInterface {
fn get_item(
&self,
slot_name: &StorageSlotName,
) -> impl FutureMaybeSend<Result<Word, AccountError>>;
fn get_map_item(
&self,
slot_name: &StorageSlotName,
key: StorageMapKey,
) -> impl FutureMaybeSend<Result<Word, AccountError>>;
}
impl AccountStorageInterface for AccountStorage {
fn get_item(
&self,
slot_name: &StorageSlotName,
) -> impl FutureMaybeSend<Result<Word, AccountError>> {
future::ready(self.get_item(slot_name))
}
fn get_map_item(
&self,
slot_name: &StorageSlotName,
key: StorageMapKey,
) -> impl FutureMaybeSend<Result<Word, AccountError>> {
future::ready(self.get_map_item(slot_name, key.as_word()))
}
}
impl AccountStorageInterface for PartialStorage {
fn get_item(
&self,
slot_name: &StorageSlotName,
) -> impl FutureMaybeSend<Result<Word, AccountError>> {
// TODO: Implement PartialStorage::get_item for convenience
future::ready(Ok(self
.header()
.find_slot_header_by_name(slot_name)
.map(|header| header.value())
.unwrap_or_default()))
}
fn get_map_item(
&self,
_slot_name: &StorageSlotName,
_key: StorageMapKey,
) -> impl FutureMaybeSend<Result<Word, AccountError>> {
async { todo!("implement PartialStorage::get_map_item") }
}
}
impl TokenMetadata {
pub async fn try_from_storage(
storage: &impl AccountStorageInterface,
) -> Result<Self, FungibleFaucetError> {
let metadata_word =
storage.get_item(TokenMetadata::metadata_slot()).await.map_err(|err| {
FungibleFaucetError::StorageLookupFailed {
slot_name: TokenMetadata::metadata_slot().clone(),
source: err,
}
})?;
TokenMetadata::try_from(metadata_word)
}
}I'm not sure if we need FutureMaybeSend here, but I suspect if we want to use this in wasm, we do, while we also want Send bounds for non-wasm targets, though I'm not sure about the end users of this.
@igamigo could you check for compatibility with AccountReader? Thanks!