Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Storage provider design and documentation #56

Merged
merged 82 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
3e15022
feat(storage-provider): Add pallet miner interface
aidan46 May 23, 2024
8166469
style: Format rs files
aidan46 May 30, 2024
b8f96d5
fix: Revert Justfile back to original
aidan46 May 30, 2024
6ca40cf
fix: Remove worker related functionality
aidan46 May 30, 2024
805f22b
feat: Add `apply_reward` function
aidan46 May 30, 2024
4f48cae
feat: Add `report_consensus_fault` function
aidan46 May 30, 2024
4c91a21
feat: Add `withdraw_balance` function
aidan46 May 30, 2024
73d3f98
feat: Add logic for change_peer_id
aidan46 May 31, 2024
be4d31c
feat: Add logic for change_owner_address
aidan46 May 31, 2024
af94e76
Merge remote-tracking branch 'origin/develop' into feat-13-storage-pr…
aidan46 May 31, 2024
3875f38
Merge remote-tracking branch 'origin/develop' into feat-13-storage-pr…
aidan46 May 31, 2024
1a95bc7
docs: Add README and DESIGN markdown
aidan46 Jun 3, 2024
f08c391
Rename `miner` to `storage provider`
aidan46 Jun 3, 2024
86adf70
feat(storage-provider): Implement pallet functions
aidan46 Jun 3, 2024
858a79d
docs: Update comments in storage provider pallet
aidan46 Jun 3, 2024
1e5a4dd
refactor: Rename storage provider pallet
aidan46 Jun 4, 2024
3cca71d
feat(storage-provider): Add feature flags
aidan46 Jun 4, 2024
84b4770
refactor: Remove `PhantomData`
aidan46 Jun 4, 2024
60afc4c
docs(storage-provider): Document error values
aidan46 Jun 4, 2024
f1c89cd
style: Align todo's to agreed practice
aidan46 Jun 4, 2024
69c8cc2
fix(storage-provider): Add TODO to README
aidan46 Jun 4, 2024
fdcdf58
fix: Add locked flag to clippy in Justfile
aidan46 Jun 4, 2024
05c2f7c
feat: Add scaffolding for storage provider benchmarks
aidan46 Jun 4, 2024
6b34d2f
feat: Add `StoragePower` to storage provider
aidan46 Jun 4, 2024
fa3869e
docs(storage-provider): Add docs to `Event`
aidan46 Jun 4, 2024
0246ab4
feat: Add TODO's for call weights
aidan46 Jun 4, 2024
7a10202
feat(storage-provider): Add `price_per_block` to map
aidan46 Jun 4, 2024
f751e86
feat(storage-provider): Add `submit_windowed_post`
aidan46 Jun 4, 2024
9277730
Merge branch 'develop' into feat-13-storage-provider-pallet-implement…
serg-temchenko Jun 4, 2024
179108c
docs(storage-provider): Update pallet documentation
aidan46 Jun 5, 2024
0a58259
feat(storage-provider): Add declare faults function
aidan46 Jun 5, 2024
26165ca
feat: Add declare faults recovered function
aidan46 Jun 5, 2024
d66aeb3
feat: Add pre commit sector function
aidan46 Jun 5, 2024
07477cf
docs: Add docs for proof of storage
aidan46 Jun 7, 2024
6e9b50a
feat: Add prove commit sector
aidan46 Jun 7, 2024
1909e30
docs: Update provider state management
aidan46 Jun 7, 2024
511e85f
docs: Add proof types
aidan46 Jun 10, 2024
66c3e59
docs: Add API docs
aidan46 Jun 10, 2024
5598cef
docs: Add note to WinningPoSt
aidan46 Jun 10, 2024
ab616db
docs: Align design doc types
aidan46 Jun 10, 2024
3115179
docs: Update docs
aidan46 Jun 10, 2024
cc13ba8
fix: Remove unused attribute
aidan46 Jun 10, 2024
03b96e6
fix: Correct benchmark module name
aidan46 Jun 11, 2024
4fe0851
docs: Change wording
aidan46 Jun 12, 2024
812c7ab
docs: Clarify pallet API docs
aidan46 Jun 12, 2024
e9aa1fa
docs: Update markdown headers
aidan46 Jun 12, 2024
0dd19f9
docs: Add reference to proof of storage docs
aidan46 Jun 12, 2024
011b068
fix: Remove 'winning' PoSt type
aidan46 Jun 12, 2024
78cab9d
fix: Simplify PoSt proof for prototype
aidan46 Jun 12, 2024
b84bf82
docs: Fix mistake in create storage provider function
aidan46 Jun 12, 2024
8c90153
docs: Add terminology section
aidan46 Jun 12, 2024
d35d041
docs: Add references to terminology
aidan46 Jun 12, 2024
9baefdb
docs: Add section about declaring faults
aidan46 Jun 12, 2024
5b5d171
docs: Add section about slashing
aidan46 Jun 12, 2024
9945888
fix: Move storage provider check
aidan46 Jun 12, 2024
b67214e
refactor: Perform SP checks before mutating info
aidan46 Jun 12, 2024
cf2bda1
docs: Correct API links
aidan46 Jun 13, 2024
7e6583e
docs: Fix link pointing to master
aidan46 Jun 13, 2024
342a5bf
fix: Rename error members
aidan46 Jun 13, 2024
f26f2c7
docs: Add docs about sealing
aidan46 Jun 13, 2024
5b009fb
docs: Reword PoS docs
aidan46 Jun 13, 2024
0e84fe4
docs: Add link to seal randomness
aidan46 Jun 13, 2024
9181c81
fix: Reduce seal proof types for prototype
aidan46 Jun 13, 2024
688e2b7
fix: Error renaming
aidan46 Jun 13, 2024
4300ab7
fix: Add _ prefix to SectorSize members
aidan46 Jun 13, 2024
5185e22
docs: Update Storage provider overview
aidan46 Jun 14, 2024
d0325b4
docs: Change wording for proving period
aidan46 Jun 14, 2024
031ded0
docs: Rename epoch to Blocknumber
aidan46 Jun 14, 2024
e94b7c3
docs: Add storage provider flow
aidan46 Jun 16, 2024
21caf6a
docs: Remove API.md
aidan46 Jun 16, 2024
c9fa3ba
fix: Remove code skeleton
aidan46 Jun 16, 2024
fa6c4f9
docs: Add hooks docs
aidan46 Jun 16, 2024
f4ec0fd
docs: Add reference for WinningPoSt
aidan46 Jun 18, 2024
670783a
docs: Add missing header
aidan46 Jun 18, 2024
0d42dd6
Merge branch 'develop' into feat-13-storage-provider-pallet-implement…
aidan46 Jun 24, 2024
64d86c2
format: Run cargo fmt
aidan46 Jun 25, 2024
2260627
Merge remote-tracking branch 'origin/develop' into feat-13-storage-pr…
aidan46 Jun 27, 2024
dea3b90
fix: Typo in proof of storage
aidan46 Jun 27, 2024
03dd042
Merge remote-tracking branch 'origin/develop' into feat-13-storage-pr…
aidan46 Jun 28, 2024
25e97a2
docs: Add comment to peer id
aidan46 Jun 28, 2024
9c19631
docs: Remove broken link
aidan46 Jun 28, 2024
b41afdd
Merge branch 'develop' into feat-13-storage-provider-pallet-implement…
aidan46 Jul 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ members = [
"cli/polka-storage-provider",
"node",
"pallets/market",
"pallets/storage-provider",
"primitives/cli",
"primitives/proofs",
"runtime",
Expand Down Expand Up @@ -91,8 +92,10 @@ url = "2.5.0"
uuid = "1.8.0"

# Local

cli-primitives = { path = "primitives/cli" }
pallet-market = { path = "pallets/market", default-features = false }
pallet-storage-provider = { path = "pallets/storage-provider", default-features = false }
polka-storage-runtime = { path = "runtime" }
primitives-proofs = { path = "primitives/proofs", default-features = false }

Expand Down
Empty file removed pallets/storage-provider/.gitkeep
Empty file.
49 changes: 49 additions & 0 deletions pallets/storage-provider/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[package]
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license-file.workspace = true
name = "pallet-storage-provider"
repository.workspace = true
version = "0.0.0"

[lints]
workspace = true

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { workspace = true, default-features = false, features = ["derive"] }
log.workspace = true
scale-info = { workspace = true, default-features = false, features = ["derive"] }

# Frame deps
frame-benchmarking = { workspace = true, default-features = false, optional = true }
frame-support = { workspace = true, default-features = false }
frame-system = { workspace = true, default-features = false }

[dev-dependencies]
sp-core = { workspace = true, default-features = false }
sp-io = { workspace = true }
sp-runtime = { workspace = true, default-features = false }

[features]
default = ["std"]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
]
try-runtime = ["frame-support/try-runtime", "frame-system/try-runtime", "sp-runtime/try-runtime"]
214 changes: 214 additions & 0 deletions pallets/storage-provider/DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# Storage Provider Pallet

