Skip to main content

Storage nodes

The storage nodes keep the metadata and the slivers of the blobs registered on IOTA, for the shards they hold, and sign the confirmations used to certify blobs. Their API takes and returns BCS for the data and JSON for everything else, and allows calls from any web page (CORS).

Most users never call it directly: the app, the reference client and the aggregator do.

Nodes: https://nodo-1.iotastorage.com to https://nodo-4.iotastorage.com. Each node's network address is registered on IOTA (nodo-N.iotastorage.com:443); clients use HTTPS for addresses on port 443. The current committee is listed by the aggregator's /v1/estado.

MethodPathBody or answer
GET/v1/healthNode ID, epoch and shards.
GET/v1/blobs/<blob ID>/statusRegistration status of the blob.
PUT/v1/blobs/<blob ID>/metadataBody: BCS BlobMetadata.
GET/v1/blobs/<blob ID>/metadataAnswer: BCS BlobMetadataWithId.
PUT/v1/blobs/<blob ID>/slivers/<pair>/<primary or secondary>Body: BCS SliverData.
GET/v1/blobs/<blob ID>/slivers/<pair>/<primary or secondary>Answer: BCS SliverData.
GET/v1/blobs/<blob ID>/confirmation/permanentSigned confirmation for a permanent blob.
GET/v1/blobs/<blob ID>/confirmation/deletable/<object ID>Signed confirmation for the deletable Blob with that object ID.

<pair> is the index of a sliver pair, from 0 to the number of shards minus one. The shard of each pair is rotated by the blob ID.

Envelopes​

JSON answers use this envelope:

{ "success": { "code": 200, "data": … } }
{ "error": { "code": 400, "message": "…" } }

Metadata and slivers are sent and returned as raw BCS bytes (application/octet-stream). A request body can be up to 64 MiB.

Health​

curl https://nodo-1.iotastorage.com/v1/health
{
"success": {
"code": 200,
"data": { "nodeId": "0x…", "epoch": 1, "shards": [25, 26, 27, "…", 49] }
}
}

nodeId is the ID of the node's staking pool on IOTA; shards are the shards it holds in the current epoch.

Status of a blob​

data is one of:

  • "nonexistent": no valid registration;
  • { "invalid": {} }: the blob ID was marked invalid on IOTA;
  • { "permanent": { "endEpoch", "isCertified", "objects" } } if there is a permanent registration, or { "deletable": { … } } if all are deletable. endEpoch is the latest end epoch, isCertified says whether one of them is certified and objects counts the Blob objects that register this blob ID.

Storing a blob​

This is what a client does to store a blob after registering it on IOTA:

  1. PUT …/metadata on every node. The node accepts it only if the blob is registered and still valid, the metadata matches the blob ID and the registered size.
  2. PUT …/slivers/<pair>/primary and …/secondary for each pair whose shard the node holds. A sliver for a shard of another node is rejected with 421. The node checks the shape of the sliver (pair, type, size).
  3. GET …/confirmation/permanent or …/confirmation/deletable/<object ID>. The node signs only if it has the metadata and all its slivers of the blob:
{
"success": {
"code": 200,
"data": { "signed": { "serializedMessage": "<base64>", "signature": "<base64>" } }
}
}

The message is a StorageConfirmation (epoch, blob ID and, for a deletable blob, its object ID), signed with the node's BLS key. The client aggregates the signatures of nodes holding a quorum of shards and certifies the blob on IOTA with certify_blob.

Reading a blob​

A reader gets the metadata from any node, checks it against the blob ID, then downloads primary slivers from the nodes until it has n − 2f of them (34 with 100 shards), decodes them and checks the blob ID of the result.

Data retention​

Nodes follow the events of the almacen package on IOTA:

  • a renewal (BlobCertified with is_extension) extends the end epoch of that Blob;
  • when a blob ID has no valid registration left, because all its Blob objects expired or were deleted with delete_blob, the nodes delete its data;
  • burning a Blob emits no event, so the nodes keep the data until its end epoch.

Not implemented yet​

Checking each sliver against its hash (it requires expanding it with Reed–Solomon), recovering slivers from other nodes, migrating shards when the committee changes, storage challenges, inconsistency proofs and TLS with the node's network key. A node that was stopped sees the blobs registered meanwhile, but does not recover their slivers. See the roadmap.