From c032385c203d08dd843281fb9628c9985c4ec37e Mon Sep 17 00:00:00 2001 From: Konrad Stepniak Date: Mon, 27 May 2024 16:19:56 +0200 Subject: [PATCH 01/12] chore: set-up a pallet-collator-power skeleton --- Cargo.lock | 15 +++++ Cargo.toml | 3 +- pallets/collator-power/.gitkeep | 0 pallets/collator-power/Cargo.toml | 50 +++++++++++++++ pallets/collator-power/README.md | 2 + pallets/collator-power/src/lib.rs | 103 ++++++++++++++++++++++++++++++ runtime/Cargo.toml | 6 ++ runtime/src/configs/mod.rs | 8 +++ runtime/src/lib.rs | 3 + 9 files changed, 189 insertions(+), 1 deletion(-) delete mode 100644 pallets/collator-power/.gitkeep create mode 100644 pallets/collator-power/Cargo.toml create mode 100644 pallets/collator-power/README.md create mode 100644 pallets/collator-power/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index adef49283..7eb52d5fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6514,6 +6514,20 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.11.0)", ] +[[package]] +name = "pallet-collator-power" +version = "0.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "pallet-collator-selection" version = "9.0.0" @@ -7806,6 +7820,7 @@ dependencies = [ "pallet-aura", "pallet-authorship", "pallet-balances", + "pallet-collator-power", "pallet-collator-selection", "pallet-message-queue", "pallet-session", diff --git a/Cargo.toml b/Cargo.toml index 21e5ab904..ac4390267 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license-file = "LICENSE" repository = "https://github.com/eigerco/polka-storage" [workspace] -members = ["node", "runtime"] +members = ["node", "pallets/collator-power", "runtime"] resolver = "2" # FIXME(#@jmg-duarte,#7,14/5/24): remove the patch once something >1.11.0 is released @@ -51,6 +51,7 @@ thiserror = { version = "1.0.48" } tracing-subscriber = { version = "0.3.18" } # Local +pallet-collator-power = { path = "pallets/collator-power", default-features = false } polka-storage-runtime = { path = "runtime" } # Substrate diff --git a/pallets/collator-power/.gitkeep b/pallets/collator-power/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/pallets/collator-power/Cargo.toml b/pallets/collator-power/Cargo.toml new file mode 100644 index 000000000..84c64dd8a --- /dev/null +++ b/pallets/collator-power/Cargo.toml @@ -0,0 +1,50 @@ +[package] +authors.workspace = true +description = "manages collators' power used in the selection process of a collator node" +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "pallet-collator-power" +publish = false +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"] } +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"] diff --git a/pallets/collator-power/README.md b/pallets/collator-power/README.md new file mode 100644 index 000000000..80d72a387 --- /dev/null +++ b/pallets/collator-power/README.md @@ -0,0 +1,2 @@ +# Collator Power Pallet + diff --git a/pallets/collator-power/src/lib.rs b/pallets/collator-power/src/lib.rs new file mode 100644 index 000000000..f650b8740 --- /dev/null +++ b/pallets/collator-power/src/lib.rs @@ -0,0 +1,103 @@ +//! # Collator Power Pallet +//! +//! Collator Power Pallet manages collator's `Power` which is used +//! in the [selection process](https://github.com/eigerco/polka-disk/blob/main/doc/research/parachain/parachain-implementation.md#collator-selection-pallet) +//! of a [Collator Node](https://github.com/eigerco/polka-disk/blob/main/doc/research/parachain/parachain-implementation.md#collator-node). +//! +//! # Overview +//! +//! The Collator Power Pallet provides functions for: +//! - ... + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use codec::{Decode, Encode}; + use frame_support::{ + dispatch::DispatchResultWithPostInfo, + pallet_prelude::*, + sp_runtime::RuntimeDebug, + traits::{Currency, ReservableCurrency}, + }; + use frame_system::{pallet_prelude::*, Config as SystemConfig}; + use scale_info::TypeInfo; + + // Allows to extract Balance of an account via the Config::Currency associated type. + // BalanceOf is a sophisticated way of getting an u128. + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The currency mechanism. + /// Used for staking Collaterals by Storage Providers + type Currency: ReservableCurrency; + + /// Unit of Storage Power of a Storage Provider + /// E.g. `u128`, used as `number of bytes` for a given SP. + type StoragePower: Parameter + Member + Clone + MaxEncodedLen; + + /// A stable ID for a Collator + type CollatorId: Parameter + Member + MaxEncodedLen; + + /// A stable ID for a Storage Provider + type StorageProviderId: Parameter + Member + MaxEncodedLen; + } + + #[derive( + Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, Default, TypeInfo, MaxEncodedLen, + )] + pub struct StorageProviderClaim { + /// Number of bytes stored by a miner + raw_bytes_power: StoragePower, + } + + #[derive( + Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] + pub struct CollatorClaim { + /// Amount of Currency that was pledged by a Collator to participate in block producer selection + pledged_collateral: Balance, + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn collator_claims)] + pub type CollatorClaims = + StorageMap<_, _, T::CollatorId, CollatorClaim>>; + + #[pallet::storage] + #[pallet::getter(fn storage_provider_claims)] + pub type StorageProviderClaims = + StorageMap<_, _, T::StorageProviderId, StorageProviderClaim>; + + #[pallet::event] + // #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Indicates that a new storage provider has been registered. + /// Newly created storage provider does not have any Power. + /// Power is updated after the Storage Provider proves it has storage available. + StorageProviderRegistered(T::AccountId), + } + + #[pallet::error] + pub enum Error { + /// If there is an entry in claims map, connected to the AccountId that tries to be registered as a Storage Provider. + StorageProviderAlreadyRegistered, + } + + #[pallet::call] + impl Pallet { + pub fn register_storage_provider(_origin: OriginFor) -> DispatchResultWithPostInfo { + todo!() + } + } +} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 6e22ebd23..5b70ff78b 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -45,6 +45,9 @@ pallet-timestamp = { workspace = true, default-features = false } pallet-transaction-payment = { workspace = true, default-features = false } pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = false } +# Local Pallets +pallet-collator-power = { workspace = true, default-features = false } + # Substrate Primitives sp-api = { workspace = true, default-features = false } sp-block-builder = { workspace = true, default-features = false } @@ -103,6 +106,7 @@ std = [ "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", + "pallet-collator-power/std", "pallet-collator-selection/std", "pallet-message-queue/std", "pallet-session/std", @@ -146,6 +150,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "hex-literal", "pallet-balances/runtime-benchmarks", + "pallet-collator-power/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", @@ -171,6 +176,7 @@ try-runtime = [ "pallet-aura/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", + "pallet-collator-power/try-runtime", "pallet-collator-selection/try-runtime", "pallet-message-queue/try-runtime", "pallet-session/try-runtime", diff --git a/runtime/src/configs/mod.rs b/runtime/src/configs/mod.rs index 77ae6bf0a..c32fd8233 100644 --- a/runtime/src/configs/mod.rs +++ b/runtime/src/configs/mod.rs @@ -303,3 +303,11 @@ impl pallet_collator_selection::Config for Runtime { type ValidatorRegistration = Session; type WeightInfo = (); } + +impl pallet_collator_power::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type StoragePower = u128; + type CollatorId = ::AccountId; + type StorageProviderId = ::AccountId; +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 1fbe72296..f7398f4dd 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -245,6 +245,9 @@ construct_runtime!( PolkadotXcm: pallet_xcm = 31, CumulusXcm: cumulus_pallet_xcm = 32, MessageQueue: pallet_message_queue = 33, + + // Polka Storage Pallets + CollatorPower: pallet_collator_power = 50, } ); From 9fec6c3e0f1a6800b296f2a793fdbce4107d5395 Mon Sep 17 00:00:00 2001 From: Konrad Stepniak Date: Tue, 28 May 2024 18:39:19 +0200 Subject: [PATCH 02/12] feat: add storage maps for sps and collators --- pallets/collator-power/src/lib.rs | 85 ++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/pallets/collator-power/src/lib.rs b/pallets/collator-power/src/lib.rs index f650b8740..ad8730167 100644 --- a/pallets/collator-power/src/lib.rs +++ b/pallets/collator-power/src/lib.rs @@ -44,26 +44,30 @@ pub mod pallet { type StoragePower: Parameter + Member + Clone + MaxEncodedLen; /// A stable ID for a Collator - type CollatorId: Parameter + Member + MaxEncodedLen; + type CollatorId: Parameter + Member + Ord + MaxEncodedLen; /// A stable ID for a Storage Provider - type StorageProviderId: Parameter + Member + MaxEncodedLen; + type StorageProviderId: Parameter + Member + Ord + MaxEncodedLen; } #[derive( Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, Default, TypeInfo, MaxEncodedLen, )] - pub struct StorageProviderClaim { - /// Number of bytes stored by a miner + pub struct StorageProviderClaim { + /// Number of bytes stored by a Storage Provider raw_bytes_power: StoragePower, + /// Stores how much currency was staked on a particular collator + delegates: BoundedBTreeMap> } #[derive( Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, )] - pub struct CollatorClaim { + pub struct CollatorClaim { /// Amount of Currency that was pledged by a Collator to participate in block producer selection - pledged_collateral: Balance, + pledged_own_collateral: Balance, + /// Stores how much every Storage Provider has staked on a given Collator + delegated_collateral: BoundedBTreeMap> } #[pallet::pallet] @@ -72,12 +76,12 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn collator_claims)] pub type CollatorClaims = - StorageMap<_, _, T::CollatorId, CollatorClaim>>; + StorageMap<_, _, T::CollatorId, CollatorClaim, T::StorageProviderId>>; #[pallet::storage] #[pallet::getter(fn storage_provider_claims)] pub type StorageProviderClaims = - StorageMap<_, _, T::StorageProviderId, StorageProviderClaim>; + StorageMap<_, _, T::StorageProviderId, StorageProviderClaim, T::StoragePower>>; #[pallet::event] // #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -94,10 +98,75 @@ pub mod pallet { StorageProviderAlreadyRegistered, } + /// Extrinsics exposed by the pallet #[pallet::call] impl Pallet { + /// Registers account as a Storage Provider + /// Initially, Storage Provider has 0 Storage Power. + /// It needs to be added via UpdateStoragePower. pub fn register_storage_provider(_origin: OriginFor) -> DispatchResultWithPostInfo { todo!() } + + /// After Storage Provider proved a sector, calls this method to update the bookkeeping about available power. + pub fn update_storage_power( + _storage_provider: OriginFor, + _raw_delta_bytes: T::StoragePower, + ) -> DispatchResultWithPostInfo { + todo!() + } + + /// Adds collator to the active collator set, the set is taken into account when `pallet collator selection` makes decision. + /// Collator initially has zero power. + /// Called with `root` privileges for now. + pub fn register_collator(_origin: OriginFor) -> DispatchResultWithPostInfo { + todo!() + } + + /// Sets a lock on `amount` of currency from a given `storageProvider` + /// Effectively staking `amount` on a `collator`. + /// Saves how much was staked, and later can be returned by `getActiveCollators()` + pub fn nominate_collator( + _storage_provider: OriginFor, + _collator: T::CollatorId, + _amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + todo!() + } + + /// Removes the `collator`'s nomination backed by `storageProvider`. + /// Returns pledged funds back to the `storageProvider`. + /// Remove a lock on `amount` of currency from a given `collator`. + /// Returns funds to the `storageProvider`. + pub fn denominate_collator( + _storage_provider: OriginFor, + _collator: T::CollatorId, + ) -> DispatchResultWithPostInfo { + todo!() + } + + /// Pledges a certain amount of balance for a more likelihood to be selected to be a block producer. + /// It's called by collator on its' own, as it's not always pledging it's entire balance. + pub fn pledge_collateral(_collator: OriginFor, _amount: BalanceOf) -> DispatchResultWithPostInfo { + todo!() + } + } + + /// Functions exposed by the pallet + /// e.g. `pallet-collator-selection` used them to make decision about the next block producer + impl Pallet { + /// Returns map of collator_id -> pledged collateral + its balance. + /// Essentially: + /// - adds pledged collateral from CollatorClaims + /// - goes through all of the Storage Provider + pub fn active_collators() { + todo!(); + } + + /// Gets total power acquired by a collator + /// Total Power = ballance pledged by a collator and collateral staked on it by Storage Providers. + pub fn get_power(_collator: T::CollatorId) { + todo!(); + } } } From 0138910ee8f3593741a64ed13d7a6170a78bf9db Mon Sep 17 00:00:00 2001 From: th7nder Date: Thu, 30 May 2024 16:40:09 +0200 Subject: [PATCH 03/12] docs: add a lovely design doc --- pallets/collator-power/DESIGN.md | 93 ++++++++++++++++++++++++ pallets/collator-power/src/lib.rs | 116 +++++------------------------- runtime/src/configs/mod.rs | 3 +- 3 files changed, 110 insertions(+), 102 deletions(-) create mode 100644 pallets/collator-power/DESIGN.md diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md new file mode 100644 index 000000000..dd6144d2a --- /dev/null +++ b/pallets/collator-power/DESIGN.md @@ -0,0 +1,93 @@ +# Overall Power Pallet Flow + +## Glossary +- **extrinsic** - state transition function on a pallet, essentially a signed transaction which requires an account with some tokens to be executed as it costs fees. +- **Miner** - [Storage Provider][5] +- **collateral** - amount of tokens staked by a miner (via `SPP`) to be able to provide storage services +- **PoSt** - [Proof of Storage][3] +- `SPP` - Storage Provider Pallet +- `CPP` - Collator Power Pallet +- `CSP` - Collator Selection Pallet +- **session** - a [session][4] is a period of time that has a constant set of validators. + +## Overview + +**Collators** are entities selected to produce **blocks** which are then finalized by relay chain's **validators**. +To participate in **block production**, a **Collator** needs to: +- stake a ***certain*** (yet to be determined) amount of tokens +- be backed by **Miners'** **Storage Power**. +Collators' staking is a requirement for participation in the process, the actual selection is based on **Storage Power**. + +The collators are selected based on **Storage Power** by `CSP` in an randonmized auction algorithm. +The more **Storage Power** has been staked on a **Collator** by the **Miner**, the more likely their chances to be selected for block production. + +This pallet works as a proxy between `SPP` and `CSP` to make collator choices. +It stores how much **Storage Power** a **Miner** has and how much was delegated by **Miners** to **Collators**. +Both `SPP` and `CSP` are [tightly coupled][2] to this pallet. + +Trade Offs [?]: + +**Collators** are separately tracked by `CSP` and this pallet gives back the `staked_power` to a **Miner** when a **Collator** disappears. +This is an intentional design decision, this could be also tracked in this pallet, however I do think it'd make this Pallet too complex. +As Collators also need to be staked and require their own registration logic. + +## Data Structures + +```rust +struct MinerClaim { + /// Indicates how much power a Miner has + raw_bytes_power: T::StoragePower; + staked_power: Map +} +``` + +## Use Cases + +### Registration + +#### Useful links +- [Creating Storage Miner in Lotus][1] + +#### Assumptions +- `create_miner(miner: T::MinerId)` is an **extrinsic**. It's called by `Storage Provider Node` on a bootstrap. We can trust it, as `T::MinerId` is essentialy an account ID. The transaction needs to be signed, for it to be signed it needs to come from an account. For it to come from an account, the account has to have an **existential deposit** and it costs money. That's how it's DOS-resistant. + +#### Flow: +1. **Miner** calls `create_miner(miner: T::MinerId)` +2. `CPP` initializes `Map`. + +### Manipulating Power + +#### Assumptions +- `SPP` only calls `CPP.update_miner_power` function after: + * Miner has been registered in `Collator Power` via `create_miner` function call + * Miner has submitted `PreCommit` sector with a certain (calculated by `SPP`) amount **Collateral** required + * Miner has proven sectors with **PoSt** via `ProveCommit` of `SPP`. +- `update_miner_power` is ***NOT** an **extrinsic**. It can only be called from `SPP` via [tight coupling][2]. + - The reason is that we can't trust that a **Miner** will call extrinsic and update it on their own. `SPP` logic will perform those updates, e.g: after (not)receiving **PoSt**, receiving **pledge collaterals**. + +#### Flow +1. `SPP` calls `CPP.update_miner_power(miner: T::MinerId, deltaStorageBytes: T::StoragePower)` +2. If Storage Power was decresed: `CPP` decreases all delegated power (to **Collators**) + - essentially means 'Slashing Miner and the Power they delegated' +3. If Storage Power was increased: `CPP` does nothing. +4. `CPP` performs bookeeping, updating `MinerClaim` + +### Delegating Power + +#### Assumptions +- It's an **extrinsic**, can be called by a **Miner**. + +#### Flow +1. **Miner** calls `CPP.delegate_power(miner: T::MinerId, collator: T::CollatorId, amount: T::StoragePower)` +2. `CPP` saves delegated **Storage Power** in **Miner's** claims (`staked_power`). +3. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. + +#### Slashing Collator (?) + +TODO: I don't have this piece of the puzzle yet. I mean... What happens if a **Miner** staked some power on a **Collator** and it misbehaved? Do we **slash** the **Miner's** staked tokens/or storage power, and if so, how? + +[1]: https://github.com/filecoin-project/lotus/blob/9851d35a3811e5339560fb706926bf63a846edae/cmd/lotus-miner/init.go#L638 +[2]: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_pallet_coupling/index.html#tight-coupling-pallets +[3]: https://spec.filecoin.io/#section-algorithms.pos +[4]: https://paritytech.github.io/polkadot-sdk/master/pallet_session/index. +[5]: https://github.com/eigerco/polka-disk/blob/main/doc/research/lotus/lotus-overview.md#Roles \ No newline at end of file diff --git a/pallets/collator-power/src/lib.rs b/pallets/collator-power/src/lib.rs index ad8730167..94dd579ff 100644 --- a/pallets/collator-power/src/lib.rs +++ b/pallets/collator-power/src/lib.rs @@ -1,9 +1,5 @@ //! # Collator Power Pallet //! -//! Collator Power Pallet manages collator's `Power` which is used -//! in the [selection process](https://github.com/eigerco/polka-disk/blob/main/doc/research/parachain/parachain-implementation.md#collator-selection-pallet) -//! of a [Collator Node](https://github.com/eigerco/polka-disk/blob/main/doc/research/parachain/parachain-implementation.md#collator-node). -//! //! # Overview //! //! The Collator Power Pallet provides functions for: @@ -20,153 +16,73 @@ pub mod pallet { dispatch::DispatchResultWithPostInfo, pallet_prelude::*, sp_runtime::RuntimeDebug, - traits::{Currency, ReservableCurrency}, }; - use frame_system::{pallet_prelude::*, Config as SystemConfig}; + use frame_system::{pallet_prelude::*}; use scale_info::TypeInfo; - // Allows to extract Balance of an account via the Config::Currency associated type. - // BalanceOf is a sophisticated way of getting an u128. - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - #[pallet::config] pub trait Config: frame_system::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The currency mechanism. - /// Used for staking Collaterals by Storage Providers - type Currency: ReservableCurrency; - - /// Unit of Storage Power of a Storage Provider + /// Unit of Storage Power of a Miner /// E.g. `u128`, used as `number of bytes` for a given SP. type StoragePower: Parameter + Member + Clone + MaxEncodedLen; /// A stable ID for a Collator type CollatorId: Parameter + Member + Ord + MaxEncodedLen; - /// A stable ID for a Storage Provider - type StorageProviderId: Parameter + Member + Ord + MaxEncodedLen; + /// A stable ID for a Miner + type MinerId: Parameter + Member + Ord + MaxEncodedLen; } #[derive( Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, Default, TypeInfo, MaxEncodedLen, )] - pub struct StorageProviderClaim { - /// Number of bytes stored by a Storage Provider + pub struct MinerClaim { + /// Number of bytes stored by a Miner raw_bytes_power: StoragePower, /// Stores how much currency was staked on a particular collator - delegates: BoundedBTreeMap> - } - - #[derive( - Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, - )] - pub struct CollatorClaim { - /// Amount of Currency that was pledged by a Collator to participate in block producer selection - pledged_own_collateral: Balance, - /// Stores how much every Storage Provider has staked on a given Collator - delegated_collateral: BoundedBTreeMap> + staked_power: BoundedBTreeMap> } #[pallet::pallet] pub struct Pallet(_); - #[pallet::storage] - #[pallet::getter(fn collator_claims)] - pub type CollatorClaims = - StorageMap<_, _, T::CollatorId, CollatorClaim, T::StorageProviderId>>; - #[pallet::storage] #[pallet::getter(fn storage_provider_claims)] - pub type StorageProviderClaims = - StorageMap<_, _, T::StorageProviderId, StorageProviderClaim, T::StoragePower>>; + pub type MinerClaims = + StorageMap<_, _, T::MinerId, MinerClaim>; #[pallet::event] // #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Indicates that a new storage provider has been registered. - /// Newly created storage provider does not have any Power. - /// Power is updated after the Storage Provider proves it has storage available. - StorageProviderRegistered(T::AccountId), + /// Indicates that a new Miner has been registered. + /// Newly created Miner does not have any Power. + /// Power is updated after the Miner proves it has storage available. + MinerRegistered(T::AccountId), } #[pallet::error] pub enum Error { - /// If there is an entry in claims map, connected to the AccountId that tries to be registered as a Storage Provider. - StorageProviderAlreadyRegistered, + /// If there is an entry in claims map, connected to the AccountId that tries to be registered as a Miner. + MinerAlreadyRegistered, } /// Extrinsics exposed by the pallet #[pallet::call] impl Pallet { - /// Registers account as a Storage Provider - /// Initially, Storage Provider has 0 Storage Power. - /// It needs to be added via UpdateStoragePower. - pub fn register_storage_provider(_origin: OriginFor) -> DispatchResultWithPostInfo { - todo!() - } - - /// After Storage Provider proved a sector, calls this method to update the bookkeeping about available power. + /// After Miner proved a sector, calls this method to update the bookkeeping about available power. pub fn update_storage_power( _storage_provider: OriginFor, _raw_delta_bytes: T::StoragePower, ) -> DispatchResultWithPostInfo { todo!() } - - /// Adds collator to the active collator set, the set is taken into account when `pallet collator selection` makes decision. - /// Collator initially has zero power. - /// Called with `root` privileges for now. - pub fn register_collator(_origin: OriginFor) -> DispatchResultWithPostInfo { - todo!() - } - - /// Sets a lock on `amount` of currency from a given `storageProvider` - /// Effectively staking `amount` on a `collator`. - /// Saves how much was staked, and later can be returned by `getActiveCollators()` - pub fn nominate_collator( - _storage_provider: OriginFor, - _collator: T::CollatorId, - _amount: BalanceOf, - ) -> DispatchResultWithPostInfo { - todo!() - } - - /// Removes the `collator`'s nomination backed by `storageProvider`. - /// Returns pledged funds back to the `storageProvider`. - /// Remove a lock on `amount` of currency from a given `collator`. - /// Returns funds to the `storageProvider`. - pub fn denominate_collator( - _storage_provider: OriginFor, - _collator: T::CollatorId, - ) -> DispatchResultWithPostInfo { - todo!() - } - - /// Pledges a certain amount of balance for a more likelihood to be selected to be a block producer. - /// It's called by collator on its' own, as it's not always pledging it's entire balance. - pub fn pledge_collateral(_collator: OriginFor, _amount: BalanceOf) -> DispatchResultWithPostInfo { - todo!() - } } /// Functions exposed by the pallet /// e.g. `pallet-collator-selection` used them to make decision about the next block producer impl Pallet { - /// Returns map of collator_id -> pledged collateral + its balance. - /// Essentially: - /// - adds pledged collateral from CollatorClaims - /// - goes through all of the Storage Provider - pub fn active_collators() { - todo!(); - } - - /// Gets total power acquired by a collator - /// Total Power = ballance pledged by a collator and collateral staked on it by Storage Providers. - pub fn get_power(_collator: T::CollatorId) { - todo!(); - } } } diff --git a/runtime/src/configs/mod.rs b/runtime/src/configs/mod.rs index c32fd8233..6e666a60f 100644 --- a/runtime/src/configs/mod.rs +++ b/runtime/src/configs/mod.rs @@ -306,8 +306,7 @@ impl pallet_collator_selection::Config for Runtime { impl pallet_collator_power::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Currency = Balances; type StoragePower = u128; type CollatorId = ::AccountId; - type StorageProviderId = ::AccountId; + type MinerId = ::AccountId; } From 567c77f084394845cf8d62e9642b3e333f6edea5 Mon Sep 17 00:00:00 2001 From: th7nder Date: Thu, 30 May 2024 19:03:22 +0200 Subject: [PATCH 04/12] docs: fix minor issues --- pallets/collator-power/DESIGN.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index dd6144d2a..3cba64151 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -4,7 +4,8 @@ - **extrinsic** - state transition function on a pallet, essentially a signed transaction which requires an account with some tokens to be executed as it costs fees. - **Miner** - [Storage Provider][5] - **collateral** - amount of tokens staked by a miner (via `SPP`) to be able to provide storage services -- **PoSt** - [Proof of Storage][3] +- **PoS** - [Proof of Storage][3] +- **PoSt** - [Proof of Space-Time][6] - `SPP` - Storage Provider Pallet - `CPP` - Collator Power Pallet - `CSP` - Collator Selection Pallet @@ -61,7 +62,7 @@ struct MinerClaim { - `SPP` only calls `CPP.update_miner_power` function after: * Miner has been registered in `Collator Power` via `create_miner` function call * Miner has submitted `PreCommit` sector with a certain (calculated by `SPP`) amount **Collateral** required - * Miner has proven sectors with **PoSt** via `ProveCommit` of `SPP`. + * Miner has proven sectors with **PoS** via `ProveCommit` of `SPP`. - `update_miner_power` is ***NOT** an **extrinsic**. It can only be called from `SPP` via [tight coupling][2]. - The reason is that we can't trust that a **Miner** will call extrinsic and update it on their own. `SPP` logic will perform those updates, e.g: after (not)receiving **PoSt**, receiving **pledge collaterals**. @@ -89,5 +90,6 @@ TODO: I don't have this piece of the puzzle yet. I mean... What happens if a **M [1]: https://github.com/filecoin-project/lotus/blob/9851d35a3811e5339560fb706926bf63a846edae/cmd/lotus-miner/init.go#L638 [2]: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_pallet_coupling/index.html#tight-coupling-pallets [3]: https://spec.filecoin.io/#section-algorithms.pos -[4]: https://paritytech.github.io/polkadot-sdk/master/pallet_session/index. -[5]: https://github.com/eigerco/polka-disk/blob/main/doc/research/lotus/lotus-overview.md#Roles \ No newline at end of file +[4]: https://paritytech.github.io/polkadot-sdk/master/pallet_session/index.html +[5]: https://github.com/eigerco/polka-disk/blob/main/doc/research/lotus/lotus-overview.md#Roles +[6]: https://spec.filecoin.io/#section-algorithms.pos.post \ No newline at end of file From 8859d5f90dd40536e6d3a45f6f8de6e509305b01 Mon Sep 17 00:00:00 2001 From: th7nder Date: Fri, 31 May 2024 13:49:09 +0200 Subject: [PATCH 05/12] docs: fix the collator role definition --- pallets/collator-power/DESIGN.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index 3cba64151..19584c36a 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -13,8 +13,9 @@ ## Overview -**Collators** are entities selected to produce **blocks** which are then finalized by relay chain's **validators**. -To participate in **block production**, a **Collator** needs to: +**Collators** are entities selected to produce state transition proofs which are then finalized by relay chain's **validators**. +They aggregate parachain transactions into **parachain block candidates*. +To participate in **block candidate production**, a **Collator** needs to: - stake a ***certain*** (yet to be determined) amount of tokens - be backed by **Miners'** **Storage Power**. Collators' staking is a requirement for participation in the process, the actual selection is based on **Storage Power**. From e823ccb1ae28f8956f8b6b74e34a68c32110fd00 Mon Sep 17 00:00:00 2001 From: th7nder Date: Fri, 31 May 2024 13:52:38 +0200 Subject: [PATCH 06/12] docs: be more precise about parachain block candidates --- pallets/collator-power/DESIGN.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index 19584c36a..0d0ccb35c 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -18,10 +18,11 @@ They aggregate parachain transactions into **parachain block candidates*. To participate in **block candidate production**, a **Collator** needs to: - stake a ***certain*** (yet to be determined) amount of tokens - be backed by **Miners'** **Storage Power**. + Collators' staking is a requirement for participation in the process, the actual selection is based on **Storage Power**. The collators are selected based on **Storage Power** by `CSP` in an randonmized auction algorithm. -The more **Storage Power** has been staked on a **Collator** by the **Miner**, the more likely their chances to be selected for block production. +The more **Storage Power** has been staked on a **Collator** by the **Miner**, the more likely their chances to be selected for parachain block candidate. This pallet works as a proxy between `SPP` and `CSP` to make collator choices. It stores how much **Storage Power** a **Miner** has and how much was delegated by **Miners** to **Collators**. From 416bb0b3ec5c0e8ea6682d4e34f796f529b7469c Mon Sep 17 00:00:00 2001 From: th7nder Date: Fri, 31 May 2024 14:33:19 +0200 Subject: [PATCH 07/12] docs: fix another stuff about block production --- pallets/collator-power/DESIGN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index 0d0ccb35c..2ad4b8022 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -22,7 +22,7 @@ To participate in **block candidate production**, a **Collator** needs to: Collators' staking is a requirement for participation in the process, the actual selection is based on **Storage Power**. The collators are selected based on **Storage Power** by `CSP` in an randonmized auction algorithm. -The more **Storage Power** has been staked on a **Collator** by the **Miner**, the more likely their chances to be selected for parachain block candidate. +The more **Storage Power** has been staked on a **Collator** by the **Miner**, the more likely their chances to be selected for parachain block candidate production. This pallet works as a proxy between `SPP` and `CSP` to make collator choices. It stores how much **Storage Power** a **Miner** has and how much was delegated by **Miners** to **Collators**. From 4c7726174518b685087ac2cba58f3fbbee12dd23 Mon Sep 17 00:00:00 2001 From: th7nder Date: Tue, 4 Jun 2024 16:38:01 +0200 Subject: [PATCH 08/12] docs: update the design to reflect established economy --- pallets/collator-power/DESIGN.md | 88 +++++++++++++++++--------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index 2ad4b8022..ad5c9a0c0 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -2,92 +2,96 @@ ## Glossary - **extrinsic** - state transition function on a pallet, essentially a signed transaction which requires an account with some tokens to be executed as it costs fees. -- **Miner** - [Storage Provider][5] +- [Storage Provider][5] - is running a full node and as well off-chain operations and provides storage to the blockchain clients. - **collateral** - amount of tokens staked by a miner (via `SPP`) to be able to provide storage services - **PoS** - [Proof of Storage][3] - **PoSt** - [Proof of Space-Time][6] - `SPP` - Storage Provider Pallet - `CPP` - Collator Power Pallet - `CSP` - Collator Selection Pallet +- `CRP` - Collator Reward Pallet - **session** - a [session][4] is a period of time that has a constant set of validators. ## Overview **Collators** are entities selected to produce state transition proofs which are then finalized by relay chain's **validators**. They aggregate parachain transactions into **parachain block candidates*. -To participate in **block candidate production**, a **Collator** needs to: -- stake a ***certain*** (yet to be determined) amount of tokens -- be backed by **Miners'** **Storage Power**. +To participate in **block candidate production**, a **Collator** needs to stake some **tokens**. +Proportionally to the amount of **tokens**, a **Collator** has a higher chance to be selected for the **block candidate production**. +**Collator** can stake his own tokens or a **Storage Provider** can delegate his tokens to the **Collator**. +**Storage Provider** by doing that can earn some tokens, when the **Collator** he delegated his tokens on is chosen for the production. +When a **Collator** is slashed, **Storage Provider** that staked their tokens on them is slashed accordingly. -Collators' staking is a requirement for participation in the process, the actual selection is based on **Storage Power**. - -The collators are selected based on **Storage Power** by `CSP` in an randonmized auction algorithm. -The more **Storage Power** has been staked on a **Collator** by the **Miner**, the more likely their chances to be selected for parachain block candidate production. +**Storage Providers** do not need to stake any tokens on Collator to support their storage resources, it's optional. +When **Storage Providers** misbehave e.g. fail to deliver some proof, they're being slashed from the collateral they pledged when for example: +- securing a new deal with a customer, +- adding storage capacity (which requires pledging). This pallet works as a proxy between `SPP` and `CSP` to make collator choices. -It stores how much **Storage Power** a **Miner** has and how much was delegated by **Miners** to **Collators**. +It stores how much power was delegated by **Miners** to **Collators**. Both `SPP` and `CSP` are [tightly coupled][2] to this pallet. -Trade Offs [?]: - -**Collators** are separately tracked by `CSP` and this pallet gives back the `staked_power` to a **Miner** when a **Collator** disappears. -This is an intentional design decision, this could be also tracked in this pallet, however I do think it'd make this Pallet too complex. -As Collators also need to be staked and require their own registration logic. - ## Data Structures ```rust -struct MinerClaim { - /// Indicates how much power a Miner has - raw_bytes_power: T::StoragePower; - staked_power: Map +struct CollatorInfo { + /// Identifier of a Collator + who: Collator, + /// Reserved deposit of a Collator + deposit: Power, + /// Delegated deposits from Storage Providers to Collators + delegated_deposit: Map } ``` ## Use Cases -### Registration +### Storage Provider Registration + +We need to identify storage providers somehow. +Calling a `Storage Provider Pallet` would create a circular dependency. +The `SPP` will call the registration function to let the `CPP` now, that a **Storage Provider** +is allowed to stake Power (tokens) on a **Collator**. #### Useful links - [Creating Storage Miner in Lotus][1] #### Assumptions -- `create_miner(miner: T::MinerId)` is an **extrinsic**. It's called by `Storage Provider Node` on a bootstrap. We can trust it, as `T::MinerId` is essentialy an account ID. The transaction needs to be signed, for it to be signed it needs to come from an account. For it to come from an account, the account has to have an **existential deposit** and it costs money. That's how it's DOS-resistant. +- `register_storage_provider(storage_provider: T::StorageProviderId)` is an **plain function**, it's called by `Storage Provider Pallet` when a new Storage Provider is registered, we trust the caller. It can only be called from `SPP` via [tight coupling][2]. #### Flow: -1. **Miner** calls `create_miner(miner: T::MinerId)` -2. `CPP` initializes `Map`. +1. `SPP` calls `register_storage_provider(storage_provider: T::StorageProviderId)` +2. `CPP` adds a `storage provider` to the `TreeSet` keeping the list of registered providers -### Manipulating Power +### Collator Registration #### Assumptions -- `SPP` only calls `CPP.update_miner_power` function after: - * Miner has been registered in `Collator Power` via `create_miner` function call - * Miner has submitted `PreCommit` sector with a certain (calculated by `SPP`) amount **Collateral** required - * Miner has proven sectors with **PoS** via `ProveCommit` of `SPP`. -- `update_miner_power` is ***NOT** an **extrinsic**. It can only be called from `SPP` via [tight coupling][2]. - - The reason is that we can't trust that a **Miner** will call extrinsic and update it on their own. `SPP` logic will perform those updates, e.g: after (not)receiving **PoSt**, receiving **pledge collaterals**. + +- **Collator** can register on its own by calling an extrinsic `register_as_collator()`. +- It requires a certain minimum amount of **collateral** (a bond) to be locked, to become a **collator**. +- After you registered as a **collator**, you can update your bond and lock even more **collateral**. #### Flow -1. `SPP` calls `CPP.update_miner_power(miner: T::MinerId, deltaStorageBytes: T::StoragePower)` -2. If Storage Power was decresed: `CPP` decreases all delegated power (to **Collators**) - - essentially means 'Slashing Miner and the Power they delegated' -3. If Storage Power was increased: `CPP` does nothing. -4. `CPP` performs bookeeping, updating `MinerClaim` -### Delegating Power +1. A node in the network calls `CPP.register_as_collator(origin: T::CollatorId)` +2. `CPP` verifies whether a account that originated the transaction has a minimum amount of **collateral** to be deposited. +3. `CPP` reserves (locks) deposited balance of the account, through `ReservableCurrency` +3. `CPP` adds `CollatorId` to the `Map` with the `deposit` equal to the minimum **bond**. + + +### Adding more Collator Power as a Collator #### Assumptions -- It's an **extrinsic**, can be called by a **Miner**. #### Flow -1. **Miner** calls `CPP.delegate_power(miner: T::MinerId, collator: T::CollatorId, amount: T::StoragePower)` -2. `CPP` saves delegated **Storage Power** in **Miner's** claims (`staked_power`). -3. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. -#### Slashing Collator (?) +x. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. + + +### Delegating power to a Collator as a Storage Provider + +### Slashing -TODO: I don't have this piece of the puzzle yet. I mean... What happens if a **Miner** staked some power on a **Collator** and it misbehaved? Do we **slash** the **Miner's** staked tokens/or storage power, and if so, how? [1]: https://github.com/filecoin-project/lotus/blob/9851d35a3811e5339560fb706926bf63a846edae/cmd/lotus-miner/init.go#L638 [2]: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_pallet_coupling/index.html#tight-coupling-pallets From 4eb3dae6c39014752964ac542de6f4b15dc4f525 Mon Sep 17 00:00:00 2001 From: th7nder Date: Tue, 4 Jun 2024 17:04:13 +0200 Subject: [PATCH 09/12] docs: adding more collator power as a collator --- pallets/collator-power/DESIGN.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index ad5c9a0c0..49b34df84 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -34,6 +34,12 @@ Both `SPP` and `CSP` are [tightly coupled][2] to this pallet. ## Data Structures ```rust +/// Store of Collators and their metadata +collators: BoundedBTreeMap> +/// List of available Storaged Providers +/// Used as an allowlist for who can stake on a Collator +storage_providers: BoundedBTreeSet + struct CollatorInfo { /// Identifier of a Collator who: Collator, @@ -53,11 +59,8 @@ Calling a `Storage Provider Pallet` would create a circular dependency. The `SPP` will call the registration function to let the `CPP` now, that a **Storage Provider** is allowed to stake Power (tokens) on a **Collator**. -#### Useful links -- [Creating Storage Miner in Lotus][1] - #### Assumptions -- `register_storage_provider(storage_provider: T::StorageProviderId)` is an **plain function**, it's called by `Storage Provider Pallet` when a new Storage Provider is registered, we trust the caller. It can only be called from `SPP` via [tight coupling][2]. +- `register_storage_provider(storage_provider: T::StorageProviderId)` is a **plain function**, it's called by `Storage Provider Pallet` when a new Storage Provider is registered, we trust the caller. It can only be called from `SPP` via [tight coupling][2]. #### Flow: 1. `SPP` calls `register_storage_provider(storage_provider: T::StorageProviderId)` @@ -78,14 +81,18 @@ is allowed to stake Power (tokens) on a **Collator**. 3. `CPP` reserves (locks) deposited balance of the account, through `ReservableCurrency` 3. `CPP` adds `CollatorId` to the `Map` with the `deposit` equal to the minimum **bond**. - ### Adding more Collator Power as a Collator #### Assumptions +- `CPP.update_bond` is an **extrinsic**, which is called by a **Collator**. +- You cannot update bond on a *Collator* that has not been registered before with `CPP.register_as_collator` +- `CPP.update_bond` can reduce as well as increase deposit, hence the Power + #### Flow -x. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. +1. **Collator** calls `CPP.update_bond(collator: T::CollatorId, new_deposit: BalanceOf)` +2. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. ### Delegating power to a Collator as a Storage Provider From 650a2e92cfdf18101968a5cd7441d980131bb9ea Mon Sep 17 00:00:00 2001 From: th7nder Date: Tue, 4 Jun 2024 17:24:24 +0200 Subject: [PATCH 10/12] docs: storage provider's delegating --- pallets/collator-power/DESIGN.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index 49b34df84..1dca1649b 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -94,11 +94,23 @@ is allowed to stake Power (tokens) on a **Collator**. 1. **Collator** calls `CPP.update_bond(collator: T::CollatorId, new_deposit: BalanceOf)` 2. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. - ### Delegating power to a Collator as a Storage Provider +#### Assumptions + +- `update_storage_provider_bond()` is an **extrinsic** that can be called by **Storage Providers** +- **Storage Provider** is present in the `storage_providers` set - has been registered with `CPP.register_storage_provider`. +- **Collator** has been registerd in `collators` TreeMap + +#### Flow + +1. **Storage Provider** calls `CPP.update_storage_provider_bond(storage_provider: T::StorageProviderId, collator: T:CollatorId, new_deposit: BalanceOf)` +2. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. + ### Slashing + + [1]: https://github.com/filecoin-project/lotus/blob/9851d35a3811e5339560fb706926bf63a846edae/cmd/lotus-miner/init.go#L638 [2]: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_pallet_coupling/index.html#tight-coupling-pallets From 4d20ff5bbc0b151054b396812602a79b5df34e53 Mon Sep 17 00:00:00 2001 From: th7nder Date: Tue, 4 Jun 2024 20:32:29 +0200 Subject: [PATCH 11/12] docs: slashing --- pallets/collator-power/DESIGN.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index 1dca1649b..eec6b8f56 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -109,6 +109,11 @@ is allowed to stake Power (tokens) on a **Collator**. ### Slashing + +### +- List of Collators +- Collator Rating + From debcfaee489638becf78f6403608550f38c43556 Mon Sep 17 00:00:00 2001 From: th7nder Date: Wed, 5 Jun 2024 21:09:41 +0200 Subject: [PATCH 12/12] docs: draft NPoS stuff --- pallets/collator-power/DESIGN.md | 55 ++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/pallets/collator-power/DESIGN.md b/pallets/collator-power/DESIGN.md index eec6b8f56..7713fdf06 100644 --- a/pallets/collator-power/DESIGN.md +++ b/pallets/collator-power/DESIGN.md @@ -1,16 +1,13 @@ # Overall Power Pallet Flow ## Glossary -- **extrinsic** - state transition function on a pallet, essentially a signed transaction which requires an account with some tokens to be executed as it costs fees. -- [Storage Provider][5] - is running a full node and as well off-chain operations and provides storage to the blockchain clients. -- **collateral** - amount of tokens staked by a miner (via `SPP`) to be able to provide storage services -- **PoS** - [Proof of Storage][3] -- **PoSt** - [Proof of Space-Time][6] +For an overview of established terms across the project look [here](../../docs/glossary.md). +This is just a handy index for shortcuts that are used in **this** design doc. + - `SPP` - Storage Provider Pallet - `CPP` - Collator Power Pallet - `CSP` - Collator Selection Pallet - `CRP` - Collator Reward Pallet -- **session** - a [session][4] is a period of time that has a constant set of validators. ## Overview @@ -107,19 +104,51 @@ is allowed to stake Power (tokens) on a **Collator**. 1. **Storage Provider** calls `CPP.update_storage_provider_bond(storage_provider: T::StorageProviderId, collator: T:CollatorId, new_deposit: BalanceOf)` 2. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. -### Slashing +### Getting list of Collator Candidates + +`Collator Selection Pallet` has it's own list of **invulnerables**, to get select next **Collator** it'll also used candidates based on the power defined in this pallet. + +#### Assumptions + +- `CPP.get_collator_candidates() -> BoundedVec` is a **plain function** that is called by `CSP` at the end of a session. + +#### Flow + +1. `CSP` calls `CPP.get_collator_candidates()` +2. `CPP` returns candidate list sorted by `Power` + +### Storage Provider Slashing + +When Storage Provider misbehaves, `Storage Provider Pallet` slashes the **Storage Provider** internally calls `update_storage_provider_bond` to decrease delegated **Power**. + +We need to consider: +- Eras vs Sessions + +### Collator Slashing + +****VERY UNSTABLE START***** +When Collator misbehaves, i.e. produces invalid block, someone needs to slash him, but who? +How does it work? Why is it important? Because then we also need to slash Storage Providers that backed him. +Lots of useful info is in the pallet reponsible for [`frame/staking`][7], we can probably use lots of implementation from there. +Seems complex enough though. It basically implements Substrate [NPoS][10], which we want to use, but with a twist. +Our twist is that, only **Storage Provider** can become **a Nominator**. Whether that's good, we are yet to determine. -### -- List of Collators -- Collator Rating +Overall process looks like this: +- [pallet_babe][8] - [BABE][9] consensus has a constant set of validators (collators) in an epoch, epoch is divided in slots. For every slot a validator is selected randomly. If other validators detect, that the leader fails, the process of **equivocation** is launched. +- [pallet_offences][11] - pallet offences exposes an `OffenceHandler` interface, which is used by `pallet_babe`. +- [pallet_staking][7] - handles **Validator**'s and **Nominators** balances, and implements `OffenceHandler` defined by `pallet_offences` and used by `pallet_babe`. - - +****VERY UNSTABLE END**** [1]: https://github.com/filecoin-project/lotus/blob/9851d35a3811e5339560fb706926bf63a846edae/cmd/lotus-miner/init.go#L638 [2]: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_pallet_coupling/index.html#tight-coupling-pallets [3]: https://spec.filecoin.io/#section-algorithms.pos [4]: https://paritytech.github.io/polkadot-sdk/master/pallet_session/index.html [5]: https://github.com/eigerco/polka-disk/blob/main/doc/research/lotus/lotus-overview.md#Roles -[6]: https://spec.filecoin.io/#section-algorithms.pos.post \ No newline at end of file +[6]: https://spec.filecoin.io/#section-algorithms.pos.post +[7]: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/staking/README.md +[8]: https://paritytech.github.io/polkadot-sdk/master/pallet_babe/index.html +[9]: https://research.web3.foundation/Polkadot/protocols/block-production/Babe +[10]: https://research.web3.foundation/Polkadot/protocols/NPoS/Overview +[11]: https://paritytech.github.io/polkadot-sdk/master/pallet_offences/index.html \ No newline at end of file