Quick reference for all available extrinsics in the storage provider pallet (pallet/src/lib.rs).
Register a new storage provider.
Parameters:
multiaddr:BoundedVec<u8, T::MaxMultiaddrLength>- network address (e.g./ip4/127.0.0.1/tcp/3333)publicKey:BoundedVec<u8, ConstU32<64>>- raw public key (32 bytes for Sr25519/Ed25519, 33 bytes for ECDSA)stake:BalanceOf<T>- Amount to stake (must be ≥MinProviderStake)
Example:
multiaddr: /ip4/127.0.0.1/tcp/3333
publicKey: 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d
stake: 1000000000000000 (1000 tokens, minimum required)
Token decimals:
- 1 token = 1,000,000,000,000 (12 decimals, like Polkadot)
- Minimum stake = 1000 tokens = 1,000,000,000,000,000
Default settings after registration — all zero / false. You must call updateProviderSettings before any agreement can be accepted.
Events: ProviderRegistered
Errors: ProviderAlreadyRegistered, InsufficientStake, InvalidPublicKey
Increase the provider's locked stake.
Parameters:
amount:BalanceOf<T>- additional amount to reserve
Example:
amount: 50000000000
Events: ProviderStakeAdded
Errors: ProviderNotFound, ArithmeticOverflow
Step 1 of a two-step exit. Announces deregistration: forces acceptingPrimary and acceptingExtensions to false, stamps deregister_at = now + DeregisterAnnouncementPeriod. Stake stays reserved and the provider remains slashable. Settings updates are blocked during the announcement window.
Parameters: none
Example:
// no parameters — caller is the provider account
deregisterProvider()
Preconditions: committed_bytes == 0 (no active agreements); no existing announcement.
Events: DeregisterAnnounced { complete_after }
Errors: ProviderNotFound, DeregisterAnnounced, ProviderHasActiveAgreements
Update pricing, availability, and capacity.
Parameters:
settings:ProviderSettings<T>minDuration:BlockNumber- minimum agreement durationmaxDuration:BlockNumber- maximum agreement durationpricePerByte:Balance- price per byte per blockacceptingPrimary:bool- accept new primary agreementsreplicaSyncPrice:Option<Balance>-Nonedisables replicas;Some(price)enables them at that per-sync priceacceptingExtensions:bool- accept agreement extensionsmaxCapacity:u64- maximum storage capacity in bytes (0= unlimited)
Example:
settings: {
minDuration: 100,
maxDuration: 10000,
pricePerByte: 1000000,
acceptingPrimary: true,
replicaSyncPrice: Some(5000000),
acceptingExtensions: true,
maxCapacity: 1099511627776 // 1 TB
}
Validation:
minDuration ≤ maxDuration- If
maxCapacity > 0:maxCapacity ≥ committed_bytesandstake ≥ maxCapacity × MinStakePerByte - Blocked while a deregistration announcement is pending
Events: ProviderSettingsUpdated
Errors: ProviderNotFound, DeregisterAnnounced, MinDurationExceedsMaxDuration, CapacityBelowCommitted, InsufficientStakeForCapacity
Per-bucket toggle that lets a provider refuse extendAgreement calls for one specific agreement without changing their global acceptingExtensions flag.
Parameters:
bucketId:BucketId(u64)blocked:bool
Example:
bucketId: 0
blocked: true
Events: ExtensionsBlocked
Errors: ProviderNotFound, AgreementNotFound, AgreementExpired
Update only the provider's network endpoint.
Parameters:
multiaddr:BoundedVec<u8, T::MaxMultiaddrLength>- new network address
Example:
multiaddr: /ip4/203.0.113.10/tcp/3333
Events: ProviderMultiaddrUpdated
Errors: ProviderNotFound
Step 2 of the two-step exit. Drains any pending checkpoint rewards into the provider's free balance, unreserves stake, and removes the provider record.
Parameters: none
Example:
// no parameters — caller is the provider account
completeDeregister()
Preconditions: previously announced (deregister_at set) and now ≥ deregister_at; still committed_bytes == 0.
Events: ProviderDeregistered { stake_returned }
Errors: ProviderNotFound, DeregisterNotAnnounced, DeregisterPeriodNotElapsed, ProviderHasActiveAgreements
Cancel a pending announcement. Clears deregister_at and restores acceptingPrimary / acceptingExtensions to true.
Parameters: none
Example:
// no parameters — caller is the provider account
cancelDeregister()
Events: DeregisterCancelled
Errors: ProviderNotFound, DeregisterNotAnnounced
Create an empty bucket; caller becomes its sole admin.
Parameters:
minProviders:u32- minimum primary-provider signatures required for a valid checkpoint
Example:
minProviders: 2
Returns: Emits BucketCreated event with assigned bucketId.
Events: BucketCreated { bucket_id, admin }
Errors: MaxMembersReached, TooManyBucketsForMember
One-shot helper: create a bucket, find the cheapest matching provider, and accept the primary agreement, all atomically.
Parameters:
maxBytes:u64- desired storage sizeduration:BlockNumber- agreement durationmaxPricePerByte:Balance- cap on provider'spricePerByte
Example:
maxBytes: 1073741824 // 1 GB
duration: 500
maxPricePerByte: 1000000
Events: BucketCreated, AgreementAccepted, ProviderAddedToBucket
Errors: NoMatchingProvider, PaymentExceedsMax, InsufficientStakeForBytes, CapacityExceeded, MaxMembersReached, TooManyBucketsForMember
Change the checkpoint signature threshold for an existing bucket.
Parameters:
bucketId:BucketId(u64)minProviders:u32- must not exceed the current primary-provider count
Example:
bucketId: 0
minProviders: 3
Errors: BucketNotFound, NotBucketAdmin, InvalidMinProviders
Freeze a bucket at the current snapshot's start_seq. Append-only afterwards; irreversible.
Parameters:
bucketId:BucketId(u64)
Example:
bucketId: 0
minProviders signatures.
Events: BucketFrozen { frozen_start_seq }
Errors: BucketNotFound, NotBucketAdmin, BucketFrozen, NoSnapshot, MinProvidersNotMet
Add a member or update an existing member's role.
Parameters:
bucketId:BucketId(u64)member:AccountId- account to add or updaterole:Role- one ofAdmin,Writer,Reader
Example:
bucketId: 0
member: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
role: Writer
Admin-quorum rules:
- Caller must be an admin.
- An admin can only demote themselves, never another admin →
CannotDemoteAdmin. - Self-demotion is rejected if it would leave the bucket with zero admins →
LastAdminCannotBeRemoved.
Events: MemberSet
Errors: BucketNotFound, NotBucketAdmin, CannotDemoteAdmin, LastAdminCannotBeRemoved, MaxMembersReached, TooManyBucketsForMember
Remove a member from a bucket. Same admin-quorum rules as setMember: admins can only remove themselves and never the last admin.
Parameters:
bucketId:BucketId(u64)member:AccountId
Example:
bucketId: 0
member: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
Events: MemberRemoved
Errors: BucketNotFound, NotBucketAdmin, MemberNotFound, CannotDemoteAdmin, LastAdminCannotBeRemoved
Permissionless cleanup. Anyone can call this to evict a slashed provider (one with stake == 0) from a bucket. The agreement's locked payment is returned to its owner; if the provider was a primary, it's removed from the bucket's primary list.
Parameters:
bucketId:BucketId(u64)provider:AccountId
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
Events: SlashedProviderRemoved, plus PrimaryProviderRemoved { reason: Slashed } if applicable
Errors: ProviderNotFound, ProviderNotSlashed, AgreementNotFound
Request a replica agreement (provider must have replicaSyncPrice: Some(_)).
Parameters:
bucketId:BucketId(u64)provider:AccountId- replica providermaxBytes:u64- storage sizeduration:BlockNumber- agreement durationmaxPayment:Balance- safety cap; must coverpricePerByte × maxBytes × durationreplicaParams:ReplicaRequestParams<Balance, BlockNumber>syncBalance:Balance- funds reserved up-front for future sync paymentsminSyncInterval:BlockNumber- rate-limit between confirmed syncs
Example:
bucketId: 0
provider: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
maxBytes: 1073741824 // 1 GB
duration: 500
maxPayment: 600000000000000000
replicaParams: {
syncBalance: 50000000,
minSyncInterval: 100
}
Funds reserved on request: storage payment plus syncBalance. The request expires if not accepted within RequestTimeout.
Events: AgreementRequested
Errors: BucketNotFound, ProviderNotFound, DeregisterAnnounced, ProviderNotAcceptingReplicas, DurationTooShort, DurationTooLong, PaymentExceedsMax, AgreementRequestAlreadyExists
Request a primary storage agreement. Caller must be a bucket admin.
Parameters:
bucketId:BucketId(u64)provider:AccountIdmaxBytes:u64- maximum storage sizeduration:BlockNumber- agreement duration in blocksmaxPayment:Balance- maximum payment willing to pay (safety cap)
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
maxBytes: 1073741824 // 1 GB
duration: 500
maxPayment: 600000000000000000
Payment calculation:
payment = pricePerByte × maxBytes × duration
payment = 1,000,000 × 1,073,741,824 × 500
payment = 536,870,912,000,000,000
Important: maxPayment must be ≥ calculated payment, or you'll get PaymentExceedsMax. Add a 10-20% buffer. See Payment Calculator.
Events: AgreementRequested
Errors: BucketNotFound, NotBucketAdmin, MaxPrimaryProvidersReached, ProviderNotFound, DeregisterAnnounced, ProviderNotAcceptingPrimary, DurationTooShort, DurationTooLong, PaymentExceedsMax, AgreementRequestAlreadyExists
Provider accepts a pending agreement request. Creates the StorageAgreement, starts the clock, and (for primaries) adds the provider to the bucket's primary list.
Parameters:
bucketId:BucketId(u64)
Example:
bucketId: 0
Note: Caller must be the provider specified in the request. Validates request hasn't expired (RequestTimeout) and that the provider has capacity headroom and enough stake (stake ≥ committed_bytes × MinStakePerByte).
Events: AgreementAccepted, plus ProviderAddedToBucket for primaries
Errors: ProviderNotFound, DeregisterAnnounced, AgreementRequestNotFound, RequestExpired, InsufficientStakeForBytes, CapacityExceeded, MaxPrimaryProvidersReached
Provider rejects a pending request; all reserved funds (payment + sync balance) return to the requester.
Parameters:
bucketId:BucketId(u64)
Example:
bucketId: 0
Events: AgreementRejected
Errors: AgreementRequestNotFound
Original requester rescinds a pending request before acceptance.
Parameters:
bucketId:BucketId(u64)provider:AccountId
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
Events: AgreementRequestWithdrawn
Errors: AgreementRequestNotFound, NotAgreementOwner
Extend an active agreement. Settles elapsed time at the old rate, then locks new payment at the provider's current rate for the additional duration.
Parameters:
bucketId:BucketId(u64)provider:AccountIdadditionalDuration:BlockNumbermaxPayment:Balance- cap on payment for the extension
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
additionalDuration: 500
maxPayment: 600000000000000000
Authorization:
- If the provider has raised their price, only the agreement owner can extend.
- If the price is the same or lower, anyone can extend (permissionless persistence — useful for frozen buckets).
Events: AgreementExtended
Errors: ProviderNotFound, DeregisterAnnounced, ProviderNotAcceptingExtensions, AgreementNotFound, AgreementExpired, AgreementExtensionsBlocked, DurationTooShort, DurationTooLong, PaymentExceedsMax, NotAgreementOwner
Owner increases the agreement's byte quota mid-term. Charges for the additional bytes over the remaining duration at the provider's current price.
Parameters:
bucketId:BucketId(u64)provider:AccountIdadditionalBytes:u64maxPayment:Balance- cap on payment for the additional bytes
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
additionalBytes: 536870912 // 0.5 GB
maxPayment: 300000000000000000
Events: AgreementToppedUp
Errors: ProviderNotFound, DeregisterAnnounced, AgreementNotFound, NotAgreementOwner, AgreementExpired, PaymentExceedsMax
End an agreement, either early or after expiry.
Parameters:
bucketId:BucketId(u64)provider:AccountIdaction:EndAction-Pay(release locked payment to provider) orBurn
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
action: Pay
Authorization:
- Early termination: only a bucket admin, and only for primary agreements (replicas can't be terminated mid-flight).
- After expiry: only the agreement owner, within the
SettlementTimeoutwindow.
Events: AgreementEnded, plus PrimaryProviderRemoved if applicable
Errors: AgreementNotFound, NotBucketAdmin, NotAgreementOwner, CannotTerminateReplica, SettlementWindowPassed
After the settlement window passes, the provider can claim the locked payment themselves.
Parameters:
bucketId:BucketId(u64)
Example:
bucketId: 0
Conditions:
now > expires_at + SettlementTimeout
Events: AgreementEnded (with full payment to provider)
Errors: AgreementNotFound, AgreementNotExpired
Client-initiated checkpoint. Submit an MMR root signed by primary providers.
Parameters:
bucketId:BucketId(u64)mmrRoot:H256- Merkle Mountain Range rootstartSeq:u64- starting sequence numberleafCount:u64- number of leaves in MMRsignatures:BoundedVec<(AccountId, MultiSignature), T::MaxPrimaryProviders>- provider signatures
Example:
bucketId: 0
mmrRoot: 0x1234567890abcdef...
startSeq: 0
leafCount: 10
signatures: [
(5GrwvaEF..., 0xsignature1...),
(5FHneW46..., 0xsignature2...)
]
Requirements:
- Caller is bucket writer or admin
- At least
minProvidersvalid signatures, each signer being a current primary - If the bucket is frozen,
startSeq ≥ frozen_start_seq
Events: BucketCheckpointed
Errors: BucketNotFound, NotBucketWriter, SnapshotViolatesFrozen, ProviderNotInSnapshot, InvalidSignature, InsufficientSignatures
Add late signatures to the current snapshot (e.g. for primaries that finished signing after the original checkpoint call).
Parameters:
bucketId:BucketId(u64)additionalSignatures:BoundedVec<(AccountId, MultiSignature), T::MaxPrimaryProviders>
Example:
bucketId: 0
additionalSignatures: [
(5FLSigC9..., 0xsignature3...)
]
Events: BucketCheckpointed (with the new signer set)
Errors: BucketNotFound, NotBucketWriter, NoSnapshot, ProviderNotInSnapshot, InvalidSignature
Provider-initiated checkpoint. Primary providers coordinate autonomously and submit on a fixed window cadence. Submitter receives CheckpointReward from the bucket's checkpoint pool (if funded).
Parameters:
bucketId:BucketId(u64)mmrRoot:H256startSeq:u64leafCount:u64window:u64- current window number (replay protection)signatures:BoundedVec<(AccountId, MultiSignature), T::MaxPrimaryProviders>
Example:
bucketId: 0
mmrRoot: 0x1234567890abcdef...
startSeq: 0
leafCount: 10
window: 42
signatures: [
(5GrwvaEF..., 0xsig1...),
(5FHneW46..., 0xsig2...)
]
Leader election: blake2_256(bucket_id || window) % primary_count. During the grace period only the elected leader may submit; afterwards any primary may submit (fallback).
Events: ProviderCheckpointSubmitted { window, leader, signers, reward }
Errors: BucketNotFound, ProviderCheckpointsDisabled, InvalidCheckpointWindow, CheckpointAlreadySubmitted, NotCheckpointLeader, ProviderNotInSnapshot, InvalidSignature, SnapshotViolatesFrozen, MinProvidersNotMet, InsufficientSignatures
Admin configuration for provider-initiated checkpoints on a bucket.
Parameters:
bucketId:BucketId(u64)interval:BlockNumber- blocks per windowgracePeriod:BlockNumber- leader-only window at the startenabled:bool
Example:
bucketId: 0
interval: 100
gracePeriod: 20
enabled: true
Events: CheckpointConfigUpdated
Errors: BucketNotFound, NotBucketAdmin
Permissionless. If a window's grace period expires without a checkpoint, anyone can report the leader: the leader is slashed by CheckpointMissPenalty and the reporter receives 10% as a bounty.
Parameters:
bucketId:BucketId(u64)window:u64
Example:
bucketId: 0
window: 42
Events: CheckpointMissPenalized
Errors: BucketNotFound, ProviderCheckpointsDisabled, InvalidCheckpointWindow, CheckpointAlreadySubmitted, WithinGracePeriod, ProviderNotInSnapshot
Provider claims accumulated rewards for a bucket.
Parameters:
bucketId:BucketId(u64)
Example:
bucketId: 0
Events: CheckpointRewardClaimed
Errors: NoRewardsToClaim
Permissionless. Anyone can top up a bucket's reward pool to incentivize provider-initiated checkpoints.
Parameters:
bucketId:BucketId(u64)amount:Balance- amount to add to the pool
Example:
bucketId: 0
amount: 100000000000000 // 100 tokens
Events: CheckpointPoolFunded
Errors: BucketNotFound
Challenge a primary provider against the current snapshot on chain. No signature needed: the snapshot itself is proof of commitment.
Parameters:
bucketId:BucketId(u64)provider:AccountIdleafIndex:u64- which leaf to challengechunkIndex:u64- which chunk within the leaf
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
leafIndex: 7
chunkIndex: 3
Deposit required: challenger must deposit collateral.
Events: ChallengeCreated
Errors: BucketNotFound, NoSnapshot, ProviderNotInSnapshot
Challenge a provider using an off-chain commitment signature. Works even when the on-chain snapshot has moved on — preferred for hot buckets.
Parameters:
bucketId:BucketId(u64)provider:AccountIdmmrRoot:H256startSeq:u64leafIndex:u64chunkIndex:u64providerSignature:MultiSignature- provider's signature over the commitment payload
Example:
bucketId: 0
provider: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
mmrRoot: 0x1234567890abcdef...
startSeq: 0
leafIndex: 7
chunkIndex: 3
providerSignature: 0xsig...
Events: ChallengeCreated
Errors: BucketNotFound, AgreementNotFound, InvalidSignature
Challenge a replica provider against the MMR root recorded by their last confirmReplicaSync. No signature needed.
Parameters:
bucketId:BucketId(u64)provider:AccountIdleafIndex:u64chunkIndex:u64
Example:
bucketId: 0
provider: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
leafIndex: 7
chunkIndex: 3
Events: ChallengeCreated
Errors: AgreementNotFound, NotReplica, InvalidSyncRoot
Provider defends an active challenge. Three response variants:
Proof { chunk_data, mmr_proof, chunk_proof }- present the chunk and Merkle proofDeleted { new_mmr_root, new_start_seq, admin, admin_signature }- show the bucket admin authorized deletionSuperseded- show the challenged state was overtaken by a newer canonical state
Parameters:
challengeId:ChallengeId<BlockNumber>response:ChallengeResponse<T>
Example:
challengeId: { bucket_id: 0, provider: 5Grwva..., created_at: 12345 }
response: Proof {
chunk_data: 0x...,
mmr_proof: [0xhash1..., 0xhash2...],
chunk_proof: [0xhash3...]
}
Cost split by response speed (challenger : provider):
| Response time | Split |
|---|---|
| Block 1 | 90 / 10 |
| Blocks 2-5 | 80 / 20 |
| Blocks 6-24 | 70 / 30 |
| Blocks 25-95 | 60 / 40 |
| Blocks 96+ | 50 / 50 |
Events: ChallengeDefended
Errors: ChallengeNotFound, NotChallengeProvider, ChallengeExpired, InvalidChallengeProof, InvalidDeletionProof, LeafBeyondCanonical
Replica provider confirms they have synced to one of the bucket's known MMR roots (current snapshot plus 6 historical entries). Deducts replicaSyncPrice from the agreement's syncBalance and pays the provider.
Parameters:
bucketId:BucketId(u64)roots:[Option<H256>; 7]- match candidates, indexed[current, hist_0, hist_1, hist_2, hist_3, hist_4, hist_5]_signature:MultiSignature- placeholder, currently unused
Example:
bucketId: 0
roots: [
Some(0xcurrentRoot...),
Some(0xhistRoot0...),
None,
None,
None,
None,
None
]
_signature: 0x...
Validation: matched root differs from the previously synced root; at least minSyncInterval blocks since last sync; syncBalance ≥ replicaSyncPrice.
Events: ReplicaSynced { position_matched, sync_payment }
Errors: AgreementNotFound, NotReplica, InvalidSyncRoot, SyncTooFrequent, InsufficientSyncBalance
Reserve additional funds for future sync payments on a replica agreement. Permissionless.
Parameters:
bucketId:BucketId(u64)provider:AccountIdamount:Balance- amount to add tosyncBalance
Example:
bucketId: 0
provider: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
amount: 50000000
Events: ReplicaSyncBalanceToppedUp
Errors: AgreementNotFound, NotReplica
enum Role { Admin, Writer, Reader }- Admin - manage members, request primary agreements, configure the bucket, terminate primaries
- Writer - submit checkpoints
- Reader - read-only
enum EndAction { Pay, Burn }enum ChallengeResponse<T> {
Proof { chunk_data, mmr_proof, chunk_proof },
Deleted { new_mmr_root, new_start_seq, admin, admin_signature },
Superseded,
}enum RemovalReason { Terminated, Expired, Slashed }For testing on local development network:
| Account | AccountId | Public Key (Sr25519) | Port |
|---|---|---|---|
| Alice | 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY |
0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d |
3333 |
| Bob | 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty |
0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48 |
3001 |
| Charlie | 5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y |
0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22 |
3002 |
1. registerProvider(multiaddr, publicKey, stake)
2. updateProviderSettings(settings) ← required to accept agreements!
1. createBucket(minProviders: 2)
2. requestPrimaryAgreement(bucketId, provider, maxBytes, duration, maxPayment)
3. [provider] acceptAgreement(bucketId)
Or in a single call:
createBucketWithStorage(maxBytes, duration, maxPricePerByte)
1. [provider with replicaSyncPrice=Some(p)] updateProviderSettings(...)
2. requestAgreement(bucketId, replicaProvider, ..., replicaParams { syncBalance, minSyncInterval })
3. [replica] acceptAgreement(bucketId)
4. [replica syncs from primary off-chain]
5. [replica] confirmReplicaSync(bucketId, roots, _signature)
1. [off-chain] collect signatures from primaries
2. checkpoint(bucketId, mmrRoot, startSeq, leafCount, signatures)
3. [optional] extendCheckpoint(...) with late signers
1. [admin] configureCheckpointWindow(bucketId, interval, gracePeriod, enabled=true)
2. [anyone, optional] fundCheckpointPool(bucketId, amount)
3. [leader] providerCheckpoint(bucketId, mmrRoot, startSeq, leafCount, window, signatures)
4. [provider] claimCheckpointRewards(bucketId)
// if leader misses:
5. [anyone] reportMissedCheckpoint(bucketId, window) // 10% bounty
// against current snapshot:
challengeCheckpoint(bucketId, provider, leafIndex, chunkIndex)
// against an off-chain commitment (hot buckets):
challengeOffchain(bucketId, provider, mmrRoot, startSeq, leafIndex, chunkIndex, providerSignature)
// against a replica:
challengeReplica(bucketId, provider, leafIndex, chunkIndex)
[provider] respondToChallenge(challengeId, response)
1. deregisterProvider() // step 1: announce (committed_bytes must be 0)
2. // wait DeregisterAnnouncementPeriod blocks
3. completeDeregister() // step 2: unreserve stake, drop record
// or change your mind:
cancelDeregister() // restores acceptingPrimary/Extensions
[anyone] removeSlashed(bucketId, slashedProvider) // permissionless
Common errors you might encounter:
| Error | Cause | Solution |
|---|---|---|
ProviderAlreadyRegistered |
Account already registered | Use a different account |
ProviderNotFound |
Account is not a registered provider | Register first |
InsufficientStake |
stake < MinProviderStake (1000 tokens) |
Use stake: 1000000000000000 |
InsufficientStakeForBytes |
New commitment would exceed stake / MinStakePerByte |
Increase stake or reduce bytes |
ProviderHasActiveAgreements |
committed_bytes > 0 at deregister |
Wait for agreements to end |
ProviderNotAcceptingPrimary |
Provider has acceptingPrimary=false |
Use a different provider |
ProviderNotAcceptingReplicas |
Provider has replicaSyncPrice=None |
Use a provider that accepts replicas |
ProviderNotAcceptingExtensions |
Provider has acceptingExtensions=false |
Use a different provider |
ProviderNotSlashed |
removeSlashed called on a non-slashed provider |
Only valid when stake == 0 |
CapacityBelowCommitted |
maxCapacity < committed_bytes |
Wait for agreements to expire or raise capacity |
CapacityExceeded |
Agreement would push committed bytes over maxCapacity |
Find a provider with more headroom |
InsufficientStakeForCapacity |
stake < maxCapacity × MinStakePerByte |
Increase stake or reduce capacity |
MinDurationExceedsMaxDuration |
Settings have minDuration > maxDuration |
Fix the values |
DeregisterAnnounced |
Operation blocked during announcement window | Call cancelDeregister to undo |
DeregisterNotAnnounced |
completeDeregister / cancelDeregister called before announcing |
Call deregisterProvider first |
DeregisterPeriodNotElapsed |
Too early to complete | Wait for deregister_at |
BucketNotFound |
Invalid bucket ID | Check bucket exists |
BucketFrozen / BucketNotFrozen |
Operation requires opposite state | — |
NotBucketAdmin / NotBucketMember / NotBucketWriter |
Caller lacks role | Have an admin assign the role |
MemberNotFound |
Member not in bucket | Add first via setMember |
CannotDemoteAdmin |
Tried to demote/remove another admin | Only an admin can demote themselves |
LastAdminCannotBeRemoved |
Demote/remove would leave bucket with zero admins | Promote another admin first |
MaxMembersReached / MaxPrimaryProvidersReached / TooManyBucketsForMember |
Bound hit | — |
MinProvidersNotMet |
Snapshot lacks minProviders signers |
Collect more signatures |
InvalidMinProviders |
minProviders > primary_count |
Lower threshold or add primaries |
AgreementNotFound / AgreementRequestNotFound |
No matching (bucket, provider) | Create the agreement/request first |
AgreementAlreadyExists / AgreementRequestAlreadyExists |
One already exists | — |
AgreementExpired / AgreementNotExpired |
Wrong lifecycle state | — |
AgreementExtensionsBlocked |
setExtensionsBlocked(true) is active for this agreement |
Use a different provider |
NotAgreementOwner |
Caller is not the requester | — |
DurationTooShort / DurationTooLong |
Outside provider's minDuration / maxDuration |
Adjust duration |
PaymentExceedsMax |
Calculated payment > maxPayment |
Calculate price × bytes × duration, add 10-20% buffer |
RequestExpired |
Request older than RequestTimeout |
Resubmit |
CannotTerminateReplica |
endAgreement early-termination tried on a replica |
Replicas can't be terminated early |
SettlementWindowPassed |
Owner did not call endAgreement in time |
Provider must use claimExpiredAgreement |
NotReplica |
Operation requires a replica agreement | — |
SyncTooFrequent |
Less than minSyncInterval since last sync |
Wait |
InvalidSyncRoot |
Provided root doesn't match snapshot or last sync | Refresh known roots |
InsufficientSyncBalance |
syncBalance < replicaSyncPrice |
Call topUpReplicaSyncBalance |
ChallengeNotFound / ChallengeAlreadyExists |
— | — |
InvalidChallengeProof / InvalidDeletionProof |
Proof did not verify | Build proof correctly |
ChallengeExpired |
Past challenge deadline | Too late to respond |
NotChallengeProvider |
Caller is not the challenged provider | — |
ProviderNotInSnapshot |
Provider didn't sign current snapshot | Add their signature via extendCheckpoint |
LeafBeyondCanonical |
Challenged leaf is beyond canonical state | — |
InvalidSignature |
Signature didn't verify against registered pubkey | Check key + payload |
NoSnapshot |
Bucket has no checkpoint yet | Call checkpoint first |
SnapshotViolatesFrozen |
startSeq < frozen_start_seq |
Use startSeq ≥ frozen_start_seq |
InsufficientSignatures |
Fewer signatures than minProviders |
Collect more |
ProviderCheckpointsDisabled |
Feature off for this bucket | configureCheckpointWindow(..., enabled=true) |
NotCheckpointLeader |
Submitter is not the elected leader during grace period | Wait until grace period ends |
CheckpointWindowNotStarted / InvalidCheckpointWindow / CheckpointAlreadySubmitted |
Window state errors | — |
InsufficientCheckpointPool |
Pool too low to pay reward | fundCheckpointPool |
NoMissedCheckpoint |
Reported window was actually submitted | — |
WithinGracePeriod |
reportMissedCheckpoint called before grace expired |
Wait |
NoRewardsToClaim |
Nothing accumulated for this provider/bucket | — |
NoMatchingProvider |
createBucketWithStorage couldn't find a fit |
Relax constraints |
InvalidMultiaddr / InvalidPublicKey |
Malformed input | Fix the value |
ArithmeticOverflow |
Internal overflow | Report; should not occur |
Runtime configuration (see runtime/src/lib.rs):
// Token configuration
UNIT = 1_000_000_000_000 // 1 token (12 decimals)
// Provider
MinProviderStake = 1_000 * UNIT // 1000 tokens = 1,000,000,000,000,000
MinStakePerByte = 1_000_000 // per byte of declared capacity (1 token per MB)
DeregisterAnnouncementPeriod // ≥ ChallengeTimeout
// Bucket / members
MaxMembers, MaxPrimaryProviders, MaxBucketsPerMember, MaxMultiaddrLength
// Agreement lifecycle
RequestTimeout = 6 * HOURS // pending request expiry
SettlementTimeout = 24 * HOURS // owner's window after expiry
ChallengeTimeout = 48 * HOURS // provider's window to respond
MaxChunkSize = 256 * 1024 // challenge response chunk cap (256 KiB)
// Provider-initiated checkpoints
DefaultCheckpointInterval = 100
DefaultCheckpointGrace = 20
CheckpointReward = 1 token
CheckpointMissPenalty = 0.5 token // reporter gets 10%Note: The runtime uses 12 decimal places (like Polkadot), so:
- Entering
1000000000000000in Polkadot.js = 1000 tokens - Minimum stake to register = 1000 tokens
Providers must stake enough to back their declared capacity:
required_stake = max_capacity × MinStakePerByte
Example:
max_capacity = 1 TB = 1,099,511,627,776 bytes
MinStakePerByte = 1,000,000
required_stake = 1,099,511,627,776 × 1,000,000 = ~1.1 × 10^18 units
Capacity rules:
maxCapacity = 0means unlimited (no stake requirement for capacity)- Provider's
committed_bytescannot exceedmaxCapacity - When accepting agreements, provider's capacity is checked