Merge branch 'develop' into next

This commit is contained in:
Luke Parker
2025-10-05 18:43:53 -04:00
102 changed files with 3016 additions and 4149 deletions

View File

@@ -12,31 +12,31 @@ rust-version = "1.85"
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-machete]
ignored = ["scale"]
[lints]
workspace = true
[dependencies]
bitvec = { version = "1", default-features = false, features = ["alloc", "serde"] }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
scale-info = { version = "2", default-features = false, features = ["derive", "bit-vec"] }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
serde = { version = "1", default-features = false, features = ["derive", "alloc"] }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-staking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-io = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-api = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-session = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-staking = { git = "https://github.com/serai-dex/substrate", default-features = false }
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false }
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-babe = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-grandpa = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
serai-primitives = { path = "../../primitives", default-features = false }
validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../primitives", default-features = false }
@@ -45,9 +45,10 @@ coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", de
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
[dev-dependencies]
pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b" }
sp-consensus-babe = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", 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"] }
@@ -63,15 +64,13 @@ std = [
"bitvec/std",
"scale/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-std/std",
"sp-api/std",
"sp-application-crypto/std",
"sp-runtime/std",
"sp-session/std",
"sp-runtime/std",
"sp-staking/std",
"sp-consensus-babe/std",
@@ -79,6 +78,7 @@ std = [
"frame-system/std",
"frame-support/std",
"pallet-session/std",
"pallet-babe/std",
"pallet-grandpa/std",
"pallet-timestamp/std",

View File

@@ -8,13 +8,13 @@ mod tests;
use core::marker::PhantomData;
use scale::{Encode, Decode};
use scale_info::TypeInfo;
use scale::{Encode, Decode, DecodeWithMemTracking};
use sp_std::{vec, vec::Vec};
use sp_core::sr25519::{Public, Signature};
use sp_application_crypto::RuntimePublic;
use sp_session::{ShouldEndSession, GetSessionNumber, GetValidatorCount};
use sp_session::{GetSessionNumber, GetValidatorCount};
use pallet_session::ShouldEndSession;
use sp_runtime::{KeyTypeId, ConsensusEngineId, traits::IsMember};
use sp_staking::offence::{ReportOffence, Offence, OffenceError};
@@ -22,7 +22,7 @@ use frame_system::{pallet_prelude::*, RawOrigin};
use frame_support::{
pallet_prelude::*,
sp_runtime::SaturatedConversion,
traits::{DisabledValidators, KeyOwnerProofSystem, FindAuthor},
traits::{DisabledValidators, KeyOwnerProofSystem, FindAuthor, OneSessionHandler},
BoundedVec, WeakBoundedVec, StoragePrefixedMap,
};
@@ -41,7 +41,7 @@ use pallet_grandpa::{
EquivocationOffence as GrandpaEquivocationOffence,
};
#[derive(Debug, Encode, Decode, TypeInfo, PartialEq, Eq, Clone)]
#[derive(Debug, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, Clone)]
pub struct MembershipProof<T: pallet::Config>(pub Public, pub PhantomData<T>);
impl<T: pallet::Config> GetSessionNumber for MembershipProof<T> {
fn session(&self) -> u32 {
@@ -80,23 +80,21 @@ pub mod pallet {
frame_system::Config<AccountId = Public>
+ coins_pallet::Config
+ dex_pallet::Config
+ pallet_session::Config
+ pallet_babe::Config
+ pallet_grandpa::Config
+ TypeInfo
{
type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;
type ShouldEndSession: ShouldEndSession<BlockNumberFor<Self>>;
}
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
pub struct AllEmbeddedEllipticCurveKeysAtGenesis {
pub embedwards25519: BoundedVec<u8, ConstU32<{ MAX_KEY_LEN }>>,
pub secq256k1: BoundedVec<u8, ConstU32<{ MAX_KEY_LEN }>>,
}
#[pallet::genesis_config]
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
#[derive(Clone, Debug)]
pub struct GenesisConfig<T: Config> {
/// Networks to spawn Serai with, and the stake requirement per key share.
///
@@ -266,7 +264,8 @@ pub mod pallet {
Amount(u64::from_be_bytes(raw))
}
fn recover_key_from_sorted_allocation_key(key: &[u8]) -> Public {
Public(key[(key.len() - 32) ..].try_into().unwrap())
let key: [u8; 32] = key[(key.len() - 32) ..].try_into().unwrap();
key.into()
}
// Returns if this validator already had an allocation set.
fn set_allocation(network: NetworkId, key: Public, amount: Amount) -> bool {
@@ -861,10 +860,13 @@ pub mod pallet {
),
Some(session),
);
Grandpa::<T>::new_session(
fn grandpa_map(i: &(Public, u64)) -> (&Public, GrandpaAuthorityId) {
(&i.0, i.0.into())
}
Grandpa::<T>::on_new_session(
true,
session,
now_validators.into_iter().map(|(id, w)| (GrandpaAuthorityId::from(id), w)).collect(),
now_validators.iter().map(grandpa_map),
next_validators.iter().map(grandpa_map),
);
// Clear SeraiDisabledIndices, only preserving keys still present in the new session
@@ -1370,19 +1372,17 @@ pub mod pallet {
fn is_disabled(index: u32) -> bool {
SeraiDisabledIndices::<T>::get(index).is_some()
}
}
}
sp_api::decl_runtime_apis! {
#[api_version(1)]
pub trait ValidatorSetsApi {
/// Returns the validator set for a given network.
fn validators(network_id: NetworkId) -> Vec<PublicKey>;
/// Returns the external network key for a given external network.
fn external_network_key(
network: ExternalNetworkId,
) -> Option<Vec<u8>>;
fn disabled_validators() -> Vec<u32> {
// TODO: Use a storage iterator here
let mut res = vec![];
for i in 0 .. MAX_KEY_SHARES_PER_SET {
let i = i.into();
if Self::is_disabled(i) {
res.push(i);
}
}
res
}
}
}

View File

@@ -5,7 +5,7 @@ use super::*;
use std::collections::HashMap;
use frame_support::{
construct_runtime,
derive_impl, construct_runtime,
traits::{ConstU16, ConstU32, ConstU64},
};
@@ -55,10 +55,9 @@ construct_runtime!(
}
);
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
@@ -69,16 +68,6 @@ impl frame_system::Config for Test {
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = ConstU64<250>;
type DbWeight = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = ConstU32<16>;
}
impl timestamp::Config for Test {
@@ -88,6 +77,16 @@ impl timestamp::Config for Test {
type WeightInfo = ();
}
pub struct GetSession;
impl pallet_session::GetCurrentSessionForSubstrate for GetSession {
fn get() -> u32 {
0
}
}
impl pallet_session::Config for Test {
type Session = GetSession;
}
impl babe::Config for Test {
type EpochDuration = ConstU64<{ FAST_EPOCH_DURATION }>;
@@ -97,6 +96,7 @@ impl babe::Config for Test {
type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;
type MaxNominators = MaxAuthorities;
type KeyOwnerProof = MembershipProof<Self>;
type EquivocationReportSystem = ();
@@ -107,6 +107,7 @@ impl grandpa::Config for Test {
type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;
type MaxNominators = MaxAuthorities;
type MaxSetIdSessionEntries = ConstU64<0>;
type KeyOwnerProof = MembershipProof<Self>;
@@ -114,18 +115,14 @@ impl grandpa::Config for Test {
}
impl coins::Config for Test {
type RuntimeEvent = RuntimeEvent;
type AllowMint = ValidatorSets;
}
impl coins::Config<coins::Instance1> for Test {
type RuntimeEvent = RuntimeEvent;
type AllowMint = ();
}
impl dex::Config for Test {
type RuntimeEvent = RuntimeEvent;
type LPFee = ConstU32<3>; // 0.3%
type MintMinLiquidity = ConstU64<10000>;
@@ -137,7 +134,6 @@ impl dex::Config for Test {
}
impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type ShouldEndSession = Babe;
}
@@ -195,7 +191,7 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
.into_iter()
.map(|validator| (validator.public().into(), 1))
.collect(),
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
epoch_config: BABE_GENESIS_EPOCH_CONFIG,
_config: PhantomData,
}
.assimilate_storage(&mut t)

View File

@@ -65,7 +65,7 @@ fn set_keys_for_session(network: ExternalNetworkId) {
network,
KeyPair(insecure_pair_from_name("Alice").public(), vec![].try_into().unwrap()),
vec![].try_into().unwrap(),
Signature([0u8; 64]),
Signature::from([0u8; 64]),
)
.unwrap();
}
@@ -103,7 +103,7 @@ fn set_keys_signature(set: &ExternalValidatorSet, key_pair: &KeyPair, pairs: &[P
&set_keys_message(set, key_pair),
);
Signature(sig.to_bytes())
Signature::from(sig.to_bytes())
}
fn get_ordered_keys(network: NetworkId, participants: &[Pair]) -> Vec<Pair> {
@@ -465,7 +465,7 @@ fn set_keys_keys_exist() {
network,
KeyPair(insecure_pair_from_name("name").public(), Vec::new().try_into().unwrap()),
vec![].try_into().unwrap(),
Signature([0u8; 64]),
Signature::from([0u8; 64]),
)
.unwrap();
@@ -473,7 +473,7 @@ fn set_keys_keys_exist() {
network,
key_pair: KeyPair(insecure_pair_from_name("name").public(), Vec::new().try_into().unwrap()),
signature_participants: vec![].try_into().unwrap(),
signature: Signature([0u8; 64]),
signature: Signature::from([0u8; 64]),
};
assert_eq!(

View File

@@ -26,15 +26,14 @@ borsh = { version = "1", default-features = false, features = ["derive", "de_str
serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "da19e1f8ca7a9e2cbf39fbfa493918eeeb45e10b", default-features = false }
serai-primitives = { path = "../../primitives", default-features = false }
[features]
std = ["zeroize", "ciphersuite/std", "dkg-musig/std", "borsh?/std", "serde?/std", "scale/std", "scale-info/std", "sp-core/std", "sp-std/std", "serai-primitives/std"]
std = ["zeroize", "ciphersuite/std", "dkg-musig/std", "borsh?/std", "serde?/std", "scale/std", "sp-core/std", "sp-std/std", "serai-primitives/std"]
borsh = ["dep:borsh", "serai-primitives/borsh"]
serde = ["dep:serde", "serai-primitives/serde"]
default = ["std"]

View File

@@ -8,8 +8,7 @@ use zeroize::Zeroize;
use dalek_ff_group::Ristretto;
use ciphersuite::{group::GroupEncoding, GroupIo};
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
use scale::{Encode, Decode, DecodeWithMemTracking, MaxEncodedLen};
#[cfg(feature = "borsh")]
use borsh::{BorshSerialize, BorshDeserialize};
@@ -39,7 +38,17 @@ pub const MAX_KEY_SHARES_PER_SET_U32: u32 = MAX_KEY_SHARES_PER_SET as u32;
/// The type used to identify a specific session of validators.
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Default,
Debug,
Encode,
Decode,
DecodeWithMemTracking,
MaxEncodedLen,
)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
@@ -48,7 +57,7 @@ pub struct Session(pub u32);
/// The type used to identify a specific validator set during a specific session.
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, DecodeWithMemTracking, MaxEncodedLen,
)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
@@ -59,7 +68,9 @@ pub struct ValidatorSet {
}
/// The type used to identify a specific validator set during a specific session.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
#[derive(
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, DecodeWithMemTracking, MaxEncodedLen,
)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -90,9 +101,8 @@ pub type ExternalKey = BoundedVec<u8, ConstU32<MAX_KEY_LEN>>;
/// The key pair for a validator set.
///
/// This is their Ristretto key, used for publishing data onto Serai, and their key on the external
/// network.
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
/// This is their Ristretto key, used for signing Batches, and their key on the external network.
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, DecodeWithMemTracking, MaxEncodedLen)]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KeyPair(
@@ -141,7 +151,7 @@ pub fn musig_key(set: ValidatorSet, set_keys: &[Public]) -> Public {
<Ristretto as GroupIo>::read_G::<&[u8]>(&mut key.0.as_ref()).expect("invalid participant"),
);
}
Public(dkg_musig::musig_key_vartime::<Ristretto>(musig_context(set), &keys).unwrap().to_bytes())
dkg_musig::musig_key_vartime::<Ristretto>(musig_context(set), &keys).unwrap().to_bytes().into()
}
/// The message for the `set_keys` signature.

View File

@@ -1,10 +1,11 @@
#![expect(clippy::cast_possible_truncation)]
use core::{num::NonZero, time::Duration};
#[cfg(feature = "std")]
use zeroize::Zeroize;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
use scale::{Encode, Decode, MaxEncodedLen, DecodeWithMemTracking};
#[cfg(feature = "borsh")]
use borsh::{BorshSerialize, BorshDeserialize};
@@ -26,7 +27,9 @@ fn downtime_per_slash_point(validators: NonZero<u16>) -> Duration {
}
/// A slash for a validator.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[derive(
Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, DecodeWithMemTracking,
)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -206,7 +209,7 @@ impl Slash {
}
}
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, DecodeWithMemTracking)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SlashReport(pub BoundedVec<Slash, ConstU32<{ MAX_KEY_SHARES_PER_SET_U32 }>>);