Storage Service

Storage service is like a constants service, but for variables.

While its declaration might looks monstrous:

interface SubstrateStorage {
    fun find(moduleName: String, itemName: String): Flow<FindStorageItemResult?>
    fun <T: Any> fetch(moduleName: String, itemName: String, type: KClass<T>): Flow<T?>
    fun <T: Any> fetch(moduleName: String, itemName: String, key: ByteArrayConvertible, type: KClass<T>): Flow<T?>
    fun <T: Any> fetch(moduleName: String, itemName: String, keys: List<ByteArrayConvertible>, type: KClass<T>): Flow<T?>
    suspend fun <T: Any> fetch(item: RuntimeModuleStorageItem, storage: RuntimeModuleStorage, type: KClass<T>): T?
    suspend fun <T: Any> fetch(
        item: RuntimeModuleStorageItem,
        key: ByteArrayConvertible,
        storage: RuntimeModuleStorage,
        type: KClass<T>
    ): T?
    suspend fun <T: Any> fetch(
        item: RuntimeModuleStorageItem,
        keys: List<ByteArrayConvertible>,
        storage: RuntimeModuleStorage, type: KClass<T>
    ): T?
}

It is practically divided into 3 behaviors.

Finding storage item

Yes, again proxy method to the lookup service. So if you can want to find streamable value use this:

val client: SubstrateClient
val storageItemResult: FindStorageItemResult = client.storage.find("System", "account")

This will give you exact item's flow, from where you can look at its contents for a debug purpose.

Result is not just storage item, but combination of this and its holding module storage class, for our internal library purpose:

data class FindStorageItemResult(
    val item: RuntimeModuleStorageItem, 
    val storage: RuntimeModuleStorage
)

But for more real life use there are fetch methods:

Fetch by lookup

val client: SubstrateClient
val keyPair: KeyPair

val account: Flow<Account?> = client.storage.fetch(
    module = "System",
    item = "account", 
    key = keyPair.publicKey.hex.encode(includePrefix = true).asByteArrayConvertible()
)

This exact method allows you to "subscribe" to the flow of your account details, but this flow is only updated by every runtime metadata change. You're free to combine this flow with whatever you want, like your balance updates event, to create always up to date assets balance for your application.

Depending on the storage item type, there might be no keys, or even multiple keys. Pleas refer to your network runtime metadata, or use find method to debug this item to see what keys are required if required at all.

Fetch by storage item

If you have storage item stored in your memory, like for continuous updates, there are several suspend functions to get the response:

val client: SubstrateClient
val keyPair: KeyPair
val storageItemResult: FindStorageItemResult // System/account find result

val account: Account? = client.storage.fetch(
    item = storageItemResult.item,
    storage = storageItemResult.storage, 
    key = keyPair.publicKey.hex.encode(includePrefix = true).asByteArrayConvertible()
)

Last updated