mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-10 13:09:24 +00:00
Compare commits
10 Commits
d74b00b9e4
...
ffae6753ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffae6753ec | ||
|
|
a04215bc13 | ||
|
|
28aea8a442 | ||
|
|
7b46477ca0 | ||
|
|
e62b62ddfb | ||
|
|
a2d8d0fd13 | ||
|
|
b2b36b17c4 | ||
|
|
9de8394efa | ||
|
|
3cb9432daa | ||
|
|
3f5150b3fa |
23
.github/workflows/tests.yml
vendored
23
.github/workflows/tests.yml
vendored
@@ -83,21 +83,16 @@ jobs:
|
||||
run: |
|
||||
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features \
|
||||
-p serai-primitives \
|
||||
-p serai-coins-primitives \
|
||||
-p serai-coins-pallet \
|
||||
-p serai-dex-pallet \
|
||||
-p serai-validator-sets-primitives \
|
||||
-p serai-validator-sets-pallet \
|
||||
-p serai-genesis-liquidity-primitives \
|
||||
-p serai-genesis-liquidity-pallet \
|
||||
-p serai-emissions-primitives \
|
||||
-p serai-emissions-pallet \
|
||||
-p serai-economic-security-pallet \
|
||||
-p serai-in-instructions-primitives \
|
||||
-p serai-in-instructions-pallet \
|
||||
-p serai-signals-primitives \
|
||||
-p serai-signals-pallet \
|
||||
-p serai-abi \
|
||||
-p serai-core-pallet \
|
||||
-p serai-coins-pallet \
|
||||
-p serai-validator-sets-pallet \
|
||||
-p serai-signals-pallet \
|
||||
-p serai-dex-pallet \
|
||||
-p serai-genesis-liquidity-pallet \
|
||||
-p serai-economic-security-pallet \
|
||||
-p serai-emissions-pallet \
|
||||
-p serai-in-instructions-pallet \
|
||||
-p serai-runtime \
|
||||
-p serai-node
|
||||
|
||||
|
||||
289
Cargo.lock
generated
289
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -84,6 +84,7 @@ members = [
|
||||
"substrate/primitives",
|
||||
"substrate/abi",
|
||||
|
||||
"substrate/core",
|
||||
"substrate/coins",
|
||||
"substrate/validator-sets",
|
||||
"substrate/signals",
|
||||
|
||||
@@ -79,6 +79,7 @@ exceptions = [
|
||||
{ allow = ["AGPL-3.0-only"], name = "serai-coordinator-libp2p-p2p" },
|
||||
{ allow = ["AGPL-3.0-only"], name = "serai-coordinator" },
|
||||
|
||||
{ allow = ["AGPL-3.0-only"], name = "serai-core-pallet" },
|
||||
{ allow = ["AGPL-3.0-only"], name = "serai-coins-pallet" },
|
||||
{ allow = ["AGPL-3.0-only"], name = "serai-dex-pallet" },
|
||||
|
||||
|
||||
@@ -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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", 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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false, features = ["serde"], optional = true }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false, 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 }
|
||||
|
||||
serai-primitives = { path = "../primitives", version = "0.1", default-features = false }
|
||||
|
||||
|
||||
@@ -44,6 +44,15 @@ pub enum Event {
|
||||
/// The coins minted.
|
||||
coins: Balance,
|
||||
},
|
||||
/// The specified coins were transferred.
|
||||
Transfer {
|
||||
/// The address transferred from.
|
||||
from: SeraiAddress,
|
||||
/// The address transferred to.
|
||||
to: SeraiAddress,
|
||||
/// The coins transferred.
|
||||
coins: Balance,
|
||||
},
|
||||
/// The specified coins were burnt.
|
||||
Burn {
|
||||
/// The address burnt from.
|
||||
@@ -58,13 +67,4 @@ pub enum Event {
|
||||
/// The `OutInstruction` specified, and the coins burnt.
|
||||
instruction: OutInstructionWithBalance,
|
||||
},
|
||||
/// The specified coins were transferred.
|
||||
Transfer {
|
||||
/// The address transferred from.
|
||||
from: SeraiAddress,
|
||||
/// The address transferred to.
|
||||
to: SeraiAddress,
|
||||
/// The coins transferred.
|
||||
coins: Balance,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -11,3 +11,10 @@ pub enum Event {
|
||||
network: ExternalNetworkId,
|
||||
},
|
||||
}
|
||||
|
||||
/// A trait representing access to the information on economic security.
|
||||
pub trait EconomicSecurity {
|
||||
/// If am external network has _ever_ achieved economic security.
|
||||
#[must_use]
|
||||
fn achieved_economic_security(network: ExternalNetworkId) -> bool;
|
||||
}
|
||||
|
||||
@@ -96,3 +96,44 @@ pub enum Event {
|
||||
/// The event for `InInstruction`s.
|
||||
InInstructions(in_instructions::Event) = 7,
|
||||
}
|
||||
|
||||
impl From<system::Event> for Event {
|
||||
fn from(event: system::Event) -> Self {
|
||||
Self::System(event)
|
||||
}
|
||||
}
|
||||
impl From<coins::Event> for Event {
|
||||
fn from(event: coins::Event) -> Self {
|
||||
Self::Coins(event)
|
||||
}
|
||||
}
|
||||
impl From<validator_sets::Event> for Event {
|
||||
fn from(event: validator_sets::Event) -> Self {
|
||||
Self::ValidatorSets(event)
|
||||
}
|
||||
}
|
||||
impl From<signals::Event> for Event {
|
||||
fn from(event: signals::Event) -> Self {
|
||||
Self::Signals(event)
|
||||
}
|
||||
}
|
||||
impl From<dex::Event> for Event {
|
||||
fn from(event: dex::Event) -> Self {
|
||||
Self::Dex(event)
|
||||
}
|
||||
}
|
||||
impl From<genesis_liquidity::Event> for Event {
|
||||
fn from(event: genesis_liquidity::Event) -> Self {
|
||||
Self::GenesisLiquidity(event)
|
||||
}
|
||||
}
|
||||
impl From<economic_security::Event> for Event {
|
||||
fn from(event: economic_security::Event) -> Self {
|
||||
Self::EconomicSecurity(event)
|
||||
}
|
||||
}
|
||||
impl From<in_instructions::Event> for Event {
|
||||
fn from(event: in_instructions::Event) -> Self {
|
||||
Self::InInstructions(event)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use serai_primitives::{
|
||||
address::SeraiAddress, network_id::NetworkId, validator_sets::ValidatorSet, signals::Signal,
|
||||
address::SeraiAddress,
|
||||
network_id::{ExternalNetworkId, NetworkId},
|
||||
signals::Signal,
|
||||
};
|
||||
|
||||
/// A call to signals.
|
||||
@@ -95,38 +97,40 @@ pub enum Event {
|
||||
/// The network with which favor for the signal was revoked.
|
||||
with_network: NetworkId,
|
||||
},
|
||||
/// A supermajority of a validator set now favor a signal.
|
||||
SetInFavor {
|
||||
/// The signal which now has a supermajority of a validator set favoring it.
|
||||
/// A supermajority of a network's validator set now favor a signal.
|
||||
NetworkInFavor {
|
||||
/// The signal which now has a supermajority of a network's validator set favoring it.
|
||||
signal: Signal,
|
||||
/// The validator set which is now considered to favor the signal.
|
||||
set: ValidatorSet,
|
||||
/// The network which is now considered to favor the signal.
|
||||
network: NetworkId,
|
||||
},
|
||||
/// A validator set is no longer considered to favor a signal.
|
||||
SetNoLongerInFavor {
|
||||
/// The signal which no longer has the validator set considered in favor of it.
|
||||
/// A network's validator set is no longer considered to favor a signal.
|
||||
NetworkNoLongerInFavor {
|
||||
/// The signal which no longer has the network considered in favor of it.
|
||||
signal: Signal,
|
||||
/// The validator set which is no longer considered to be in favor of the signal.
|
||||
set: ValidatorSet,
|
||||
/// The network which is no longer considered to be in favor of the signal.
|
||||
network: NetworkId,
|
||||
},
|
||||
/// A retirement signal has been locked in.
|
||||
RetirementSignalLockedIn {
|
||||
/// The signal which has been locked in.
|
||||
signal: [u8; 32],
|
||||
},
|
||||
/// A validator set's ability to publish batches was halted.
|
||||
/// A network's ability to publish batches was halted.
|
||||
///
|
||||
/// This also halts set rotation in effect, as handovers are via new sets starting to publish
|
||||
/// batches.
|
||||
SetHalted {
|
||||
/// The signal which has been locked in.
|
||||
signal: [u8; 32],
|
||||
NetworkHalted {
|
||||
/// The network which has been halted.
|
||||
network: ExternalNetworkId,
|
||||
},
|
||||
/// An account has stood against a signal.
|
||||
AgainstSignal {
|
||||
/// The signal stood against.
|
||||
signal: Signal,
|
||||
/// The account which stood against the signal.
|
||||
who: SeraiAddress,
|
||||
account: SeraiAddress,
|
||||
/// The network with which this was expressed.
|
||||
with_network: NetworkId,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -297,6 +297,8 @@ mod substrate {
|
||||
/// Begin execution of a transaction.
|
||||
fn start_transaction(&self);
|
||||
/// Consume the next nonce for an account.
|
||||
///
|
||||
/// This MUST NOT be called if the next nonce is `u32::MAX`. The caller MAY panic in that case.
|
||||
fn consume_next_nonce(&self, signer: &SeraiAddress);
|
||||
/// Have the transaction pay its SRI fee.
|
||||
fn pay_fee(&self, signer: &SeraiAddress, fee: Amount) -> Result<(), TransactionValidityError>;
|
||||
@@ -425,13 +427,20 @@ mod substrate {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?;
|
||||
}
|
||||
}
|
||||
match self.1.next_nonce(signer).cmp(nonce) {
|
||||
core::cmp::Ordering::Less => {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?
|
||||
|
||||
{
|
||||
let next_nonce = self.1.next_nonce(signer);
|
||||
if next_nonce == u32::MAX {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner))?;
|
||||
}
|
||||
core::cmp::Ordering::Equal => {}
|
||||
core::cmp::Ordering::Greater => {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Future))?
|
||||
match next_nonce.cmp(nonce) {
|
||||
core::cmp::Ordering::Less => {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?
|
||||
}
|
||||
core::cmp::Ordering::Equal => {}
|
||||
core::cmp::Ordering::Greater => {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Future))?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = "d4624c561765c13b38eb566e435131a8c329a543", optional = true }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", optional = true }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
async-lock = "3"
|
||||
|
||||
|
||||
@@ -18,38 +18,45 @@ 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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { 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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
serai-primitives = { path = "../primitives", default-features = false, features = ["serde", "non_canonical_scale_derivations"] }
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
serai-core-pallet = { path = "../core", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false, features = ["std"] }
|
||||
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"] }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"scale/std",
|
||||
|
||||
"sp-core/std",
|
||||
"sp-std/std",
|
||||
"sp-runtime/std",
|
||||
|
||||
"frame-system/std",
|
||||
"frame-support/std",
|
||||
|
||||
"serai-primitives/std",
|
||||
"serai-abi/std",
|
||||
"serai-core-pallet/std",
|
||||
]
|
||||
|
||||
try-runtime = [
|
||||
"frame-system/try-runtime",
|
||||
"frame-support/try-runtime",
|
||||
|
||||
"serai-abi/try-runtime",
|
||||
"serai-core-pallet/try-runtime",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
|
||||
"serai-core-pallet/runtime-benchmarks",
|
||||
]
|
||||
|
||||
default = ["std"]
|
||||
|
||||
@@ -11,7 +11,8 @@ mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use serai_primitives::balance::ExternalBalance;
|
||||
use serai_abi::primitives::balance::ExternalBalance;
|
||||
use serai_core_pallet::Pallet as Core;
|
||||
|
||||
/// The decider for if a mint is allowed or not.
|
||||
pub trait AllowMint {
|
||||
@@ -27,7 +28,7 @@ impl AllowMint for AlwaysAllowMint {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
#[frame_support::pallet]
|
||||
mod pallet {
|
||||
use core::any::TypeId;
|
||||
@@ -38,7 +39,10 @@ mod pallet {
|
||||
use frame_system::pallet_prelude::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
use serai_primitives::{coin::*, balance::*, instructions::OutInstructionWithBalance};
|
||||
use serai_abi::{
|
||||
primitives::{coin::*, balance::*, instructions::OutInstructionWithBalance},
|
||||
coins::Event,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -53,7 +57,9 @@ mod pallet {
|
||||
|
||||
/// The configuration of this pallet.
|
||||
#[pallet::config]
|
||||
pub trait Config<I: 'static = ()>: frame_system::Config<AccountId = Public> {
|
||||
pub trait Config<I: 'static = ()>:
|
||||
frame_system::Config<AccountId = Public> + serai_core_pallet::Config
|
||||
{
|
||||
/// What decides if mints are allowed.
|
||||
type AllowMint: AllowMint;
|
||||
}
|
||||
@@ -90,42 +96,6 @@ mod pallet {
|
||||
BurnWithInstructionNotAllowed,
|
||||
}
|
||||
|
||||
/// An event emitted.
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(fn deposit_event)]
|
||||
pub enum Event<T: Config<I>, I: 'static = ()> {
|
||||
/// Coins were minted.
|
||||
Mint {
|
||||
/// The account minted to.
|
||||
to: Public,
|
||||
/// The balance minted.
|
||||
balance: Balance,
|
||||
},
|
||||
/// Coins were transferred.
|
||||
Transfer {
|
||||
/// The account transferred from.
|
||||
from: Public,
|
||||
/// The account transferred to.
|
||||
to: Public,
|
||||
/// The balance transferred.
|
||||
balance: Balance,
|
||||
},
|
||||
/// Coins were burnt.
|
||||
Burn {
|
||||
/// The account burnt from.
|
||||
from: Public,
|
||||
/// The balance burnt.
|
||||
balance: Balance,
|
||||
},
|
||||
/// Coins were burnt with an instruction.
|
||||
BurnWithInstruction {
|
||||
/// The account burnt from.
|
||||
from: Public,
|
||||
/// The instruction, and associated balance.
|
||||
instruction: OutInstructionWithBalance,
|
||||
},
|
||||
}
|
||||
|
||||
/// The Pallet struct.
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T, I = ()>(_);
|
||||
@@ -151,6 +121,16 @@ mod pallet {
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
fn emit_event(event: Event) {
|
||||
if TypeId::of::<I>() == TypeId::of::<CoinsInstance>() {
|
||||
Core::<T>::emit_event(event)
|
||||
} else if TypeId::of::<I>() == TypeId::of::<LiquidityTokensInstance>() {
|
||||
// The DEX pallet is expected to emit this event
|
||||
} else {
|
||||
panic!("unrecognized instance type for `coins::Pallet` made it into an execution context")
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the balance of `coin` for the specified account.
|
||||
pub fn balance(
|
||||
of: impl scale::EncodeLike<Public>,
|
||||
@@ -195,10 +175,10 @@ mod pallet {
|
||||
/// Mint `balance` to the given account.
|
||||
///
|
||||
/// Errors if any amount overflows.
|
||||
pub fn mint(to: Public, balance: Balance) -> Result<(), Error<T, I>> {
|
||||
pub fn mint(to: Public, coins: Balance) -> Result<(), Error<T, I>> {
|
||||
{
|
||||
// If this is an external coin, check if we can mint it
|
||||
let external_balance = ExternalBalance::try_from(balance);
|
||||
let external_balance = ExternalBalance::try_from(coins);
|
||||
let can_mint_external = external_balance.as_ref().map(T::AllowMint::is_allowed);
|
||||
// If it was native to the Serai network, we can always mint it
|
||||
let can_mint = can_mint_external.unwrap_or(true);
|
||||
@@ -208,14 +188,14 @@ mod pallet {
|
||||
}
|
||||
|
||||
// update the balance
|
||||
Self::increase_balance_internal(to, balance)?;
|
||||
Self::increase_balance_internal(to, coins)?;
|
||||
|
||||
// update the supply
|
||||
let new_supply = (Supply::<T, I>::get(balance.coin) + balance.amount)
|
||||
.ok_or(Error::<T, I>::AmountOverflowed)?;
|
||||
Supply::<T, I>::set(balance.coin, new_supply);
|
||||
let new_supply =
|
||||
(Supply::<T, I>::get(coins.coin) + coins.amount).ok_or(Error::<T, I>::AmountOverflowed)?;
|
||||
Supply::<T, I>::set(coins.coin, new_supply);
|
||||
|
||||
Self::deposit_event(Event::Mint { to, balance });
|
||||
Self::emit_event(Event::Mint { to: to.into(), coins });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -238,12 +218,12 @@ mod pallet {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Transfer `balance` from `from` to `to`.
|
||||
pub fn transfer_fn(from: Public, to: Public, balance: Balance) -> Result<(), Error<T, I>> {
|
||||
/// Transfer `coins` from `from` to `to`.
|
||||
pub fn transfer_fn(from: Public, to: Public, coins: Balance) -> Result<(), Error<T, I>> {
|
||||
// update balances of accounts
|
||||
Self::decrease_balance_internal(from, balance)?;
|
||||
Self::increase_balance_internal(to, balance)?;
|
||||
Self::deposit_event(Event::Transfer { from, to, balance });
|
||||
Self::decrease_balance_internal(from, coins)?;
|
||||
Self::increase_balance_internal(to, coins)?;
|
||||
Self::emit_event(Event::Transfer { from: from.into(), to: to.into(), coins });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -253,19 +233,19 @@ mod pallet {
|
||||
/// Transfer `balance` from the signer to `to`.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||
pub fn transfer(origin: OriginFor<T>, to: Public, balance: Balance) -> DispatchResult {
|
||||
pub fn transfer(origin: OriginFor<T>, to: Public, coins: Balance) -> DispatchResult {
|
||||
let from = ensure_signed(origin)?;
|
||||
Self::transfer_fn(from, to, balance)?;
|
||||
Self::transfer_fn(from, to, coins)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Burn `balance` from the signer.
|
||||
/// Burn `coins` from the signer.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||
pub fn burn(origin: OriginFor<T>, balance: Balance) -> DispatchResult {
|
||||
pub fn burn(origin: OriginFor<T>, coins: Balance) -> DispatchResult {
|
||||
let from = ensure_signed(origin)?;
|
||||
Self::burn_internal(from, balance)?;
|
||||
Self::deposit_event(Event::Burn { from, balance });
|
||||
Self::burn_internal(from, coins)?;
|
||||
Self::emit_event(Event::Burn { from: from.into(), coins });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -283,7 +263,7 @@ mod pallet {
|
||||
|
||||
let from = ensure_signed(origin)?;
|
||||
Self::burn_internal(from, instruction.balance.into())?;
|
||||
Self::deposit_event(Event::BurnWithInstruction { from, instruction });
|
||||
Self::emit_event(Event::BurnWithInstruction { from: from.into(), instruction });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Test environment for Coins pallet.
|
||||
|
||||
use sp_runtime::BuildStorage;
|
||||
use borsh::BorshDeserialize;
|
||||
|
||||
use frame_support::{derive_impl, construct_runtime};
|
||||
use frame_support::{sp_runtime::BuildStorage, derive_impl, construct_runtime};
|
||||
|
||||
use crate::{self as coins, CoinsInstance};
|
||||
|
||||
@@ -10,6 +10,7 @@ construct_runtime!(
|
||||
pub enum Test
|
||||
{
|
||||
System: frame_system,
|
||||
Core: serai_core_pallet,
|
||||
Coins: coins::<CoinsInstance>,
|
||||
}
|
||||
);
|
||||
@@ -17,15 +18,28 @@ construct_runtime!(
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Test {
|
||||
type AccountId = sp_core::sr25519::Public;
|
||||
type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
|
||||
type Lookup = frame_support::sp_runtime::traits::IdentityLookup<Self::AccountId>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
}
|
||||
|
||||
impl serai_core_pallet::Config for Test {}
|
||||
|
||||
impl crate::Config<CoinsInstance> for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AllowMint = crate::AlwaysAllowMint;
|
||||
}
|
||||
|
||||
impl TryFrom<RuntimeEvent> for serai_abi::Event {
|
||||
type Error = ();
|
||||
fn try_from(event: RuntimeEvent) -> Result<serai_abi::Event, ()> {
|
||||
match event {
|
||||
RuntimeEvent::Core(serai_core_pallet::Event::Event(event)) => {
|
||||
Ok(serai_abi::Event::deserialize_reader(&mut event.as_slice()).unwrap())
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use sp_core::{Pair as _, sr25519::Pair};
|
||||
use frame_system::RawOrigin;
|
||||
|
||||
use serai_primitives::{coin::*, balance::*, address::*, instructions::*};
|
||||
use serai_abi::primitives::{coin::*, balance::*, address::*, instructions::*};
|
||||
|
||||
use crate::mock::*;
|
||||
|
||||
pub type CoinsEvent = crate::Event<Test, crate::CoinsInstance>;
|
||||
pub type CoinsEvent = serai_abi::coins::Event;
|
||||
|
||||
#[test]
|
||||
fn mint() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Core::start_transaction();
|
||||
|
||||
// minting u64::MAX should work
|
||||
let coin = Coin::Serai;
|
||||
let to = Pair::generate().0.public();
|
||||
@@ -25,10 +27,10 @@ fn mint() {
|
||||
assert_eq!(Coins::supply(coin), balance.amount);
|
||||
|
||||
// test events
|
||||
let mint_events = System::events()
|
||||
let mint_events = Core::events()
|
||||
.iter()
|
||||
.filter_map(|event| {
|
||||
if let RuntimeEvent::Coins(e) = &event.event {
|
||||
if let serai_abi::Event::Coins(e) = &event {
|
||||
if matches!(e, CoinsEvent::Mint { .. }) {
|
||||
Some(e.clone())
|
||||
} else {
|
||||
@@ -40,13 +42,15 @@ fn mint() {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(mint_events, vec![CoinsEvent::Mint { to, balance }]);
|
||||
assert_eq!(mint_events, vec![CoinsEvent::Mint { to: to.into(), coins: balance }]);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn burn_with_instruction() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Core::start_transaction();
|
||||
|
||||
// mint some coin
|
||||
let coin = Coin::External(ExternalCoin::Bitcoin);
|
||||
let to = Pair::generate().0.public();
|
||||
@@ -76,10 +80,10 @@ fn burn_with_instruction() {
|
||||
assert_eq!(Coins::balance(to, coin), Amount(0));
|
||||
assert_eq!(Coins::supply(coin), Amount(0));
|
||||
|
||||
let burn_events = System::events()
|
||||
let burn_events = Core::events()
|
||||
.iter()
|
||||
.filter_map(|event| {
|
||||
if let RuntimeEvent::Coins(e) = &event.event {
|
||||
if let serai_abi::Event::Coins(e) = &event {
|
||||
if matches!(e, CoinsEvent::BurnWithInstruction { .. }) {
|
||||
Some(e.clone())
|
||||
} else {
|
||||
@@ -91,13 +95,15 @@ fn burn_with_instruction() {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(burn_events, vec![CoinsEvent::BurnWithInstruction { from: to, instruction }]);
|
||||
assert_eq!(burn_events, vec![CoinsEvent::BurnWithInstruction { from: to.into(), instruction }]);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Core::start_transaction();
|
||||
|
||||
// mint some coin
|
||||
let coin = Coin::External(ExternalCoin::Bitcoin);
|
||||
let from = Pair::generate().0.public();
|
||||
|
||||
50
substrate/core/Cargo.toml
Normal file
50
substrate/core/Cargo.toml
Normal file
@@ -0,0 +1,50 @@
|
||||
[package]
|
||||
name = "serai-core-pallet"
|
||||
version = "0.1.0"
|
||||
description = "Core pallet"
|
||||
license = "AGPL-3.0-only"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/core"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"borsh/std",
|
||||
"scale/std",
|
||||
|
||||
"sp-core/std",
|
||||
|
||||
"frame-system/std",
|
||||
"frame-support/std",
|
||||
|
||||
"serai-abi/std",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
]
|
||||
|
||||
try-runtime = ["serai-abi/try-runtime"]
|
||||
|
||||
default = ["std"]
|
||||
15
substrate/core/LICENSE
Normal file
15
substrate/core/LICENSE
Normal file
@@ -0,0 +1,15 @@
|
||||
AGPL-3.0-only license
|
||||
|
||||
Copyright (c) 2023-2025 Luke Parker
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License Version 3 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
1
substrate/core/README.md
Normal file
1
substrate/core/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# Serai Core Pallet
|
||||
52
substrate/core/src/iumt.rs
Normal file
52
substrate/core/src/iumt.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use borsh::BorshSerialize;
|
||||
|
||||
use serai_abi::primitives::merkle::{UnbalancedMerkleTree, IncrementalUnbalancedMerkleTree as Iumt};
|
||||
|
||||
/// A wrapper around a `StorageValue` which offers a high-level API as an
|
||||
/// `IncrementalUnbalancedMerkleTree`.
|
||||
pub struct IncrementalUnbalancedMerkleTree<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
const BRANCH_TAG: u8 = 1,
|
||||
const LEAF_TAG: u8 = 0,
|
||||
>(PhantomData<T>);
|
||||
impl<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
const BRANCH_TAG: u8,
|
||||
const LEAF_TAG: u8,
|
||||
> IncrementalUnbalancedMerkleTree<T, BRANCH_TAG, LEAF_TAG>
|
||||
{
|
||||
/// Create a new Merkle tree, expecting there to be none already present.
|
||||
///
|
||||
/// Panics if a Merkle tree was already present.
|
||||
pub fn new_expecting_none() {
|
||||
T::mutate(|value| {
|
||||
assert!(value.is_none());
|
||||
*value = Some(Iumt::new());
|
||||
});
|
||||
}
|
||||
/// Append a leaf to the Merkle tree.
|
||||
///
|
||||
/// Panics if no Merkle tree was present.
|
||||
pub fn append<L: BorshSerialize>(leaf: &L) {
|
||||
let leaf = sp_core::blake2_256(&borsh::to_vec(&(LEAF_TAG, leaf)).unwrap());
|
||||
|
||||
T::mutate(|value| {
|
||||
let tree = value.as_mut().unwrap();
|
||||
tree.append(BRANCH_TAG, leaf);
|
||||
})
|
||||
}
|
||||
/// Get the unbalanced merkle tree.
|
||||
///
|
||||
/// Panics if no Merkle tree was present.
|
||||
pub fn get() -> UnbalancedMerkleTree {
|
||||
T::get().unwrap().calculate(BRANCH_TAG)
|
||||
}
|
||||
/// Take the Merkle tree.
|
||||
///
|
||||
/// Panics if no Merkle tree was present.
|
||||
pub fn take() -> UnbalancedMerkleTree {
|
||||
T::mutate(|value| value.take().unwrap().calculate(BRANCH_TAG))
|
||||
}
|
||||
}
|
||||
179
substrate/core/src/lib.rs
Normal file
179
substrate/core/src/lib.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod iumt;
|
||||
pub use iumt::*;
|
||||
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
use serai_abi::primitives::{prelude::*, merkle::IncrementalUnbalancedMerkleTree as Iumt};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// The set of all blocks prior added to the blockchain.
|
||||
#[pallet::storage]
|
||||
pub(super) type Blocks<T: Config> = StorageMap<_, Identity, T::Hash, (), OptionQuery>;
|
||||
/// The Merkle tree of all blocks added to the blockchain.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlocksCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlocksCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<BlocksCommitment<T>>;
|
||||
|
||||
/// The Merkle tree of all transactions within the current block.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlockTransactionsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlockTransactionsCommitmentMerkle<T> =
|
||||
IncrementalUnbalancedMerkleTree<BlockTransactionsCommitment<T>>;
|
||||
|
||||
/// The hashes of events caused by the current transaction.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type TransactionEvents<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type TransactionEventsMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
TransactionEvents<T>,
|
||||
{ serai_abi::TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG },
|
||||
{ serai_abi::TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG },
|
||||
>;
|
||||
/// The roots of the Merkle trees of each transaction's events.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlockEventsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlockEventsCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
BlockEventsCommitment<T>,
|
||||
{ serai_abi::EVENTS_COMMITMENT_BRANCH_TAG },
|
||||
{ serai_abi::EVENTS_COMMITMENT_LEAF_TAG },
|
||||
>;
|
||||
|
||||
/// A mapping from an account to its next nonce.
|
||||
#[pallet::storage]
|
||||
type NextNonce<T: Config> = StorageMap<_, Blake2_128Concat, SeraiAddress, T::Nonce, ValueQuery>;
|
||||
|
||||
/// Mapping from Serai's events to Substrate's.
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// An event from Serai.
|
||||
Event(Vec<u8>),
|
||||
}
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config<Hash: Into<[u8; 32]>> {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// If a block exists on the current blockchain.
|
||||
#[must_use]
|
||||
pub fn block_exists(hash: impl scale::EncodeLike<T::Hash>) -> bool {
|
||||
Blocks::<T>::contains_key(hash)
|
||||
}
|
||||
|
||||
/// The next nonce for an account.
|
||||
#[must_use]
|
||||
pub fn next_nonce(account: &SeraiAddress) -> T::Nonce {
|
||||
NextNonce::<T>::get(account)
|
||||
}
|
||||
|
||||
/// Consume the next nonce for an account.
|
||||
///
|
||||
/// Panics if the current nonce is `<_>::MAX`.
|
||||
pub fn consume_next_nonce(signer: &SeraiAddress) {
|
||||
NextNonce::<T>::mutate(signer, |value| {
|
||||
*value = value
|
||||
.checked_add(&T::Nonce::one())
|
||||
.expect("`consume_next_nonce` called when current nonce is <_>::MAX")
|
||||
});
|
||||
}
|
||||
|
||||
/// The code to run when beginning execution of a transaction.
|
||||
///
|
||||
/// The caller MUST ensure two transactions aren't simultaneously started.
|
||||
pub fn start_transaction() {
|
||||
TransactionEventsMerkle::<T>::new_expecting_none();
|
||||
}
|
||||
|
||||
/// Emit an event.
|
||||
pub fn emit_event(event: impl Into<serai_abi::Event>) {
|
||||
let event = event.into();
|
||||
TransactionEventsMerkle::<T>::append(&event);
|
||||
Self::deposit_event(Event::Event(borsh::to_vec(&event).unwrap()));
|
||||
}
|
||||
|
||||
/// End execution of a transaction.
|
||||
pub fn end_transaction(transaction_hash: [u8; 32]) {
|
||||
BlockTransactionsCommitmentMerkle::<T>::append(&transaction_hash);
|
||||
|
||||
let transaction_events_root = TransactionEventsMerkle::<T>::take().root;
|
||||
|
||||
// Append the leaf (the transaction's hash and its events' root) to the block's events'
|
||||
// commitment
|
||||
BlockEventsCommitmentMerkle::<T>::append(&(&transaction_hash, &transaction_events_root));
|
||||
}
|
||||
|
||||
/// Fetch all of Serai's events.
|
||||
///
|
||||
/// This MUST only be used for testing purposes.
|
||||
pub fn events() -> Vec<serai_abi::Event>
|
||||
where
|
||||
serai_abi::Event: TryFrom<T::RuntimeEvent>,
|
||||
{
|
||||
frame_system::Pallet::<T>::events()
|
||||
.into_iter()
|
||||
.filter_map(|e| serai_abi::Event::try_from(e.event).ok())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use pallet::*;
|
||||
|
||||
/// The code to run at the start of a block for this pallet.
|
||||
pub struct StartOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
|
||||
fn pre_inherents() {
|
||||
use frame_support::pallet_prelude::Zero;
|
||||
|
||||
if frame_system::Pallet::<T>::block_number().is_zero() {
|
||||
BlocksCommitmentMerkle::<T>::new_expecting_none();
|
||||
} else {
|
||||
let parent_hash = frame_system::Pallet::<T>::parent_hash();
|
||||
Blocks::<T>::set(parent_hash, Some(()));
|
||||
let parent_hash: [u8; 32] = parent_hash.into();
|
||||
BlocksCommitmentMerkle::<T>::append(&parent_hash);
|
||||
}
|
||||
|
||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||
}
|
||||
}
|
||||
|
||||
/// The code to run at the end of a block for this pallet.
|
||||
pub struct EndOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PostTransactions for EndOfBlock<T> {
|
||||
fn post_transactions() {
|
||||
use serai_abi::SeraiExecutionDigest;
|
||||
frame_system::Pallet::<T>::deposit_log(
|
||||
frame_support::sp_runtime::generic::DigestItem::Consensus(
|
||||
SeraiExecutionDigest::CONSENSUS_ID,
|
||||
borsh::to_vec(&SeraiExecutionDigest {
|
||||
builds_upon: BlocksCommitmentMerkle::<T>::get(),
|
||||
transactions_commitment: BlockTransactionsCommitmentMerkle::<T>::take(),
|
||||
events_commitment: BlockEventsCommitmentMerkle::<T>::take(),
|
||||
})
|
||||
.unwrap(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false, optional = true }
|
||||
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 }
|
||||
|
||||
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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", 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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
[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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
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 }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", 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 = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sp-keystore = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sp-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sp-blockchain = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
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" }
|
||||
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
|
||||
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 = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-transaction-pool-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-client-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-network-common = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-network = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
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-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-authority-discovery = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
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-telemetry = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-cli = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false, features = ["rocksdb"] }
|
||||
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-rpc-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
sc-rpc-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
|
||||
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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
|
||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["alloc"] }
|
||||
schnorr-signatures = { path = "../../crypto/schnorr", default-features = false }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{vec, vec::Vec};
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
@@ -6,8 +6,10 @@ use borsh::{BorshSerialize, BorshDeserialize};
|
||||
use ciphersuite::{group::GroupEncoding, GroupIo};
|
||||
use dalek_ff_group::Ristretto;
|
||||
|
||||
use sp_core::sr25519::Public;
|
||||
|
||||
use crate::{
|
||||
crypto::{Public, KeyPair},
|
||||
crypto::KeyPair,
|
||||
network_id::{ExternalNetworkId, NetworkId},
|
||||
balance::Amount,
|
||||
};
|
||||
@@ -86,15 +88,17 @@ impl ExternalValidatorSet {
|
||||
|
||||
/// The MuSig public key for a validator set.
|
||||
///
|
||||
/// This function panics on invalid input, per the definition of `dkg::musig::musig_key`.
|
||||
pub fn musig_key(&self, set_keys: &[Public]) -> Public {
|
||||
let mut keys = Vec::new();
|
||||
for key in set_keys {
|
||||
keys.push(
|
||||
<Ristretto as GroupIo>::read_G::<&[u8]>(&mut key.0.as_ref()).expect("invalid participant"),
|
||||
/// This function panics on invalid points as keys and on invalid input, per the definition of
|
||||
/// `dkg::musig::musig_key`.
|
||||
pub fn musig_key(&self, keys: &[Public]) -> Public {
|
||||
let mut decompressed_keys = vec![];
|
||||
for key in keys {
|
||||
decompressed_keys.push(
|
||||
<Ristretto as GroupIo>::read_G::<&[u8]>(&mut key.0.as_slice())
|
||||
.expect("invalid participant"),
|
||||
);
|
||||
}
|
||||
Public(dkg::musig_key::<Ristretto>(self.musig_context(), &keys).unwrap().to_bytes())
|
||||
dkg::musig_key::<Ristretto>(self.musig_context(), &decompressed_keys).unwrap().to_bytes().into()
|
||||
}
|
||||
|
||||
/// The message for the `set_keys` signature.
|
||||
@@ -150,7 +154,7 @@ impl KeyShares {
|
||||
/// Reduction occurs by reducing each validator in a reverse round-robin. This means the
|
||||
/// validators with the least key shares are evicted first.
|
||||
#[must_use]
|
||||
pub fn amortize_excess(validators: &mut [(sp_core::sr25519::Public, KeyShares)]) -> usize {
|
||||
pub fn amortize_excess(validators: &mut [(Public, KeyShares)]) -> usize {
|
||||
let total_key_shares = validators.iter().map(|(_key, shares)| shares.0).sum::<u16>();
|
||||
let mut actual_len = validators.len();
|
||||
let mut offset = 1;
|
||||
|
||||
@@ -18,27 +18,26 @@ ignored = ["scale"]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-version = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
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 }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-executive = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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-executive = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||
|
||||
serai-core-pallet = { path = "../core", default-features = false }
|
||||
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||
serai-validator-sets-pallet = { path = "../validator-sets", default-features = false }
|
||||
serai-signals-pallet = { path = "../signals", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543" }
|
||||
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7" }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
@@ -55,6 +54,7 @@ std = [
|
||||
"frame-support/std",
|
||||
"frame-executive/std",
|
||||
|
||||
"serai-core-pallet/std",
|
||||
"serai-coins-pallet/std",
|
||||
"serai-validator-sets-pallet/std",
|
||||
"serai-signals-pallet/std",
|
||||
@@ -69,6 +69,7 @@ try-runtime = [
|
||||
"frame-support/try-runtime",
|
||||
"frame-executive/try-runtime",
|
||||
|
||||
"serai-core-pallet/try-runtime",
|
||||
"serai-coins-pallet/try-runtime",
|
||||
"serai-validator-sets-pallet/try-runtime",
|
||||
"serai-signals-pallet/try-runtime",
|
||||
@@ -80,6 +81,8 @@ runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
|
||||
"serai-core-pallet/runtime-benchmarks",
|
||||
"serai-coins-pallet/runtime-benchmarks",
|
||||
"serai-validator-sets-pallet/runtime-benchmarks",
|
||||
"serai-signals-pallet/runtime-benchmarks",
|
||||
]
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use borsh::BorshSerialize;
|
||||
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
use serai_abi::{
|
||||
primitives::merkle::{UnbalancedMerkleTree, IncrementalUnbalancedMerkleTree as Iumt},
|
||||
*,
|
||||
};
|
||||
|
||||
/// A wrapper around a `StorageValue` which offers a high-level API as an IUMT.
|
||||
struct IncrementalUnbalancedMerkleTree<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
const BRANCH_TAG: u8 = 1,
|
||||
const LEAF_TAG: u8 = 0,
|
||||
>(PhantomData<T>);
|
||||
impl<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
const BRANCH_TAG: u8,
|
||||
const LEAF_TAG: u8,
|
||||
> IncrementalUnbalancedMerkleTree<T, BRANCH_TAG, LEAF_TAG>
|
||||
{
|
||||
/// Create a new Merkle tree, expecting there to be none already present.
|
||||
///
|
||||
/// Panics if a Merkle tree was already present.
|
||||
fn new_expecting_none() {
|
||||
T::mutate(|value| {
|
||||
assert!(value.is_none());
|
||||
*value = Some(Iumt::new());
|
||||
});
|
||||
}
|
||||
/// Append a leaf to the Merkle tree.
|
||||
///
|
||||
/// Panics if no Merkle tree was present.
|
||||
fn append<L: BorshSerialize>(leaf: &L) {
|
||||
let leaf = sp_core::blake2_256(&borsh::to_vec(&(LEAF_TAG, leaf)).unwrap());
|
||||
|
||||
T::mutate(|value| {
|
||||
let tree = value.as_mut().unwrap();
|
||||
tree.append(BRANCH_TAG, leaf);
|
||||
})
|
||||
}
|
||||
/// Get the unbalanced merkle tree.
|
||||
///
|
||||
/// Panics if no Merkle tree was present.
|
||||
fn get() -> UnbalancedMerkleTree {
|
||||
T::get().unwrap().calculate(BRANCH_TAG)
|
||||
}
|
||||
/// Take the Merkle tree.
|
||||
///
|
||||
/// Panics if no Merkle tree was present.
|
||||
fn take() -> UnbalancedMerkleTree {
|
||||
T::mutate(|value| value.take().unwrap().calculate(BRANCH_TAG))
|
||||
}
|
||||
}
|
||||
|
||||
#[frame_support::pallet]
|
||||
mod pallet {
|
||||
use super::*;
|
||||
|
||||
/// The set of all blocks prior added to the blockchain.
|
||||
#[pallet::storage]
|
||||
pub type Blocks<T: Config> = StorageMap<_, Identity, T::Hash, (), OptionQuery>;
|
||||
/// The Merkle tree of all blocks added to the blockchain.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlocksCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlocksCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<BlocksCommitment<T>>;
|
||||
|
||||
/// The Merkle tree of all transactions within the current block.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlockTransactionsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlockTransactionsCommitmentMerkle<T> =
|
||||
IncrementalUnbalancedMerkleTree<BlockTransactionsCommitment<T>>;
|
||||
|
||||
/// The hashes of events caused by the current transaction.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type TransactionEvents<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type TransactionEventsMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
TransactionEvents<T>,
|
||||
TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG,
|
||||
TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG,
|
||||
>;
|
||||
/// The roots of the Merkle trees of each transaction's events.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlockEventsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlockEventsCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
BlockEventsCommitment<T>,
|
||||
EVENTS_COMMITMENT_BRANCH_TAG,
|
||||
EVENTS_COMMITMENT_LEAF_TAG,
|
||||
>;
|
||||
|
||||
/// A mapping from an account to its next nonce.
|
||||
#[pallet::storage]
|
||||
pub type NextNonce<T: Config> =
|
||||
StorageMap<_, Blake2_128Concat, T::AccountId, T::Nonce, ValueQuery>;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config<Hash: Into<[u8; 32]>> {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn start_transaction() {
|
||||
TransactionEventsMerkle::<T>::new_expecting_none();
|
||||
}
|
||||
// TODO: Have this called
|
||||
pub fn on_event(event: impl TryInto<serai_abi::Event>) {
|
||||
if let Ok(event) = event.try_into() {
|
||||
TransactionEventsMerkle::<T>::append(&event);
|
||||
}
|
||||
}
|
||||
pub fn end_transaction(transaction_hash: [u8; 32]) {
|
||||
BlockTransactionsCommitmentMerkle::<T>::append(&transaction_hash);
|
||||
|
||||
let transaction_events_root = TransactionEventsMerkle::<T>::take().root;
|
||||
|
||||
// Append the leaf (the transaction's hash and its events' root) to the block's events'
|
||||
// commitment
|
||||
BlockEventsCommitmentMerkle::<T>::append(&(&transaction_hash, &transaction_events_root));
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(super) use pallet::*;
|
||||
|
||||
pub struct StartOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
|
||||
fn pre_inherents() {
|
||||
if frame_system::Pallet::<T>::block_number().is_zero() {
|
||||
BlocksCommitmentMerkle::<T>::new_expecting_none();
|
||||
} else {
|
||||
let parent_hash = frame_system::Pallet::<T>::parent_hash();
|
||||
Blocks::<T>::set(parent_hash, Some(()));
|
||||
let parent_hash: [u8; 32] = parent_hash.into();
|
||||
BlocksCommitmentMerkle::<T>::append(&parent_hash);
|
||||
}
|
||||
|
||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EndOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PostTransactions for EndOfBlock<T> {
|
||||
fn post_transactions() {
|
||||
frame_system::Pallet::<T>::deposit_log(sp_runtime::generic::DigestItem::Consensus(
|
||||
SeraiExecutionDigest::CONSENSUS_ID,
|
||||
borsh::to_vec(&SeraiExecutionDigest {
|
||||
builds_upon: BlocksCommitmentMerkle::<T>::get(),
|
||||
transactions_commitment: BlockTransactionsCommitmentMerkle::<T>::take(),
|
||||
events_commitment: BlockEventsCommitmentMerkle::<T>::take(),
|
||||
})
|
||||
.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ extern crate alloc;
|
||||
use alloc::borrow::Cow;
|
||||
|
||||
use sp_core::sr25519::Public;
|
||||
use sp_runtime::{Perbill, Weight, traits::Header as _};
|
||||
use sp_runtime::{Perbill, Weight};
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
#[rustfmt::skip]
|
||||
@@ -19,8 +19,6 @@ use serai_abi::{
|
||||
|
||||
use serai_coins_pallet::{CoinsInstance, LiquidityTokensInstance};
|
||||
|
||||
mod core_pallet;
|
||||
|
||||
type Block = SubstrateBlock;
|
||||
|
||||
/// The lookup for a SeraiAddress -> Public.
|
||||
@@ -75,7 +73,7 @@ mod runtime {
|
||||
pub type System = frame_system::Pallet<Runtime>;
|
||||
|
||||
#[runtime::pallet_index(1)]
|
||||
pub type Core = core_pallet::Pallet<Runtime>;
|
||||
pub type Core = serai_core_pallet::Pallet<Runtime>;
|
||||
|
||||
#[runtime::pallet_index(2)]
|
||||
pub type Coins = serai_coins_pallet::Pallet<Runtime, CoinsInstance>;
|
||||
@@ -125,12 +123,12 @@ impl frame_system::Config for Runtime {
|
||||
type SingleBlockMigrations = ();
|
||||
type MultiBlockMigrator = ();
|
||||
|
||||
type PreInherents = core_pallet::StartOfBlock<Runtime>;
|
||||
type PreInherents = serai_core_pallet::StartOfBlock<Runtime>;
|
||||
type PostInherents = ();
|
||||
type PostTransactions = core_pallet::EndOfBlock<Runtime>;
|
||||
type PostTransactions = serai_core_pallet::EndOfBlock<Runtime>;
|
||||
}
|
||||
|
||||
impl core_pallet::Config for Runtime {}
|
||||
impl serai_core_pallet::Config for Runtime {}
|
||||
|
||||
impl serai_coins_pallet::Config<CoinsInstance> for Runtime {
|
||||
type AllowMint = serai_coins_pallet::AlwaysAllowMint; // TODO
|
||||
@@ -138,7 +136,9 @@ impl serai_coins_pallet::Config<CoinsInstance> for Runtime {
|
||||
impl serai_coins_pallet::Config<LiquidityTokensInstance> for Runtime {
|
||||
type AllowMint = serai_coins_pallet::AlwaysAllowMint;
|
||||
}
|
||||
impl serai_validator_sets_pallet::Config for Runtime {}
|
||||
impl serai_validator_sets_pallet::Config for Runtime {
|
||||
type ShouldEndSession = Babe;
|
||||
}
|
||||
impl serai_signals_pallet::Config for Runtime {
|
||||
type RetirementValidityDuration = sp_core::ConstU64<0>; // TODO
|
||||
type RetirementLockInDuration = sp_core::ConstU64<0>; // TODO
|
||||
@@ -160,11 +160,9 @@ impl From<serai_abi::Call> for RuntimeCall {
|
||||
use serai_abi::coins::Call;
|
||||
match call {
|
||||
Call::transfer { to, coins } => {
|
||||
RuntimeCall::Coins(serai_coins_pallet::Call::transfer { to: to.into(), balance: coins })
|
||||
}
|
||||
Call::burn { coins } => {
|
||||
RuntimeCall::Coins(serai_coins_pallet::Call::burn { balance: coins })
|
||||
RuntimeCall::Coins(serai_coins_pallet::Call::transfer { to: to.into(), coins })
|
||||
}
|
||||
Call::burn { coins } => RuntimeCall::Coins(serai_coins_pallet::Call::burn { coins }),
|
||||
Call::burn_with_instruction { instruction } => {
|
||||
RuntimeCall::Coins(serai_coins_pallet::Call::burn_with_instruction { instruction })
|
||||
}
|
||||
@@ -197,7 +195,7 @@ impl From<serai_abi::Call> for RuntimeCall {
|
||||
Call::transfer_liquidity { to, liquidity_tokens } => {
|
||||
RuntimeCall::LiquidityTokens(serai_coins_pallet::Call::transfer {
|
||||
to: to.into(),
|
||||
balance: liquidity_tokens.into(),
|
||||
coins: liquidity_tokens.into(),
|
||||
})
|
||||
}
|
||||
Call::add_liquidity { .. } |
|
||||
@@ -230,7 +228,6 @@ sp_api::impl_runtime_apis! {
|
||||
VERSION
|
||||
}
|
||||
fn initialize_block(header: &Header) -> sp_runtime::ExtrinsicInclusionMode {
|
||||
core_pallet::Blocks::<Runtime>::set(header.parent_hash(), Some(()));
|
||||
Executive::initialize_block(header)
|
||||
}
|
||||
fn execute_block(block: Block) {
|
||||
@@ -257,7 +254,7 @@ impl serai_abi::TransactionContext for Context {
|
||||
|
||||
/// If a block is present in the blockchain.
|
||||
fn block_is_present_in_blockchain(&self, hash: &serai_abi::primitives::BlockHash) -> bool {
|
||||
core_pallet::Blocks::<Runtime>::get(hash).is_some()
|
||||
serai_core_pallet::Pallet::<Runtime>::block_exists(hash)
|
||||
}
|
||||
/// The time embedded into the current block.
|
||||
fn current_time(&self) -> Option<u64> {
|
||||
@@ -265,7 +262,7 @@ impl serai_abi::TransactionContext for Context {
|
||||
}
|
||||
/// Get the next nonce for an account.
|
||||
fn next_nonce(&self, signer: &SeraiAddress) -> u32 {
|
||||
core_pallet::NextNonce::<Runtime>::get(signer)
|
||||
serai_core_pallet::Pallet::<Runtime>::next_nonce(signer)
|
||||
}
|
||||
/// If the signer can pay the SRI fee.
|
||||
fn can_pay_fee(
|
||||
@@ -284,11 +281,10 @@ impl serai_abi::TransactionContext for Context {
|
||||
}
|
||||
|
||||
fn start_transaction(&self) {
|
||||
Core::start_transaction();
|
||||
Core::start_transaction()
|
||||
}
|
||||
/// Consume the next nonce for an account.
|
||||
fn consume_next_nonce(&self, signer: &SeraiAddress) {
|
||||
core_pallet::NextNonce::<Runtime>::mutate(signer, |value| *value += 1);
|
||||
serai_core_pallet::Pallet::<Runtime>::consume_next_nonce(signer)
|
||||
}
|
||||
/// Have the transaction pay its SRI fee.
|
||||
fn pay_fee(
|
||||
@@ -430,28 +426,11 @@ impl timestamp::Config for Runtime {
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
impl transaction_payment::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type OnChargeTransaction = Coins;
|
||||
type OperationalFeeMultiplier = ConstU8<5>;
|
||||
type WeightToFee = IdentityFee<SubstrateAmount>;
|
||||
type LengthToFee = IdentityFee<SubstrateAmount>;
|
||||
type FeeMultiplierUpdate = ();
|
||||
}
|
||||
|
||||
impl coins::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AllowMint = ValidatorSets;
|
||||
}
|
||||
|
||||
impl coins::Config<coins::Instance1> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AllowMint = ();
|
||||
}
|
||||
|
||||
impl dex::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
|
||||
type LPFee = ConstU32<3>; // 0.3%
|
||||
type MintMinLiquidity = ConstU64<10000>;
|
||||
|
||||
@@ -462,12 +441,6 @@ impl dex::Config for Runtime {
|
||||
type WeightInfo = dex::weights::SubstrateWeight<Runtime>;
|
||||
}
|
||||
|
||||
impl validator_sets::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
|
||||
type ShouldEndSession = Babe;
|
||||
}
|
||||
|
||||
pub struct IdentityValidatorIdOf;
|
||||
impl Convert<PublicKey, Option<PublicKey>> for IdentityValidatorIdOf {
|
||||
fn convert(key: PublicKey) -> Option<PublicKey> {
|
||||
|
||||
@@ -21,37 +21,47 @@ 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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-core = { 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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
||||
serai-core-pallet = { path = "../core", default-features = false }
|
||||
serai-validator-sets-pallet = { path = "../validator-sets", default-features = false }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"scale/std",
|
||||
|
||||
"sp-core/std",
|
||||
"sp-io/std",
|
||||
|
||||
"frame-system/std",
|
||||
"frame-support/std",
|
||||
|
||||
"serai-abi/std",
|
||||
|
||||
"validator-sets-pallet/std",
|
||||
"serai-core-pallet/std",
|
||||
"serai-validator-sets-pallet/std",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
|
||||
"serai-core-pallet/runtime-benchmarks",
|
||||
"serai-validator-sets-pallet/runtime-benchmarks",
|
||||
]
|
||||
|
||||
# TODO
|
||||
try-runtime = []
|
||||
try-runtime = [
|
||||
"frame-system/try-runtime",
|
||||
"frame-support/try-runtime",
|
||||
|
||||
"serai-abi/try-runtime",
|
||||
|
||||
"serai-core-pallet/try-runtime",
|
||||
"serai-validator-sets-pallet/try-runtime",
|
||||
]
|
||||
|
||||
default = ["std"]
|
||||
|
||||
@@ -12,17 +12,19 @@ pub mod pallet {
|
||||
|
||||
use serai_abi::{
|
||||
primitives::{prelude::*, signals::*},
|
||||
signals::Event,
|
||||
SubstrateBlock,
|
||||
};
|
||||
|
||||
use frame_system::pallet_prelude::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
use validator_sets_pallet::{Config as VsConfig, Pallet as VsPallet};
|
||||
use serai_validator_sets_pallet::{Config as VsConfig, Pallet as VsPallet};
|
||||
use serai_core_pallet::{Config as CoreConfig, Pallet as Core};
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config:
|
||||
frame_system::Config<AccountId = Public, Block = SubstrateBlock> + VsConfig
|
||||
frame_system::Config<AccountId = Public, Block = SubstrateBlock> + VsConfig + CoreConfig
|
||||
{
|
||||
/// How long a candidate retirement signal is valid for.
|
||||
///
|
||||
@@ -172,12 +174,12 @@ pub mod pallet {
|
||||
let prior_in_favor = NetworksInFavor::<T>::contains_key((signal, network));
|
||||
NetworksInFavor::<T>::set((signal, network), Some(()));
|
||||
if !prior_in_favor {
|
||||
todo!("Event");
|
||||
Core::<T>::emit_event(Event::NetworkInFavor { signal, network });
|
||||
}
|
||||
} else {
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
if NetworksInFavor::<T>::take((signal, network)).is_some() {
|
||||
todo!("Event");
|
||||
Core::<T>::emit_event(Event::NetworkNoLongerInFavor { signal, network });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +227,11 @@ pub mod pallet {
|
||||
Err::<(), _>(Error::<T>::RevokingNonExistentFavor)?;
|
||||
}
|
||||
Favors::<T>::remove((signal, for_network), validator);
|
||||
// TODO: Event
|
||||
Core::<T>::emit_event(Event::FavorRevoked {
|
||||
signal,
|
||||
by: validator.into(),
|
||||
with_network: for_network,
|
||||
});
|
||||
|
||||
// Update the tally for this network
|
||||
Self::tally_for_network(signal, for_network);
|
||||
@@ -278,9 +284,10 @@ pub mod pallet {
|
||||
This prevents a malicious actor from frontrunning a proposal, causing them to be the
|
||||
registrant, just to cancel it later.
|
||||
*/
|
||||
let registrant = SeraiAddress::from(validator);
|
||||
let signal = RegisteredRetirementSignal {
|
||||
in_favor_of,
|
||||
registrant: validator.into(),
|
||||
registrant,
|
||||
registered_at: frame_system::Pallet::<T>::block_number(),
|
||||
};
|
||||
let signal_id = signal.id();
|
||||
@@ -290,7 +297,12 @@ pub mod pallet {
|
||||
}
|
||||
RegisteredRetirementSignals::<T>::set(signal_id, Some(signal));
|
||||
|
||||
// TODO: Event
|
||||
Core::<T>::emit_event(Event::RetirementSignalRegistered {
|
||||
signal: signal_id,
|
||||
in_favor_of,
|
||||
registrant,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -322,7 +334,8 @@ pub mod pallet {
|
||||
LockedInRetirement::<T>::kill();
|
||||
}
|
||||
|
||||
// TODO: Event
|
||||
Core::<T>::emit_event(Event::RetirementSignalRevoked { signal: retirement_signal });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -366,7 +379,12 @@ pub mod pallet {
|
||||
|
||||
// Set the validator as in favor
|
||||
Favors::<T>::set((signal, for_network), validator, Some(()));
|
||||
// TODO: Event
|
||||
|
||||
Core::<T>::emit_event(Event::SignalFavored {
|
||||
signal,
|
||||
by: validator.into(),
|
||||
with_network: for_network,
|
||||
});
|
||||
|
||||
// Check if the network is in favor
|
||||
let network_in_favor = Self::tally_for_network(signal, for_network);
|
||||
@@ -380,11 +398,11 @@ pub mod pallet {
|
||||
signal_id,
|
||||
frame_system::Pallet::<T>::block_number() + T::RetirementLockInDuration::get(),
|
||||
)));
|
||||
// TODO: Event
|
||||
Core::<T>::emit_event(Event::RetirementSignalLockedIn { signal: signal_id });
|
||||
}
|
||||
Signal::Halt(network) => {
|
||||
Halted::<T>::set(network, Some(()));
|
||||
// TODO: Event
|
||||
Core::<T>::emit_event(Event::NetworkHalted { network });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -451,53 +469,15 @@ pub mod pallet {
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the event
|
||||
// TODO: Event
|
||||
Core::<T>::emit_event(Event::AgainstSignal {
|
||||
signal,
|
||||
account: validator.into(),
|
||||
with_network: for_network,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
RetirementSignalRegistered {
|
||||
signal: [u8; 32],
|
||||
in_favor_of: [u8; 32],
|
||||
registrant: T::AccountId,
|
||||
},
|
||||
RetirementSignalRevoked {
|
||||
signal_id: [u8; 32],
|
||||
},
|
||||
SignalFavored {
|
||||
signal_id: Signal,
|
||||
by: T::AccountId,
|
||||
for_network: NetworkId,
|
||||
},
|
||||
SetInFavor {
|
||||
signal_id: Signal,
|
||||
set: ValidatorSet,
|
||||
},
|
||||
RetirementSignalLockedIn {
|
||||
signal_id: [u8; 32],
|
||||
},
|
||||
SetNoLongerInFavor {
|
||||
signal_id: Signal,
|
||||
set: ValidatorSet,
|
||||
},
|
||||
FavorRevoked {
|
||||
signal_id: Signal,
|
||||
by: T::AccountId,
|
||||
for_network: NetworkId,
|
||||
},
|
||||
AgainstSignal {
|
||||
signal_id: Signal,
|
||||
who: T::AccountId,
|
||||
for_network: NetworkId,
|
||||
},
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
@@ -20,32 +20,27 @@ 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 = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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-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 }
|
||||
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", 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 }
|
||||
|
||||
serai-primitives = { path = "../primitives", default-features = false, features = ["non_canonical_scale_derivations"] }
|
||||
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 }
|
||||
|
||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
|
||||
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
#pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
|
||||
#sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "d4624c561765c13b38eb566e435131a8c329a543", default-features = false }
|
||||
|
||||
#ciphersuite = { path = "../../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||
#dalek-ff-group = { path = "../../../crypto/dalek-ff-group", default-features = false, features = ["std"] }
|
||||
#dkg-musig = { path = "../../../crypto/dkg/musig", default-features = false, features = ["std"] }
|
||||
#frost = { package = "modular-frost", path = "../../../crypto/frost", features = ["tests"] }
|
||||
#schnorrkel = { path = "../../../crypto/schnorrkel", package = "frost-schnorrkel" }
|
||||
|
||||
zeroize = "^1.5"
|
||||
|
||||
rand_core = "0.6"
|
||||
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||
|
||||
[features]
|
||||
@@ -55,28 +50,39 @@ std = [
|
||||
"scale/std",
|
||||
|
||||
"sp-core/std",
|
||||
"sp-application-crypto/std",
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"sp-api/std",
|
||||
|
||||
"frame-system/std",
|
||||
"frame-support/std",
|
||||
|
||||
"serai-primitives/std",
|
||||
"pallet-session/std",
|
||||
"pallet-babe/std",
|
||||
"pallet-grandpa/std",
|
||||
|
||||
"coins-pallet/std",
|
||||
"serai-abi/std",
|
||||
|
||||
"serai-coins-pallet/std",
|
||||
]
|
||||
|
||||
try-runtime = [
|
||||
"serai-abi/try-runtime",
|
||||
|
||||
"frame-system/try-runtime",
|
||||
"frame-support/try-runtime",
|
||||
|
||||
"sp-runtime/try-runtime",
|
||||
"pallet-session/try-runtime",
|
||||
"pallet-babe/try-runtime",
|
||||
"pallet-grandpa/try-runtime",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
|
||||
"pallet-babe/runtime-benchmarks",
|
||||
"pallet-grandpa/runtime-benchmarks",
|
||||
]
|
||||
|
||||
default = ["std"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use sp_core::{Encode, sr25519::Public};
|
||||
|
||||
use serai_primitives::{network_id::NetworkId, balance::Amount, validator_sets::KeyShares};
|
||||
use serai_abi::primitives::{network_id::NetworkId, balance::Amount, validator_sets::KeyShares};
|
||||
|
||||
use frame_support::storage::{StorageMap, StoragePrefixedMap};
|
||||
|
||||
@@ -14,11 +14,16 @@ pub(crate) type SortedAllocationsKey = (NetworkId, [u8; 8], [u8; 16], Public);
|
||||
/// This storage is expected to be owned by the `Allocations` interface and not directly read/write
|
||||
/// to.
|
||||
pub(crate) trait AllocationsStorage {
|
||||
/// An opaque map storing allocations.
|
||||
/// An map storing allocations.
|
||||
///
|
||||
/// This is opaque and to be exclusively read/write by `Allocations`.
|
||||
type Allocations: StorageMap<AllocationsKey, Amount, Query = Option<Amount>>;
|
||||
/// An opaque map storing allocations in a sorted manner.
|
||||
|
||||
/// An map storing allocations in a sorted manner.
|
||||
///
|
||||
/// This MUST be instantiated with a map using `Identity` for its hasher.
|
||||
///
|
||||
/// This is opaque and to be exclusively read/write by `Allocations`.
|
||||
/*
|
||||
This is premised on the underlying trie iterating from keys with low-bytes to keys with
|
||||
high-bytes.
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
use sp_core::sr25519::Public;
|
||||
|
||||
use serai_primitives::{crypto::SignedEmbeddedEllipticCurveKeys, network_id::*};
|
||||
use serai_abi::primitives::{crypto::SignedEmbeddedEllipticCurveKeys, network_id::*};
|
||||
|
||||
use frame_support::storage::StorageDoubleMap;
|
||||
|
||||
pub(crate) trait EmbeddedEllipticCurveKeysStorage {
|
||||
/// An opaque map storing keys on an embedded elliptic curve.
|
||||
/// An map storing keys on an embedded elliptic curve.
|
||||
///
|
||||
/// This is opaque and to be exclusively read/write by `EmbeddedEllipticCurveKeys`.
|
||||
type EmbeddedEllipticCurveKeys: StorageDoubleMap<
|
||||
ExternalNetworkId,
|
||||
Public,
|
||||
serai_primitives::crypto::EmbeddedEllipticCurveKeys,
|
||||
Query = Option<serai_primitives::crypto::EmbeddedEllipticCurveKeys>,
|
||||
serai_abi::primitives::crypto::EmbeddedEllipticCurveKeys,
|
||||
Query = Option<serai_abi::primitives::crypto::EmbeddedEllipticCurveKeys>,
|
||||
>;
|
||||
}
|
||||
|
||||
|
||||
49
substrate/validator-sets/src/keys.rs
Normal file
49
substrate/validator-sets/src/keys.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use sp_core::sr25519::Public;
|
||||
|
||||
use serai_abi::primitives::{
|
||||
crypto::{ExternalKey, KeyPair},
|
||||
validator_sets::ExternalValidatorSet,
|
||||
};
|
||||
|
||||
use frame_support::storage::StorageMap;
|
||||
|
||||
pub(crate) trait KeysStorage {
|
||||
/// An map storing keys validator sets use for oraclization.
|
||||
///
|
||||
/// This is opaque and to be exclusively read/write by `Keys`.
|
||||
type OraclizationKeys: StorageMap<ExternalValidatorSet, Public, Query = Option<Public>>;
|
||||
|
||||
/// An map storing keys validator sets use for interacting with external networks.
|
||||
///
|
||||
/// This is opaque and to be exclusively read/write by `Keys`.
|
||||
type ExternalKeys: StorageMap<ExternalValidatorSet, ExternalKey, Query = Option<ExternalKey>>;
|
||||
}
|
||||
|
||||
/// An interface for managing validators' embedded elliptic curve keys.
|
||||
pub(crate) trait Keys {
|
||||
/// If a validator set has yet to set keys.
|
||||
#[must_use]
|
||||
fn needs_to_set_keys(set: ExternalValidatorSet) -> bool;
|
||||
|
||||
/// Set the pair of keys for an external network.
|
||||
fn set_keys(set: ExternalValidatorSet, key_pair: KeyPair);
|
||||
|
||||
/// Clear a historic set of keys.
|
||||
fn clear_keys(set: ExternalValidatorSet);
|
||||
}
|
||||
|
||||
impl<S: KeysStorage> Keys for S {
|
||||
fn needs_to_set_keys(set: ExternalValidatorSet) -> bool {
|
||||
S::OraclizationKeys::contains_key(set)
|
||||
}
|
||||
|
||||
fn set_keys(set: ExternalValidatorSet, key_pair: KeyPair) {
|
||||
S::OraclizationKeys::insert(set, Public::from(key_pair.0 .0));
|
||||
S::ExternalKeys::insert(set, key_pair.1);
|
||||
}
|
||||
|
||||
fn clear_keys(set: ExternalValidatorSet) {
|
||||
S::OraclizationKeys::remove(set);
|
||||
S::ExternalKeys::remove(set);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,11 +18,11 @@ use sp_runtime::{
|
||||
BuildStorage,
|
||||
};
|
||||
|
||||
use serai_primitives::*;
|
||||
use serai_abi::primitives::*;
|
||||
use validator_sets::{primitives::MAX_KEY_SHARES_PER_SET_U32, MembershipProof};
|
||||
|
||||
pub use crate as validator_sets;
|
||||
pub use coins_pallet as coins;
|
||||
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;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use alloc::vec::Vec;
|
||||
use sp_core::{Encode, Decode, ConstU32, sr25519::Public, bounded::BoundedVec};
|
||||
|
||||
use serai_primitives::{
|
||||
use serai_abi::primitives::{
|
||||
network_id::NetworkId,
|
||||
balance::Amount,
|
||||
validator_sets::{KeyShares as KeySharesStruct, Session, ValidatorSet},
|
||||
validator_sets::{KeyShares as KeySharesStruct, Session, ExternalValidatorSet, ValidatorSet},
|
||||
};
|
||||
|
||||
use frame_support::storage::{StorageValue, StorageMap, StorageDoubleMap, StoragePrefixedMap};
|
||||
|
||||
use crate::{embedded_elliptic_curve_keys::EmbeddedEllipticCurveKeys, allocations::Allocations};
|
||||
use crate::{
|
||||
embedded_elliptic_curve_keys::EmbeddedEllipticCurveKeys, allocations::Allocations, keys::Keys,
|
||||
};
|
||||
|
||||
/// The list of genesis validators.
|
||||
pub(crate) type GenesisValidators =
|
||||
@@ -18,7 +20,7 @@ pub(crate) type GenesisValidators =
|
||||
/// The key for the SelectedValidators map.
|
||||
pub(crate) type SelectedValidatorsKey = (ValidatorSet, [u8; 16], Public);
|
||||
|
||||
pub(crate) trait SessionsStorage: EmbeddedEllipticCurveKeys + Allocations {
|
||||
pub(crate) trait SessionsStorage: EmbeddedEllipticCurveKeys + Allocations + Keys {
|
||||
/// The genesis validators
|
||||
///
|
||||
/// The usage of is shared with the rest of the pallet. `Sessions` only reads it.
|
||||
@@ -148,7 +150,9 @@ pub(crate) trait Sessions {
|
||||
///
|
||||
/// Doesn't spawn the next session if the latest decided session has yet to start. This bounds
|
||||
/// the current session to be the latest decided session or the one prior.
|
||||
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool);
|
||||
///
|
||||
/// Returns `true` if the next session was decided. Returns `false` otherwise.
|
||||
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool) -> bool;
|
||||
|
||||
/// Have the latest-decided session accept the handover from the current set, if one exists.
|
||||
///
|
||||
@@ -215,10 +219,23 @@ pub(crate) trait Sessions {
|
||||
|
||||
/// The stake for the current validator set.
|
||||
fn stake_for_current_validator_set(network: NetworkId) -> Option<Amount>;
|
||||
|
||||
/// The selected validators for a set.
|
||||
///
|
||||
/// This will return an empty iterator if the validators have yet to be decided, or if the
|
||||
/// selected validators were cleared due to being historic.
|
||||
fn selected_validators(set: ValidatorSet) -> impl Iterator<Item = (Public, KeySharesStruct)>;
|
||||
|
||||
/// The validators for the Serai network, in the form expected by BABE, GRANDPA.
|
||||
fn serai_validators(session: Session) -> Vec<(Public, Public)> {
|
||||
Self::selected_validators(ValidatorSet { network: NetworkId::Serai, session })
|
||||
.map(|(validator, _key_shares)| (validator, validator))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool) {
|
||||
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool) -> bool {
|
||||
// If we haven't rotated to the latest decided session, return
|
||||
// This prevents us from deciding session #n+2 when we haven't even started #n+1
|
||||
let current_session = Storage::CurrentSession::get(network);
|
||||
@@ -228,12 +245,12 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
// If the latest decided session is current, we can decide the next session
|
||||
} else {
|
||||
// If we already have a pending session, don't spawn a new one
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
(Some(current), None) => unreachable!("current session but never decided a session"),
|
||||
(Some(_current), None) => unreachable!("current session but never decided a session"),
|
||||
// If we decided our first session, but didn't start it, don't decide another session
|
||||
(None, Some(latest)) => return,
|
||||
(None, Some(_latest)) => return false,
|
||||
(None, None) => {
|
||||
// If we've never started a session, we can decide the first session
|
||||
}
|
||||
@@ -273,6 +290,11 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
selected_validators.append(&mut genesis_validators);
|
||||
}
|
||||
|
||||
// If we failed to select any validators, return `false` now
|
||||
if total_key_shares == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let latest_decided_session = Storage::LatestDecidedSession::mutate(network, |session| {
|
||||
let next_session = session.map(|session| Session(session.0 + 1)).unwrap_or(Session(0));
|
||||
*session = Some(next_session);
|
||||
@@ -290,6 +312,8 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
key_shares,
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn accept_handover(network: NetworkId) {
|
||||
@@ -324,6 +348,12 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
let historic_set = ValidatorSet { network, session: historic_session };
|
||||
Storage::KeyShares::remove(historic_set);
|
||||
clear_selected_validators::<Storage::SelectedValidators>(historic_set);
|
||||
match historic_set.network {
|
||||
NetworkId::Serai => {}
|
||||
NetworkId::External(network) => {
|
||||
Storage::clear_keys(ExternalValidatorSet { network, session: historic_session })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,37 +379,45 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
Err(AllocationError::AllocationLessThanKeyShare)?
|
||||
}
|
||||
|
||||
/*
|
||||
If the validator set has a single point of failure, the following does nothing. If the
|
||||
validator set has decentralized and doesn't have a single point of failure, the following
|
||||
will ensure this allocation doesn't create a single point of failure.
|
||||
*/
|
||||
{
|
||||
// Check the validator set's current expected key shares
|
||||
let expected_key_shares = Self::expected_key_shares(network, allocation_per_key_share);
|
||||
// Check if the top validator in this set may be faulty without causing a halt under this f
|
||||
let currently_tolerates_single_point_of_failure = if let Some(top_validator) =
|
||||
Self::iter_allocations(network, allocation_per_key_share).next()
|
||||
let new_key_shares =
|
||||
KeySharesStruct::from_allocation(new_allocation, allocation_per_key_share);
|
||||
|
||||
// If this would guarantee this validator will be a single point of failure, error
|
||||
if ((3 * new_key_shares.0) + 1) > KeySharesStruct::MAX_PER_SET {
|
||||
Err(AllocationError::IntroducesSinglePointOfFailure)?;
|
||||
}
|
||||
|
||||
/*
|
||||
If the validator set has a single point of failure, the following does nothing. If the
|
||||
validator set has decentralized and doesn't have a single point of failure, the following
|
||||
will ensure this allocation doesn't create a single point of failure.
|
||||
*/
|
||||
{
|
||||
let (_key, amount) = top_validator;
|
||||
let key_shares = KeySharesStruct::from_allocation(amount, allocation_per_key_share);
|
||||
key_shares.0 <= (expected_key_shares.0 / 3)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// If the set currently tolerates the fault of the top validator, don't let that change
|
||||
if currently_tolerates_single_point_of_failure {
|
||||
let old_key_shares =
|
||||
KeySharesStruct::from_allocation(old_allocation, allocation_per_key_share);
|
||||
let new_key_shares =
|
||||
KeySharesStruct::from_allocation(new_allocation, allocation_per_key_share);
|
||||
// Update the amount of expected key shares per the key shares added
|
||||
let expected_key_shares = KeySharesStruct::saturating_from(
|
||||
expected_key_shares.0 + (new_key_shares.0 - old_key_shares.0),
|
||||
);
|
||||
// If the new key shares exceeds the fault tolerance, don't allow the allocation
|
||||
if new_key_shares.0 > (expected_key_shares.0 / 3) {
|
||||
Err(AllocationError::IntroducesSinglePointOfFailure)?
|
||||
// Check the validator set's current expected key shares
|
||||
let expected_key_shares = Self::expected_key_shares(network, allocation_per_key_share);
|
||||
// Check if the top validator in this set may be faulty without causing a halt under this f
|
||||
let currently_tolerates_single_point_of_failure = if let Some(top_validator) =
|
||||
Self::iter_allocations(network, allocation_per_key_share).next()
|
||||
{
|
||||
let (_key, amount) = top_validator;
|
||||
let key_shares = KeySharesStruct::from_allocation(amount, allocation_per_key_share);
|
||||
key_shares.0 <= (expected_key_shares.0 / 3)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// If the set currently tolerates the fault of the top validator, don't let that change
|
||||
if currently_tolerates_single_point_of_failure {
|
||||
let old_key_shares =
|
||||
KeySharesStruct::from_allocation(old_allocation, allocation_per_key_share);
|
||||
// Update the amount of expected key shares per the key shares added
|
||||
let expected_key_shares = KeySharesStruct::saturating_from(
|
||||
expected_key_shares.0 + (new_key_shares.0 - old_key_shares.0),
|
||||
);
|
||||
// If the new key shares exceeds the fault tolerance, don't allow the allocation
|
||||
if new_key_shares.0 > (expected_key_shares.0 / 3) {
|
||||
Err(AllocationError::IntroducesSinglePointOfFailure)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -524,4 +562,8 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
||||
fn stake_for_current_validator_set(network: NetworkId) -> Option<Amount> {
|
||||
Storage::TotalAllocatedStake::get(network)
|
||||
}
|
||||
|
||||
fn selected_validators(set: ValidatorSet) -> impl Iterator<Item = (Public, KeySharesStruct)> {
|
||||
selected_validators::<Storage::SelectedValidators>(set)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ use sp_core::{
|
||||
};
|
||||
use sp_runtime::traits::ValidateUnsigned;
|
||||
|
||||
use serai_primitives::*;
|
||||
use serai_abi::primitives::*;
|
||||
|
||||
fn active_network_validators(network: NetworkId) -> Vec<(Public, u64)> {
|
||||
if network == NetworkId::Serai {
|
||||
|
||||
Reference in New Issue
Block a user