Skip to content

Commit

Permalink
move economic security into it's own pallet
Browse files Browse the repository at this point in the history
  • Loading branch information
akildemir authored and akildemir committed Aug 15, 2024
1 parent 3563c67 commit 49ea38b
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 49 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

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

8 changes: 8 additions & 0 deletions substrate/abi/src/economic_security.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use serai_primitives::NetworkId;

#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Event {
EconomicSecurityBlock { network: NetworkId, block: u64 },
}
3 changes: 3 additions & 0 deletions substrate/abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub mod validator_sets;
pub mod genesis_liquidity;
pub mod emissions;

pub mod economic_security;

pub mod in_instructions;

pub mod signals;
Expand Down Expand Up @@ -60,6 +62,7 @@ pub enum Event {
ValidatorSets(validator_sets::Event),
GenesisLiquidity(genesis_liquidity::Event),
Emissions,
EconomicSecurity(economic_security::Event),
InInstructions(in_instructions::Event),
Signals(signals::Event),
Babe,
Expand Down
48 changes: 48 additions & 0 deletions substrate/economic-security/pallet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[package]
name = "serai-economic-security-pallet"
version = "0.1.0"
description = "Economic Security pallet for Serai"
license = "AGPL-3.0-only"
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/economic-security/pallet"
authors = ["Akil Demir <[email protected]>"]
edition = "2021"
rust-version = "1.77"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[package.metadata.cargo-machete]
ignored = ["scale", "scale-info"]

[lints]
workspace = true

[dependencies]
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }

frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false }
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }

dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }

serai-primitives = { path = "../../primitives", default-features = false }

[features]
std = [
"scale/std",
"scale-info/std",

"frame-system/std",
"frame-support/std",

"dex-pallet/std",
"coins-pallet/std",

"serai-primitives/std",
]
try-runtime = [] # TODO

default = ["std"]
15 changes: 15 additions & 0 deletions substrate/economic-security/pallet/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
AGPL-3.0-only license

Copyright (c) 2024 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/>.
56 changes: 56 additions & 0 deletions substrate/economic-security/pallet/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#![cfg_attr(not(feature = "std"), no_std)]

#[allow(clippy::cast_possible_truncation, clippy::no_effect_underscore_binding, clippy::empty_docs)]
#[frame_support::pallet]
pub mod pallet {
use frame_system::pallet_prelude::*;
use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion};

use dex_pallet::{Config as DexConfig, Pallet as Dex};
use coins_pallet::{Config as CoinsConfig, AllowMint};

use serai_primitives::*;

#[pallet::config]
pub trait Config: frame_system::Config + CoinsConfig + DexConfig {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}

#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config> {
EconomicSecurityBlock { network: NetworkId, block: u64 },
}

#[pallet::pallet]
pub struct Pallet<T>(PhantomData<T>);

#[pallet::storage]
#[pallet::getter(fn economic_security_block)]
pub(crate) type EconomicSecurityBlock<T: Config> =
StorageMap<_, Identity, NetworkId, BlockNumberFor<T>, OptionQuery>;

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_initialize(n: BlockNumberFor<T>) -> Weight {
// we accept we reached economic security once we can mint smallest amount of a network's coin
for coin in COINS {
let existing = EconomicSecurityBlock::<T>::get(coin.network());
if existing.is_none() &&
Dex::<T>::security_oracle_value(coin).is_some() &&
<T as CoinsConfig>::AllowMint::is_allowed(&Balance { coin, amount: Amount(1) })
{
EconomicSecurityBlock::<T>::set(coin.network(), Some(n));
Self::deposit_event(Event::EconomicSecurityBlock {
network: coin.network(),
block: n.saturated_into::<u64>(),
});
}
}

Weight::zero() // TODO
}
}
}

pub use pallet::*;
4 changes: 4 additions & 0 deletions substrate/emissions/pallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../..
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path = "../../genesis-liquidity/pallet", default-features = false }

economic-security-pallet = { package = "serai-economic-security-pallet", path = "../../economic-security/pallet", default-features = false }

