Skip to content
Tenzro
Documentation menu
Compute, data and storage

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

  1. 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.
  2. 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.
  3. Prove. Every epoch the provider answers a proof-of-retrievability challenge.
  4. Pay. A passing proof moves one byte-epoch slice from the consumer's prepaid balance to the provider. A miss moves nothing.
  5. 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:

OutcomeMeaning
ChargedThe proof passed; one byte-epoch slice moved to the provider
MissedThe proof failed or was not answered; nothing moved
ClosedThe 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.

PolicyWho may read
publicAnyone; only the owner administers
owner_onlyOnly the owner DID. The default.
did_allowlistA named set of DIDs
capability_requiredHolders 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.

bash
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>
bash
curl -s https://rpc.tenzro.xyz/v1/files \
  -H "X-Tenzro-Api-Key: $TENZRO_API_KEY" \
  -F purpose=fine_tune -F file=@dataset.parquet

Build 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.

bash
# 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...
MethodAccess
tenzro_storageStoreObjectowner
tenzro_storageOpenDealowner (the renter signs)
tenzro_storageGetDeal, tenzro_storageStatusopen
tenzro_prepaidDeposit, tenzro_prepaidWithdrawowner
tenzro_prepaidBalanceopen
tenzro_storageSetPricing, tenzro_storageChargeEpochadmin (the provider's operator)

Become a storage provider

Run a node with the storage role and bond for the capacity you offer:

bash
tenzro-node --roles storage --data-dir ./data
tenzro stake deposit <amount> --provider-type storage --terabytes 8

See Operators and roles and the provide and rent storage tutorial.