mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-14 15:09:23 +00:00
fix pr comments
This commit is contained in:
@@ -204,14 +204,12 @@ impl<D: Db> CosignEvaluator<D> {
|
|||||||
|
|
||||||
let mut total_stake = 0;
|
let mut total_stake = 0;
|
||||||
let mut total_on_distinct_chain = 0;
|
let mut total_on_distinct_chain = 0;
|
||||||
// TODO: `network` isn't being used in the following loop. is this a bug?
|
for network in EXTERNAL_NETWORKS {
|
||||||
// why are we going through the networks here?
|
|
||||||
for _network in EXTERNAL_NETWORKS {
|
|
||||||
// Get the current set for this network
|
// Get the current set for this network
|
||||||
let set_with_keys = {
|
let set_with_keys = {
|
||||||
let mut res;
|
let mut res;
|
||||||
while {
|
while {
|
||||||
res = set_with_keys_fn(&serai, cosign.network).await;
|
res = set_with_keys_fn(&serai, network).await;
|
||||||
res.is_err()
|
res.is_err()
|
||||||
} {
|
} {
|
||||||
log::error!(
|
log::error!(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
|
|||||||
use serai_client::{
|
use serai_client::{
|
||||||
coins::CoinsEvent,
|
coins::CoinsEvent,
|
||||||
in_instructions::InInstructionsEvent,
|
in_instructions::InInstructionsEvent,
|
||||||
primitives::{BlockHash, ExternalNetworkId, NetworkId},
|
primitives::{BlockHash, ExternalNetworkId},
|
||||||
validator_sets::{
|
validator_sets::{
|
||||||
primitives::{ExternalValidatorSet, ValidatorSet},
|
primitives::{ExternalValidatorSet, ValidatorSet},
|
||||||
ValidatorSetsEvent,
|
ValidatorSetsEvent,
|
||||||
@@ -229,13 +229,8 @@ async fn handle_block<D: Db, Pro: Processors>(
|
|||||||
panic!("NewSet event wasn't NewSet: {new_set:?}");
|
panic!("NewSet event wasn't NewSet: {new_set:?}");
|
||||||
};
|
};
|
||||||
|
|
||||||
// If this is Serai, do nothing
|
|
||||||
// We only coordinate/process external networks
|
// We only coordinate/process external networks
|
||||||
if set.network == NetworkId::Serai {
|
let Ok(set) = ExternalValidatorSet::try_from(set) else { continue };
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let set: ExternalValidatorSet = set.try_into().unwrap();
|
|
||||||
if HandledEvent::is_unhandled(db, hash, event_id) {
|
if HandledEvent::is_unhandled(db, hash, event_id) {
|
||||||
log::info!("found fresh new set event {:?}", new_set);
|
log::info!("found fresh new set event {:?}", new_set);
|
||||||
let mut txn = db.txn();
|
let mut txn = db.txn();
|
||||||
@@ -290,11 +285,7 @@ async fn handle_block<D: Db, Pro: Processors>(
|
|||||||
panic!("AcceptedHandover event wasn't AcceptedHandover: {accepted_handover:?}");
|
panic!("AcceptedHandover event wasn't AcceptedHandover: {accepted_handover:?}");
|
||||||
};
|
};
|
||||||
|
|
||||||
if set.network == NetworkId::Serai {
|
let Ok(set) = ExternalValidatorSet::try_from(set) else { continue };
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let set: ExternalValidatorSet = set.try_into().unwrap();
|
|
||||||
if HandledEvent::is_unhandled(db, hash, event_id) {
|
if HandledEvent::is_unhandled(db, hash, event_id) {
|
||||||
log::info!("found fresh accepted handover event {:?}", accepted_handover);
|
log::info!("found fresh accepted handover event {:?}", accepted_handover);
|
||||||
// TODO: This isn't atomic with the event handling
|
// TODO: This isn't atomic with the event handling
|
||||||
@@ -312,11 +303,7 @@ async fn handle_block<D: Db, Pro: Processors>(
|
|||||||
panic!("SetRetired event wasn't SetRetired: {retired_set:?}");
|
panic!("SetRetired event wasn't SetRetired: {retired_set:?}");
|
||||||
};
|
};
|
||||||
|
|
||||||
if set.network == NetworkId::Serai {
|
let Ok(set) = ExternalValidatorSet::try_from(set) else { continue };
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let set: ExternalValidatorSet = set.try_into().unwrap();
|
|
||||||
if HandledEvent::is_unhandled(db, hash, event_id) {
|
if HandledEvent::is_unhandled(db, hash, event_id) {
|
||||||
log::info!("found fresh set retired event {:?}", retired_set);
|
log::info!("found fresh set retired event {:?}", retired_set);
|
||||||
let mut txn = db.txn();
|
let mut txn = db.txn();
|
||||||
|
|||||||
@@ -161,11 +161,9 @@ pub mod pallet {
|
|||||||
pub fn mint(to: Public, balance: Balance) -> Result<(), Error<T, I>> {
|
pub fn mint(to: Public, balance: Balance) -> Result<(), Error<T, I>> {
|
||||||
// If the coin isn't Serai, which we're always allowed to mint, and the mint isn't explicitly
|
// If the coin isn't Serai, which we're always allowed to mint, and the mint isn't explicitly
|
||||||
// allowed, error
|
// allowed, error
|
||||||
if !balance.coin.is_native() &&
|
if !ExternalCoin::try_from(balance.coin)
|
||||||
(!T::AllowMint::is_allowed(&ExternalBalance {
|
.map(|coin| T::AllowMint::is_allowed(&ExternalBalance { coin, amount: balance.amount }))
|
||||||
coin: balance.coin.try_into().unwrap(),
|
.unwrap_or(true)
|
||||||
amount: balance.amount,
|
|
||||||
}))
|
|
||||||
{
|
{
|
||||||
Err(Error::<T, I>::MintNotAllowed)?;
|
Err(Error::<T, I>::MintNotAllowed)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -509,7 +509,7 @@ pub mod pallet {
|
|||||||
|
|
||||||
/// A hook to be called whenever a network's session is rotated.
|
/// A hook to be called whenever a network's session is rotated.
|
||||||
pub fn on_new_session(network: NetworkId) {
|
pub fn on_new_session(network: NetworkId) {
|
||||||
// reset the oracle value
|
// Only track the price for non-SRI coins as this is SRI denominated
|
||||||
if let NetworkId::External(n) = network {
|
if let NetworkId::External(n) = network {
|
||||||
for coin in n.coins() {
|
for coin in n.coins() {
|
||||||
SecurityOracleValue::<T>::set(coin, Self::median_price(coin));
|
SecurityOracleValue::<T>::set(coin, Self::median_price(coin));
|
||||||
@@ -936,11 +936,9 @@ pub mod pallet {
|
|||||||
pub fn get_pool_id(coin1: Coin, coin2: Coin) -> Result<PoolId, Error<T>> {
|
pub fn get_pool_id(coin1: Coin, coin2: Coin) -> Result<PoolId, Error<T>> {
|
||||||
ensure!((coin1 == Coin::Serai) || (coin2 == Coin::Serai), Error::<T>::PoolNotFound);
|
ensure!((coin1 == Coin::Serai) || (coin2 == Coin::Serai), Error::<T>::PoolNotFound);
|
||||||
ensure!(coin1 != coin2, Error::<T>::EqualCoins);
|
ensure!(coin1 != coin2, Error::<T>::EqualCoins);
|
||||||
if coin1 == Coin::Serai {
|
ExternalCoin::try_from(coin1)
|
||||||
Ok(coin2.try_into().unwrap())
|
.or_else(|()| ExternalCoin::try_from(coin2))
|
||||||
} else {
|
.map_err(|()| Error::<T>::PoolNotFound)
|
||||||
Ok(coin1.try_into().unwrap())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the balance of each coin in the pool.
|
/// Returns the balance of each coin in the pool.
|
||||||
|
|||||||
@@ -244,12 +244,13 @@ pub mod pallet {
|
|||||||
|
|
||||||
// distribute the rewards within the network
|
// distribute the rewards within the network
|
||||||
for (n, reward) in rewards_per_network {
|
for (n, reward) in rewards_per_network {
|
||||||
let (validators_reward, network_pool_reward) = if n == NetworkId::Serai {
|
let validators_reward = if let NetworkId::External(external_network) = n {
|
||||||
(reward, 0)
|
|
||||||
} else {
|
|
||||||
// calculate pool vs validator share
|
// calculate pool vs validator share
|
||||||
let capacity = ValidatorSets::<T>::total_allocated_stake(n).unwrap_or(Amount(0)).0;
|
let capacity =
|
||||||
let required = ValidatorSets::<T>::required_stake_for_network(n.try_into().unwrap());
|
ValidatorSets::<T>::total_allocated_stake(NetworkId::from(external_network))
|
||||||
|
.unwrap_or(Amount(0))
|
||||||
|
.0;
|
||||||
|
let required = ValidatorSets::<T>::required_stake_for_network(external_network);
|
||||||
let unused_capacity = capacity.saturating_sub(required);
|
let unused_capacity = capacity.saturating_sub(required);
|
||||||
|
|
||||||
let distribution = unused_capacity.saturating_mul(ACCURACY_MULTIPLIER) / capacity;
|
let distribution = unused_capacity.saturating_mul(ACCURACY_MULTIPLIER) / capacity;
|
||||||
@@ -257,42 +258,44 @@ pub mod pallet {
|
|||||||
|
|
||||||
let validators_reward = DESIRED_DISTRIBUTION.saturating_mul(reward) / total;
|
let validators_reward = DESIRED_DISTRIBUTION.saturating_mul(reward) / total;
|
||||||
let network_pool_reward = reward.saturating_sub(validators_reward);
|
let network_pool_reward = reward.saturating_sub(validators_reward);
|
||||||
(validators_reward, network_pool_reward)
|
|
||||||
|
// send the rest to the pool
|
||||||
|
if network_pool_reward != 0 {
|
||||||
|
// these should be available to unwrap if we have a network_pool_reward. Because that
|
||||||
|
// means we had an unused capacity hence in a post-ec era.
|
||||||
|
let vpn = volume_per_network.as_ref().unwrap();
|
||||||
|
let vpc = volume_per_coin.as_ref().unwrap();
|
||||||
|
for c in external_network.coins() {
|
||||||
|
let pool_reward = u64::try_from(
|
||||||
|
u128::from(network_pool_reward).saturating_mul(u128::from(vpc[&c])) /
|
||||||
|
u128::from(vpn[&n]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if Coins::<T>::mint(
|
||||||
|
Dex::<T>::get_pool_account(c),
|
||||||
|
Balance { coin: Coin::Serai, amount: Amount(pool_reward) },
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
// TODO: log the failure
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validators_reward
|
||||||
|
} else {
|
||||||
|
reward
|
||||||
};
|
};
|
||||||
|
|
||||||
// distribute validators rewards
|
// distribute validators rewards
|
||||||
Self::distribute_to_validators(n, validators_reward);
|
Self::distribute_to_validators(n, validators_reward);
|
||||||
|
|
||||||
// send the rest to the pool
|
|
||||||
if network_pool_reward != 0 {
|
|
||||||
// these should be available to unwrap if we have a network_pool_reward. Because that
|
|
||||||
// means we had an unused capacity hence in a post-ec era.
|
|
||||||
let vpn = volume_per_network.as_ref().unwrap();
|
|
||||||
let vpc = volume_per_coin.as_ref().unwrap();
|
|
||||||
for c in n.coins() {
|
|
||||||
let pool_reward = u64::try_from(
|
|
||||||
u128::from(network_pool_reward)
|
|
||||||
.saturating_mul(u128::from(vpc[&c.try_into().unwrap()])) /
|
|
||||||
u128::from(vpn[&n]),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if Coins::<T>::mint(
|
|
||||||
Dex::<T>::get_pool_account(c.try_into().unwrap()),
|
|
||||||
Balance { coin: Coin::Serai, amount: Amount(pool_reward) },
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
// TODO: log the failure
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we have the past session participants here in the emissions pallet so that we can
|
// TODO: we have the past session participants here in the emissions pallet so that we can
|
||||||
// distribute rewards to them in the next session. Ideally we should be able to fetch this
|
// distribute rewards to them in the next session. Ideally we should be able to fetch this
|
||||||
// information from valiadtor sets pallet.
|
// information from validator sets pallet.
|
||||||
Self::update_participants();
|
Self::update_participants();
|
||||||
Weight::zero() // TODO
|
Weight::zero() // TODO
|
||||||
}
|
}
|
||||||
@@ -365,6 +368,18 @@ pub mod pallet {
|
|||||||
if EconomicSecurity::<T>::economic_security_block(n).is_some() {
|
if EconomicSecurity::<T>::economic_security_block(n).is_some() {
|
||||||
Err(Error::<T>::NetworkHasEconomicSecurity)?;
|
Err(Error::<T>::NetworkHasEconomicSecurity)?;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// we target 20% of the network's stake to be behind the Serai network
|
||||||
|
let mut total_stake = 0;
|
||||||
|
for n in NETWORKS {
|
||||||
|
total_stake += ValidatorSets::<T>::total_allocated_stake(n).unwrap_or(Amount(0)).0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stake = ValidatorSets::<T>::total_allocated_stake(network).unwrap_or(Amount(0)).0;
|
||||||
|
let desired_stake = total_stake / (100 / SERAI_VALIDATORS_DESIRED_PERCENTAGE);
|
||||||
|
if stake >= desired_stake {
|
||||||
|
Err(Error::<T>::NetworkHasEconomicSecurity)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swap half of the liquidity for SRI to form PoL.
|
// swap half of the liquidity for SRI to form PoL.
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use serai_primitives::ExternalBalance;
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
@@ -21,7 +20,7 @@ use sp_std::vec::Vec;
|
|||||||
use sp_runtime::RuntimeDebug;
|
use sp_runtime::RuntimeDebug;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
use serai_primitives::{BlockHash, Balance, ExternalNetworkId, NetworkId, SeraiAddress, ExternalAddress, system_address};
|
use serai_primitives::{BlockHash, Balance, ExternalNetworkId, NetworkId, SeraiAddress, ExternalBalance, ExternalAddress, system_address};
|
||||||
|
|
||||||
mod shorthand;
|
mod shorthand;
|
||||||
pub use shorthand::*;
|
pub use shorthand::*;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use scale::{Encode, Decode, MaxEncodedLen};
|
use scale::{Decode, Encode, EncodeLike, MaxEncodedLen};
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
|
|
||||||
#[cfg(feature = "borsh")]
|
#[cfg(feature = "borsh")]
|
||||||
@@ -16,11 +16,8 @@ use sp_std::{vec, vec::Vec};
|
|||||||
use crate::{borsh_serialize_bounded_vec, borsh_deserialize_bounded_vec};
|
use crate::{borsh_serialize_bounded_vec, borsh_deserialize_bounded_vec};
|
||||||
|
|
||||||
/// The type used to identify external networks.
|
/// The type used to identify external networks.
|
||||||
#[derive(
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, TypeInfo)]
|
||||||
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, PartialOrd, Ord, MaxEncodedLen, TypeInfo,
|
|
||||||
)]
|
|
||||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum ExternalNetworkId {
|
pub enum ExternalNetworkId {
|
||||||
Bitcoin,
|
Bitcoin,
|
||||||
@@ -28,18 +25,105 @@ pub enum ExternalNetworkId {
|
|||||||
Monero,
|
Monero,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Encode for ExternalNetworkId {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
ExternalNetworkId::Bitcoin => vec![1],
|
||||||
|
ExternalNetworkId::Ethereum => vec![2],
|
||||||
|
ExternalNetworkId::Monero => vec![3],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decode for ExternalNetworkId {
|
||||||
|
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||||
|
let kind = input.read_byte()?;
|
||||||
|
match kind {
|
||||||
|
1 => Ok(Self::Bitcoin),
|
||||||
|
2 => Ok(Self::Ethereum),
|
||||||
|
3 => Ok(Self::Monero),
|
||||||
|
_ => Err(scale::Error::from("invalid format")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaxEncodedLen for ExternalNetworkId {
|
||||||
|
fn max_encoded_len() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeLike for ExternalNetworkId {}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshSerialize for ExternalNetworkId {
|
||||||
|
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_all(&self.encode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshDeserialize for ExternalNetworkId {
|
||||||
|
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||||
|
let mut kind = [0; 1];
|
||||||
|
reader.read_exact(&mut kind)?;
|
||||||
|
ExternalNetworkId::decode(&mut kind.as_slice())
|
||||||
|
.map_err(|_| std::io::Error::other("invalid format"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The type used to identify networks.
|
/// The type used to identify networks.
|
||||||
#[derive(
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, TypeInfo)]
|
||||||
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, PartialOrd, Ord, MaxEncodedLen, TypeInfo,
|
|
||||||
)]
|
|
||||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum NetworkId {
|
pub enum NetworkId {
|
||||||
Serai,
|
Serai,
|
||||||
External(ExternalNetworkId),
|
External(ExternalNetworkId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Encode for NetworkId {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
NetworkId::Serai => vec![0],
|
||||||
|
NetworkId::External(network) => network.encode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decode for NetworkId {
|
||||||
|
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||||
|
let kind = input.read_byte()?;
|
||||||
|
match kind {
|
||||||
|
0 => Ok(Self::Serai),
|
||||||
|
_ => Ok(ExternalNetworkId::decode(input)?.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaxEncodedLen for NetworkId {
|
||||||
|
fn max_encoded_len() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeLike for NetworkId {}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshSerialize for NetworkId {
|
||||||
|
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_all(&self.encode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshDeserialize for NetworkId {
|
||||||
|
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||||
|
let mut kind = [0; 1];
|
||||||
|
reader.read_exact(&mut kind)?;
|
||||||
|
NetworkId::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ExternalNetworkId {
|
impl ExternalNetworkId {
|
||||||
pub fn coins(&self) -> Vec<ExternalCoin> {
|
pub fn coins(&self) -> Vec<ExternalCoin> {
|
||||||
match self {
|
match self {
|
||||||
@@ -63,11 +147,7 @@ impl NetworkId {
|
|||||||
|
|
||||||
impl From<ExternalNetworkId> for NetworkId {
|
impl From<ExternalNetworkId> for NetworkId {
|
||||||
fn from(network: ExternalNetworkId) -> Self {
|
fn from(network: ExternalNetworkId) -> Self {
|
||||||
match network {
|
NetworkId::External(network)
|
||||||
ExternalNetworkId::Bitcoin => Self::External(ExternalNetworkId::Bitcoin),
|
|
||||||
ExternalNetworkId::Ethereum => Self::External(ExternalNetworkId::Ethereum),
|
|
||||||
ExternalNetworkId::Monero => Self::External(ExternalNetworkId::Monero),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,24 +183,9 @@ pub const COINS: [Coin; 5] = [
|
|||||||
Coin::External(ExternalCoin::Monero),
|
Coin::External(ExternalCoin::Monero),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// The type used to identify coins.
|
|
||||||
#[derive(
|
|
||||||
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
|
|
||||||
)]
|
|
||||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
|
||||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
pub enum Coin {
|
|
||||||
Serai,
|
|
||||||
External(ExternalCoin),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type used to identify external coins.
|
/// The type used to identify external coins.
|
||||||
#[derive(
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)]
|
||||||
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
|
|
||||||
)]
|
|
||||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum ExternalCoin {
|
pub enum ExternalCoin {
|
||||||
Bitcoin,
|
Bitcoin,
|
||||||
@@ -129,14 +194,108 @@ pub enum ExternalCoin {
|
|||||||
Monero,
|
Monero,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Encode for ExternalCoin {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
ExternalCoin::Bitcoin => vec![4],
|
||||||
|
ExternalCoin::Ether => vec![5],
|
||||||
|
ExternalCoin::Dai => vec![6],
|
||||||
|
ExternalCoin::Monero => vec![7],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decode for ExternalCoin {
|
||||||
|
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||||
|
let kind = input.read_byte()?;
|
||||||
|
match kind {
|
||||||
|
4 => Ok(Self::Bitcoin),
|
||||||
|
5 => Ok(Self::Ether),
|
||||||
|
6 => Ok(Self::Dai),
|
||||||
|
7 => Ok(Self::Monero),
|
||||||
|
_ => Err(scale::Error::from("invalid format")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MaxEncodedLen for ExternalCoin {
|
||||||
|
fn max_encoded_len() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeLike for ExternalCoin {}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshSerialize for ExternalCoin {
|
||||||
|
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_all(&self.encode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshDeserialize for ExternalCoin {
|
||||||
|
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||||
|
let mut kind = [0; 1];
|
||||||
|
reader.read_exact(&mut kind)?;
|
||||||
|
ExternalCoin::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type used to identify coins.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub enum Coin {
|
||||||
|
Serai,
|
||||||
|
External(ExternalCoin),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encode for Coin {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
Coin::Serai => vec![0],
|
||||||
|
Coin::External(ec) => ec.encode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decode for Coin {
|
||||||
|
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||||
|
let kind = input.read_byte()?;
|
||||||
|
match kind {
|
||||||
|
0 => Ok(Self::Serai),
|
||||||
|
_ => Ok(ExternalCoin::decode(input)?.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaxEncodedLen for Coin {
|
||||||
|
fn max_encoded_len() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeLike for Coin {}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshSerialize for Coin {
|
||||||
|
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
writer.write_all(&self.encode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "borsh")]
|
||||||
|
impl BorshDeserialize for Coin {
|
||||||
|
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||||
|
let mut kind = [0; 1];
|
||||||
|
reader.read_exact(&mut kind)?;
|
||||||
|
Coin::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ExternalCoin> for Coin {
|
impl From<ExternalCoin> for Coin {
|
||||||
fn from(coin: ExternalCoin) -> Self {
|
fn from(coin: ExternalCoin) -> Self {
|
||||||
match coin {
|
Coin::External(coin)
|
||||||
ExternalCoin::Bitcoin => Self::External(ExternalCoin::Bitcoin),
|
|
||||||
ExternalCoin::Ether => Self::External(ExternalCoin::Ether),
|
|
||||||
ExternalCoin::Dai => Self::External(ExternalCoin::Dai),
|
|
||||||
ExternalCoin::Monero => Self::External(ExternalCoin::Monero),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,6 @@ pub mod pallet {
|
|||||||
///
|
///
|
||||||
/// This will still include participants which were removed from the DKG.
|
/// This will still include participants which were removed from the DKG.
|
||||||
pub fn in_set(network: NetworkId, account: Public) -> bool {
|
pub fn in_set(network: NetworkId, account: Public) -> bool {
|
||||||
// TODO: should InSet only work for `ExternalNetworkId`?
|
|
||||||
if InSet::<T>::contains_key(network, account) {
|
if InSet::<T>::contains_key(network, account) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -695,23 +694,23 @@ pub mod pallet {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let NetworkId::External(n) = network {
|
let NetworkId::External(n) = network else {
|
||||||
// The current session must have set keys for its handover to be completed
|
|
||||||
if !Keys::<T>::contains_key(ExternalValidatorSet { network: n, session }) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This must be the first session (which has set keys) OR the prior session must have been
|
|
||||||
// retired (signified by its keys no longer being present)
|
|
||||||
(session.0 == 0) ||
|
|
||||||
(!Keys::<T>::contains_key(ExternalValidatorSet {
|
|
||||||
network: n,
|
|
||||||
session: Session(session.0 - 1),
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
// Handover is automatically complete for Serai as it doesn't have a handover protocol
|
// Handover is automatically complete for Serai as it doesn't have a handover protocol
|
||||||
true
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The current session must have set keys for its handover to be completed
|
||||||
|
if !Keys::<T>::contains_key(ExternalValidatorSet { network: n, session }) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This must be the first session (which has set keys) OR the prior session must have been
|
||||||
|
// retired (signified by its keys no longer being present)
|
||||||
|
(session.0 == 0) ||
|
||||||
|
(!Keys::<T>::contains_key(ExternalValidatorSet {
|
||||||
|
network: n,
|
||||||
|
session: Session(session.0 - 1),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_session() {
|
fn new_session() {
|
||||||
@@ -744,9 +743,6 @@ pub mod pallet {
|
|||||||
// Serai doesn't set keys and network slashes are handled by BABE/GRANDPA
|
// Serai doesn't set keys and network slashes are handled by BABE/GRANDPA
|
||||||
if let NetworkId::External(n) = set.network {
|
if let NetworkId::External(n) = set.network {
|
||||||
// If the prior prior set didn't report, emit they're retired now
|
// If the prior prior set didn't report, emit they're retired now
|
||||||
// TODO: we will emit the events 1 session late if there was no call to report_slashes.
|
|
||||||
// Also report_slashes calls must be made after the set publishes its first batch for this
|
|
||||||
// flow to work as expected.
|
|
||||||
if PendingSlashReport::<T>::get(n).is_some() {
|
if PendingSlashReport::<T>::get(n).is_some() {
|
||||||
Self::deposit_event(Event::SetRetired {
|
Self::deposit_event(Event::SetRetired {
|
||||||
set: ValidatorSet { network: set.network, session: Session(set.session.0 - 1) },
|
set: ValidatorSet { network: set.network, session: Session(set.session.0 - 1) },
|
||||||
|
|||||||
Reference in New Issue
Block a user