Skip to content

Storage

Ishinka edited this page May 12, 2022 · 3 revisions

This component contains abstractions which allow to interact with blockchain's data storage items.

The StorageNMap interface represents the proxy to the storage of data in a blockchain that persists between the blocks.

Normally storage items are used as part of the Pallet API.

Get the Value by Key(s)

The get method of StorageNMap receives one or more keys depending on the storage item type or no key in case of the StorageValue type and returns the requested value.

The example below shows how to get the hash of the block of number 0 from the BlockHash storage of the System pallet which has a single key and returns the values of BlockHash type:

SystemPallet systemPallet = api.pallet(SystemPallet.class);
CompletableFuture<BlockHash> blockHash = systemPallet
        .blockHash()
        .get(0);

Get the Value by Key(s) Starting at a Specific Block

The at method of StorageNMap receives BlockHash of the block used as a starting point for searching the requested value for the entry keys specified.

The example below shows how to get sudo account from the Key storage of the Sudo pallet starting from the genesis block (the storage item has no key and returns values of AccountId type):

BlockHash genesis = api.rpc.chain().getBlockHash(0).join();

CompletableFuture<AccountId> blockHash = sudoKeyStorage.at(genesis);

Get Remaining Keys, Entries of which Start from the Given Keys (the method can be called with no arguments):

The keys method of StorageNMap returns a collection of keys, each item of which contains the remaining keys of the entry.

SystemPallet systemPallet = api.pallet(SystemPallet.class);

// get a collection that can be iterated or used for a multi-query
KeyCollection<BlockHash> keyCollection = systemPallet
        .blockHash()
        .keys()
        .join();


// Iterate the collection of the keys and add them into the list
List<Integer> listOfKeys = new ArrayList<>();
keyCollection
        .iterator()
        .forEachRemaining(c -> c.consume(keys -> listOfKeys.add((Integer) keys.get(0))));


// Request the collection of values by these keys
KeyValueCollection<BlockHash> valueCollection = keyCollection
        .multi()
        .execute
        .join();


// Iterate the collection of the values and add them into the list
List<BlockHash> listOfValues = new ArrayList<>();
valueCollection
        .iterator()
        .forEachRemaining(e -> e.consume((value, keys) -> listOfValues.add(value)));

Also the keysAt and keysPaged methods are available which bring almost the same functions.

The keysAt method returns a collection of keys starting from the block, hash of which is passed as the argument.

The keyPaged method returns a collection of keys in portions with a specific size.

Execute a Multi-query Involving Different Storage Items

The query method of StorageNMap wraps a request to the storage and allows it to be combined with other requests.

QueryableKey<AccountId> getSudo = sudoKeyStorage.query();
QueryableKey<BlockHash> getBlockHash = systemPallet
        .blockHash()
        .query(0); // make a query for getting hash of the block with the number 0

// Execute both queries for the single request 
MultiQuery<Object> multiQuery = getSudo.join(getBlockHash);
KeyValueCollection<Object> valueCollection = multiQuery.execute().join();

// Iterate the collection of the values and add them into the list
List<Object> listOfValues = new ArrayList<>();
valueCollection
        .iterator()
        .forEachRemaining(e -> e.consume((value, keys) -> listOfValues.add(value)));

// Get sudo
AccountId sudo = (AccountId) list.get(0);

// Get the hash of the block
BlockHash hash = (BlockHash) list.get(1);

Get Remaining Keys and Proper Values, Entries of which Start from the Given Keys (the method can be called with no arguments):

The entries method returns a key-value collection, each item of which contains the remaining keys of the entry and its value.

SystemPallet systemPallet = api.pallet(SystemPallet.class);

// Get a collection
KeyValueCollection<BlockHash> entries = systemPallet
        .blockHash()
        .entries()
        .join();

// Iterate the collection of the entries and put keys and values into the map
Map<Integer, BlockHash> map = new HashMap<>();
entries
        .iterator()
        .forEachRemaining(e -> e.consume((value, keys) -> map.put((Integer) keys.get(0), value)));

Also the entriesPaged method is available that returns an iterator which provides a key-value collection in portions with a specific size.

Subscribe for Changes of the Storage

The subscribe method allows to subscribe for changes happening on storage item's entries with given args.

final int blockNumber = 2;

StorageNMap<BlockHash> storage = systemPallet
        .blockHash();
Supplier<CompletableFuture<Boolean>> unsubscribe = storage.subscribe((exception, block, v, keys) -> {
        if (exception == null) {
            // do something using the value, keys and the hash of the block where the change happened
        }
    }, Arg.of(blockNumber))
    .join();
Clone this wiki locally