Skip to content

Commit

Permalink
Merge branch 'develop' into feat/11/market-pallet-sector-terminate
Browse files Browse the repository at this point in the history
  • Loading branch information
jmg-duarte authored Jul 4, 2024
2 parents a587e6d + 0c61a06 commit 4765752
Show file tree
Hide file tree
Showing 11 changed files with 587 additions and 263 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion pallets/storage-provider/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[package]
authors.workspace = true
description = "Handles storage provider registration and proofs"
edition.workspace = true
homepage.workspace = true
license-file.workspace = true
Expand All @@ -17,14 +18,16 @@ targets = ["x86_64-unknown-linux-gnu"]
codec = { workspace = true, default-features = false, features = ["derive"] }
log.workspace = true
scale-info = { workspace = true, default-features = false, features = ["derive"] }
sp-arithmetic = { workspace = true, default-features = false }
sp-core = { workspace = true, default-features = false }

# 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 }
pallet-balances = { workspace = true, default-features = false }
sp-io = { workspace = true }
sp-runtime = { workspace = true, default-features = false }

Expand All @@ -41,6 +44,7 @@ std = [
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"pallet-balances/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
Expand Down
99 changes: 1 addition & 98 deletions pallets/storage-provider/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@
- [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)
Expand Down Expand Up @@ -81,40 +77,6 @@ By implementing these penalties, storage providers are incentivised to maintain

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.
Expand All @@ -132,65 +94,6 @@ Sealing a sector using Proof-of-Replication (PoRep) is a computation-intensive p
- **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
Expand All @@ -211,4 +114,4 @@ When the storage provider has completed their PoSt, they must submit it to the n

## 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).
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).
119 changes: 108 additions & 11 deletions pallets/storage-provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,50 @@
//! The Storage Provider Pallet is the source of truth for anything storage provider related.
#![cfg_attr(not(feature = "std"), no_std)]
pub use pallet::{Config, Pallet};
use scale_info::prelude::string::String;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarks;

mod types;
#[cfg(test)]
mod mock;

pub use pallet::{Config, Pallet};
#[cfg(test)]
mod test;

mod proofs;
mod sector;
mod storage_provider;

type Cid = String;

#[frame_support::pallet(dev_mode)]
pub mod pallet {
use core::fmt::Debug;

use codec::{Decode, Encode};
use frame_support::pallet_prelude::{IsType, StorageMap};
use frame_support::{
dispatch::DispatchResultWithPostInfo,
ensure,
pallet_prelude::*,
traits::{Currency, ReservableCurrency},
};
use frame_system::{ensure_signed, pallet_prelude::*, Config as SystemConfig};
use scale_info::TypeInfo;

use crate::types::StorageProviderInfo;
use crate::{
proofs::{
assign_proving_period_offset, current_deadline_index, current_proving_period_start,
RegisteredPoStProof,
},
storage_provider::{StorageProviderInfo, StorageProviderState},
};

/// Allows to extract Balance of an account via the Config::Currency associated type.
/// BalanceOf is a sophisticated way of getting an u128.
type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as SystemConfig>::AccountId>>::Balance;

#[pallet::pallet]
#[pallet::without_storage_info] // Allows to define storage items without fixed size
Expand All @@ -42,21 +69,91 @@ pub mod pallet {
/// https://github.com/libp2p/specs/blob/2ea41e8c769f1bead8e637a9d4ebf8c791976e8a/peer-ids/peer-ids.md#peer-ids
/// More information about libp2p peer ids: https://docs.libp2p.io/concepts/fundamentals/peers/
type PeerId: Clone + Debug + Decode + Encode + Eq + TypeInfo;

/// Currency mechanism, used for collateral
type Currency: ReservableCurrency<Self::AccountId>;

#[pallet::constant] // put the constant in metadata
/// Proving period for submitting Window PoSt, 24 hours is blocks
type WPoStProvingPeriod: Get<BlockNumberFor<Self>>;

#[pallet::constant] // put the constant in metadata
/// Window PoSt challenge window (default 30 minutes in blocks)
type WPoStChallengeWindow: Get<BlockNumberFor<Self>>;
}

// Need some storage type that keeps track of sectors, deadlines and terminations.
// Could be added to this type maybe?
/// Need some storage type that keeps track of sectors, deadlines and terminations.
#[pallet::storage]
#[pallet::getter(fn storage_providers)]
pub type StorageProviders<T: Config> =
StorageMap<_, _, T::AccountId, StorageProviderInfo<T::AccountId, T::PeerId>>;
pub type StorageProviders<T: Config> = StorageMap<
_,
_,
T::AccountId,
StorageProviderState<T::PeerId, BalanceOf<T>, BlockNumberFor<T>>,
>;

#[pallet::event]
pub enum Event<T: Config> {}
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config> {
/// Emitted when a new storage provider is registered.
StorageProviderRegistered {
owner: T::AccountId,
info: StorageProviderInfo<T::PeerId>,
},
}

#[pallet::error]
pub enum Error<T> {}
pub enum Error<T> {
/// Emitted when a storage provider is trying to be registered
/// but there is already storage provider registered for that `AccountId`.
StorageProviderExists,
/// Emitted when a type conversion fails.
ConversionError,
}

#[pallet::call]
impl<T: Config> Pallet<T> {}
impl<T: Config> Pallet<T> {
pub fn register_storage_provider(
origin: OriginFor<T>,
peer_id: T::PeerId,
window_post_proof_type: RegisteredPoStProof,
) -> DispatchResultWithPostInfo {
// Check that the extrinsic was signed and get the signer
// This will be the owner of the storage provider
let owner = ensure_signed(origin)?;

// Ensure that the storage provider does not exist yet
ensure!(
!StorageProviders::<T>::contains_key(&owner),
Error::<T>::StorageProviderExists
);

let proving_period = T::WPoStProvingPeriod::get();

let current_block = <frame_system::Pallet<T>>::block_number();

let offset = assign_proving_period_offset::<T::AccountId, BlockNumberFor<T>>(
&owner,
current_block,
proving_period,
)
.map_err(|_| Error::<T>::ConversionError)?;

let period_start = current_proving_period_start(current_block, offset, proving_period);

let deadline_idx =
current_deadline_index(current_block, period_start, T::WPoStChallengeWindow::get());

let info = StorageProviderInfo::new(peer_id, window_post_proof_type);

let state = StorageProviderState::new(&info, period_start, deadline_idx);

StorageProviders::<T>::insert(&owner, state);

// Emit event
Self::deposit_event(Event::StorageProviderRegistered { owner, info });

Ok(().into())
}
}
}
Loading

0 comments on commit 4765752

Please sign in to comment.