Binary Storage
Oak Chain stores large binaries in IPFS, with CID references in Oak. Validators store CIDs only (46 bytes), not the binaries themselves.
Why This Matters
Binary handling drives cost, latency, and trust. Mixing binary blobs into consensus storage creates unnecessary load and weak operational clarity.
What You'll Prove
- You can keep consensus state lean by storing CID references in Oak.
- You can host binaries independently while preserving verifiable integrity.
- You can serve media through edge infrastructure without losing provenance.
Next Action
Follow the upload and retrieval flow below to publish one binary and verify its CID-backed integrity end-to-end.
The Truth → Provenance → Edge Flow
This is the beautiful insight: Oak Chain is the source of truth (CIDs), while binaries flow through author storage to edge CDNs.
How It Works
- Oak Chain stores the CID (content-addressed hash). This is the truth.
- Author hosts the binary (IPFS, Azure Blob, or pinning service). This is provenance.
- Edge CDN caches the binary globally (Cloudflare R2, Fastly). This is delivery.
- User can verify binary integrity by hashing and comparing to the CID
Why This Is Beautiful
| Property | Benefit |
|---|---|
| Immutable provenance | CID in Oak Chain proves what the binary SHOULD be |
| Decentralized truth | Validators consensus on CID, not on binary storage |
| Perfect cache key | CID never changes = CDN can cache forever |
| Trustless verification | Anyone can hash binary and compare to Oak Chain CID |
| Economic separation | Validators handle consensus, authors handle storage, CDN handles delivery |
Architecture
Why IPFS?
| Benefit | Description |
|---|---|
| Content-addressed | CID = hash of content, immutable |
| Decentralized | No single point of failure |
| Deduplication | Same content = same CID |
| Author-owned | Authors control their storage |
How It Works
1. Author Uploads to IPFS
# Upload binary to IPFS
ipfs add my-image.jpg
# Returns: QmXyz...abc (CID)2. Author Writes CID to Oak
curl -X POST http://localhost:8090/v1/propose-write \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "proposalId=0x1111111111111111111111111111111111111111111111111111111111111111" \
-d "walletAddress=0x742d35Cc..." \
-d "organization=PixelPirates" \
-d "message={\"jcr:primaryType\":\"dam:Asset\",\"jcr:content\":{\"renditions\":{\"original\":{\"ipfs:cid\":\"QmXyz...abc\",\"jcr:mimeType\":\"image/jpeg\",\"size\":1048576}}}}" \
-d "contentType=dam:Asset" \
-d "ethereumTxHash=0x..." \
-d "signature=0x..."3. Readers Fetch from IPFS
# Get metadata from Oak
curl "http://localhost:8090/api/explore?path=/oak-chain/.../content/dam/images/hero"
# Response includes CID
{
"renditions": {
"original": {
"ipfs:cid": "QmXyz...abc",
...
}
}
}
# Fetch binary from IPFS gateway
curl https://ipfs.io/ipfs/QmXyz...abc > image.jpgDirect Binary Access
For performance, use direct IPFS access:
async function getAsset(path) {
// 1. Get metadata from Oak
const meta = await fetch(`http://validator:8090/api/explore?path=${encodeURIComponent(path)}`);
const { renditions } = await meta.json();
// 2. Get binary from IPFS (direct, no validator)
const cid = renditions.original['ipfs:cid'];
const binary = await fetch(`https://ipfs.io/ipfs/${cid}`);
return binary.blob();
}Storage Model
Validators Store CIDs Only
Validator Storage:
├── Oak Segments (structured content + CIDs)
└── NO binary blobsAuthors Own Binaries
Authors are responsible for:
- Uploading to IPFS
- Pinning (ensuring availability)
- Paying for IPFS storage (Filecoin, Pinata, etc.)
This separates:
- Consensus (validators) - structured content
- Storage (IPFS) - binary blobs
Pinning Services
| Service | Description |
|---|---|
| Pinata | Managed IPFS pinning |
| Infura IPFS | Enterprise IPFS |
| Filecoin | Decentralized storage deals |
| web3.storage | Free tier available |
Example: Image Upload Flow
import { create } from 'ipfs-http-client';
const ipfs = create({ url: 'https://ipfs.infura.io:5001' });
async function uploadImage(file, wallet, org, proposalId, paymentTxHash) {
// 1. Upload to IPFS
const { cid } = await ipfs.add(file);
console.log('IPFS CID:', cid.toString());
// 2. Write metadata to Oak
const response = await fetch('http://validator:8090/v1/propose-write', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
proposalId,
walletAddress: wallet,
organization: org,
message: JSON.stringify({
'jcr:primaryType': 'dam:Asset',
'ipfs:cid': cid.toString(),
'jcr:mimeType': file.type,
'size': file.size,
'uploadedAt': new Date().toISOString()
}),
contentType: 'dam:Asset',
ethereumTxHash: paymentTxHash, // From payment
signature: '0x...' // Signed message
})
});
return { cid: cid.toString(), oakPath: response.path };
}For author-owned IPFS flows, the important fields are still proposalId, ethereumTxHash, signature, and the CID-backed metadata. If your payment flow uses a contract class, send the same paymentTier value with the write request.
Garbage Collection
When content is deleted from Oak:
- CID reference removed from Oak
- Binary remains in IPFS (content-addressed)
- Author can unpin if no longer needed
- IPFS GC eventually removes unpinned content
Next Steps
- Content Paths - Path structure
- Streaming - Real-time events