Distributed storage (SLOT1)

Topic: Java API

See other Java API features at Software Developer Central: Java API at whole, Contracts Service, Distributed Storage, etc.

To start using Java API, you can add com.icodici:universa_core:3.14.4 dependency from Universa public Maven repository. See more details at Maven repository page.

This feature is available in package com.icodici.universa.node2.network, as a part of Client class; see it on GitHub at  UniversaBlockchain/universa/…/network/Client.java.


Distributed storage is designed to provide secure distributed storage over the Universa network: each Universa node keeps its copy of the information and receives payment for it. The client can query the network for the information in the distributed storage and receive its copy from any node.

The balance

Universa keep information in the pre-paid storage slots where both storage space and time are charged. The unit to measure data storage for some period of time is a storage unit, which allows to store 1024 bytes of data for 24 hours, or, Kilo-Day, or KD.

As space and time could be traded, the 100kd is enough to keep 10kb of data for 10 days, or 100kb of data for 1 day.

It sounds more complex than it actually is. In fact, the system recalculates the number of storage days left each time the amount of stored data is changed. For example, you can keep one revision, and the new revisions may be both bigger and smaller than the first revision kept. Therefore the system recalculates storage time left every time the revision changes.

The KD rate

KD can be purchased for U (stage 1) and UTN (stage 2) only. The current rate can be achieved with special API call.

Storage slots

The SLOT is a simplest storage unit capable of keeping the latest revisions of some contract, tracked contract. User create a slot contract, prepays some KDs and puts some data in it. The slot keeps the contract and updates it as new revisions appear as long as the balance is positive and the new revision owner matches slot creator keys.

In the other words, one can prepay the keeping only own contracts, when ownership is transferred, the slot will not copy and retain contract data anymore. In that case, though, slot owner can update the slot with new keys to keep the track providing these are in its disposal.

Slots are manipulated by creating and updating special kind of Universa smart contract.

Other types of storage

We plan to add the general binary data storage to hold any type of information, stay tuned for updates.


Unless it is otherwise specified, all API calls are performed using Universa protected client channel using client key authorization.

Get the KD rate (under develop)

storageGetRate() -> { "U" : decimal_string }

Returns the rate at the call moment. There is no guarantee the rate will not be changed in the future.

Create a slot

The client creates a special contract type using the prepaid parcel with a minimum payment of 100U (which is roughly equivalent to €1). The smaller payment will not be accepted and the slot will not be created. The payment will be converted to KDs balance using the current KD rate as the prepaid balance.

The contract to store and track is stored inside the slot contract (in data section). The prepaid balance should be enogh to keep the stored contract for 30 days. In other words, if the transaction pack of the stored contract takes 8kb of disk space, the prepaid balancs should be at least 240KD. If it is less, the slot contract will not be approved and the slot will not be created.

  • definition.extended_type: SLOT1 (note that definition.extended_type is not available for free usage, unlike definition.data so this key won't be misused by occasion).

  • creator role: sign in with all keys needed to play owner role in the tracking contract

  • state.data.tracking_contract: the transaction pack with contract data to store and track. Note that the contract will always be accepted as long as the balance is above minimal, but its newer revisions will be tracked only as long as new revision owner role can be played with lates slot contract revision creator keys. E.g. one can store anything, but can track only own changes.

  • state.data.keep_revisions: (int): positive number. Will keep up to specified number of revisions. Older revisions will be dropped automatically.

  • modify_data permission on data.action field, better allowed for owner role. It is important to perform actions such as top up the balance or close the slot passing the remaining balance to another slot.

It is important to add permissions to modify tracking contract and keep_revisions field to be able to edit slot settings.

The Node checks that the slot is OK and balance is enough, and then registers the contract as usual and creates the storage slots, returning a slot state extra result (ItemResult#extra).

Slot state structure

    slot_id: binary, 
    expires_at: unixtime, 
    data_size: int_bytes,
    tracking_origin: binary_ID,
    revisions: [
        { revision: int, id: binary_ID, size: int_size_in_bytes }
  • slot_id: is the origin of the slot contrat

  • expires_at: time to slot expiration providing no data will be changed.

  • data_size: number of bytes used with all revisions kept

  • tracking_origin: the origin of the tracking contract

  • revisions: revisions in the storage, for each the revition number and id are returned.

Note that the slot contract is also kept in the distributed storage and its size is counted in data_size, so the data_size > sum(revisions.size) so the difference is the slot contract size.

Change the slot

Is performed by approving new version of the slot contract, as usual, like chaging the tracking contract, changing the number of kept revisions and so on.

Important. When the tracking contract is being reassigned, it clears the storage, so all the information in it will be lost.

Returns the slot state structure, as slot creation does.

If the change is made with a paying parcel, the extra payment will top up the slot balance.

Top up the balance

Create a new revision with a paying parcel with desired payment, set the data.action: top_up/(timestamp) where timestamp should be current unix timestamp.

Returns the slot state structure.

Close the slot

Under considering.

Querying the slot info (under develop)

Is performed using an authenticated API call:

queryContract(slot_id: binary) 
    -> (slot state structire)

Getting the stored contract

Is performed using an authenticated API call:

queryContract(slot_id: binary, origin_id: binary, contract_id: binary)
   -> binary

Only one origin_id or contract_id is allowed. For the origin_id the latest revision will be returned.