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

refactor: ♻️ storage-proofs -> proofs-dealer-trie #12

Merged
merged 8 commits into from
Mar 19, 2024
34 changes: 17 additions & 17 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions pallets/storage-proofs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-storage-proofs"
description = "Pallet for managing, challenging and veryfing storage proofs in StorageHub."
name = "pallet-proofs-dealer-trie"
description = "Pallet for managing, challenging and veryfing proofs submitted by providers, where each provider's information is stored as a Merkle Patricia Trie."
version = "0.1.0"
homepage = { workspace = true }
license = { workspace = true }
Expand Down
177 changes: 71 additions & 106 deletions pallets/storage-proofs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use frame_support::{
inherent::IsFatalError,
pallet_prelude::*,
sp_runtime::{
traits::{AtLeast32BitUnsigned, CheckEqual, MaybeDisplay, SimpleBitOps},
traits::{CheckEqual, MaybeDisplay, SimpleBitOps},
RuntimeString,
},
traits::fungible,
Expand All @@ -45,7 +45,7 @@ pub mod pallet {
use frame_system::pallet_prelude::*;
use scale_info::prelude::fmt::Debug;
use sp_trie::CompactProof;
use types::SpFor;
use types::ProviderFor;

use crate::types::*;
use crate::*;
Expand All @@ -55,16 +55,9 @@ pub mod pallet {
/// Because this pallet emits events, it depends on the runtime's definition of an event.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// The Storage Providers pallet.
/// To check if whoever submits a proof is a registered Storage Provider.
type StorageProviders: crate::StorageProvidersInterface<AccountId = Self::AccountId>;

/// The File System pallet.
/// To check if the root submitted in a proof is valid for the Storage Provider.
type FileSystem: crate::FileSystemInterface<
StorageProvider = SpFor<Self>,
ForestRoot = ForestRootFor<Self>,
>;
/// The Providers pallet.
/// To check if whoever submits a proof is a registered Provider.
type ProvidersPallet: crate::ProvidersInterface<AccountId = Self::AccountId>;

/// Type to access the Balances Pallet.
type NativeBalance: fungible::Inspect<Self::AccountId>
Expand Down Expand Up @@ -97,9 +90,9 @@ pub mod pallet {
#[pallet::constant]
type MaxChallengesPerBlock: Get<u32> + FullCodec;

/// The maximum number of Storage Providers that can be challenged in block.
/// The maximum number of Providers that can be challenged in block.
#[pallet::constant]
type MaxSpsChallengedPerBlock: Get<u32> + FullCodec;
type MaxProvidersChallengedPerBlock: Get<u32> + FullCodec;

/// The number of blocks that challenges history is kept for.
/// After this many blocks, challenges are removed from `Challenges` StorageMap.
Expand All @@ -115,7 +108,7 @@ pub mod pallet {
/// The number of blocks in between a checkpoint challenges round (i.e. with custom challenges).
/// This is used to determine when to include the challenges from the `ChallengesQueue` and
/// `PriorityChallengesQueue` in the `BlockToChallenges` StorageMap. These checkpoint challenge
/// rounds have to be answered by ALL Storage Providers, and this is enforced by the
/// rounds have to be answered by ALL Providers, and this is enforced by the
/// `submit_proof` extrinsic.
#[pallet::constant]
type CheckpointChallengePeriod: Get<u32>;
Expand All @@ -138,10 +131,10 @@ pub mod pallet {
BoundedVec<FileKeyFor<T>, MaxChallengesPerBlockFor<T>>,
>;

/// A mapping from block number to a vector of challenged Storage Providers for that block.
/// A mapping from block number to a vector of challenged Providers for that block.
///
/// This is used to keep track of the Storage Providers that have been challenged, and should
/// submit a proof by the time of the block used as the key. Storage Providers who do submit
/// This is used to keep track of the Providers that have been challenged, and should
/// submit a proof by the time of the block used as the key. Providers who do submit
/// a proof are removed from their respective entry and pushed forward to the next block in
/// which they should submit a proof. Those who are still in the entry by the time the block
/// is reached are considered to have failed to submit a proof and subject to slashing.
Expand All @@ -151,16 +144,16 @@ pub mod pallet {
_,
Blake2_128Concat,
BlockNumberFor<T>,
BoundedVec<SpFor<T>, MaxSpsChallengedPerBlockFor<T>>,
BoundedVec<ProviderFor<T>, MaxSpsChallengedPerBlockFor<T>>,
>;

/// A mapping from a Storage Provider to the last block number they submitted a proof for.
/// If for a Storage Provider `sp`, `LastBlockSpSubmittedProofFor[sp]` is `n`, then the
/// Storage Provider should submit a proof for block `n + stake_to_challenge_period(sp)`.
/// A mapping from a Provider to the last block number they submitted a proof for.
/// If for a Provider `sp`, `LastBlockSpSubmittedProofFor[sp]` is `n`, then the
/// Provider should submit a proof for block `n + stake_to_challenge_period(sp)`.
#[pallet::storage]
#[pallet::getter(fn last_block_sp_submitted_proof_for)]
pub type LastBlockSpSubmittedProofFor<T: Config> =
StorageMap<_, Blake2_128Concat, SpFor<T>, BlockNumberFor<T>>;
StorageMap<_, Blake2_128Concat, ProviderFor<T>, BlockNumberFor<T>>;

/// A queue of file keys that have been challenged manually.
///
Expand Down Expand Up @@ -192,7 +185,7 @@ pub mod pallet {
///
/// This is used to determine when to include the challenges from the `ChallengesQueue` and
/// `PriorityChallengesQueue` in the `BlockToChallenges` StorageMap. These checkpoint challenge
/// rounds have to be answered by ALL Storage Providers, and this is enforced by the
/// rounds have to be answered by ALL Providers, and this is enforced by the
/// `submit_proof` extrinsic.
#[pallet::storage]
#[pallet::getter(fn last_checkpoint_block)]
Expand All @@ -207,13 +200,13 @@ pub mod pallet {
/// [who, file_key_challenged]
NewChallenge(AccountIdFor<T>, FileKeyFor<T>),

/// A storage proof was rejected.
/// [storage_provider, proof, reason]
ProofRejected(AccountIdFor<T>, CompactProof, ProofRejectionReason),
/// A proof was rejected.
/// [provider, proof, reason]
ProofRejected(ProviderFor<T>, CompactProof, ProofRejectionReason),

/// A storage proof was accepted.
/// [storage_provider, proof]
ProofAccepted(AccountIdFor<T>, CompactProof),
/// A proof was accepted.
/// [provider, proof]
ProofAccepted(ProviderFor<T>, CompactProof),
}

// Errors inform users that something went wrong.
Expand All @@ -223,8 +216,8 @@ pub mod pallet {
/// until some of the challenges in the queue are dispatched.
ChallengesQueueOverflow,

/// The proof submitter is not a registered Storage Provider.
NotStorageProvider,
/// The proof submitter is not a registered Provider.
NotProvider,
}

#[pallet::call]
Expand All @@ -234,7 +227,7 @@ pub mod pallet {
/// This function allows anyone to add a new challenge to the `ChallengesQueue`.
/// The challenge will be dispatched in the coming blocks.
/// Regular users are charged a small fee for submitting a challenge, which
/// goes to the Treasury. Unless the one calling is a registered Storage Provider.
/// goes to the Treasury. Unless the one calling is a registered Provider.
///
/// TODO: Consider checking also if there was a request to change MSP.
#[pallet::call_index(0)]
Expand All @@ -255,25 +248,25 @@ pub mod pallet {
Ok(().into())
}

/// For a Storage Provider to submit a storage proof.
/// For a Provider to submit a proof.
///
/// Checks that `storage_provider` is a registered Storage Provider. If none
/// is provided, the proof submitter is considered to be the Storage Provider.
/// Relies on a File System pallet to check if the root is valid for the Storage Provider.
/// Checks that `provider` is a registered Provider. If none
/// is provided, the proof submitter is considered to be the Provider.
/// Relies on a File System pallet to check if the root is valid for the Provider.
/// Validates that the proof corresponds to a challenge that was made in the past,
/// by checking the `BlockToChallenges` StorageMap. The block number that the Storage
/// by checking the `BlockToChallenges` StorageMap. The block number that the
/// Provider should have submitted a proof is calculated based on the last block they
/// submitted a proof for (`LastBlockSpSubmittedProofFor`), and the proving period for
/// that Storage Provider, which is a function of their stake.
/// that Provider, which is a function of their stake.
/// This extrinsic also checks that there hasn't been a checkpoint challenge round
/// in between the last time the Storage Provider submitted a proof for and the block
/// for which the proof is being submitted. If there has been, the Storage Provider is
/// in between the last time the Provider submitted a proof for and the block
/// for which the proof is being submitted. If there has been, the Provider is
/// subject to slashing.
///
/// If valid:
/// - Pushes forward the Storage Provider in the `BlockToChallengedSps` StorageMap a number
/// of blocks corresponding to the stake of the Storage Provider.
/// - Registers this block as the last block in which the Storage Provider submitted a proof.
/// - Pushes forward the Provider in the `BlockToChallengedSps` StorageMap a number
/// of blocks corresponding to the stake of the Provider.
/// - Registers this block as the last block in which the Provider submitted a proof.
///
/// Execution of this extrinsic should be refunded if the proof is valid.
#[pallet::call_index(1)]
Expand All @@ -283,16 +276,26 @@ pub mod pallet {
proof: CompactProof,
root: ForestRootFor<T>,
challenge_block: BlockNumberFor<T>,
storage_provider: Option<AccountIdFor<T>>,
provider: Option<ProviderFor<T>>,
) -> DispatchResultWithPostInfo {
// Check that the extrinsic was signed and get the signer.
let who = ensure_signed(origin)?;

// Getting provider from the origin if none is provided.
let provider = match provider {
Some(provider) => provider,
None => {
let sp = T::ProvidersPallet::get_provider(who.clone())
.ok_or(Error::<T>::NotProvider)?;
sp
}
};

// TODO: Handle result of verification.
Self::do_submit_proof(&who, &proof)?;
Self::do_submit_proof(&provider, &proof)?;

// TODO: Emit correct event.
Self::deposit_event(Event::ProofAccepted(who, proof));
Self::deposit_event(Event::ProofAccepted(provider, proof));

// Return a successful DispatchResultWithPostInfo
Ok(().into())
Expand All @@ -308,9 +311,9 @@ pub mod pallet {
/// `PriorityChallengesQueue`. This custom challenges are only included in "checkpoint"
/// blocks
///
/// Additionally, it takes care of checking if there are Storage Providers that have
/// Additionally, it takes care of checking if there are Providers that have
/// failed to submit a proof, and should have submitted one by this block. It does so
/// by checking the `BlockToChallengedSps` StorageMap. If a Storage Provider is found
/// by checking the `BlockToChallengedSps` StorageMap. If a Provider is found
/// to have failed to submit a proof, it is subject to slashing.
///
/// Finally, it cleans up:
Expand Down Expand Up @@ -387,67 +390,20 @@ impl InherentError {
}
}

// TODO: Move this to Storage Providers pallet.
/// A trait to lookup registered Storage Providers.
/// A trait to lookup registered Providers, their Merkle Patricia Trie roots and their stake.
///
/// It is abstracted over the `AccountId` type, `StorageProvider` type, total number of users
/// and Balance type.
pub trait StorageProvidersInterface {
/// It is abstracted over the `AccountId` type, `Provider` type, `Balance` type and `MerkleHash` type.
pub trait ProvidersInterface {
/// The type which can be used to identify accounts.
type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + Ord + MaxEncodedLen;
/// The type corresponding to the staking balance of a registered Storage Provider.
/// The type which represents a registered Provider.
type Provider: Parameter + Member + MaybeSerializeDeserialize + Debug + Ord + MaxEncodedLen;
/// The type corresponding to the staking balance of a registered Provider.
type Balance: fungible::Inspect<Self::AccountId>
+ fungible::hold::Inspect<Self::AccountId>
+ fungible::freeze::Inspect<Self::AccountId>;
ffarall marked this conversation as resolved.
Show resolved Hide resolved
/// The type which represents a registered Storage Provider.
type StorageProvider: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Debug
+ Ord
+ MaxEncodedLen;
/// The type which represents the total number of registered Storage Provider.
type UserCount: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Ord
+ AtLeast32BitUnsigned
+ FullCodec
+ Copy
+ Default
+ Debug
+ scale_info::TypeInfo
+ MaxEncodedLen;

/// Lookup a registered StorageProvider by their AccountId.
fn get_sp(who: Self::AccountId) -> Option<Self::StorageProvider>;

/// Check if an account is a registered Storage Provider.
fn is_sp(who: Self::AccountId) -> bool;

/// Lookup the total number of registered Storage Providers.
fn total_sps() -> Self::UserCount;

/// Get the stake for a registered Storage Provider.
fn get_stake(who: Self::StorageProvider) -> Self::Balance;
}

// TODO: Move this to File System pallet.
/// A trait to lookup registered Storage Providers.
///
/// It is abstracted over the, `StorageProvider` type and `ForestRoot` type.
pub trait FileSystemInterface {
/// The type which represents a registered user.
type StorageProvider: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Debug
+ Ord
+ MaxEncodedLen;

/// The type for a root of a Merkle Patricia Forest.
/// Generally a hash (the output of a Hasher).
type ForestRoot: Parameter
/// The type corresponding to the root of a registered Provider.
type MerkleHash: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Debug
Expand All @@ -462,8 +418,17 @@ pub trait FileSystemInterface {
+ MaxEncodedLen
+ FullCodec;

/// Check if a Merkle Patricia Forest root hash belongs to a given Storage Provider.
fn is_valid_root_for_sp(who: Self::StorageProvider, root: Self::ForestRoot) -> bool;
/// Check if an account is a registered Provider.
fn is_provider(who: Self::Provider) -> bool;

// Get Provider from AccountId, if it is a registered Provider.
fn get_provider(who: Self::AccountId) -> Option<Self::Provider>;

/// Get the root for a registered Provider.
fn get_root(who: Self::Provider) -> Option<Self::MerkleHash>;

/// Get the stake for a registered Provider.
fn get_stake(who: Self::Provider) -> Option<Self::Balance>;
ffarall marked this conversation as resolved.
Show resolved Hide resolved
}

// TODO: Move this to a primitives crate.
Expand Down
Loading
Loading