ADR 013: Fibre API
ADR 013: Fibre API
Authors
@cmwaters
Changelog
- 2026-03-10: Initial version
Status
Proposed
Context
Celestia is introducing Fibre, a new data availability mechanism that disperses blob data across Fibre Service Providers (FSPs) using erasure coding, validator attestations, and a pre-funded escrow model.
Fibre differs from the existing blob flow in several important ways:
- Blob data is uploaded to FSPs instead of being stored directly in the data square.
- Retrieval reconstructs the original blob from rows fetched from FSPs.
- A Fibre blob is represented on-chain by a system-level share version
2blob. - Payment is based on escrow accounts and
MsgPayForFibre, rather than only on the existingPayForBlobflow.
At the same time, Fibre overlaps substantially with the existing blob UX:
- Users still submit data under namespaces.
- Included Fibre blobs still appear on-chain as namespaced blob data.
- Callers still need to enumerate blobs in namespaces and watch new blobs as they arrive.
The existing celestia-node blob module already exposes the main operations
applications use today:
SubmitGetGetAllSubscribe
This design should preserve that API wherever Fibre semantics match it, while also exposing Fibre-native functionality that does not fit cleanly into the blob module.
The design goals are:
- Integrate Fibre blobs into the blob module as much as possible
- Avoid breaking existing blob APIs
- Avoid multiple competing ways to perform the same common task
- Support mixed share versions within the same namespace
- Expose Fibre-specific account and data-plane functionality explicitly
Decision
Celestia Node will use a hybrid API design:
- The existing blob module will support Fibre share version
2wherever the semantics are compatible with the existing blob API. - A separate Fibre module will expose Fibre-native operations that are not a natural fit for the blob module, including escrow account management and Fibre-specific data-plane retrieval.
This means the blob module remains the primary API for chain-visible blob operations, while the Fibre module provides direct access to Fibre-specific workflows.
Detailed Design
Blob module
The blob module should absorb Fibre support where callers are still working with chain-visible blobs.
Submit
blob.Submit continues to accept a list of blobs and routes behavior by share
version:
Submit(ctx, blobs, opts)
- Share version
0or1- Use the existing
PayForBlobflow
- Use the existing
- Share version
2- Use the Fibre submission flow underneath
- Encode Fibre rows
- Upload rows to FSPs
- Collect validator signatures
- Submit
MsgPayForFibre
This keeps Fibre submission aligned with existing blob submission for callers who are already constructing blobs and choosing a share version.
Note: this will only return height and not the commitment. User will need to derive the commitment themself.
GetAll
blob.GetAll should support mixed namespaces that contain share versions 0,
1, and 2:
GetAll(ctx, height, namespaces)
For share version 2, the blob module returns the on-chain system-level Fibre
blob, because that is what is actually committed into the data square. This
keeps GetAll consistent with its current role as a namespaced on-chain blob
enumeration API.
Subscribe
blob.Subscribe should also support mixed namespaces and emit share version 2
blobs when a MsgPayForFibre results in a Fibre system blob being included:
Subscribe(ctx, namespace)
This preserves the existing subscription model for clients that watch namespace activity without requiring them to learn a second streaming API.
Get
blob.Get(ctx, height, namespace, commitment) should not be extended to Fibre
by assumption in this ADR.
The existing method is defined in terms of retrieving a specific on-chain blob by namespace and commitment from the data square. Fibre's native retrieval model is different: the client retrieves and reconstructs blob data from FSPs using the Fibre commitment. It is expected that a user should be ale to retreive the fibre system level blobs in the namespace.
This ADR therefore leaves blob.Get unchanged and treats Fibre support there as
follow-up work only if the method signature and semantics are confirmed to line
up.
Fibre module
The Fibre module should expose the Fibre-native operations that do not belong in the blob module.
Data-plane operations
The Fibre module should define its public types alongside its methods:
type Namespace = libshare.Namespace
type Commitment [32]byte
type ValidatorSignature []byte
type UploadResult struct {
Commitment Commitment
ValidatorSignatures []ValidatorSignature
PaymentPromise *PaymentPromise
RetentionUntil *time.Time
}
type SubmitResult struct {
Commitment Commitment
ValidatorSignatures []ValidatorSignature
Height uint64
TxHash string
PaymentPromise *PaymentPromise
RetentionUntil *time.Time
}
type PaymentPromise struct {
ChainID string
Namespace Namespace
BlobSize uint32
Commitment Commitment
RowVersion uint32
ValsetHeight uint64
CreationTimestamp time.Time
Signature []byte
}
type Module interface {
Upload(ctx context.Context, ns Namespace, data []byte) (UploadResult, error)
Submit(ctx context.Context, ns Namespace, data []byte) (SubmitResult, error)
Get(ctx context.Context, ns Namespace, commitment Commitment) ([]byte, error)
Account() AccountModule
}
Commitmentis the Fibre commitment:SHA256(rowRoot || rlcOrigRoot).UploadResultcaptures the artifacts produced by off-chain Fibre upload.SubmitResultextendsUploadResultwith the on-chain confirmation returned afterMsgPayForFibresubmission.PaymentPromiseis surfaced as a first-class type because it is central to both staged and full-service Fibre flows.Uploadperforms the Fibre upload flow optimized for low latency. It encodes the blob, constructs the payment promise, uploads rows to FSPs, and aggregates validator signatures. It should also submitMsgPayForFibrein the background to settle the payment, as long as this does not add latency to the Upload call itself. Upload returns as soon as the off-chain upload and signature collection is complete (~1 network round trip), without waiting for on-chain confirmation. This is the preferred method for latency-sensitive callers.Submitperforms the full Fibre upload flow and waits for on-chain confirmation. It includes payment promise construction, row upload, validator signature aggregation, andMsgPayForFibresubmission, blocking until the transaction is included in a block. This provides the caller with the confirmation height, at the cost of higher latency (~2x block time).Getretrieves and reconstructs the original Fibre blob from FSPs by Fibre commitment.
These are Fibre-native operations and should not compete with the blob module's chain-oriented APIs.
Upload exists for callers that prioritize low latency over on-chain
confirmation. Because it returns after off-chain upload without waiting for
block inclusion, a caller gets a response in roughly one network round trip to
FSPs, compared to Submit which adds at least one block time for MsgPayForFibre
confirmation. This makes Upload the right choice for latency-sensitive
applications that do not need to know the confirmation height immediately.
Upload should submit MsgPayForFibre in the background to ensure that the
Fibre payment is settled without requiring the caller to handle it. This avoids
relying on a separate timeout agent as the primary payment mechanism and keeps
the caller's interaction simple: one call, data is available, payment is handled.
The background submission must not block or delay the Upload response.
Escrow account management
The Fibre module should also expose escrow management methods derived from the
x/fibre account interface:
type PendingWithdrawal struct {
Amount sdk.Coin
AvailableAt time.Time
CreationHeight uint64
}
type EscrowAccount struct {
Signer string
CurrentBalance uint64
AvailableBalance uint64
}
type AccountModule interface {
QueryEscrowAccount(ctx context.Context, signer string) (*EscrowAccount, error)
Deposit(ctx context.Context, signer string, amount sdk.Coin) (*EscrowAccount, error)
Withdraw(ctx context.Context, signer string, amount sdk.Coin) (*PendingWithdrawal, error)
PendingWithdrawals(ctx context.Context, signer string) ([]PendingWithdrawal, error)
}
These functions are Fibre-specific operations and do not belong in the blob module.
Rationale
This design balances integration with clarity.
Preserve one API for overlapping blob workflows
Submit, GetAll, and Subscribe are still fundamentally blob-module
operations, even when share version 2 is involved. Keeping them in blob
avoids fragmenting the common application path for submitting blobs and
enumerating namespace contents.
Avoid forcing Fibre-native behavior into blob APIs
Escrow management and Fibre data-plane retrieval are not generic blob concerns. Placing them in a dedicated Fibre module keeps the blob API simpler and makes the Fibre surface explicit.
Support both low-latency and confirmed Fibre flows
Fibre enables two distinct latency profiles:
Upload(~1 round trip): The blob is erasure coded, uploaded to FSPs, and validator signatures are collected. The caller gets a response as soon as the data is available on the DA layer, without waiting for Celestia consensus.MsgPayForFibreis submitted in the background to settle the payment. This is the lowest latency path and is the main advantage Fibre offers over the existingPayForBlobflow.Submit(~2x block time): Same as Upload, but blocks untilMsgPayForFibreis confirmed on-chain. The caller gets the confirmation height, which is needed for applications that require Celestia consensus ordering.
Having both methods avoids forcing latency-sensitive callers to wait for chain confirmation they don't need, while still providing a simple single-call path for callers that do need ordering or finality.
Note: Upload submitting MsgPayForFibre in the background is a deliberate
design choice. The payment must be settled to avoid losing escrow funds, and
making this automatic removes the burden from callers. This is not the same as
relying on a timeout agent — the PFF is submitted proactively after every
upload, the agent is only a backup for edge cases where submission fails.
Avoid premature coupling on blob.Get
The blob.Get signature assumes a specific lookup model based on an on-chain
blob commitment at a given height. Fibre's native Get is defined by Fibre
commitment and FSP retrieval semantics. Treating them as the same without
verification would overload the API with ambiguous semantics.
Consequences
Positive
- Existing blob users can adopt Fibre incrementally through share version
2. - Namespace enumeration and subscription continue to work through the blob module across mixed share versions.
- Fibre-specific capabilities are exposed explicitly instead of being hidden in blob-module options.
- Callers can choose between a staged
Uploadflow and a fullSubmitflow. - The API separates chain-visible blob workflows from Fibre-native escrow and retrieval workflows.
Negative
- Fibre functionality is split across two modules.
blob.Getremains asymmetric withSubmit,GetAll, andSubscribeuntil a follow-up decision confirms whether Fibre belongs there.- Implementations must clearly document the difference between on-chain Fibre system blobs and Fibre-native reconstructed blob data.
Alternatives Considered
Blob-only design
One alternative is to force all Fibre functionality into the blob module.
Rejected because escrow account management and Fibre-native Upload, Submit,
and Get are
not natural blob-module operations and would make the blob API carry
Fibre-specific concepts.
Fully separate Fibre API
Another alternative is to introduce a completely separate Fibre API for submit, enumeration, and subscription.
Rejected because it would duplicate the blob module's role for common operations, fragment the user experience, and make mixed-version namespaces more awkward to work with.
Extend blob.Get immediately
Another alternative is to define Fibre support for blob.Get now.
Rejected for now because the lookup key and retrieval semantics have not yet been shown to match the current blob API cleanly.
References
- ADR 009: Public API
- Blob service implementation
- Blob type and share version handling
- Client Blob API usage examples
- go-square Fibre share version 2 layout
- celestia-app Fibre core types (
PaymentPromise,EscrowAccount,Withdrawal) - celestia-app Fibre query API (
EscrowAccount,Withdrawals,ValidatePaymentPromise) - celestia-app Fibre tx API (
MsgPayForFibre, escrow deposit, withdrawal)