mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-10 13:09:24 +00:00
Compare commits
6 Commits
ffae6753ec
...
ea66cd0d1a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea66cd0d1a | ||
|
|
8b32fba458 | ||
|
|
e63acf3f67 | ||
|
|
d373d2a4c9 | ||
|
|
cbf998ff30 | ||
|
|
ef07253a27 |
@@ -7,6 +7,10 @@ runs:
|
||||
- name: Remove unused packages
|
||||
shell: bash
|
||||
run: |
|
||||
# Ensure the repositories are synced
|
||||
sudo apt update -y
|
||||
|
||||
# Actually perform the removals
|
||||
sudo apt remove -y "*powershell*" "*nuget*" "*bazel*" "*ansible*" "*terraform*" "*heroku*" "*aws*" azure-cli
|
||||
sudo apt remove -y "*nodejs*" "*npm*" "*yarn*" "*java*" "*kotlin*" "*golang*" "*swift*" "*julia*" "*fortran*" "*android*"
|
||||
sudo apt remove -y "*apache2*" "*nginx*" "*firefox*" "*chromium*" "*chrome*" "*edge*"
|
||||
@@ -14,8 +18,9 @@ runs:
|
||||
sudo apt remove -y --allow-remove-essential -f shim-signed *python3*
|
||||
# This removal command requires the prior removals due to unmet dependencies otherwise
|
||||
sudo apt remove -y "*qemu*" "*sql*" "*texinfo*" "*imagemagick*"
|
||||
|
||||
# Reinstall python3 as a general dependency of a functional operating system
|
||||
sudo apt install python3
|
||||
sudo apt install -y python3 --fix-missing
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
- name: Remove unused packages
|
||||
|
||||
447
Cargo.lock
generated
447
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -22,12 +22,12 @@ workspace = true
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||
|
||||
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serde = { version = "1", default-features = false, features = ["derive"], optional = true }
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"], optional = true }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false, features = ["serde"], optional = true }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false, optional = true }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false, features = ["serde"], optional = true }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false, optional = true }
|
||||
|
||||
serai-primitives = { path = "../primitives", version = "0.1", default-features = false }
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use serai_primitives::network_id::ExternalNetworkId;
|
||||
use serai_primitives::{
|
||||
network_id::ExternalNetworkId,
|
||||
balance::{Amount, ExternalBalance},
|
||||
};
|
||||
|
||||
/// An event from economic security.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
@@ -14,7 +17,10 @@ pub enum Event {
|
||||
|
||||
/// A trait representing access to the information on economic security.
|
||||
pub trait EconomicSecurity {
|
||||
/// If am external network has _ever_ achieved economic security.
|
||||
/// If an external network has _ever_ achieved economic security.
|
||||
#[must_use]
|
||||
fn achieved_economic_security(network: ExternalNetworkId) -> bool;
|
||||
|
||||
/// The security oracle's valuation of this balance in SRI.
|
||||
fn sri_value(balance: ExternalBalance) -> Amount;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ pub enum Call {
|
||||
stand_against {
|
||||
/// The signal to stand against.
|
||||
signal: Signal,
|
||||
/// The network this validator is standing against the signal on behalf of.
|
||||
with_network: NetworkId,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ use serai_primitives::{
|
||||
pub enum Call {
|
||||
/// Set the keys for a validator set.
|
||||
set_keys {
|
||||
/// The validator set which is setting their keys.
|
||||
validator_set: ExternalValidatorSet,
|
||||
/// The network whose latest decided validator set is setting their keys..
|
||||
network: ExternalNetworkId,
|
||||
/// The keys being set.
|
||||
key_pair: KeyPair,
|
||||
/// The participants in the validator set who signed off on these keys.
|
||||
@@ -29,8 +29,8 @@ pub enum Call {
|
||||
},
|
||||
/// Report a validator set's slashes onto Serai.
|
||||
report_slashes {
|
||||
/// The validator set which is setting their keys.
|
||||
validator_set: ExternalValidatorSet,
|
||||
/// The network whose latest retired validator set is reporting their slashes.
|
||||
network: ExternalNetworkId,
|
||||
/// The slashes they're reporting.
|
||||
slashes: SlashReport,
|
||||
/// The signature confirming the validity of this slash report.
|
||||
@@ -77,12 +77,24 @@ impl Call {
|
||||
}
|
||||
}
|
||||
|
||||
/// The timeline for a deallocation.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum DeallocationTimeline {
|
||||
/// The deallocation is available immediately.
|
||||
Immediate,
|
||||
/// The dealocation was delayed.
|
||||
Delayed {
|
||||
/// The session the deallocation unlocks at and can be claimed.
|
||||
unlocks_at: Session,
|
||||
},
|
||||
}
|
||||
|
||||
/// An event from the validator sets.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
/// A new validator set was declared.
|
||||
NewSet {
|
||||
/// The set declared.
|
||||
/// A new validator set was decided.
|
||||
SetDecided {
|
||||
/// The set decided.
|
||||
set: ValidatorSet,
|
||||
},
|
||||
/// A validator set has set their keys.
|
||||
@@ -97,10 +109,20 @@ pub enum Event {
|
||||
/// The set which accepted responsibility from the prior set.
|
||||
set: ValidatorSet,
|
||||
},
|
||||
/// A validator set has retired.
|
||||
SetRetired {
|
||||
/// The set retired.
|
||||
set: ValidatorSet,
|
||||
/// A slash report has been entered for this validator set.
|
||||
///
|
||||
/// This may be due to a slash report being published or a default being used due to one not
|
||||
/// being received within time.
|
||||
SlashReport {
|
||||
/// The set whose slash report has been entered.
|
||||
set: ExternalValidatorSet,
|
||||
},
|
||||
/// A validator set their keys on an embedded elliptic curve for a network.
|
||||
SetEmbeddedEllipticCurveKeys {
|
||||
/// The validator which set their keys.
|
||||
validator: SeraiAddress,
|
||||
/// The network which they set embedded elliptic curve keys for.
|
||||
network: ExternalNetworkId,
|
||||
},
|
||||
/// A validator's allocation to a network has increased.
|
||||
Allocation {
|
||||
@@ -119,13 +141,11 @@ pub enum Event {
|
||||
network: NetworkId,
|
||||
/// The amount of stake deallocated.
|
||||
amount: Amount,
|
||||
/// The session which claiming the deallocation was delayed until.
|
||||
delayed_until: Option<Session>,
|
||||
/// The timeline for this deallocation.
|
||||
timeline: DeallocationTimeline,
|
||||
},
|
||||
/// A validator's deallocation from a network has been claimed.
|
||||
///
|
||||
/// This is only emited for deallocations which were delayed and has to be explicitly claimed.
|
||||
DeallocationClaimed {
|
||||
/// A validator's delayed deallocation from a network has been claimed.
|
||||
DelayedDeallocationClaimed {
|
||||
/// The validator who claimed their deallocation.
|
||||
validator: SeraiAddress,
|
||||
/// The validator set the deallocation was delayed until.
|
||||
|
||||
@@ -31,9 +31,9 @@ serde_json = { version = "1", optional = true }
|
||||
serai-abi = { path = "../abi", version = "0.1" }
|
||||
|
||||
multiaddr = { version = "0.18", optional = true }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", optional = true }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", optional = true }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", optional = true }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", optional = true }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", optional = true }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", optional = true }
|
||||
|
||||
async-lock = "3"
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ workspace = true
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
serai-core-pallet = { path = "../core", default-features = false }
|
||||
@@ -29,7 +29,7 @@ serai-core-pallet = { path = "../core", default-features = false }
|
||||
[dev-dependencies]
|
||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false, features = ["std"] }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false, features = ["std"] }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
|
||||
@@ -49,10 +49,12 @@ mod pallet {
|
||||
/// The instance used to represent coins on the Serai network.
|
||||
///
|
||||
/// This would either be SRI itself or the sriXYZ coins swappable via pools.
|
||||
#[derive(Default)]
|
||||
pub struct CoinsInstance;
|
||||
/// The instance used to represent liquidity tokens on the Serai network.
|
||||
///
|
||||
/// Coin::XYZ would be considered as the liquidity token for the Coin::SRI - Coin::XYZ pool.
|
||||
#[derive(Default)]
|
||||
pub struct LiquidityTokensInstance;
|
||||
|
||||
/// The configuration of this pallet.
|
||||
@@ -66,7 +68,7 @@ mod pallet {
|
||||
|
||||
/// The genesis state to use for this pallet.
|
||||
#[pallet::genesis_config]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
|
||||
/// The balances to initiate the state with.
|
||||
///
|
||||
@@ -76,10 +78,9 @@ mod pallet {
|
||||
/// PhantomData to bind `I`.
|
||||
pub _instance: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
|
||||
fn default() -> Self {
|
||||
GenesisConfig { accounts: Default::default(), _instance: Default::default() }
|
||||
Self { accounts: Default::default(), _instance: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ borsh = { version = "1", default-features = false, features = ["derive", "de_str
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
|
||||
@@ -21,15 +21,15 @@ workspace = true
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false }
|
||||
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false, optional = true }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false, optional = true }
|
||||
|
||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ workspace = true
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
dex-pallet = { package = "serai-dex-pallet", path = "../dex", default-features = false }
|
||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||
@@ -30,16 +30,16 @@ coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-feat
|
||||
serai-primitives = { path = "../primitives", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
||||
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
|
||||
@@ -21,11 +21,11 @@ workspace = true
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
||||
|
||||
@@ -21,12 +21,12 @@ workspace = true
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
dex-pallet = { package = "serai-dex-pallet", path = "../dex", default-features = false }
|
||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||
|
||||
@@ -24,14 +24,14 @@ bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] }
|
||||
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serai-primitives = { path = "../primitives", default-features = false }
|
||||
|
||||
@@ -42,9 +42,9 @@ genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path =
|
||||
emissions-pallet = { package = "serai-emissions-pallet", path = "../emissions", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
economic-security-pallet = { package = "serai-economic-security-pallet", path = "../economic-security", default-features = false }
|
||||
|
||||
|
||||
@@ -34,16 +34,16 @@ secq256k1 = { path = "../../crypto/secq256k1" }
|
||||
|
||||
libp2p = "0.56"
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-keystore = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-blockchain = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sp-keystore = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sp-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sp-blockchain = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
|
||||
serai-runtime = { path = "../runtime", features = ["std"] }
|
||||
|
||||
@@ -55,24 +55,24 @@ jsonrpsee = { version = "0.24", features = ["server"] }
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
sc-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-transaction-pool-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-client-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-network-common = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-network = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sc-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-transaction-pool-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-client-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-network-common = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-network = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
sc-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-authority-discovery = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-authority-discovery = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
|
||||
sc-telemetry = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-cli = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false, features = ["rocksdb"] }
|
||||
sc-telemetry = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
sc-cli = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false, features = ["rocksdb"] }
|
||||
|
||||
sc-rpc-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
sc-rpc-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
|
||||
serai-env = { path = "../../common/env" }
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ borsh = { version = "1", default-features = false, features = ["derive", "de_str
|
||||
|
||||
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"], optional = true }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["alloc"] }
|
||||
schnorr-signatures = { path = "../../crypto/schnorr", default-features = false }
|
||||
|
||||
@@ -20,16 +20,22 @@ workspace = true
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-version = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-version = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-executive = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-executive = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serai-core-pallet = { path = "../core", default-features = false }
|
||||
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||
@@ -37,13 +43,14 @@ serai-validator-sets-pallet = { path = "../validator-sets", default-features = f
|
||||
serai-signals-pallet = { path = "../signals", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9" }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"scale/std",
|
||||
|
||||
"sp-core/std",
|
||||
"sp-session/std",
|
||||
"sp-version/std",
|
||||
"sp-runtime/std",
|
||||
"sp-api/std",
|
||||
@@ -54,6 +61,10 @@ std = [
|
||||
"frame-support/std",
|
||||
"frame-executive/std",
|
||||
|
||||
"pallet-session/std",
|
||||
"pallet-babe/std",
|
||||
"pallet-grandpa/std",
|
||||
|
||||
"serai-core-pallet/std",
|
||||
"serai-coins-pallet/std",
|
||||
"serai-validator-sets-pallet/std",
|
||||
@@ -69,6 +80,10 @@ try-runtime = [
|
||||
"frame-support/try-runtime",
|
||||
"frame-executive/try-runtime",
|
||||
|
||||
"pallet-session/try-runtime",
|
||||
"pallet-babe/try-runtime",
|
||||
"pallet-grandpa/try-runtime",
|
||||
|
||||
"serai-core-pallet/try-runtime",
|
||||
"serai-coins-pallet/try-runtime",
|
||||
"serai-validator-sets-pallet/try-runtime",
|
||||
@@ -81,6 +96,10 @@ runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
|
||||
"pallet-babe/runtime-benchmarks",
|
||||
"pallet-grandpa/runtime-benchmarks",
|
||||
|
||||
"pallet-session/runtime-benchmarks",
|
||||
"serai-core-pallet/runtime-benchmarks",
|
||||
"serai-coins-pallet/runtime-benchmarks",
|
||||
"serai-validator-sets-pallet/runtime-benchmarks",
|
||||
|
||||
@@ -8,13 +8,17 @@ extern crate alloc;
|
||||
|
||||
use alloc::borrow::Cow;
|
||||
|
||||
use sp_core::sr25519::Public;
|
||||
use sp_core::{ConstU32, ConstU64, sr25519::Public};
|
||||
use sp_runtime::{Perbill, Weight};
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
#[rustfmt::skip]
|
||||
use serai_abi::{
|
||||
primitives::address::SeraiAddress, SubstrateHeader as Header, SubstrateBlock,
|
||||
primitives::{
|
||||
network_id::{ExternalNetworkId, NetworkId},
|
||||
balance::{Amount, ExternalBalance},
|
||||
address::SeraiAddress,
|
||||
},
|
||||
SubstrateHeader as Header, SubstrateBlock,
|
||||
};
|
||||
|
||||
use serai_coins_pallet::{CoinsInstance, LiquidityTokensInstance};
|
||||
@@ -79,13 +83,22 @@ mod runtime {
|
||||
pub type Coins = serai_coins_pallet::Pallet<Runtime, CoinsInstance>;
|
||||
|
||||
#[runtime::pallet_index(3)]
|
||||
pub type LiquidityTokens = serai_coins_pallet::Pallet<Runtime, LiquidityTokensInstance>;
|
||||
|
||||
#[runtime::pallet_index(4)]
|
||||
pub type ValidatorSets = serai_validator_sets_pallet::Pallet<Runtime>;
|
||||
|
||||
#[runtime::pallet_index(5)]
|
||||
#[runtime::pallet_index(4)]
|
||||
pub type Signals = serai_signals_pallet::Pallet<Runtime>;
|
||||
|
||||
#[runtime::pallet_index(5)]
|
||||
pub type LiquidityTokens = serai_coins_pallet::Pallet<Runtime, LiquidityTokensInstance>;
|
||||
|
||||
#[runtime::pallet_index(0xfd)]
|
||||
pub type Session = pallet_session::Pallet<Runtime>;
|
||||
|
||||
#[runtime::pallet_index(0xfe)]
|
||||
pub type Babe = pallet_babe::Pallet<Runtime>;
|
||||
|
||||
#[runtime::pallet_index(0xff)]
|
||||
pub type Grandpa = pallet_grandpa::Pallet<Runtime>;
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
@@ -104,7 +117,7 @@ impl frame_system::Config for Runtime {
|
||||
type Block = Block;
|
||||
// Don't track old block hashes within the System pallet
|
||||
// We use not a number -> hash index, but a hash -> () index, in our own pallet
|
||||
type BlockHashCount = sp_core::ConstU64<1>;
|
||||
type BlockHashCount = ConstU64<1>;
|
||||
type DbWeight = frame_support::weights::constants::RocksDbWeight;
|
||||
type Version = Version;
|
||||
type PalletInfo = PalletInfo;
|
||||
@@ -118,7 +131,7 @@ impl frame_system::Config for Runtime {
|
||||
// We don't invoke any hooks on-set-code as we don't perform upgrades via the blockchain yet via
|
||||
// nodes, ensuring everyone who upgrades consents to the rules they upgrade to
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = sp_core::ConstU32<{ u32::MAX }>;
|
||||
type MaxConsumers = ConstU32<{ u32::MAX }>;
|
||||
// No migrations set
|
||||
type SingleBlockMigrations = ();
|
||||
type MultiBlockMigrator = ();
|
||||
@@ -133,15 +146,84 @@ impl serai_core_pallet::Config for Runtime {}
|
||||
impl serai_coins_pallet::Config<CoinsInstance> for Runtime {
|
||||
type AllowMint = serai_coins_pallet::AlwaysAllowMint; // TODO
|
||||
}
|
||||
impl serai_coins_pallet::Config<LiquidityTokensInstance> for Runtime {
|
||||
type AllowMint = serai_coins_pallet::AlwaysAllowMint;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct EconomicSecurity; // TODO
|
||||
impl serai_abi::economic_security::EconomicSecurity for EconomicSecurity {
|
||||
fn achieved_economic_security(_network: ExternalNetworkId) -> bool {
|
||||
false
|
||||
}
|
||||
fn sri_value(_balance: ExternalBalance) -> Amount {
|
||||
Amount(0)
|
||||
}
|
||||
}
|
||||
impl serai_validator_sets_pallet::Config for Runtime {
|
||||
type ShouldEndSession = Babe;
|
||||
type EconomicSecurity = EconomicSecurity;
|
||||
}
|
||||
impl serai_signals_pallet::Config for Runtime {
|
||||
type RetirementValidityDuration = sp_core::ConstU64<0>; // TODO
|
||||
type RetirementLockInDuration = sp_core::ConstU64<0>; // TODO
|
||||
type RetirementValidityDuration = ConstU64<0>; // TODO
|
||||
type RetirementLockInDuration = ConstU64<0>; // TODO
|
||||
}
|
||||
impl serai_coins_pallet::Config<LiquidityTokensInstance> for Runtime {
|
||||
type AllowMint = serai_coins_pallet::AlwaysAllowMint;
|
||||
}
|
||||
|
||||
/*
|
||||
`pallet-babe` requires we implement `pallet-timestamp` for the associated constants. It does not
|
||||
actually require we offer the timestamp pallet however, and we don't as we follow our methodology
|
||||
(using the block header for timestamps, not an inherent transaction).
|
||||
|
||||
TODO: Set timestamp when executing a block.
|
||||
*/
|
||||
impl pallet_timestamp::Config for Runtime {
|
||||
type Moment = u64;
|
||||
type OnTimestampSet = Babe;
|
||||
type MinimumPeriod = ConstU64<0>; // TODO
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct GetCurrentSessionForSubstrate;
|
||||
impl pallet_session::GetCurrentSessionForSubstrate for GetCurrentSessionForSubstrate {
|
||||
fn get() -> u32 {
|
||||
serai_validator_sets_pallet::Pallet::<Runtime>::current_session(NetworkId::Serai)
|
||||
.map(|session| session.0)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
impl pallet_session::Config for Runtime {
|
||||
type Session = GetCurrentSessionForSubstrate;
|
||||
}
|
||||
|
||||
type MaxAuthorities =
|
||||
ConstU32<{ serai_abi::primitives::validator_sets::KeyShares::MAX_PER_SET_U32 }>;
|
||||
impl pallet_babe::Config for Runtime {
|
||||
type EpochDuration = ConstU64<0>; // TODO
|
||||
|
||||
type ExpectedBlockTime = ConstU64<0>; // TODO
|
||||
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
|
||||
|
||||
type WeightInfo = ();
|
||||
type MaxAuthorities = MaxAuthorities;
|
||||
type MaxNominators = ConstU32<1>;
|
||||
|
||||
// TODO: https://github.com/serai-dex/serai/issues/657
|
||||
type DisabledValidators = ();
|
||||
type KeyOwnerProof = sp_session::MembershipProof;
|
||||
type EquivocationReportSystem = ();
|
||||
}
|
||||
impl pallet_grandpa::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
|
||||
type WeightInfo = ();
|
||||
type MaxAuthorities = MaxAuthorities;
|
||||
type MaxNominators = ConstU32<1>;
|
||||
|
||||
// TODO: https://github.com/serai-dex/serai/issues/657
|
||||
type MaxSetIdSessionEntries = ConstU64<0>;
|
||||
type KeyOwnerProof = sp_session::MembershipProof;
|
||||
type EquivocationReportSystem = ();
|
||||
}
|
||||
|
||||
impl From<Option<SeraiAddress>> for RuntimeOrigin {
|
||||
@@ -158,36 +240,54 @@ impl From<serai_abi::Call> for RuntimeCall {
|
||||
match call {
|
||||
serai_abi::Call::Coins(call) => {
|
||||
use serai_abi::coins::Call;
|
||||
match call {
|
||||
Call::transfer { to, coins } => {
|
||||
RuntimeCall::Coins(serai_coins_pallet::Call::transfer { to: to.into(), coins })
|
||||
}
|
||||
Call::burn { coins } => RuntimeCall::Coins(serai_coins_pallet::Call::burn { coins }),
|
||||
use serai_coins_pallet::Call as Scall;
|
||||
RuntimeCall::Coins(match call {
|
||||
Call::transfer { to, coins } => Scall::transfer { to: to.into(), coins },
|
||||
Call::burn { coins } => Scall::burn { coins },
|
||||
Call::burn_with_instruction { instruction } => {
|
||||
RuntimeCall::Coins(serai_coins_pallet::Call::burn_with_instruction { instruction })
|
||||
Scall::burn_with_instruction { instruction }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::ValidatorSets(call) => {
|
||||
use serai_abi::validator_sets::Call;
|
||||
match call {
|
||||
Call::set_keys { .. } |
|
||||
Call::report_slashes { .. } |
|
||||
Call::set_embedded_elliptic_curve_keys { .. } |
|
||||
Call::allocate { .. } |
|
||||
Call::deallocate { .. } |
|
||||
Call::claim_deallocation { .. } => todo!("TODO"),
|
||||
}
|
||||
use serai_validator_sets_pallet::Call as Scall;
|
||||
RuntimeCall::ValidatorSets(match call {
|
||||
Call::set_keys { network, key_pair, signature_participants, signature } => {
|
||||
Scall::set_keys { network, key_pair, signature_participants, signature }
|
||||
}
|
||||
Call::report_slashes { network, slashes, signature } => {
|
||||
Scall::report_slashes { network, slashes, signature }
|
||||
}
|
||||
Call::set_embedded_elliptic_curve_keys { keys } => {
|
||||
Scall::set_embedded_elliptic_curve_keys { keys }
|
||||
}
|
||||
Call::allocate { network, amount } => Scall::allocate { network, amount },
|
||||
Call::deallocate { network, amount } => Scall::deallocate { network, amount },
|
||||
Call::claim_deallocation { deallocation } => Scall::claim_deallocation {
|
||||
network: deallocation.network,
|
||||
session: deallocation.session,
|
||||
},
|
||||
})
|
||||
}
|
||||
serai_abi::Call::Signals(call) => {
|
||||
use serai_abi::signals::Call;
|
||||
match call {
|
||||
Call::register_retirement_signal { .. } |
|
||||
Call::revoke_retirement_signal { .. } |
|
||||
Call::favor { .. } |
|
||||
Call::revoke_favor { .. } |
|
||||
Call::stand_against { .. } => todo!("TODO"),
|
||||
}
|
||||
use serai_signals_pallet::Call as Scall;
|
||||
RuntimeCall::Signals(match call {
|
||||
Call::register_retirement_signal { in_favor_of } => {
|
||||
Scall::register_retirement_signal { in_favor_of }
|
||||
}
|
||||
Call::revoke_retirement_signal { was_in_favor_of } => {
|
||||
Scall::revoke_retirement_signal { retirement_signal: was_in_favor_of }
|
||||
}
|
||||
Call::favor { signal, with_network } => Scall::favor { signal, with_network },
|
||||
Call::revoke_favor { signal, with_network } => {
|
||||
Scall::revoke_favor { signal, with_network }
|
||||
}
|
||||
Call::stand_against { signal, with_network } => {
|
||||
Scall::stand_against { signal, with_network }
|
||||
}
|
||||
})
|
||||
}
|
||||
serai_abi::Call::Dex(call) => {
|
||||
use serai_abi::dex::Call;
|
||||
@@ -331,9 +431,6 @@ pub use in_instructions_pallet as in_instructions;
|
||||
|
||||
pub use signals_pallet as signals;
|
||||
|
||||
pub use pallet_babe as babe;
|
||||
pub use pallet_grandpa as grandpa;
|
||||
|
||||
pub use genesis_liquidity_pallet as genesis_liquidity;
|
||||
pub use emissions_pallet as emissions;
|
||||
|
||||
@@ -492,43 +589,9 @@ impl pallet_authorship::Config for Runtime {
|
||||
type EventHandler = ();
|
||||
}
|
||||
|
||||
// Maximum number of authorities per session.
|
||||
pub type MaxAuthorities = ConstU32<{ validator_sets::primitives::MAX_KEY_SHARES_PER_SET_U32 }>;
|
||||
|
||||
/// Longevity of an offence report.
|
||||
pub type ReportLongevity = <Runtime as pallet_babe::Config>::EpochDuration;
|
||||
|
||||
impl babe::Config for Runtime {
|
||||
#[cfg(feature = "fast-epoch")]
|
||||
type EpochDuration = ConstU64<{ FAST_EPOCH_DURATION }>;
|
||||
|
||||
#[cfg(not(feature = "fast-epoch"))]
|
||||
type EpochDuration = ConstU64<{ 4 * 7 * DAYS }>;
|
||||
|
||||
type ExpectedBlockTime = ConstU64<{ TARGET_BLOCK_TIME * 1000 }>;
|
||||
type EpochChangeTrigger = babe::ExternalTrigger;
|
||||
type DisabledValidators = ValidatorSets;
|
||||
|
||||
type WeightInfo = ();
|
||||
type MaxAuthorities = MaxAuthorities;
|
||||
|
||||
type KeyOwnerProof = MembershipProof<Self>;
|
||||
type EquivocationReportSystem =
|
||||
babe::EquivocationReportSystem<Self, ValidatorSets, ValidatorSets, ReportLongevity>;
|
||||
}
|
||||
|
||||
impl grandpa::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
|
||||
type WeightInfo = ();
|
||||
type MaxAuthorities = MaxAuthorities;
|
||||
|
||||
type MaxSetIdSessionEntries = ConstU64<0>;
|
||||
type KeyOwnerProof = MembershipProof<Self>;
|
||||
type EquivocationReportSystem =
|
||||
grandpa::EquivocationReportSystem<Self, ValidatorSets, ValidatorSets, ReportLongevity>;
|
||||
}
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
System: system exclude_parts { Call },
|
||||
|
||||
@@ -21,10 +21,10 @@ workspace = true
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
|
||||
@@ -36,13 +36,13 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[derive(Debug, Encode, Decode)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
_config: PhantomData<T>,
|
||||
}
|
||||
impl<T: Config> Default for GenesisConfig<T> {
|
||||
fn default() -> Self {
|
||||
GenesisConfig { _config: PhantomData }
|
||||
Self { _config: PhantomData }
|
||||
}
|
||||
}
|
||||
#[pallet::genesis_build]
|
||||
@@ -221,20 +221,16 @@ pub mod pallet {
|
||||
fn revoke_favor_internal(
|
||||
validator: T::AccountId,
|
||||
signal: Signal,
|
||||
for_network: NetworkId,
|
||||
with_network: NetworkId,
|
||||
) -> DispatchResult {
|
||||
if !Favors::<T>::contains_key((signal, for_network), validator) {
|
||||
if !Favors::<T>::contains_key((signal, with_network), validator) {
|
||||
Err::<(), _>(Error::<T>::RevokingNonExistentFavor)?;
|
||||
}
|
||||
Favors::<T>::remove((signal, for_network), validator);
|
||||
Core::<T>::emit_event(Event::FavorRevoked {
|
||||
signal,
|
||||
by: validator.into(),
|
||||
with_network: for_network,
|
||||
});
|
||||
Favors::<T>::remove((signal, with_network), validator);
|
||||
Core::<T>::emit_event(Event::FavorRevoked { signal, by: validator.into(), with_network });
|
||||
|
||||
// Update the tally for this network
|
||||
Self::tally_for_network(signal, for_network);
|
||||
Self::tally_for_network(signal, with_network);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -342,7 +338,7 @@ pub mod pallet {
|
||||
/// Favor a signal.
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||
pub fn favor(origin: OriginFor<T>, signal: Signal, for_network: NetworkId) -> DispatchResult {
|
||||
pub fn favor(origin: OriginFor<T>, signal: Signal, with_network: NetworkId) -> DispatchResult {
|
||||
let validator = ensure_signed(origin)?;
|
||||
|
||||
// Perform the relevant checks for this class of signal
|
||||
@@ -373,21 +369,17 @@ pub mod pallet {
|
||||
Signal::Halt { .. } => {}
|
||||
}
|
||||
|
||||
if Favors::<T>::contains_key((signal, for_network), validator) {
|
||||
if Favors::<T>::contains_key((signal, with_network), validator) {
|
||||
Err::<(), _>(Error::<T>::AlreadyInFavor)?;
|
||||
}
|
||||
|
||||
// Set the validator as in favor
|
||||
Favors::<T>::set((signal, for_network), validator, Some(()));
|
||||
Favors::<T>::set((signal, with_network), validator, Some(()));
|
||||
|
||||
Core::<T>::emit_event(Event::SignalFavored {
|
||||
signal,
|
||||
by: validator.into(),
|
||||
with_network: for_network,
|
||||
});
|
||||
Core::<T>::emit_event(Event::SignalFavored { signal, by: validator.into(), with_network });
|
||||
|
||||
// Check if the network is in favor
|
||||
let network_in_favor = Self::tally_for_network(signal, for_network);
|
||||
let network_in_favor = Self::tally_for_network(signal, with_network);
|
||||
|
||||
// If this network is in favor, check if enough networks are
|
||||
if network_in_favor && Self::tally_for_all_networks(signal) {
|
||||
@@ -416,7 +408,7 @@ pub mod pallet {
|
||||
pub fn revoke_favor(
|
||||
origin: OriginFor<T>,
|
||||
signal: Signal,
|
||||
for_network: NetworkId,
|
||||
with_network: NetworkId,
|
||||
) -> DispatchResult {
|
||||
match signal {
|
||||
Signal::Retire { .. } => {
|
||||
@@ -428,7 +420,7 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
let validator = ensure_signed(origin)?;
|
||||
Self::revoke_favor_internal(validator, signal, for_network)
|
||||
Self::revoke_favor_internal(validator, signal, with_network)
|
||||
}
|
||||
|
||||
/// Emit an event standing against the signal.
|
||||
@@ -442,7 +434,7 @@ pub mod pallet {
|
||||
pub fn stand_against(
|
||||
origin: OriginFor<T>,
|
||||
signal: Signal,
|
||||
for_network: NetworkId,
|
||||
with_network: NetworkId,
|
||||
) -> DispatchResult {
|
||||
match signal {
|
||||
Signal::Retire { .. } => {
|
||||
@@ -455,8 +447,8 @@ pub mod pallet {
|
||||
|
||||
let validator = ensure_signed(origin)?;
|
||||
// If currently in favor, revoke the favor
|
||||
if Favors::<T>::contains_key((signal, for_network), validator) {
|
||||
Self::revoke_favor_internal(validator, signal, for_network)?;
|
||||
if Favors::<T>::contains_key((signal, with_network), validator) {
|
||||
Self::revoke_favor_internal(validator, signal, with_network)?;
|
||||
} else {
|
||||
// Check this Signal exists (which would've been implied by `Favors` for it existing)
|
||||
match signal {
|
||||
@@ -472,7 +464,7 @@ pub mod pallet {
|
||||
Core::<T>::emit_event(Event::AgainstSignal {
|
||||
signal,
|
||||
account: validator.into(),
|
||||
with_network: for_network,
|
||||
with_network,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -20,20 +20,21 @@ bitvec = { version = "1", default-features = false, features = ["alloc", "serde"
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ef18bfc7029d4a3d7c27e1d0b84da5091628a7d9", default-features = false }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
serai-core-pallet = { path = "../core", default-features = false }
|
||||
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -63,6 +64,7 @@ std = [
|
||||
|
||||
"serai-abi/std",
|
||||
|
||||
"serai-core-pallet/std",
|
||||
"serai-coins-pallet/std",
|
||||
]
|
||||
|
||||
@@ -75,6 +77,9 @@ try-runtime = [
|
||||
"pallet-session/try-runtime",
|
||||
"pallet-babe/try-runtime",
|
||||
"pallet-grandpa/try-runtime",
|
||||
|
||||
"serai-core-pallet/try-runtime",
|
||||
"serai-coins-pallet/try-runtime",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
@@ -83,6 +88,9 @@ runtime-benchmarks = [
|
||||
|
||||
"pallet-babe/runtime-benchmarks",
|
||||
"pallet-grandpa/runtime-benchmarks",
|
||||
|
||||
"serai-core-pallet/runtime-benchmarks",
|
||||
"serai-coins-pallet/runtime-benchmarks",
|
||||
]
|
||||
|
||||
default = ["std"]
|
||||
|
||||
@@ -30,6 +30,9 @@ pub(crate) trait Keys {
|
||||
|
||||
/// Clear a historic set of keys.
|
||||
fn clear_keys(set: ExternalValidatorSet);
|
||||
|
||||
/// The oraclization key for a validator set.
|
||||
fn oraclization_key(set: ExternalValidatorSet) -> Option<Public>;
|
||||
}
|
||||
|
||||
impl<S: KeysStorage> Keys for S {
|
||||
@@ -46,4 +49,8 @@ impl<S: KeysStorage> Keys for S {
|
||||
S::OraclizationKeys::remove(set);
|
||||
S::ExternalKeys::remove(set);
|
||||
}
|
||||
|
||||
fn oraclization_key(set: ExternalValidatorSet) -> Option<Public> {
|
||||
S::OraclizationKeys::get(set)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{vec, vec::Vec};
|
||||
|
||||
mod embedded_elliptic_curve_keys;
|
||||
use embedded_elliptic_curve_keys::*;
|
||||
@@ -21,6 +21,7 @@ use keys::{KeysStorage, Keys as _};
|
||||
#[frame_support::pallet]
|
||||
mod pallet {
|
||||
use sp_core::sr25519::Public;
|
||||
use sp_application_crypto::RuntimePublic;
|
||||
|
||||
use frame_system::pallet_prelude::*;
|
||||
use frame_support::{pallet_prelude::*, traits::OneSessionHandler};
|
||||
@@ -35,13 +36,18 @@ mod pallet {
|
||||
network_id::*,
|
||||
coin::*,
|
||||
balance::*,
|
||||
validator_sets::{Session, ExternalValidatorSet, ValidatorSet, KeyShares as KeySharesStruct},
|
||||
validator_sets::{
|
||||
Session, ExternalValidatorSet, ValidatorSet, KeyShares as KeySharesStruct, SlashReport,
|
||||
},
|
||||
address::SeraiAddress,
|
||||
},
|
||||
economic_security::EconomicSecurity,
|
||||
validator_sets::{DeallocationTimeline, Event},
|
||||
};
|
||||
|
||||
use serai_coins_pallet::Pallet as Coins;
|
||||
use serai_core_pallet::Pallet as Core;
|
||||
use serai_coins_pallet::AllowMint;
|
||||
type Coins<T> = serai_coins_pallet::Pallet<T, serai_coins_pallet::CoinsInstance>;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -51,6 +57,7 @@ mod pallet {
|
||||
+ pallet_session::Config
|
||||
+ pallet_babe::Config
|
||||
+ pallet_grandpa::Config
|
||||
+ serai_core_pallet::Config
|
||||
+ serai_coins_pallet::Config<serai_coins_pallet::CoinsInstance>
|
||||
{
|
||||
type ShouldEndSession: ShouldEndSession<BlockNumberFor<Self>>;
|
||||
@@ -58,11 +65,16 @@ mod pallet {
|
||||
}
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
/// List of participants to place in the initial validator sets.
|
||||
pub participants: Vec<(T::AccountId, Vec<SignedEmbeddedEllipticCurveKeys>)>,
|
||||
}
|
||||
impl<T: Config> Default for GenesisConfig<T> {
|
||||
fn default() -> Self {
|
||||
Self { participants: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
@@ -123,8 +135,12 @@ mod pallet {
|
||||
#[pallet::storage]
|
||||
type DelayedDeallocations<T: Config> =
|
||||
StorageDoubleMap<_, Blake2_128Concat, Public, Identity, Session, Amount, OptionQuery>;
|
||||
#[pallet::storage]
|
||||
type PendingSlashReport<T: Config> = StorageMap<_, Identity, ExternalNetworkId, (), OptionQuery>;
|
||||
|
||||
impl<T: Config> SessionsStorage for Abstractions<T> {
|
||||
type Config = T;
|
||||
|
||||
type GenesisValidators = GenesisValidators<T>;
|
||||
type AllocationPerKeyShare = AllocationPerKeyShare<T>;
|
||||
type CurrentSession = CurrentSession<T>;
|
||||
@@ -133,6 +149,7 @@ mod pallet {
|
||||
type SelectedValidators = SelectedValidators<T>;
|
||||
type TotalAllocatedStake = TotalAllocatedStake<T>;
|
||||
type DelayedDeallocations = DelayedDeallocations<T>;
|
||||
type PendingSlashReport = PendingSlashReport<T>;
|
||||
}
|
||||
|
||||
// Satisfy the `Keys` abstractions
|
||||
@@ -148,51 +165,6 @@ mod pallet {
|
||||
type ExternalKeys = ExternalKeys<T>;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
/// The key for validator sets which can (and still need to) publish their slash reports.
|
||||
#[pallet::storage]
|
||||
pub type PendingSlashReport<T: Config> =
|
||||
StorageMap<_, Identity, ExternalNetworkId, Public, OptionQuery>;
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
NewSet {
|
||||
set: ValidatorSet,
|
||||
},
|
||||
ParticipantRemoved {
|
||||
set: ValidatorSet,
|
||||
removed: T::AccountId,
|
||||
},
|
||||
KeyGen {
|
||||
set: ExternalValidatorSet,
|
||||
key_pair: KeyPair,
|
||||
},
|
||||
AcceptedHandover {
|
||||
set: ValidatorSet,
|
||||
},
|
||||
SetRetired {
|
||||
set: ValidatorSet,
|
||||
},
|
||||
AllocationIncreased {
|
||||
validator: T::AccountId,
|
||||
network: NetworkId,
|
||||
amount: Amount,
|
||||
},
|
||||
AllocationDecreased {
|
||||
validator: T::AccountId,
|
||||
network: NetworkId,
|
||||
amount: Amount,
|
||||
delayed_until: Option<Session>,
|
||||
},
|
||||
DeallocationClaimed {
|
||||
validator: T::AccountId,
|
||||
network: NetworkId,
|
||||
session: Session,
|
||||
},
|
||||
}
|
||||
*/
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// The provided embedded elliptic curve keys were invalid.
|
||||
@@ -308,116 +280,28 @@ mod pallet {
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO
|
||||
/// Decreases a validator's allocation to a set.
|
||||
///
|
||||
/// Errors if the capacity provided by this allocation is in use.
|
||||
///
|
||||
/// Errors if a partial decrease of allocation which puts the remaining allocation below the
|
||||
/// minimum requirement.
|
||||
///
|
||||
/// The capacity prior provided by the allocation is immediately removed, in order to ensure it
|
||||
/// doesn't become used (preventing deallocation).
|
||||
///
|
||||
/// Returns if the amount is immediately eligible for deallocation.
|
||||
fn decrease_allocation(
|
||||
network: NetworkId,
|
||||
account: T::AccountId,
|
||||
amount: Amount,
|
||||
) -> Result<bool, DispatchError> {
|
||||
// Check it's safe to decrease this set's stake by this amount
|
||||
if let NetworkId::External(n) = network {
|
||||
let new_total_staked = Self::total_allocated_stake(NetworkId::from(n))
|
||||
.unwrap()
|
||||
.0
|
||||
.checked_sub(amount.0)
|
||||
.ok_or(Error::<T>::NotEnoughAllocated)?;
|
||||
let required_stake = Self::required_stake_for_network(n);
|
||||
if new_total_staked < required_stake {
|
||||
Err(Error::<T>::DeallocationWouldRemoveEconomicSecurity)?;
|
||||
}
|
||||
}
|
||||
|
||||
let decreased_key_shares =
|
||||
(old_allocation / allocation_per_key_share) > (new_allocation / allocation_per_key_share);
|
||||
|
||||
// If this decreases the validator's key shares, error if the new set is unable to handle
|
||||
// byzantine faults
|
||||
let mut was_bft = None;
|
||||
if decreased_key_shares {
|
||||
was_bft = Some(Self::is_bft(network));
|
||||
}
|
||||
|
||||
if let Some(was_bft) = was_bft {
|
||||
if was_bft && (!Self::is_bft(network)) {
|
||||
Err(Error::<T>::DeallocationWouldRemoveFaultTolerance)?;
|
||||
}
|
||||
}
|
||||
|
||||
Sessions::<T>::decrease_allocation(network, account, amount)
|
||||
/// The required amount of stake for a balance.
|
||||
fn stake_requirement(balance: ExternalBalance) -> AmountRepr {
|
||||
let value = T::EconomicSecurity::sri_value(balance).0;
|
||||
// As 67% can misbehave, 67% of stake must be sufficient to secure this
|
||||
let requirement = value.saturating_mul(3) / 2;
|
||||
// We add an additional margin of 20%
|
||||
let margin = requirement / 5;
|
||||
requirement.saturating_add(margin)
|
||||
}
|
||||
|
||||
// TODO: This is called retire_set, yet just starts retiring the set
|
||||
// Update the nomenclature within this function
|
||||
pub fn retire_set(set: ValidatorSet) {
|
||||
// Serai doesn't set keys and network slashes are handled by BABE/GRANDPA
|
||||
if let NetworkId::External(n) = set.network {
|
||||
// If the prior prior set didn't report, emit they're retired now
|
||||
if PendingSlashReport::<T>::get(n).is_some() {
|
||||
Self::deposit_event(Event::SetRetired {
|
||||
set: ValidatorSet { network: set.network, session: Session(set.session.0 - 1) },
|
||||
});
|
||||
}
|
||||
|
||||
// This overwrites the prior value as the prior to-report set's stake presumably just
|
||||
// unlocked, making their report unenforceable
|
||||
let keys =
|
||||
Keys::<T>::take(ExternalValidatorSet { network: n, session: set.session }).unwrap();
|
||||
PendingSlashReport::<T>::set(n, Some(keys.0));
|
||||
} else {
|
||||
// emit the event for serai network
|
||||
Self::deposit_event(Event::SetRetired { set });
|
||||
}
|
||||
|
||||
// We're retiring this set because the set after it accepted the handover
|
||||
Self::deposit_event(Event::AcceptedHandover {
|
||||
set: ValidatorSet { network: set.network, session: Session(set.session.0 + 1) },
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the required stake in terms SRI for a given `Balance`.
|
||||
pub fn required_stake(balance: &ExternalBalance) -> SubstrateAmount {
|
||||
use dex_pallet::HigherPrecisionBalance;
|
||||
|
||||
// This is inclusive to an increase in accuracy
|
||||
let sri_per_coin = Dex::<T>::security_oracle_value(balance.coin).unwrap_or(Amount(0));
|
||||
|
||||
// See dex-pallet for the reasoning on these
|
||||
let coin_decimals = balance.coin.decimals().max(5);
|
||||
let accuracy_increase = HigherPrecisionBalance::from(SubstrateAmount::pow(10, coin_decimals));
|
||||
|
||||
let total_coin_value = u64::try_from(
|
||||
HigherPrecisionBalance::from(balance.amount.0) *
|
||||
HigherPrecisionBalance::from(sri_per_coin.0) /
|
||||
accuracy_increase,
|
||||
)
|
||||
.unwrap_or(u64::MAX);
|
||||
|
||||
// required stake formula (COIN_VALUE * 1.5) + margin(20%)
|
||||
let required_stake = total_coin_value.saturating_mul(3).saturating_div(2);
|
||||
required_stake.saturating_add(total_coin_value.saturating_div(5))
|
||||
}
|
||||
|
||||
/// Returns the current total required stake for a given `network`.
|
||||
pub fn required_stake_for_network(network: ExternalNetworkId) -> SubstrateAmount {
|
||||
let mut total_required = 0;
|
||||
/// The required amount of stake for a network.
|
||||
fn network_stake_requirement(network: ExternalNetworkId) -> AmountRepr {
|
||||
let mut requirement = AmountRepr::zero();
|
||||
for coin in network.coins() {
|
||||
let supply = Coins::<T>::supply(Coin::from(coin));
|
||||
total_required += Self::required_stake(&ExternalBalance { coin, amount: Amount(supply) });
|
||||
requirement = requirement
|
||||
.saturating_add(Self::stake_requirement(ExternalBalance { coin, amount: supply }));
|
||||
}
|
||||
total_required
|
||||
requirement
|
||||
}
|
||||
|
||||
/* TODO
|
||||
pub fn distribute_block_rewards(
|
||||
network: NetworkId,
|
||||
account: T::AccountId,
|
||||
@@ -541,7 +425,9 @@ mod pallet {
|
||||
let session = Self::current_session(NetworkId::from(network))
|
||||
.expect("validated `set_keys` for a non-existent session");
|
||||
let set = ExternalValidatorSet { network, session };
|
||||
Abstractions::<T>::set_keys(set, key_pair);
|
||||
Abstractions::<T>::set_keys(set, key_pair.clone());
|
||||
|
||||
Core::<T>::emit_event(Event::SetKeys { set, key_pair });
|
||||
|
||||
// If this is the first session of an external network, mark them current, not solely decided
|
||||
if session == Session(0) {
|
||||
@@ -551,7 +437,6 @@ mod pallet {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/* TODO
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight((0, DispatchClass::Operational))] // TODO
|
||||
pub fn report_slashes(
|
||||
@@ -562,24 +447,13 @@ mod pallet {
|
||||
) -> DispatchResult {
|
||||
ensure_none(origin)?;
|
||||
|
||||
// signature isn't checked as this is an unsigned transaction, and validate_unsigned
|
||||
// (called by pre_dispatch) checks it
|
||||
// `signature` is checked within `ValidateUnsigned`
|
||||
let _ = signature;
|
||||
|
||||
// TODO: Handle slashes
|
||||
let _ = slashes;
|
||||
|
||||
// Emit set retireed
|
||||
Pallet::<T>::deposit_event(Event::SetRetired {
|
||||
set: ValidatorSet {
|
||||
network: network.into(),
|
||||
session: Session(Self::session(NetworkId::from(network)).unwrap().0 - 1),
|
||||
},
|
||||
});
|
||||
Abstractions::<T>::handle_slash_report(network, slashes);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||
@@ -587,11 +461,16 @@ mod pallet {
|
||||
origin: OriginFor<T>,
|
||||
keys: SignedEmbeddedEllipticCurveKeys,
|
||||
) -> DispatchResult {
|
||||
let signer = ensure_signed(origin)?;
|
||||
let validator = ensure_signed(origin)?;
|
||||
let network = keys.network();
|
||||
<Abstractions<T> as crate::EmbeddedEllipticCurveKeys>::set_embedded_elliptic_curve_keys(
|
||||
signer, keys,
|
||||
validator, keys,
|
||||
)
|
||||
.map_err(|()| Error::<T>::InvalidEmbeddedEllipticCurveKeys)?;
|
||||
Core::<T>::emit_event(Event::SetEmbeddedEllipticCurveKeys {
|
||||
validator: validator.into(),
|
||||
network,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -599,11 +478,7 @@ mod pallet {
|
||||
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||
pub fn allocate(origin: OriginFor<T>, network: NetworkId, amount: Amount) -> DispatchResult {
|
||||
let validator = ensure_signed(origin)?;
|
||||
Coins::<T, serai_coins_pallet::CoinsInstance>::transfer_fn(
|
||||
validator,
|
||||
Self::account(),
|
||||
Balance { coin: Coin::Serai, amount },
|
||||
)?;
|
||||
Coins::<T>::transfer_fn(validator, Self::account(), Balance { coin: Coin::Serai, amount })?;
|
||||
Abstractions::<T>::increase_allocation(network, validator, amount, false)
|
||||
.map_err(Error::<T>::AllocationError)?;
|
||||
Ok(())
|
||||
@@ -612,16 +487,20 @@ mod pallet {
|
||||
#[pallet::call_index(4)]
|
||||
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||
pub fn deallocate(origin: OriginFor<T>, network: NetworkId, amount: Amount) -> DispatchResult {
|
||||
let account = ensure_signed(origin)?;
|
||||
let validator = ensure_signed(origin)?;
|
||||
|
||||
let deallocation_timeline = Abstractions::<T>::decrease_allocation(network, account, amount)
|
||||
let timeline = Abstractions::<T>::decrease_allocation(network, validator, amount)
|
||||
.map_err(Error::<T>::DeallocationError)?;
|
||||
if matches!(deallocation_timeline, DeallocationTimeline::Immediate) {
|
||||
Coins::<T, serai_coins_pallet::CoinsInstance>::transfer_fn(
|
||||
Self::account(),
|
||||
account,
|
||||
Balance { coin: Coin::Serai, amount },
|
||||
)?;
|
||||
|
||||
Core::<T>::emit_event(Event::Deallocation {
|
||||
validator: validator.into(),
|
||||
network,
|
||||
amount,
|
||||
timeline,
|
||||
});
|
||||
|
||||
if matches!(timeline, DeallocationTimeline::Immediate) {
|
||||
Coins::<T>::transfer_fn(Self::account(), validator, Balance { coin: Coin::Serai, amount })?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -634,14 +513,16 @@ mod pallet {
|
||||
network: NetworkId,
|
||||
session: Session,
|
||||
) -> DispatchResult {
|
||||
let account = ensure_signed(origin)?;
|
||||
let amount = Abstractions::<T>::claim_delayed_deallocation(account, network, session)
|
||||
let validator = ensure_signed(origin)?;
|
||||
let amount = Abstractions::<T>::claim_delayed_deallocation(validator, network, session)
|
||||
.map_err(Error::<T>::DeallocationError)?;
|
||||
Coins::<T, serai_coins_pallet::CoinsInstance>::transfer_fn(
|
||||
Self::account(),
|
||||
account,
|
||||
Balance { coin: Coin::Serai, amount },
|
||||
)?;
|
||||
|
||||
Core::<T>::emit_event(Event::DelayedDeallocationClaimed {
|
||||
validator: validator.into(),
|
||||
deallocation: ValidatorSet { network, session },
|
||||
});
|
||||
|
||||
Coins::<T>::transfer_fn(Self::account(), validator, Balance { coin: Coin::Serai, amount })?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -705,7 +586,6 @@ mod pallet {
|
||||
}
|
||||
|
||||
// Verify the signature with the MuSig key of the signers
|
||||
use sp_application_crypto::RuntimePublic;
|
||||
if !set.musig_key(&signers).verify(&set.set_keys_message(key_pair), &signature.0.into()) {
|
||||
Err(InvalidTransaction::BadProof)?;
|
||||
}
|
||||
@@ -716,30 +596,23 @@ mod pallet {
|
||||
.propagate(true)
|
||||
.build()
|
||||
}
|
||||
/* TODO
|
||||
Call::report_slashes { network, ref slashes, ref signature } => {
|
||||
let network = *network;
|
||||
let Some(key) = PendingSlashReport::<T>::take(network) else {
|
||||
// Assumed already published
|
||||
|
||||
let Some(key) = Abstractions::<T>::waiting_for_slash_report(network) else {
|
||||
Err(InvalidTransaction::Stale)?
|
||||
};
|
||||
|
||||
// There must have been a previous session is PendingSlashReport is populated
|
||||
let set = ExternalValidatorSet {
|
||||
network,
|
||||
session: Session(Self::session(NetworkId::from(network)).unwrap().0 - 1),
|
||||
};
|
||||
if !key.verify(&slashes.report_slashes_message(), signature) {
|
||||
if !key.verify(&slashes.report_slashes_message(), &signature.0.into()) {
|
||||
Err(InvalidTransaction::BadProof)?;
|
||||
}
|
||||
|
||||
ValidTransaction::with_tag_prefix("ValidatorSets")
|
||||
.and_provides((1, set))
|
||||
.longevity(MAX_KEY_SHARES_PER_SET_U32.into())
|
||||
.and_provides((1, key))
|
||||
.longevity(KeySharesStruct::MAX_PER_SET_U32.into())
|
||||
.propagate(true)
|
||||
.build()
|
||||
}
|
||||
*/
|
||||
Call::set_embedded_elliptic_curve_keys { .. } |
|
||||
Call::allocate { .. } |
|
||||
Call::deallocate { .. } |
|
||||
@@ -754,20 +627,20 @@ mod pallet {
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO
|
||||
/*
|
||||
TODO: Add an intent. While we shouldn't allow `Transfer`, `AddLiquidity` when we're within a
|
||||
certain range of the limit, we should still allow swaps.
|
||||
*/
|
||||
impl<T: Config> AllowMint for Pallet<T> {
|
||||
fn is_allowed(balance: &ExternalBalance) -> bool {
|
||||
// get the required stake
|
||||
let current_required = Self::required_stake_for_network(balance.coin.network());
|
||||
let new_required = current_required + Self::required_stake(balance);
|
||||
|
||||
// get the total stake for the network & compare.
|
||||
let current_requirement = Self::network_stake_requirement(balance.coin.network());
|
||||
let new_requirement = current_requirement.saturating_add(Self::stake_requirement(*balance));
|
||||
let staked =
|
||||
Self::total_allocated_stake(NetworkId::from(balance.coin.network())).unwrap_or(Amount(0));
|
||||
staked.0 >= new_required
|
||||
Abstractions::<T>::stake_for_current_validator_set(balance.coin.network().into())
|
||||
.unwrap_or(Amount(0));
|
||||
staked.0 >= new_requirement
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
pub use pallet::*;
|
||||
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
//! Test environment for ValidatorSets pallet.
|
||||
|
||||
use super::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use frame_support::{
|
||||
construct_runtime,
|
||||
traits::{ConstU16, ConstU32, ConstU64},
|
||||
};
|
||||
|
||||
use sp_core::{
|
||||
H256, Pair as PairTrait,
|
||||
sr25519::{Public, Pair},
|
||||
};
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
BuildStorage,
|
||||
};
|
||||
|
||||
use serai_abi::primitives::*;
|
||||
use validator_sets::{primitives::MAX_KEY_SHARES_PER_SET_U32, MembershipProof};
|
||||
|
||||
pub use crate as validator_sets;
|
||||
pub use serai_coins_pallet as coins;
|
||||
pub use dex_pallet as dex;
|
||||
pub use pallet_babe as babe;
|
||||
pub use pallet_grandpa as grandpa;
|
||||
pub use pallet_timestamp as timestamp;
|
||||
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
// Maximum number of authorities per session.
|
||||
pub type MaxAuthorities = ConstU32<{ MAX_KEY_SHARES_PER_SET_U32 }>;
|
||||
|
||||
pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
|
||||
pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
|
||||
sp_consensus_babe::BabeEpochConfiguration {
|
||||
c: PRIMARY_PROBABILITY,
|
||||
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
};
|
||||
|
||||
pub const MEDIAN_PRICE_WINDOW_LENGTH: u16 = 10;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Test
|
||||
{
|
||||
System: frame_system,
|
||||
Timestamp: timestamp,
|
||||
Coins: coins,
|
||||
LiquidityTokens: coins::<Instance1>::{Pallet, Call, Storage, Event<T>},
|
||||
ValidatorSets: validator_sets,
|
||||
Dex: dex,
|
||||
Babe: babe,
|
||||
Grandpa: grandpa,
|
||||
}
|
||||
);
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type Nonce = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = Public;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Block = Block;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BlockHashCount = ConstU64<250>;
|
||||
type DbWeight = ();
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = ();
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = ConstU32<16>;
|
||||
}
|
||||
|
||||
impl timestamp::Config for Test {
|
||||
type Moment = u64;
|
||||
type OnTimestampSet = Babe;
|
||||
type MinimumPeriod = ConstU64<{ (TARGET_BLOCK_TIME * 1000) / 2 }>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
impl babe::Config for Test {
|
||||
type EpochDuration = ConstU64<{ FAST_EPOCH_DURATION }>;
|
||||
|
||||
type ExpectedBlockTime = ConstU64<{ TARGET_BLOCK_TIME * 1000 }>;
|
||||
type EpochChangeTrigger = babe::ExternalTrigger;
|
||||
type DisabledValidators = ValidatorSets;
|
||||
|
||||
type WeightInfo = ();
|
||||
type MaxAuthorities = MaxAuthorities;
|
||||
|
||||
type KeyOwnerProof = MembershipProof<Self>;
|
||||
type EquivocationReportSystem = ();
|
||||
}
|
||||
|
||||
impl grandpa::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
|
||||
type WeightInfo = ();
|
||||
type MaxAuthorities = MaxAuthorities;
|
||||
|
||||
type MaxSetIdSessionEntries = ConstU64<0>;
|
||||
type KeyOwnerProof = MembershipProof<Self>;
|
||||
type EquivocationReportSystem = ();
|
||||
}
|
||||
|
||||
impl coins::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AllowMint = ValidatorSets;
|
||||
}
|
||||
|
||||
impl coins::Config<coins::Instance1> for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AllowMint = ();
|
||||
}
|
||||
|
||||
impl dex::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
|
||||
type LPFee = ConstU32<3>; // 0.3%
|
||||
type MintMinLiquidity = ConstU64<10000>;
|
||||
|
||||
type MaxSwapPathLength = ConstU32<3>; // coin1 -> SRI -> coin2
|
||||
|
||||
type MedianPriceWindowLength = ConstU16<{ MEDIAN_PRICE_WINDOW_LENGTH }>;
|
||||
|
||||
type WeightInfo = dex::weights::SubstrateWeight<Test>;
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type ShouldEndSession = Babe;
|
||||
}
|
||||
|
||||
// For a const we can't define
|
||||
pub fn genesis_participants() -> Vec<Pair> {
|
||||
vec![
|
||||
insecure_pair_from_name("Alice"),
|
||||
insecure_pair_from_name("Bob"),
|
||||
insecure_pair_from_name("Charlie"),
|
||||
insecure_pair_from_name("Dave"),
|
||||
]
|
||||
}
|
||||
|
||||
// Amounts for single key share per network
|
||||
pub fn key_shares() -> HashMap<NetworkId, Amount> {
|
||||
HashMap::from([
|
||||
(NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))),
|
||||
(NetworkId::External(ExternalNetworkId::Bitcoin), Amount(1_000_000 * 10_u64.pow(8))),
|
||||
(NetworkId::External(ExternalNetworkId::Ethereum), Amount(1_000_000 * 10_u64.pow(8))),
|
||||
(NetworkId::External(ExternalNetworkId::Monero), Amount(100_000 * 10_u64.pow(8))),
|
||||
])
|
||||
}
|
||||
|
||||
pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
|
||||
let networks: Vec<(NetworkId, Amount)> = key_shares().into_iter().collect::<Vec<_>>();
|
||||
|
||||
coins::GenesisConfig::<Test> {
|
||||
accounts: genesis_participants()
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|a| (a.public(), Balance { coin: Coin::Serai, amount: Amount(1 << 60) }))
|
||||
.collect(),
|
||||
_ignore: Default::default(),
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
#[expect(unused_variables, unreachable_code, clippy::diverging_sub_expression)]
|
||||
validator_sets::GenesisConfig::<Test> {
|
||||
networks,
|
||||
participants: genesis_participants()
|
||||
.into_iter()
|
||||
.map(|p| {
|
||||
let keys: crate::AllEmbeddedEllipticCurveKeysAtGenesis = todo!("TODO");
|
||||
(p.public(), keys)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
babe::GenesisConfig::<Test> {
|
||||
authorities: genesis_participants()
|
||||
.into_iter()
|
||||
.map(|validator| (validator.public().into(), 1))
|
||||
.collect(),
|
||||
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
|
||||
_config: PhantomData,
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
grandpa::GenesisConfig::<Test> {
|
||||
authorities: genesis_participants()
|
||||
.into_iter()
|
||||
.map(|validator| (validator.public().into(), 1))
|
||||
.collect(),
|
||||
_config: PhantomData,
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = sp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| System::set_block_number(0));
|
||||
ext
|
||||
}
|
||||
@@ -1,14 +1,21 @@
|
||||
use alloc::vec::Vec;
|
||||
use sp_core::{Encode, Decode, ConstU32, sr25519::Public, bounded::BoundedVec};
|
||||
|
||||
use serai_abi::primitives::{
|
||||
network_id::NetworkId,
|
||||
balance::Amount,
|
||||
validator_sets::{KeyShares as KeySharesStruct, Session, ExternalValidatorSet, ValidatorSet},
|
||||
use serai_abi::{
|
||||
primitives::{
|
||||
network_id::{ExternalNetworkId, NetworkId},
|
||||
balance::Amount,
|
||||
validator_sets::{
|
||||
KeyShares as KeySharesStruct, Session, ExternalValidatorSet, ValidatorSet, SlashReport,
|
||||
},
|
||||
},
|
||||
validator_sets::{DeallocationTimeline, Event},
|
||||
};
|
||||
|
||||
use frame_support::storage::{StorageValue, StorageMap, StorageDoubleMap, StoragePrefixedMap};
|
||||
|
||||
use serai_core_pallet::Pallet as Core;
|
||||
|
||||
use crate::{
|
||||
embedded_elliptic_curve_keys::EmbeddedEllipticCurveKeys, allocations::Allocations, keys::Keys,
|
||||
};
|
||||
@@ -21,6 +28,9 @@ pub(crate) type GenesisValidators =
|
||||
pub(crate) type SelectedValidatorsKey = (ValidatorSet, [u8; 16], Public);
|
||||
|
||||
pub(crate) trait SessionsStorage: EmbeddedEllipticCurveKeys + Allocations + Keys {
|
||||
/// The configuration for the core pallet.
|
||||
type Config: serai_core_pallet::Config;
|
||||
|
||||
/// The genesis validators
|
||||
///
|
||||
/// The usage of is shared with the rest of the pallet. `Sessions` only reads it.
|
||||
@@ -68,6 +78,11 @@ pub(crate) trait SessionsStorage: EmbeddedEllipticCurveKeys + Allocations + Keys
|
||||
///
|
||||
/// This is opaque and to be exclusively read/write by `Sessions`.
|
||||
type DelayedDeallocations: StorageDoubleMap<Public, Session, Amount, Query = Option<Amount>>;
|
||||
|
||||
/// Networks for which we're awaiting slash reports.
|
||||
///
|
||||
/// This is opaque and to be exclusively read/write by `Sessions`.
|
||||
type PendingSlashReport: StorageMap<ExternalNetworkId, (), Query = Option<()>>;
|
||||
}
|
||||
|
||||
/// The storage key for the SelectedValidators map.
|
||||
@@ -119,11 +134,6 @@ pub enum AllocationError {
|
||||
IntroducesSinglePointOfFailure,
|
||||
}
|
||||
|
||||
pub(crate) enum DeallocationTimeline {
|
||||
Immediate,
|
||||
Delayed { unlocks_at: Session },
|
||||
}
|
||||
|
||||
/// An error when deallocating.
|
||||
#[derive(
|
||||
scale::Encode, scale::Decode, scale::DecodeWithMemTracking, frame_support::PalletError,
|
||||
@@ -193,6 +203,11 @@ pub(crate) trait Sessions {
|
||||
session: Session,
|
||||
) -> Result<Amount, DeallocationError>;
|
||||
|
||||
/// Handle a slash report.
|
||||
///
|
||||
/// This will panic if this slash report isn't pending.
|
||||
fn handle_slash_report(network: ExternalNetworkId, slashes: SlashReport);
|
||||
|
||||
/// The currently active session for a network.
|
||||
fn current_session(network: NetworkId) -> Option<Session>;
|
||||
|
||||
@@ -232,6 +247,11 @@ pub(crate) trait Sessions {
|
||||
.map(|(validator, _key_shares)| (validator, validator))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// If this network is awaiting a slash report.
|
||||
///
|
||||
/// If so, this returns the key which should publish the slash report.
|
||||
fn waiting_for_slash_report(network: ExternalNetworkId) -> Option<Public>;
|
||||
}
|
||||
|
||||
impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
@@ -313,11 +333,13 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
);
|
||||
}
|
||||
|
||||
Core::<Storage::Config>::emit_event(Event::SetDecided { set: latest_decided_set });
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn accept_handover(network: NetworkId) {
|
||||
let current = {
|
||||
let (prior, current) = {
|
||||
let current = Storage::CurrentSession::get(network);
|
||||
let latest_decided = Storage::LatestDecidedSession::get(network)
|
||||
.expect("accepting handover but never decided a session");
|
||||
@@ -328,8 +350,8 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
);
|
||||
// Set the CurrentSession variable
|
||||
Storage::CurrentSession::set(network, Some(latest_decided));
|
||||
// Return `latest_decided` as `current` as it is now current
|
||||
latest_decided
|
||||
// Return `latest_decided` as `current` as it is now current, and `current` as `prior`
|
||||
(current, latest_decided)
|
||||
};
|
||||
|
||||
let mut total_allocated_stake = Amount(0);
|
||||
@@ -343,6 +365,23 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
// Update the total allocated stake variable to the current session
|
||||
Storage::TotalAllocatedStake::set(network, Some(total_allocated_stake));
|
||||
|
||||
match network {
|
||||
NetworkId::Serai => {}
|
||||
NetworkId::External(network) => {
|
||||
// If this network never submitted its slash report, treat it as submitting `vec![]`
|
||||
if Storage::PendingSlashReport::take(network).is_some() {
|
||||
Core::<Storage::Config>::emit_event(Event::SlashReport {
|
||||
set: ExternalValidatorSet {
|
||||
network,
|
||||
session: prior.expect("pending slash report yet no prior session"),
|
||||
},
|
||||
});
|
||||
}
|
||||
// Mark this network as pending a slash report
|
||||
Storage::PendingSlashReport::insert(network, ());
|
||||
}
|
||||
}
|
||||
|
||||
// Clean-up the historic set's storage, if one exists
|
||||
if let Some(historic_session) = current.0.checked_sub(2).map(Session) {
|
||||
let historic_set = ValidatorSet { network, session: historic_session };
|
||||
@@ -355,6 +394,10 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core::<Storage::Config>::emit_event(Event::AcceptedHandover {
|
||||
set: ValidatorSet { network, session: current },
|
||||
});
|
||||
}
|
||||
|
||||
fn increase_allocation(
|
||||
@@ -437,6 +480,12 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
}
|
||||
}
|
||||
|
||||
Core::<Storage::Config>::emit_event(Event::Allocation {
|
||||
validator: validator.into(),
|
||||
network,
|
||||
amount,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -445,6 +494,9 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
validator: Public,
|
||||
amount: Amount,
|
||||
) -> Result<DeallocationTimeline, DeallocationError> {
|
||||
// TODO: Check if this would introduce a single point of failure
|
||||
// TODO: Check if this would violate economic security
|
||||
|
||||
/*
|
||||
Decrease the allocation.
|
||||
|
||||
@@ -522,6 +574,22 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
Ok(DeallocationTimeline::Immediate)
|
||||
}
|
||||
|
||||
fn handle_slash_report(network: ExternalNetworkId, _slashes: SlashReport) {
|
||||
Storage::PendingSlashReport::take(network)
|
||||
.expect("handling a slash report which wasn't pending");
|
||||
|
||||
let current_session =
|
||||
Self::current_session(network.into()).expect("handling slash report yet no current session");
|
||||
let prior_session = Session(
|
||||
current_session.0.checked_sub(1).expect("handling slash report yet no prior session"),
|
||||
);
|
||||
Core::<Storage::Config>::emit_event(Event::SlashReport {
|
||||
set: ExternalValidatorSet { network, session: prior_session },
|
||||
});
|
||||
|
||||
// TODO: Actually handle `_slashes`
|
||||
}
|
||||
|
||||
fn claim_delayed_deallocation(
|
||||
validator: Public,
|
||||
network: NetworkId,
|
||||
@@ -566,4 +634,19 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
fn selected_validators(set: ValidatorSet) -> impl Iterator<Item = (Public, KeySharesStruct)> {
|
||||
selected_validators::<Storage::SelectedValidators>(set)
|
||||
}
|
||||
|
||||
fn waiting_for_slash_report(network: ExternalNetworkId) -> Option<Public> {
|
||||
if !Storage::PendingSlashReport::contains_key(network) {
|
||||
None?;
|
||||
}
|
||||
let current_session = Self::current_session(network.into())
|
||||
.expect("network awaiting slash report yet no current session");
|
||||
let prior_session = Session(
|
||||
current_session.0.checked_sub(1).expect("network awaiting slash report yet no prior session"),
|
||||
);
|
||||
Some(
|
||||
Storage::oraclization_key(ExternalValidatorSet { network, session: prior_session })
|
||||
.expect("no oraclization key for set waiting for a slash report"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,558 +0,0 @@
|
||||
use crate::{mock::*, primitives::*};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ciphersuite::{WrappedGroup, GroupIo};
|
||||
use dkg_musig::musig;
|
||||
use schnorrkel::{frost::curve::Ristretto, Schnorrkel};
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
use rand_core::OsRng;
|
||||
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok,
|
||||
pallet_prelude::{InvalidTransaction, TransactionSource},
|
||||
traits::{OnFinalize, OnInitialize},
|
||||
};
|
||||
use frame_system::RawOrigin;
|
||||
|
||||
use sp_core::{
|
||||
sr25519::{Public, Pair, Signature},
|
||||
Pair as PairTrait,
|
||||
};
|
||||
use sp_runtime::traits::ValidateUnsigned;
|
||||
|
||||
use serai_abi::primitives::*;
|
||||
|
||||
fn active_network_validators(network: NetworkId) -> Vec<(Public, u64)> {
|
||||
if network == NetworkId::Serai {
|
||||
Babe::authorities().into_iter().map(|(id, key_share)| (id.into_inner(), key_share)).collect()
|
||||
} else {
|
||||
ValidatorSets::participants_for_latest_decided_set(network).unwrap().into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_session_and_active_validators(network: NetworkId, participants: &[Public], session: u32) {
|
||||
let mut validators: Vec<Public> = active_network_validators(network)
|
||||
.into_iter()
|
||||
.map(|(p, ks)| {
|
||||
assert_eq!(ks, 1);
|
||||
p
|
||||
})
|
||||
.collect();
|
||||
validators.sort();
|
||||
|
||||
assert_eq!(ValidatorSets::session(network).unwrap(), Session(session));
|
||||
assert_eq!(participants, validators);
|
||||
|
||||
// TODO: how to make sure block finalizations work as usual here?
|
||||
}
|
||||
|
||||
fn get_session_at_which_changes_activate(network: NetworkId) -> u32 {
|
||||
let current_session = ValidatorSets::session(network).unwrap().0;
|
||||
// changes should be active in the next session
|
||||
if network == NetworkId::Serai {
|
||||
// it takes 1 extra session for serai net to make the changes active.
|
||||
current_session + 2
|
||||
} else {
|
||||
current_session + 1
|
||||
}
|
||||
}
|
||||
|
||||
fn set_keys_for_session(network: ExternalNetworkId) {
|
||||
ValidatorSets::set_keys(
|
||||
RawOrigin::None.into(),
|
||||
network,
|
||||
KeyPair(insecure_pair_from_name("Alice").public(), vec![].try_into().unwrap()),
|
||||
vec![].try_into().unwrap(),
|
||||
Signature([0u8; 64]),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn set_keys_signature(set: &ExternalValidatorSet, key_pair: &KeyPair, pairs: &[Pair]) -> Signature {
|
||||
let mut pub_keys = vec![];
|
||||
for pair in pairs {
|
||||
let public_key =
|
||||
<Ristretto as GroupIo>::read_G::<&[u8]>(&mut pair.public().0.as_ref()).unwrap();
|
||||
pub_keys.push(public_key);
|
||||
}
|
||||
|
||||
let mut threshold_keys = vec![];
|
||||
for i in 0 .. pairs.len() {
|
||||
let secret_key = <Ristretto as GroupIo>::read_F::<&[u8]>(
|
||||
&mut pairs[i].as_ref().secret.to_bytes()[.. 32].as_ref(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(Ristretto::generator() * secret_key, pub_keys[i]);
|
||||
|
||||
threshold_keys.push(
|
||||
musig::<Ristretto>(musig_context((*set).into()), Zeroizing::new(secret_key), &pub_keys)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut musig_keys = HashMap::new();
|
||||
for threshold_keys in threshold_keys {
|
||||
musig_keys.insert(threshold_keys.params().i(), threshold_keys);
|
||||
}
|
||||
|
||||
let sig = frost::tests::sign_without_caching(
|
||||
&mut OsRng,
|
||||
frost::tests::algorithm_machines(&mut OsRng, &Schnorrkel::new(b"substrate"), &musig_keys),
|
||||
&set_keys_message(set, key_pair),
|
||||
);
|
||||
|
||||
Signature(sig.to_bytes())
|
||||
}
|
||||
|
||||
fn get_ordered_keys(network: NetworkId, participants: &[Pair]) -> Vec<Pair> {
|
||||
// retrieve the current session validators so that we know the order of the keys
|
||||
// that is necessary for the correct musig signature.
|
||||
let validators = ValidatorSets::participants_for_latest_decided_set(network).unwrap();
|
||||
|
||||
// collect the pairs of the validators
|
||||
let mut pairs = vec![];
|
||||
for (v, _) in validators {
|
||||
let p = participants.iter().find(|pair| pair.public() == v).unwrap().clone();
|
||||
pairs.push(p);
|
||||
}
|
||||
|
||||
pairs
|
||||
}
|
||||
|
||||
fn rotate_session_until(network: NetworkId, session: u32) {
|
||||
let mut current = ValidatorSets::session(network).unwrap().0;
|
||||
while current < session {
|
||||
Babe::on_initialize(System::block_number() + 1);
|
||||
ValidatorSets::rotate_session();
|
||||
if let NetworkId::External(n) = network {
|
||||
set_keys_for_session(n);
|
||||
}
|
||||
ValidatorSets::retire_set(ValidatorSet { session: Session(current), network });
|
||||
current += 1;
|
||||
}
|
||||
assert_eq!(current, session);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rotate_session() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let genesis_participants: Vec<Public> =
|
||||
genesis_participants().into_iter().map(|p| p.public()).collect();
|
||||
let key_shares = key_shares();
|
||||
|
||||
let mut participants = HashMap::from([
|
||||
(NetworkId::Serai, genesis_participants.clone()),
|
||||
(NetworkId::External(ExternalNetworkId::Bitcoin), genesis_participants.clone()),
|
||||
(NetworkId::External(ExternalNetworkId::Ethereum), genesis_participants.clone()),
|
||||
(NetworkId::External(ExternalNetworkId::Monero), genesis_participants),
|
||||
]);
|
||||
|
||||
// rotate session
|
||||
for network in NETWORKS {
|
||||
let participants = participants.get_mut(&network).unwrap();
|
||||
|
||||
// verify for session 0
|
||||
participants.sort();
|
||||
if let NetworkId::External(n) = network {
|
||||
set_keys_for_session(n);
|
||||
}
|
||||
verify_session_and_active_validators(network, participants, 0);
|
||||
|
||||
// add 1 participant
|
||||
let new_participant = insecure_pair_from_name("new-guy").public();
|
||||
Coins::mint(new_participant, Balance { coin: Coin::Serai, amount: key_shares[&network] })
|
||||
.unwrap();
|
||||
ValidatorSets::allocate(
|
||||
RawOrigin::Signed(new_participant).into(),
|
||||
network,
|
||||
key_shares[&network],
|
||||
)
|
||||
.unwrap();
|
||||
participants.push(new_participant);
|
||||
|
||||
// move network to the activation session
|
||||
let activation_session = get_session_at_which_changes_activate(network);
|
||||
rotate_session_until(network, activation_session);
|
||||
|
||||
// verify
|
||||
participants.sort();
|
||||
verify_session_and_active_validators(network, participants, activation_session);
|
||||
|
||||
// remove 1 participant
|
||||
let participant_to_remove = participants[0];
|
||||
ValidatorSets::deallocate(
|
||||
RawOrigin::Signed(participant_to_remove).into(),
|
||||
network,
|
||||
key_shares[&network],
|
||||
)
|
||||
.unwrap();
|
||||
participants
|
||||
.swap_remove(participants.iter().position(|k| *k == participant_to_remove).unwrap());
|
||||
|
||||
// check pending deallocations
|
||||
let pending = ValidatorSets::pending_deallocations(
|
||||
(network, participant_to_remove),
|
||||
Session(if network == NetworkId::Serai {
|
||||
activation_session + 3
|
||||
} else {
|
||||
activation_session + 2
|
||||
}),
|
||||
);
|
||||
assert_eq!(pending, Some(key_shares[&network]));
|
||||
|
||||
// move network to the activation session
|
||||
let activation_session = get_session_at_which_changes_activate(network);
|
||||
rotate_session_until(network, activation_session);
|
||||
|
||||
// verify
|
||||
participants.sort();
|
||||
verify_session_and_active_validators(network, participants, activation_session);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let genesis_participants: Vec<Public> =
|
||||
genesis_participants().into_iter().map(|p| p.public()).collect();
|
||||
let key_shares = key_shares();
|
||||
let participant = insecure_pair_from_name("random1").public();
|
||||
let network = NetworkId::External(ExternalNetworkId::Ethereum);
|
||||
|
||||
// check genesis TAS
|
||||
set_keys_for_session(network.try_into().unwrap());
|
||||
assert_eq!(
|
||||
ValidatorSets::total_allocated_stake(network).unwrap().0,
|
||||
key_shares[&network].0 * u64::try_from(genesis_participants.len()).unwrap()
|
||||
);
|
||||
|
||||
// we can't allocate less than a key share
|
||||
let amount = Amount(key_shares[&network].0 * 3);
|
||||
Coins::mint(participant, Balance { coin: Coin::Serai, amount }).unwrap();
|
||||
assert_noop!(
|
||||
ValidatorSets::allocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
Amount(key_shares[&network].0 - 1)
|
||||
),
|
||||
validator_sets::Error::<Test>::InsufficientAllocation
|
||||
);
|
||||
|
||||
// we can't allocate too much that the net exhibits the ability to handle any single node
|
||||
// becoming byzantine
|
||||
assert_noop!(
|
||||
ValidatorSets::allocate(RawOrigin::Signed(participant).into(), network, amount),
|
||||
validator_sets::Error::<Test>::AllocationWouldRemoveFaultTolerance
|
||||
);
|
||||
|
||||
// we should be allocate a proper amount
|
||||
assert_ok!(ValidatorSets::allocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
));
|
||||
assert_eq!(Coins::balance(participant, Coin::Serai).0, amount.0 - key_shares[&network].0);
|
||||
|
||||
// check new amount is reflected on TAS on new session
|
||||
rotate_session_until(network, 1);
|
||||
assert_eq!(
|
||||
ValidatorSets::total_allocated_stake(network).unwrap().0,
|
||||
key_shares[&network].0 * (u64::try_from(genesis_participants.len()).unwrap() + 1)
|
||||
);
|
||||
|
||||
// check that new participants match
|
||||
let mut active_participants: Vec<Public> =
|
||||
active_network_validators(network).into_iter().map(|(p, _)| p).collect();
|
||||
|
||||
let mut current_participants = genesis_participants.clone();
|
||||
current_participants.push(participant);
|
||||
|
||||
current_participants.sort();
|
||||
active_participants.sort();
|
||||
assert_eq!(current_participants, active_participants);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deallocate_pending() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let genesis_participants: Vec<Public> =
|
||||
genesis_participants().into_iter().map(|p| p.public()).collect();
|
||||
let key_shares = key_shares();
|
||||
let participant = insecure_pair_from_name("random1").public();
|
||||
let network = NetworkId::External(ExternalNetworkId::Bitcoin);
|
||||
|
||||
// check genesis TAS
|
||||
set_keys_for_session(network.try_into().unwrap());
|
||||
assert_eq!(
|
||||
ValidatorSets::total_allocated_stake(network).unwrap().0,
|
||||
key_shares[&network].0 * u64::try_from(genesis_participants.len()).unwrap()
|
||||
);
|
||||
|
||||
// allocate some amount
|
||||
Coins::mint(participant, Balance { coin: Coin::Serai, amount: key_shares[&network] }).unwrap();
|
||||
assert_ok!(ValidatorSets::allocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
));
|
||||
assert_eq!(Coins::balance(participant, Coin::Serai).0, 0);
|
||||
|
||||
// move to next session
|
||||
let mut current_session = ValidatorSets::session(network).unwrap().0;
|
||||
current_session += 1;
|
||||
rotate_session_until(network, current_session);
|
||||
assert_eq!(
|
||||
ValidatorSets::total_allocated_stake(network).unwrap().0,
|
||||
key_shares[&network].0 * (u64::try_from(genesis_participants.len()).unwrap() + 1)
|
||||
);
|
||||
|
||||
// we can deallocate all of our allocation
|
||||
assert_ok!(ValidatorSets::deallocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
));
|
||||
|
||||
// check pending deallocations
|
||||
let pending_session =
|
||||
if network == NetworkId::Serai { current_session + 3 } else { current_session + 2 };
|
||||
assert_eq!(
|
||||
ValidatorSets::pending_deallocations((network, participant), Session(pending_session)),
|
||||
Some(key_shares[&network])
|
||||
);
|
||||
|
||||
// we can't claim it immediately
|
||||
assert_noop!(
|
||||
ValidatorSets::claim_deallocation(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
Session(pending_session),
|
||||
),
|
||||
validator_sets::Error::<Test>::NonExistentDeallocation
|
||||
);
|
||||
|
||||
// we should be able to claim it in the pending session
|
||||
rotate_session_until(network, pending_session);
|
||||
assert_ok!(ValidatorSets::claim_deallocation(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
Session(pending_session),
|
||||
));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deallocate_immediately() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let genesis_participants: Vec<Public> =
|
||||
genesis_participants().into_iter().map(|p| p.public()).collect();
|
||||
let key_shares = key_shares();
|
||||
let participant = insecure_pair_from_name("random1").public();
|
||||
let network = NetworkId::External(ExternalNetworkId::Monero);
|
||||
|
||||
// check genesis TAS
|
||||
set_keys_for_session(network.try_into().unwrap());
|
||||
assert_eq!(
|
||||
ValidatorSets::total_allocated_stake(network).unwrap().0,
|
||||
key_shares[&network].0 * u64::try_from(genesis_participants.len()).unwrap()
|
||||
);
|
||||
|
||||
// we can't deallocate when we don't have an allocation
|
||||
assert_noop!(
|
||||
ValidatorSets::deallocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
),
|
||||
validator_sets::Error::<Test>::NonExistentValidator
|
||||
);
|
||||
|
||||
// allocate some amount
|
||||
Coins::mint(participant, Balance { coin: Coin::Serai, amount: key_shares[&network] }).unwrap();
|
||||
assert_ok!(ValidatorSets::allocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
));
|
||||
assert_eq!(Coins::balance(participant, Coin::Serai).0, 0);
|
||||
|
||||
// we can't deallocate more than our allocation
|
||||
assert_noop!(
|
||||
ValidatorSets::deallocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
Amount(key_shares[&network].0 + 1)
|
||||
),
|
||||
validator_sets::Error::<Test>::NotEnoughAllocated
|
||||
);
|
||||
|
||||
// we can't deallocate an amount that would left us less than a key share as long as it isn't 0
|
||||
assert_noop!(
|
||||
ValidatorSets::deallocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
Amount(key_shares[&network].0 / 2)
|
||||
),
|
||||
validator_sets::Error::<Test>::DeallocationWouldRemoveParticipant
|
||||
);
|
||||
|
||||
// we can deallocate all of our allocation
|
||||
assert_ok!(ValidatorSets::deallocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
));
|
||||
|
||||
// It should be immediately deallocated since we are not yet in an active set
|
||||
assert_eq!(Coins::balance(participant, Coin::Serai), key_shares[&network]);
|
||||
assert!(ValidatorSets::pending_deallocations((network, participant), Session(1)).is_none());
|
||||
|
||||
// allocate again
|
||||
assert_ok!(ValidatorSets::allocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
));
|
||||
assert_eq!(Coins::balance(participant, Coin::Serai).0, 0);
|
||||
|
||||
// make a pool so that we have security oracle value for the coin
|
||||
let liq_acc = insecure_pair_from_name("liq-acc").public();
|
||||
let coin = ExternalCoin::Monero;
|
||||
let balance = ExternalBalance { coin, amount: Amount(2 * key_shares[&network].0) };
|
||||
Coins::mint(liq_acc, balance.into()).unwrap();
|
||||
Coins::mint(liq_acc, Balance { coin: Coin::Serai, amount: balance.amount }).unwrap();
|
||||
Dex::add_liquidity(
|
||||
RawOrigin::Signed(liq_acc).into(),
|
||||
coin,
|
||||
balance.amount.0 / 2,
|
||||
balance.amount.0 / 2,
|
||||
1,
|
||||
1,
|
||||
liq_acc,
|
||||
)
|
||||
.unwrap();
|
||||
Dex::on_finalize(1);
|
||||
assert!(Dex::security_oracle_value(coin).unwrap().0 > 0);
|
||||
|
||||
// we can't deallocate if it would break economic security
|
||||
// The reason we don't have economic security for the network now is that we just set
|
||||
// the value for coin/SRI to 1:1 when making the pool and we minted 2 * key_share amount
|
||||
// of coin but we only allocated 1 key_share of SRI for the network although we need more than
|
||||
// 3 for the same amount of coin.
|
||||
assert_noop!(
|
||||
ValidatorSets::deallocate(
|
||||
RawOrigin::Signed(participant).into(),
|
||||
network,
|
||||
key_shares[&network]
|
||||
),
|
||||
validator_sets::Error::<Test>::DeallocationWouldRemoveEconomicSecurity
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_keys_keys_exist() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let network = ExternalNetworkId::Monero;
|
||||
|
||||
// set the keys first
|
||||
ValidatorSets::set_keys(
|
||||
RawOrigin::None.into(),
|
||||
network,
|
||||
KeyPair(insecure_pair_from_name("name").public(), Vec::new().try_into().unwrap()),
|
||||
vec![].try_into().unwrap(),
|
||||
Signature([0u8; 64]),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let call = validator_sets::Call::<Test>::set_keys {
|
||||
network,
|
||||
key_pair: KeyPair(insecure_pair_from_name("name").public(), Vec::new().try_into().unwrap()),
|
||||
signature_participants: vec![].try_into().unwrap(),
|
||||
signature: Signature([0u8; 64]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
ValidatorSets::validate_unsigned(TransactionSource::External, &call),
|
||||
InvalidTransaction::Stale.into()
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_keys_invalid_signature() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let network = ExternalNetworkId::Ethereum;
|
||||
let mut participants = get_ordered_keys(network.into(), &genesis_participants());
|
||||
|
||||
// we can't have invalid set
|
||||
let mut set = ExternalValidatorSet { network, session: Session(1) };
|
||||
let key_pair =
|
||||
KeyPair(insecure_pair_from_name("name").public(), Vec::new().try_into().unwrap());
|
||||
let signature = set_keys_signature(&set, &key_pair, &participants);
|
||||
|
||||
let call = validator_sets::Call::<Test>::set_keys {
|
||||
network,
|
||||
key_pair: key_pair.clone(),
|
||||
signature_participants: vec![].try_into().unwrap(),
|
||||
signature,
|
||||
};
|
||||
assert_eq!(
|
||||
ValidatorSets::validate_unsigned(TransactionSource::External, &call),
|
||||
InvalidTransaction::BadProof.into()
|
||||
);
|
||||
|
||||
// fix the set
|
||||
set.session = Session(0);
|
||||
|
||||
// participants should match
|
||||
participants.push(insecure_pair_from_name("random1"));
|
||||
let signature = set_keys_signature(&set, &key_pair, &participants);
|
||||
|
||||
let call = validator_sets::Call::<Test>::set_keys {
|
||||
network,
|
||||
key_pair: key_pair.clone(),
|
||||
signature_participants: vec![].try_into().unwrap(),
|
||||
signature,
|
||||
};
|
||||
assert_eq!(
|
||||
ValidatorSets::validate_unsigned(TransactionSource::External, &call),
|
||||
InvalidTransaction::BadProof.into()
|
||||
);
|
||||
|
||||
// fix the participants
|
||||
participants.pop();
|
||||
|
||||
// msg key pair and the key pair to set should match
|
||||
let key_pair2 =
|
||||
KeyPair(insecure_pair_from_name("name2").public(), Vec::new().try_into().unwrap());
|
||||
let signature = set_keys_signature(&set, &key_pair2, &participants);
|
||||
|
||||
let call = validator_sets::Call::<Test>::set_keys {
|
||||
network,
|
||||
key_pair: key_pair.clone(),
|
||||
signature_participants: vec![].try_into().unwrap(),
|
||||
signature,
|
||||
};
|
||||
assert_eq!(
|
||||
ValidatorSets::validate_unsigned(TransactionSource::External, &call),
|
||||
InvalidTransaction::BadProof.into()
|
||||
);
|
||||
|
||||
// use the same key pair
|
||||
let signature = set_keys_signature(&set, &key_pair, &participants);
|
||||
let call = validator_sets::Call::<Test>::set_keys {
|
||||
network,
|
||||
key_pair,
|
||||
signature_participants: vec![].try_into().unwrap(),
|
||||
signature,
|
||||
};
|
||||
ValidatorSets::validate_unsigned(TransactionSource::External, &call).unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: add report_slashes tests when the feature is complete.
|
||||
Reference in New Issue
Block a user