Implement `AccountStorageInterface` to abstract over account storage
- Lingua principale
- Rust
- Stelle
- 132
- Fork
- 167
- Merge medio
- 1g 23h
- PR unite (30g)
- 110
Descrizione
As it came up in https://github.com/0xMiden/protocol/issues/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](https://github.com/0xMiden/miden-client/blob/6fa0454a15521293d35259d9e99f93b19470a80f/crates/rust-client/src/account/account_reader.rs#L40-L43)).
The general goal is:
```rust
impl NetworkFungibleFaucet {
pub async fn try_from_interface(
interface: AccountInterface,
storage: &impl AccountStorageInterface,
) -> Result {
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:
```rust
pub trait AccountStorageInterface {
fn get_item(
&self,
slot_name: &StorageSlotName,
) -> impl FutureMaybeSend>;
fn get_map_item(
&self,
slot_name: &StorageSlotName,
key: StorageMapKey,
) -> impl FutureMaybeSend>;
}
impl AccountStorageInterface for AccountStorage {
fn get_item(
&self,
slot_name: &StorageSlotName,
) -> impl FutureMaybeSend> {
future::ready(self.get_item(slot_name))
}
fn get_map_item(
&self,
slot_name: &StorageSlotName,
key: StorageMapKey,
) -> impl FutureMaybeSend> {
future::ready(self.get_map_item(slot_name, key.as_word()))
}
}
impl AccountStorageInterface for PartialStorage {
fn get_item(
&self,
slot_name: &StorageSlotName,
) -> impl FutureMaybeSend> {
// 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> {
async { todo!("implement PartialStorage::get_map_item") }
}
}
impl TokenMetadata {
pub async fn try_from_storage(
storage: &impl AccountStorageInterface,
) -> Result {
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!
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.