Merge branch 'develop' into next

This resolves the conflicts and gets the workspace `Cargo.toml`s to not be
invalid. It doesn't actually get clippy to pass again yet.

Does move `crypto/dkg/src/evrf` into a new `crypto/dkg/evrf` crate (which does
not yet compile).
This commit is contained in:
Luke Parker
2025-08-23 15:04:39 -04:00
319 changed files with 4016 additions and 26990 deletions

View File

@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/substrate/client"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = ["serai"]
edition = "2021"
rust-version = "1.80"
rust-version = "1.82"
[package.metadata.docs.rs]
all-features = true
@@ -41,8 +41,9 @@ simple-request = { path = "../../common/request", version = "0.1", optional = tr
bitcoin = { version = "0.32", optional = true }
dalek-ff-group = { path = "../../crypto/dalek-ff-group", optional = true }
ciphersuite = { path = "../../crypto/ciphersuite", version = "0.4", optional = true }
monero-address = { path = "../../networks/monero/wallet/address", version = "0.1.0", default-features = false, features = ["std"], optional = true }
monero-address = { git = "https://github.com/kayabaNerve/monero-oxide", rev = "b6dd1a9ff7ac6b96eb7cb488a4501fd1f6f2dd1e", version = "0.1.0", default-features = false, features = ["std"], optional = true }
[dev-dependencies]
rand_core = "0.6"
@@ -50,7 +51,9 @@ hex = "0.4"
blake2 = "0.10"
ciphersuite = { path = "../../crypto/ciphersuite", features = ["ristretto", "secp256k1"] }
dalek-ff-group = { path = "../../crypto/dalek-ff-group" }
ciphersuite = { path = "../../crypto/ciphersuite" }
dkg-musig = { path = "../../crypto/dkg/musig" }
frost = { package = "modular-frost", path = "../../crypto/frost", features = ["tests"] }
schnorrkel = { path = "../../crypto/schnorrkel", package = "frost-schnorrkel" }
@@ -66,7 +69,7 @@ borsh = ["serai-abi/borsh"]
networks = []
bitcoin = ["networks", "dep:bitcoin"]
ethereum = ["networks"]
monero = ["networks", "ciphersuite/ed25519", "monero-address"]
monero = ["networks", "dalek-ff-group", "ciphersuite", "monero-address"]
# Assumes the default usage is to use Serai as a DEX, which doesn't actually
# require connecting to a Serai node

View File

@@ -1,6 +1,9 @@
use core::{str::FromStr, fmt};
use ciphersuite::{Ciphersuite, Ed25519};
use scale::{Encode, Decode};
use dalek_ff_group::Ed25519;
use ciphersuite::Ciphersuite;
use monero_address::{Network, AddressType as MoneroAddressType, MoneroAddress};

View File

@@ -3,8 +3,9 @@ use std::collections::HashMap;
use rand_core::{RngCore, OsRng};
use zeroize::Zeroizing;
use ciphersuite::{Ciphersuite, Ristretto};
use frost::dkg::musig::musig;
use dalek_ff_group::Ristretto;
use ciphersuite::Ciphersuite;
use dkg_musig::musig;
use schnorrkel::Schnorrkel;
use sp_core::{sr25519::Signature, Pair as PairTrait};
@@ -103,7 +104,7 @@ async fn set_values(serai: &Serai, values: &Values) {
assert_eq!(Ristretto::generator() * secret_key, public_key);
let threshold_keys =
musig::<Ristretto>(&musig_context(set), &Zeroizing::new(secret_key), &[public_key]).unwrap();
musig::<Ristretto>(musig_context(set), Zeroizing::new(secret_key), &[public_key]).unwrap();
let sig = frost::tests::sign_without_caching(
&mut OsRng,

View File

@@ -49,17 +49,24 @@ macro_rules! serai_test {
test.provide_container(composition);
test.run_async(|ops| async move {
// Sleep until the Substrate RPC starts
let serai_rpc = ops.handle(handle).host_port(9944).unwrap();
let serai_rpc = format!("http://{}:{}", serai_rpc.0, serai_rpc.1);
// Bound execution to 60 seconds
for _ in 0 .. 60 {
let mut ticks = 0;
let serai_rpc = loop {
// Bound execution to 60 seconds
if ticks > 60 {
panic!("Serai node didn't start within 60 seconds");
}
tokio::time::sleep(core::time::Duration::from_secs(1)).await;
ticks += 1;
let Some(serai_rpc) = ops.handle(handle).host_port(9944) else { continue };
let serai_rpc = format!("http://{}:{}", serai_rpc.0, serai_rpc.1);
let Ok(client) = Serai::new(serai_rpc.clone()).await else { continue };
if client.latest_finalized_block_hash().await.is_err() {
continue;
}
break;
}
break serai_rpc;
};
#[allow(clippy::redundant_closure_call)]
$test(Serai::new(serai_rpc).await.unwrap()).await;
}).await;

View File

@@ -11,8 +11,9 @@ use sp_core::{
Pair as PairTrait,
};
use ciphersuite::{Ciphersuite, Ristretto};
use frost::dkg::musig::musig;
use dalek_ff_group::Ristretto;
use ciphersuite::Ciphersuite;
use dkg_musig::musig;
use schnorrkel::Schnorrkel;
use serai_client::{
@@ -49,8 +50,7 @@ pub async fn set_keys(
assert_eq!(Ristretto::generator() * secret_key, pub_keys[i]);
threshold_keys.push(
musig::<Ristretto>(&musig_context(set.into()), &Zeroizing::new(secret_key), &pub_keys)
.unwrap(),
musig::<Ristretto>(musig_context(set.into()), Zeroizing::new(secret_key), &pub_keys).unwrap(),
);
}

View File

@@ -81,7 +81,7 @@ serai-env = { path = "../../common/env" }
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }
bitcoin-serai = { path = "../../networks/bitcoin", default-features = false, features = ["std", "hazmat"] }
monero-address = { path = "../../networks/monero/wallet/address", default-features = false, features = ["std"] }
monero-address = { git = "https://github.com/kayabaNerve/monero-oxide", rev = "b6dd1a9ff7ac6b96eb7cb488a4501fd1f6f2dd1e", default-features = false, features = ["std"] }
[build-dependencies]
substrate-build-script-utils = { git = "https://github.com/serai-dex/substrate" }

View File

@@ -76,7 +76,7 @@ frame-system-rpc-runtime-api = { git = "https://github.com/serai-dex/substrate",
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/serai-dex/substrate", default-features = false }
[build-dependencies]
substrate-wasm-builder = { git = "https://github.com/serai-dex/substrate" }
substrate-wasm-builder = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next" }
[features]
std = [

View File

@@ -1,12 +1,4 @@
use substrate_wasm_builder::WasmBuilder;
fn main() {
WasmBuilder::new()
.with_current_project()
// https://substrate.stackexchange.com/questions/12124
// TODO: Remove once we've moved to polkadot-sdk
.disable_runtime_version_section_check()
.export_heap_base()
.import_memory()
.build()
#[cfg(feature = "std")]
substrate_wasm_builder::WasmBuilder::build_using_defaults();
}

View File

@@ -212,7 +212,6 @@ impl TryInto<Call> for RuntimeCall {
coins::Call::burn_with_instruction { instruction } => {
serai_abi::coins::Call::burn_with_instruction { instruction }
}
_ => Err(())?,
}),
RuntimeCall::LiquidityTokens(call) => Call::LiquidityTokens(match call {
coins::Call::transfer { to, balance } => {
@@ -266,7 +265,6 @@ impl TryInto<Call> for RuntimeCall {
send_to: send_to.into(),
}
}
_ => Err(())?,
}),
RuntimeCall::GenesisLiquidity(call) => Call::GenesisLiquidity(match call {
genesis_liquidity::Call::remove_coin_liquidity { balance } => {
@@ -275,7 +273,6 @@ impl TryInto<Call> for RuntimeCall {
genesis_liquidity::Call::oraclize_values { values, signature } => {
serai_abi::genesis_liquidity::Call::oraclize_values { values, signature }
}
_ => Err(())?,
}),
RuntimeCall::ValidatorSets(call) => Call::ValidatorSets(match call {
validator_sets::Call::set_keys { network, key_pair, signature_participants, signature } => {
@@ -304,13 +301,11 @@ impl TryInto<Call> for RuntimeCall {
validator_sets::Call::claim_deallocation { network, session } => {
serai_abi::validator_sets::Call::claim_deallocation { network, session }
}
_ => Err(())?,
}),
RuntimeCall::InInstructions(call) => Call::InInstructions(match call {
in_instructions::Call::execute_batch { batch } => {
serai_abi::in_instructions::Call::execute_batch { batch }
}
_ => Err(())?,
}),
RuntimeCall::Signals(call) => Call::Signals(match call {
signals::Call::register_retirement_signal { in_favor_of } => {
@@ -328,7 +323,6 @@ impl TryInto<Call> for RuntimeCall {
signals::Call::stand_against { signal_id, for_network } => {
serai_abi::signals::Call::stand_against { signal_id, for_network }
}
_ => Err(())?,
}),
RuntimeCall::Babe(call) => Call::Babe(match call {
babe::Call::report_equivocation { equivocation_proof, key_owner_proof } => {
@@ -366,7 +360,6 @@ impl TryInto<Call> for RuntimeCall {
}
_ => Err(())?,
}),
_ => Err(())?,
})
}
}

View File

@@ -49,7 +49,7 @@ pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-fea
sp-consensus-babe = { git = "https://github.com/serai-dex/substrate", default-features = false }
ciphersuite = { path = "../../../crypto/ciphersuite", features = ["ristretto"] }
ciphersuite = { path = "../../../crypto/ciphersuite", features = ["std"] }
frost = { package = "modular-frost", path = "../../../crypto/frost", features = ["tests"] }
schnorrkel = { path = "../../../crypto/schnorrkel", package = "frost-schnorrkel" }
@@ -71,7 +71,7 @@ std = [
"sp-runtime/std",
"sp-session/std",
"sp-staking/std",
"sp-consensus-babe/std",
"frame-system/std",

View File

@@ -18,8 +18,9 @@ workspace = true
[dependencies]
zeroize = { version = "^1.5", features = ["derive"], optional = true }
ciphersuite = { path = "../../../crypto/ciphersuite", version = "0.4", default-features = false, features = ["alloc", "ristretto"] }
dkg = { path = "../../../crypto/dkg", version = "0.5", default-features = false }
dalek-ff-group = { path = "../../../crypto/dalek-ff-group", default-features = false, features = ["alloc"] }
ciphersuite = { path = "../../../crypto/ciphersuite", version = "0.4", default-features = false, features = ["alloc"] }
dkg-musig = { path = "../../../crypto/dkg/musig", default-features = false }
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
@@ -33,7 +34,7 @@ sp-std = { git = "https://github.com/serai-dex/substrate", default-features = fa
serai-primitives = { path = "../../primitives", default-features = false }
[features]
std = ["zeroize", "ciphersuite/std", "dkg/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", "scale-info/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

@@ -5,7 +5,8 @@ use core::time::Duration;
#[cfg(feature = "std")]
use zeroize::Zeroize;
use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
use dalek_ff_group::Ristretto;
use ciphersuite::{group::GroupEncoding, Ciphersuite};
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
@@ -121,8 +122,13 @@ impl Zeroize for KeyPair {
}
/// The MuSig context for a validator set.
pub fn musig_context(set: ValidatorSet) -> Vec<u8> {
(b"ValidatorSets-musig_key".as_ref(), set).encode()
pub fn musig_context(set: ValidatorSet) -> [u8; 32] {
let mut context = [0; 32];
const DST: &[u8] = b"ValidatorSets-musig_key";
context[.. DST.len()].copy_from_slice(DST);
let set = set.encode();
context[DST.len() .. (DST.len() + set.len())].copy_from_slice(&set);
context
}
/// The MuSig public key for a validator set.
@@ -136,7 +142,7 @@ pub fn musig_key(set: ValidatorSet, set_keys: &[Public]) -> Public {
.expect("invalid participant"),
);
}
Public(dkg::musig::musig_key::<Ristretto>(&musig_context(set), &keys).unwrap().to_bytes())
Public(dkg_musig::musig_key_vartime::<Ristretto>(musig_context(set), &keys).unwrap().to_bytes())
}
/// The message for the `set_keys` signature.