- [Storage Provider Pallet](#storage-provider-pallet)
- [Overview](#overview)
- [Constants \& Terminology](#constants--terminology)
- [Usage](#usage)
- [Registering storage providers](#registering-storage-providers)
- [Modifying storage provider information](#modifying-storage-provider-information)
- [Declaring storage faults](#declaring-storage-faults)
- [Declaring storage faults recovered](#declaring-storage-faults-recovered)
- [Storage fault slashing](#storage-fault-slashing)
- [Fault Fee (FF)](#fault-fee-ff)
- [Sector Penalty (SP)](#sector-penalty-sp)
- [Termination Penalty (TP)](#termination-penalty-tp)
- [State management for Storage Providers](#state-management-for-storage-providers)
- [Static information about a Storage Provider](#static-information-about-a-storage-provider)
- [Sector sealing](#sector-sealing)
- [Data structures](#data-structures)
- [Proof of Spacetime](#proof-of-spacetime)
- [Proof of Replication](#proof-of-replication)
- [Storage Provider Flow](#storage-provider-flow)
- [Registration](#registration)
- [Commit](#commit)
- [Proof of Spacetime submission](#proof-of-spacetime-submission)
- [Storage provider pallet hooks](#storage-provider-pallet-hooks)

## Overview

The `Storage Provider Pallet` handles the creation of storage providers and facilitates storage providers and client in creating storage deals. Storage providers must provide Proof of Spacetime and Proof of Replication to the `Storage Provider Pallet` in order to prevent the pallet impose penalties on the storage providers through [slashing](#storage-fault-slashing).

### Constants & Terminology

- **Sector**: The sector is the default unit of storage that providers put in the network. A sector is a contiguous array of bytes that a storage provider puts together, seals, and performs Proofs of Spacetime on. Storage providers store data on the network in fixed-size sectors.
- **Partition**: A group of 2349 sectors proven simultaneously.
- **Proving Period**: The average period for proving all sectors maintained by a provider (default set to 24 hours).
- **Deadline**: One of the multiple points during a proving period when proofs for some partitions are due.
- **Challenge Window**: The period immediately before a deadline during which a challenge can be generated by the chain and the requisite proofs computed.
- **Provider Size**: The amount of proven storage maintained by a single storage provider.

## Usage

### Registering storage providers

A storage provider indexes in the storage provider pallet itself when it starts up by calling the `create_storage_provider` extrinsic with it's `PeerId` as an argument. The public key will be extracted from the origin and is used to modify on-chain information and receive rewards. The `PeerId` is given by the storage provider so clients can use that to connect to the storage provider.
aidan46 marked this conversation as resolved.
Show resolved Hide resolved

### Modifying storage provider information

The `Storage Provider Pallet` allows storage providers to modify their information such as changing the peer id, through `change_peer_id` and changing owners, through `change_owner_address`.

### Declaring storage faults

A storage provider can declare sectors as faulty, through the `declare_faults`, for any sectors that it cannot generate `WindowPoSt` proofs. A storage provider has to declare the sector as faulty **before** the challenge window. Until the sectors are recovered they will be masked from proofs in subsequent proving periods.
aidan46 marked this conversation as resolved.
Show resolved Hide resolved

### Declaring storage faults recovered

After a storage provider has declared some sectors as faulty, it can recover those sectors. The storage provider can use the `declare_faults_recovered` method to set the sectors it previously declared as faulty to recovering.

## Storage fault slashing

Storage Fault Slashing refers to a set of penalties that storage providers may incur if they fail to maintain sector reliability or choose to voluntarily exit the network. These penalties include Fault Fees, Sector Penalties, and Termination Fees. Below is a detailed explanation of each type of penalty.

### Fault Fee (FF)

- **Description**: A penalty incurred by a storage provider for each day that a sector is offline.
- **Rationale**: Ensures that storage providers maintain high availability and reliability of their committed data.

### Sector Penalty (SP)

- **Description**: A penalty incurred by a storage provider for a sector that becomes faulted without being declared as such before a WindowPoSt (Proof-of-Spacetime) check.
- **Rationale**: Encourages storage providers to promptly declare any faults to avoid more severe penalties.
- **Details**: If a fault is detected during a WindowPoSt check, the sector will incur an SP and will continue to incur a FF until the fault is resolved.

### Termination Penalty (TP)

- **Description**: A penalty incurred when a sector is either voluntarily or involuntarily terminated and removed from the network.
- **Rationale**: Discourages storage providers from arbitrarily terminating sectors and ensures they fulfill their storage commitments.

By implementing these penalties, storage providers are incentivised to maintain the reliability and availability of the data they store. This system of Storage Fault Slashing helps maintain the integrity and reliability of our decentralized storage network.

### State management for Storage Providers

In our parachain, the state management for all storage providers is handled collectively, unlike Filecoin, which manages the state for individual storage providers.

### Static information about a Storage Provider

The below struct and its fields ensure that all necessary static information about a Storage provider is encapsulated, allowing for efficient management and interaction within the parachain.

```rust
pub struct StorageProviderInfo<AccountId, PeerId> {
/// Libp2p identity that should be used when connecting to this Storage Provider
pub peer_id: PeerId,

/// The proof type used by this Storage provider for sealing sectors.
/// Rationale: Different StorageProviders may use different proof types for sealing sectors. By storing
/// the `window_post_proof_type`, we can ensure that the correct proof mechanisms are applied and verified
/// according to the provider's chosen method. This enhances compatibility and integrity in the proof-of-storage
/// processes.
pub window_post_proof_type: RegisteredPoStProof,

/// Amount of space in each sector committed to the network by this Storage Provider
///
/// Rationale: The `sector_size` indicates the amount of data each sector can hold. This information is crucial
/// for calculating storage capacity, economic incentives, and the validation process. It ensures that the storage
/// commitments made by the provider are transparent and verifiable.
pub sector_size: SectorSize,

/// The number of sectors in each Window PoSt partition (proof).
/// This is computed from the proof type and represented here redundantly.
///
/// Rationale: The `window_post_partition_sectors` field specifies the number of sectors included in each
/// Window PoSt proof partition. This redundancy ensures that partition calculations are consistent and
/// simplifies the process of generating and verifying proofs. By storing this value, we enhance the efficiency
/// of proof operations and reduce computational overhead during runtime.
pub window_post_partition_sectors: u64,
}
```

## Sector sealing

Before a sector can be used, the storage provider must seal the sector, which involves encoding the data in the sector to prepare it for the proving process.

- **Unsealed Sector**: An unsealed sector is a sector containing raw data that has not yet been sealed.
- **UnsealedCID (CommD)**: The root hash of the unsealed sector’s Merkle tree, also referred to as CommD or "data commitment."
- **Sealed Sector**: A sector that has been encoded and prepared for the proving process.
- **SealedCID (CommR)**: The root hash of the sealed sector’s Merkle tree, also referred to as CommR or "replica commitment."

By sealing sectors, storage providers ensure that data is properly encoded and ready for the proof-of-storage process, maintaining the integrity and security of the stored data in the network.

Sealing a sector using Proof-of-Replication (PoRep) is a computation-intensive process that results in a unique encoding of the sector. Once the data is sealed, storage providers follow these steps:

- **Generate a Proof**: Create a proof that the data has been correctly sealed.
- **Run a SNARK on the Proof**: Compress the proof using a Succinct Non-interactive Argument of Knowledge (SNARK).
- **Submit the Compressed Proof:** Submit the result of the compression to the blockchain as certification of the storage commitment.

## Data structures

### Proof of Spacetime

> [!NOTE]
> For more information about proofs check out the [proof of storage docs](./PROOF-OF-STORAGE.md)

Proof of Spacetime indicates the version and the sector size of the proof. This type is used by the Storage Provider when initially starting up to indicate what PoSt version it will use to submit Window PoSt proof.

```rust
pub enum RegisteredPoStProof {
StackedDRGWindow2KiBV1P1,
}
```

The `SectorSize` indicates one of a set of possible sizes in the network.

```rust
#[repr(u64)]
pub enum SectorSize {
_2KiB,
}
```

The `PoStProof` is the proof of spacetime data that is stored on chain

```rust
pub struct PoStProof {
pub post_proof: RegisteredPoStProof,
pub proof_bytes: Vec<u8>,
}
```

### Proof of Replication

> [!NOTE]
> For more information about proofs check out the [proof of storage docs](./PROOF-OF-STORAGE.md)

Proof of Replication is used when a Storage Provider wants to store data on behalf of a client and receives a piece of client data. The data will first be placed in a sector after which that sector is sealed by the storage provider. Then a unique encoding, which serves as proof that the Storage Provider has replicated a copy of the data they agreed to store, is generated. Finally, the proof is compressed and submitted to the network as certification of storage.

```rust
/// This type indicates the seal proof type which defines the version and the sector size
pub enum RegisteredSealProof {
StackedDRG2KiBV1P1,
}
```

The unique encoding created during the sealing process is generated using the sealed data, the storage provider who seals the data and the time at which the data was sealed.

```rust
/// This type is passed into the pre commit function on the storage provider pallet
pub struct SectorPreCommitInfo {
pub seal_proof: RegisteredSealProof,
pub sector_number: SectorNumber,
pub sealed_cid: Cid,
pub expiration: u64,
}
```

## Storage Provider Flow

### Registration

The first thing a storage provider must do is register itself by calling `storage_provider.create_storage_provider(peer_id: PeerId, window_post_proof_type: RegisteredPoStProof)`. At this point there are no funds locked in the storage provider pallet. The next step is to place storage market asks on the market, this is done through the market pallet. After that the storage provider needs to make deals with clients and begin filling up sectors with data. When they have a full sector they should seal the sector.
jmg-duarte marked this conversation as resolved.
Show resolved Hide resolved

### Commit

When the storage provider has completed their first seal, they should post it to the storage provider pallet by calling `storage_provider.pre_commit_sector(sectors: SectorPreCommitInfo)`. If the storage provider had zero committed sectors before this call, this begins their proving period. The proving period is a fixed amount of time in which the storage provider must submit a Proof of Space Time to the network.
th7nder marked this conversation as resolved.
Show resolved Hide resolved
During this period, the storage provider may also commit to new sectors, but they will not be included in proofs of space time until the next proving period starts. During the prove commit call, the storage provider pledges some collateral in case they fail to submit their PoSt on time.

### Proof of Spacetime submission

When the storage provider has completed their PoSt, they must submit it to the network by calling `storage_provider.submit_windowed_post(deadline: u64, partitions: Vec<u64>, proofs: Vec<PostProof>)`. There are two different types of submissions:
th7nder marked this conversation as resolved.
Show resolved Hide resolved

- **Standard Submission**: A standard submission is one that makes it on-chain before the end of the proving period.
- **Penalize Submission**:A penalized submission is one that makes it on-chain after the end of the proving period, but before the generation attack threshold. These submissions count as valid PoSt submissions, but the miner must pay a penalty for their late submission. See [storage fault slashing](#storage-fault-slashing).

## Storage provider pallet hooks

Substrate pallet hooks execute some actions when certain conditions are met. We use these hooks, when a block finalizes, to check if storage providers are up to date with their proofs. If a proof needs to be submitted but isn't the storage provider pallet will penalize the storage provider accordingly [slash](#storage-fault-slashing) their collateral that the locked up during the [pre commit section](#commit).
Loading