Decentralised storage
Store data with bonded providers: erasure-coded shards, a proof of retrievability every epoch, and payment per byte-epoch only when the proof passes.
Any node with spare disk can hold data for the network and be paid for it. A home server, a homelab NAS or a data centre rack all join the same market. Consumers pay per byte per epoch, and they pay only for epochs in which the provider proves it still holds the data. Providers back that promise with a bond.
How it works
- Store. An object is erasure-coded into data and parity shards and published over the iroh data plane. Each shard is content-addressed, so anyone who fetches it can check it.
- Open a deal. The consumer opens a deal with a provider for a number of epochs. The per-epoch price is the object size times the provider's rate per byte-epoch.
- Prove. Every epoch the provider answers a proof-of-retrievability challenge.
- Pay. A passing proof moves one byte-epoch slice from the consumer's prepaid balance to the provider. A miss moves nothing.
- Enforce. Repeated misses end the deal, refund the unearned remainder, slash the provider's bond and re-replicate the object to a healthy provider.
Erasure coding
Objects are split into data shards and parity shards and spread across providers. The object can be rebuilt from any sufficient subset, so losing a provider does not lose the data. Files uploaded through /v1/files use four data and two parity shards, which survives any two providers disappearing at once. On the market layer you choose the scheme yourself.
Proof of retrievability
A challenge samples a subset of an object's shards. The provider fetches those shards and returns a digest keyed to a fresh nonce for that challenge. A stale or precomputed answer fails, and a provider that has dropped the data cannot produce the digest. Sampling means the provider must really hold the data, without the network re-downloading the whole object every epoch.
Each epoch settles to one of three outcomes:
| Outcome | Meaning |
|---|---|
Charged | The proof passed; one byte-epoch slice moved to the provider |
Missed | The proof failed or was not answered; nothing moved |
Closed | The deal reached its term or ran out of coverage |
Bonded SLAs
A storage provider bonds TNZO against the capacity it offers. The bond is the provider's SLA: it covers what the provider owes across every open deal, and it is what gets slashed when retrievability fails. A provider cannot open a deal its bond cannot cover on top of everything else it owes, including any compute rentals on the same node, because storage and compute share one coverage budget per provider.
The meter and the penalty are separate. The meter only ever moves value between consumer and provider. Slashing is applied by the network from the record of misses, and the slashed bond is burned. See SLA attestation and metering and Slashing.
Pricing
Storage is priced per byte-epoch, billed as it is used. A provider chooses:
- Fixed: a flat rate per byte-epoch;
- Network-dynamic: a rate that follows storage utilisation across the network through an EIP-1559-style controller, with a gentler curve than compute because storage commitments last longer.
Consumers fund a prepaid balance once. Each epoch streams a slice out of it, a miss returns that slice to the withdrawable balance, and anything unspent can be withdrawn at any time. Prepaid balances survive node restarts.
Access control
Every stored object has an owner and an access policy. Retrieval is checked before any shard is returned.
| Policy | Who may read |
|---|---|
public | Anyone; only the owner administers |
owner_only | Only the owner DID. The default. |
did_allowlist | A named set of DIDs |
capability_required | Holders of a capability token for the read action |
Store files as a developer
The tenant layer, /v1/files, is shaped like a familiar files API. The subject of your API key owns the file, a deal opens on upload, and filenames come back on every listing. Every route, reads included, needs an X-Tenzro-Api-Key with the storage scope, and other tenants' files are indistinguishable from files that do not exist.
tenzro files upload ./dataset.parquet --purpose fine_tune
tenzro files list
tenzro files download <file_id> --out ./dataset.parquet
tenzro files usage
tenzro files delete <file_id>curl -s https://rpc.tenzro.xyz/v1/files \
-H "X-Tenzro-Api-Key: $TENZRO_API_KEY" \
-F purpose=fine_tune -F file=@dataset.parquetBuild on the market layer
The market layer addresses objects by an id you choose and leaves ownership, funding and naming to you. Use it to build your own storage product.
# Erasure-code and publish an object
tenzro node storage store --object-id weights-v3 --owner 0x... --file ./weights.gguf \
--data-shards 4 --parity-shards 2
# Fund a prepaid balance, then open a deal
tenzro escrow prepaid-deposit --renter 0x... --amount 5000000000000000000
tenzro node storage open-deal --object-id weights-v3 --renter 0x... \
--size-bytes 4200000000 --total-epochs 720
tenzro node storage deal --deal <deal_id>
tenzro escrow prepaid-balance --renter 0x...| Method | Access |
|---|---|
tenzro_storageStoreObject | owner |
tenzro_storageOpenDeal | owner (the renter signs) |
tenzro_storageGetDeal, tenzro_storageStatus | open |
tenzro_prepaidDeposit, tenzro_prepaidWithdraw | owner |
tenzro_prepaidBalance | open |
tenzro_storageSetPricing, tenzro_storageChargeEpoch | admin (the provider's operator) |
Become a storage provider
Run a node with the storage role and bond for the capacity you offer:
tenzro-node --roles storage --data-dir ./data
tenzro stake deposit <amount> --provider-type storage --terabytes 8See Operators and roles and the provide and rent storage tutorial.
Related
- Databases, for queryable data rather than objects
- Compute rental, which shares the same bond
- Machine Economy