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.
| Method | Path | Body or answer |
|---|---|---|
GET | /v1/health | Node ID, epoch and shards. |
GET | /v1/blobs/<blob ID>/status | Registration status of the blob. |
PUT | /v1/blobs/<blob ID>/metadata | Body: BCS BlobMetadata. |
GET | /v1/blobs/<blob ID>/metadata | Answer: 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/permanent | Signed 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.endEpochis the latest end epoch,isCertifiedsays whether one of them is certified andobjectscounts theBlobobjects that register this blob ID.
Storing a blob
This is what a client does to store a blob after registering it on IOTA:
PUT …/metadataon 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.PUT …/slivers/<pair>/primaryand…/secondaryfor 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).GET …/confirmation/permanentor…/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 (
BlobCertifiedwithis_extension) extends the end epoch of thatBlob; - when a blob ID has no valid registration left, because all its
Blobobjects expired or were deleted withdelete_blob, the nodes delete its data; - burning a
Blobemits 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.