0xMiden / 0xMiden/protocol

Implement `AccountStorageInterface` to abstract over account storage

未關閉
#2,623 2 則留言 1 個 reaction 已指派 0 人 在 GitHub 檢視
rust
主要語言
Rust
星號
132
分支
167
平均合併
1 天 23 小時
30 天內合併 PR
110

描述

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!

貢獻指南

開啟貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。