serai-primitives = { path = "../../primitives", default-features = false }
validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../validator-sets/primitives", default-features = false }
emissions-primitives = { package = "serai-emissions-primitives", path = "../primitives", default-features = false }
Expand All @@ -52,6 +54,8 @@ std = [
"validator-sets-pallet/std",
"dex-pallet/std",
"genesis-liquidity-pallet/std",

"economic-security-pallet/std",

"serai-primitives/std",
"emissions-primitives/std",
Expand Down
37 changes: 7 additions & 30 deletions substrate/emissions/pallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ pub mod pallet {
use sp_std::{vec, vec::Vec, ops::Mul, collections::btree_map::BTreeMap};
use sp_runtime;

use coins_pallet::{Config as CoinsConfig, Pallet as Coins, AllowMint};
use coins_pallet::{Config as CoinsConfig, Pallet as Coins};
use dex_pallet::{Config as DexConfig, Pallet as Dex};

use validator_sets_pallet::{Pallet as ValidatorSets, Config as ValidatorSetsConfig};
use genesis_liquidity_pallet::{Pallet as GenesisLiquidity, Config as GenesisLiquidityConfig};

use economic_security_pallet::{Config as EconomicSecurityConfig, Pallet as EconomicSecurity};

use serai_primitives::*;
use validator_sets_primitives::{MAX_KEY_SHARES_PER_SET, Session};
pub use emissions_primitives as primitives;
Expand All @@ -28,6 +30,7 @@ pub mod pallet {
+ CoinsConfig
+ DexConfig
+ GenesisLiquidityConfig
+ EconomicSecurityConfig
{
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
Expand Down Expand Up @@ -76,12 +79,6 @@ pub mod pallet {
#[pallet::getter(fn session)]
pub type CurrentSession<T: Config> = StorageMap<_, Identity, NetworkId, u32, ValueQuery>;

// TODO: Find a better place for this
#[pallet::storage]
#[pallet::getter(fn economic_security_reached)]
pub(crate) type EconomicSecurityReached<T: Config> =
StorageMap<_, Identity, NetworkId, bool, ValueQuery>;

// TODO: Find a better place for this
#[pallet::storage]
pub(crate) type GenesisCompleteBlock<T: Config> = StorageValue<_, u64, OptionQuery>;
Expand All @@ -99,7 +96,6 @@ pub mod pallet {
}
Participants::<T>::set(id, Some(participants.try_into().unwrap()));
CurrentSession::<T>::set(id, 0);
EconomicSecurityReached::<T>::set(id, false);
}
}
}
Expand All @@ -112,26 +108,7 @@ pub mod pallet {
{
GenesisCompleteBlock::<T>::set(Some(n.saturated_into::<u64>()));
}

// we wait 1 extra block after genesis ended to see the changes. We only need this extra
// block in dev&test networks where we start the chain with accounts that already has some
// staked SRI. So when we check for ec-security pre-genesis we look like we are economically
// secure. The reason for this although we only check for it once the genesis is complete(so
// if the genesis complete we shouldn't be economically secure because the funds are not
// enough) is because ValidatorSets pallet runs before the genesis pallet in runtime.
// So ValidatorSets pallet sees the old state until next block.
// TODO: revisit this when mainnet genesis validator stake code is done.
let gcb = GenesisCompleteBlock::<T>::get();
let genesis_ended = gcb.is_some() && (n.saturated_into::<u64>() > gcb.unwrap());

// we accept we reached economic security once we can mint smallest amount of a network's coin
for coin in COINS {
let check = genesis_ended && !Self::economic_security_reached(coin.network());
if check && <T as CoinsConfig>::AllowMint::is_allowed(&Balance { coin, amount: Amount(1) })
{
EconomicSecurityReached::<T>::set(coin.network(), true);
}
}
let genesis_ended = GenesisLiquidity::<T>::genesis_complete().is_some();

// check if we got a new session
let mut session_changed = false;
Expand Down Expand Up @@ -351,7 +328,7 @@ pub mod pallet {
continue;
}

if !Self::economic_security_reached(n) {
if EconomicSecurity::<T>::economic_security_block(n).is_none() {
return true;
}
}
Expand Down Expand Up @@ -393,7 +370,7 @@ pub mod pallet {
balance: Balance,
) -> DispatchResult {
// check the network didn't reach the economic security yet
if Self::economic_security_reached(network) {
if EconomicSecurity::<T>::economic_security_block(network).is_some() {
Err(Error::<T>::NetworkHasEconomicSecurity)?;
}

Expand Down
4 changes: 4 additions & 0 deletions substrate/genesis-liquidity/pallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../../validator-sets/pallet", default-features = false }

economic-security-pallet = { package = "serai-economic-security-pallet", path = "../../economic-security/pallet", default-features = false }

serai-primitives = { path = "../../primitives", default-features = false }
genesis-liquidity-primitives = { package = "serai-genesis-liquidity-primitives", path = "../primitives", default-features = false }
validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../validator-sets/primitives", default-features = false }
Expand All @@ -53,6 +55,8 @@ std = [
"dex-pallet/std",
"validator-sets-pallet/std",

"economic-security-pallet/std",

"serai-primitives/std",
"genesis-liquidity-primitives/std",
"validator-sets-primitives/std",
Expand Down
25 changes: 6 additions & 19 deletions substrate/genesis-liquidity/pallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ pub mod pallet {
use sp_application_crypto::RuntimePublic;

use dex_pallet::{Pallet as Dex, Config as DexConfig};
use coins_pallet::{Config as CoinsConfig, Pallet as Coins, AllowMint};
use coins_pallet::{Config as CoinsConfig, Pallet as Coins};
use validator_sets_pallet::{Config as VsConfig, Pallet as ValidatorSets};

use economic_security_pallet::{Config as EconomicSecurityConfig, Pallet as EconomicSecurity};

use serai_primitives::*;
use validator_sets_primitives::{ValidatorSet, musig_key};
pub use genesis_liquidity_primitives as primitives;
Expand All @@ -29,6 +31,7 @@ pub mod pallet {
frame_system::Config
+ VsConfig
+ DexConfig
+ EconomicSecurityConfig
+ CoinsConfig
+ coins_pallet::Config<coins_pallet::Instance1>
{
Expand All @@ -49,7 +52,6 @@ pub mod pallet {
GenesisLiquidityAdded { by: SeraiAddress, balance: Balance },
GenesisLiquidityRemoved { by: SeraiAddress, balance: Balance },
GenesisLiquidityAddedToPool { coin1: Balance, sri: Amount },
EconomicSecurityReached { network: NetworkId },
}

#[pallet::pallet]
Expand All @@ -64,10 +66,6 @@ pub mod pallet {
#[pallet::storage]
pub(crate) type Supply<T: Config> = StorageMap<_, Identity, Coin, LiquidityAmount, OptionQuery>;

#[pallet::storage]
pub(crate) type EconomicSecurityReached<T: Config> =
StorageMap<_, Identity, NetworkId, BlockNumberFor<T>, OptionQuery>;

#[pallet::storage]
pub(crate) type Oracle<T: Config> = StorageMap<_, Identity, Coin, u64, OptionQuery>;

Expand Down Expand Up @@ -170,18 +168,6 @@ pub mod pallet {
GenesisComplete::<T>::set(Some(()));
}

// we accept we reached economic security once we can mint smallest amount of a network's coin
// TODO: move EconomicSecurity to a separate pallet
for coin in COINS {
let existing = EconomicSecurityReached::<T>::get(coin.network());
if existing.is_none() &&
<T as CoinsConfig>::AllowMint::is_allowed(&Balance { coin, amount: Amount(1) })
{
EconomicSecurityReached::<T>::set(coin.network(), Some(n));
Self::deposit_event(Event::EconomicSecurityReached { network: coin.network() });
}
}

Weight::zero() // TODO
}
}
Expand Down Expand Up @@ -237,7 +223,8 @@ pub mod pallet {
fn blocks_since_ec_security() -> Option<u64> {
let mut min = u64::MAX;
for n in NETWORKS {
let ec_security_block = EconomicSecurityReached::<T>::get(n)?.saturated_into::<u64>();
let ec_security_block =
EconomicSecurity::<T>::economic_security_block(n)?.saturated_into::<u64>();
let current = <frame_system::Pallet<T>>::block_number().saturated_into::<u64>();
let diff = current.saturating_sub(ec_security_block);
min = diff.min(min);
Expand Down
Loading

0 comments on commit 49ea38b

Please sign in to comment.