-
Notifications
You must be signed in to change notification settings - Fork 0
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: interface and data structures for Collator Power Pallet #53
Closed
Closed
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
c032385
chore: set-up a pallet-collator-power skeleton
th7nder 9fec6c3
feat: add storage maps for sps and collators
th7nder 0138910
docs: add a lovely design doc
th7nder 567c77f
docs: fix minor issues
th7nder 8859d5f
docs: fix the collator role definition
th7nder e823ccb
docs: be more precise about parachain block candidates
th7nder 416bb0b
docs: fix another stuff about block production
th7nder 4c77261
docs: update the design to reflect established economy
th7nder 4eb3dae
docs: adding more collator power as a collator
th7nder 650a2e9
docs: storage provider's delegating
th7nder 4d20ff5
docs: slashing
th7nder debcfae
docs: draft NPoS stuff
th7nder File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# Overall Power Pallet Flow | ||
|
||
## Glossary | ||
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 | ||
|
||
## 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 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. | ||
|
||
**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 power was delegated by **Miners** to **Collators**. | ||
Both `SPP` and `CSP` are [tightly coupled][2] to this pallet. | ||
|
||
## Data Structures | ||
|
||
```rust | ||
/// Store of Collators and their metadata | ||
collators: BoundedBTreeMap<CollatorId, StoragePower, ConstU32<100>> | ||
/// List of available Storaged Providers | ||
/// Used as an allowlist for who can stake on a Collator | ||
storage_providers: BoundedBTreeSet<StorageProviderId> | ||
|
||
struct CollatorInfo<Collator, StorageProvider, Power> { | ||
/// Identifier of a Collator | ||
who: Collator, | ||
/// Reserved deposit of a Collator | ||
deposit: Power, | ||
/// Delegated deposits from Storage Providers to Collators | ||
delegated_deposit: Map<StorageProvider, Power> | ||
} | ||
``` | ||
|
||
## Use Cases | ||
|
||
### 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**. | ||
|
||
#### Assumptions | ||
- `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)` | ||
2. `CPP` adds a `storage provider` to the `TreeSet` keeping the list of registered providers | ||
|
||
### Collator Registration | ||
|
||
#### Assumptions | ||
|
||
- **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. 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<Collator, CollatorInfo>` 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 | ||
|
||
1. **Collator** calls `CPP.update_bond(collator: T::CollatorId, new_deposit: BalanceOf<T>)` | ||
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<T>)` | ||
2. In the next **session**, the saved Power is picked up by `CSP`, by calling `CPP.get_collator_power(collator: T::CollatorId) -> T::StoragePower`. | ||
|
||
|
||
### 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<CollatorId, Power>` 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. | ||
|
||
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 | ||
[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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Collator Power Pallet | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
//! # Collator Power Pallet | ||
//! | ||
//! # 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, | ||
}; | ||
use frame_system::{pallet_prelude::*}; | ||
use scale_info::TypeInfo; | ||
|
||
#[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<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; | ||
|
||
/// 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 Miner | ||
type MinerId: Parameter + Member + Ord + MaxEncodedLen; | ||
} | ||
|
||
#[derive( | ||
Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, Default, TypeInfo, MaxEncodedLen, | ||
)] | ||
pub struct MinerClaim<CollatorId: Ord, StoragePower> { | ||
/// Number of bytes stored by a Miner | ||
raw_bytes_power: StoragePower, | ||
th7nder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// Stores how much currency was staked on a particular collator | ||
staked_power: BoundedBTreeMap<CollatorId, StoragePower, ConstU32<10>> | ||
} | ||
|
||
#[pallet::pallet] | ||
pub struct Pallet<T>(_); | ||
th7nder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#[pallet::storage] | ||
#[pallet::getter(fn storage_provider_claims)] | ||
pub type MinerClaims<T: Config> = | ||
StorageMap<_, _, T::MinerId, MinerClaim<T::CollatorId, T::StoragePower>>; | ||
|
||
#[pallet::event] | ||
// #[pallet::generate_deposit(pub(super) fn deposit_event)] | ||
pub enum Event<T: Config> { | ||
/// 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<T> { | ||
/// 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<T: Config> Pallet<T> { | ||
/// After Miner proved a sector, calls this method to update the bookkeeping about available power. | ||
pub fn update_storage_power( | ||
_storage_provider: OriginFor<T>, | ||
_raw_delta_bytes: T::StoragePower, | ||
) -> DispatchResultWithPostInfo { | ||
todo!() | ||
} | ||
} | ||
|
||
/// Functions exposed by the pallet | ||
/// e.g. `pallet-collator-selection` used them to make decision about the next block producer | ||
impl<T: Config> Pallet<T> { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are using mono repo for our work, the glossary could be made in a separate, higher-level document to keep terminology consistent across the project.