Finish merging in the develop branch

This commit is contained in:
Luke Parker 2025-01-30 03:14:24 -05:00
parent 258c02ff39
commit a275023cfc
No known key found for this signature in database
62 changed files with 452 additions and 508 deletions
Cargo.lockCargo.toml
coordinator
patches/tiny-bip39
processor
bitcoin/src
ethereum/src
monero/src
primitives/src
scanner/src
scheduler/utxo
primitives/src
standard/src
transaction-chaining/src
substrate
client
coins/pallet/src
in-instructions
pallet/src
primitives/src
node/src
primitives/src
validator-sets
pallet/src
primitives/src

60
Cargo.lock generated
View file

@ -5630,19 +5630,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "monero-seed"
version = "0.1.0"
dependencies = [
"curve25519-dalek",
"hex",
"monero-primitives",
"rand_core",
"std-shims",
"thiserror 2.0.9",
"zeroize",
]
[[package]]
name = "monero-serai"
version = "0.1.4-alpha"
@ -5717,21 +5704,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "monero-wallet-util"
version = "0.1.0"
dependencies = [
"curve25519-dalek",
"hex",
"monero-seed",
"monero-wallet",
"polyseed",
"rand_core",
"std-shims",
"thiserror 2.0.9",
"zeroize",
]
[[package]]
name = "multiaddr"
version = "0.18.1"
@ -6478,17 +6450,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156"
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "pasta_curves"
version = "0.5.1"
@ -6533,9 +6494,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest 0.10.7",
"hmac",
"password-hash",
"sha2",
]
[[package]]
@ -6658,20 +6616,6 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "polyseed"
version = "0.1.0"
dependencies = [
"hex",
"pbkdf2 0.12.2",
"rand_core",
"sha3",
"std-shims",
"subtle",
"thiserror 2.0.9",
"zeroize",
]
[[package]]
name = "polyval"
version = "0.6.2"
@ -9006,6 +8950,7 @@ dependencies = [
"serai-coins-primitives",
"serai-primitives",
"sp-core",
"sp-io",
"sp-runtime",
"sp-std",
]
@ -9445,7 +9390,7 @@ dependencies = [
"generalized-bulletproofs-circuit-abstraction",
"generalized-bulletproofs-ec-gadgets",
"minimal-ed448",
"monero-wallet-util",
"monero-wallet",
"multiexp",
"schnorr-signatures",
"secq256k1",
@ -9531,6 +9476,7 @@ dependencies = [
"sp-core",
"sp-io",
"sp-runtime",
"sp-std",
"zeroize",
]

View file

@ -191,9 +191,6 @@ parking_lot = { path = "patches/parking_lot" }
zstd = { path = "patches/zstd" }
# Needed for WAL compression
rocksdb = { path = "patches/rocksdb" }
# 1.0.1 was yanked due to a breaking change (an extra field)
# 2.0 has fewer dependencies and still works within our tree
tiny-bip39 = { path = "patches/tiny-bip39" }
# is-terminal now has an std-based solution with an equivalent API
is-terminal = { path = "patches/is-terminal" }

View file

@ -3,7 +3,7 @@ use std::{sync::Arc, collections::HashMap};
use serai_client::{
primitives::{SeraiAddress, Amount},
validator_sets::primitives::ValidatorSet,
validator_sets::primitives::ExternalValidatorSet,
Serai,
};
@ -28,7 +28,7 @@ db_channel! {
CosignIntendChannels {
GlobalSessionsChannel: () -> ([u8; 32], GlobalSession),
BlockEvents: () -> BlockEventData,
IntendedCosigns: (set: ValidatorSet) -> CosignIntent,
IntendedCosigns: (set: ExternalValidatorSet) -> CosignIntent,
}
}
@ -110,7 +110,7 @@ impl<D: Db> ContinuallyRan for CosignIntendTask<D> {
keys.insert(set.network, SeraiAddress::from(*key));
let stake = serai
.validator_sets()
.total_allocated_stake(set.network)
.total_allocated_stake(set.network.into())
.await
.map_err(|e| format!("{e:?}"))?
.unwrap_or(Amount(0))

View file

@ -11,8 +11,8 @@ use scale::{Encode, Decode};
use borsh::{BorshSerialize, BorshDeserialize};
use serai_client::{
primitives::{NetworkId, SeraiAddress},
validator_sets::primitives::{Session, ValidatorSet, KeyPair},
primitives::{ExternalNetworkId, SeraiAddress},
validator_sets::primitives::{Session, ExternalValidatorSet, KeyPair},
Public, Block, Serai, TemporalSerai,
};
@ -52,13 +52,13 @@ pub const COSIGN_CONTEXT: &[u8] = b"/serai/coordinator/cosign";
#[derive(Debug, BorshSerialize, BorshDeserialize)]
pub(crate) struct GlobalSession {
pub(crate) start_block_number: u64,
pub(crate) sets: Vec<ValidatorSet>,
pub(crate) keys: HashMap<NetworkId, SeraiAddress>,
pub(crate) stakes: HashMap<NetworkId, u64>,
pub(crate) sets: Vec<ExternalValidatorSet>,
pub(crate) keys: HashMap<ExternalNetworkId, SeraiAddress>,
pub(crate) stakes: HashMap<ExternalNetworkId, u64>,
pub(crate) total_stake: u64,
}
impl GlobalSession {
fn id(mut cosigners: Vec<ValidatorSet>) -> [u8; 32] {
fn id(mut cosigners: Vec<ExternalValidatorSet>) -> [u8; 32] {
cosigners.sort_by_key(|a| borsh::to_vec(a).unwrap());
Blake2s256::digest(borsh::to_vec(&cosigners).unwrap()).into()
}
@ -101,12 +101,12 @@ pub struct Cosign {
/// The hash of the block to cosign.
pub block_hash: [u8; 32],
/// The actual cosigner.
pub cosigner: NetworkId,
pub cosigner: ExternalNetworkId,
}
impl CosignIntent {
/// Convert this into a `Cosign`.
pub fn into_cosign(self, cosigner: NetworkId) -> Cosign {
pub fn into_cosign(self, cosigner: ExternalNetworkId) -> Cosign {
let CosignIntent { global_session, block_number, block_hash, notable: _ } = self;
Cosign { global_session, block_number, block_hash, cosigner }
}
@ -166,7 +166,10 @@ create_db! {
// one notable block. All validator sets will explicitly produce a cosign for their notable
// block, causing the latest cosigned block for a global session to either be the global
// session's notable cosigns or the network's latest cosigns.
NetworksLatestCosignedBlock: (global_session: [u8; 32], network: NetworkId) -> SignedCosign,
NetworksLatestCosignedBlock: (
global_session: [u8; 32],
network: ExternalNetworkId
) -> SignedCosign,
// Cosigns received for blocks not locally recognized as finalized.
Faults: (global_session: [u8; 32]) -> Vec<SignedCosign>,
// The global session which faulted.
@ -177,15 +180,10 @@ create_db! {
/// Fetch the keys used for cosigning by a specific network.
async fn keys_for_network(
serai: &TemporalSerai<'_>,
network: NetworkId,
network: ExternalNetworkId,
) -> Result<Option<(Session, KeyPair)>, String> {
// The Serai network never cosigns so it has no keys for cosigning
if network == NetworkId::Serai {
return Ok(None);
}
let Some(latest_session) =
serai.validator_sets().session(network).await.map_err(|e| format!("{e:?}"))?
serai.validator_sets().session(network.into()).await.map_err(|e| format!("{e:?}"))?
else {
// If this network hasn't had a session declared, move on
return Ok(None);
@ -194,7 +192,7 @@ async fn keys_for_network(
// Get the keys for the latest session
if let Some(keys) = serai
.validator_sets()
.keys(ValidatorSet { network, session: latest_session })
.keys(ExternalValidatorSet { network, session: latest_session })
.await
.map_err(|e| format!("{e:?}"))?
{
@ -205,7 +203,7 @@ async fn keys_for_network(
if let Some(prior_session) = latest_session.0.checked_sub(1).map(Session) {
if let Some(keys) = serai
.validator_sets()
.keys(ValidatorSet { network, session: prior_session })
.keys(ExternalValidatorSet { network, session: prior_session })
.await
.map_err(|e| format!("{e:?}"))?
{
@ -216,16 +214,19 @@ async fn keys_for_network(
Ok(None)
}
/// Fetch the `ValidatorSet`s, and their associated keys, used for cosigning as of this block.
async fn cosigning_sets(serai: &TemporalSerai<'_>) -> Result<Vec<(ValidatorSet, Public)>, String> {
let mut sets = Vec::with_capacity(serai_client::primitives::NETWORKS.len());
for network in serai_client::primitives::NETWORKS {
/// Fetch the `ExternalValidatorSet`s, and their associated keys, used for cosigning as of this
/// block.
async fn cosigning_sets(
serai: &TemporalSerai<'_>,
) -> Result<Vec<(ExternalValidatorSet, Public)>, String> {
let mut sets = Vec::with_capacity(serai_client::primitives::EXTERNAL_NETWORKS.len());
for network in serai_client::primitives::EXTERNAL_NETWORKS {
let Some((session, keys)) = keys_for_network(serai, network).await? else {
// If this network doesn't have usable keys, move on
continue;
};
sets.push((ValidatorSet { network, session }, keys.0));
sets.push((ExternalValidatorSet { network, session }, keys.0));
}
Ok(sets)
}
@ -345,8 +346,8 @@ impl<D: Db> Cosigning<D> {
/// If this global session hasn't produced any notable cosigns, this will return the latest
/// cosigns for this session.
pub fn notable_cosigns(getter: &impl Get, global_session: [u8; 32]) -> Vec<SignedCosign> {
let mut cosigns = Vec::with_capacity(serai_client::primitives::NETWORKS.len());
for network in serai_client::primitives::NETWORKS {
let mut cosigns = Vec::with_capacity(serai_client::primitives::EXTERNAL_NETWORKS.len());
for network in serai_client::primitives::EXTERNAL_NETWORKS {
if let Some(cosign) = NetworksLatestCosignedBlock::get(getter, global_session, network) {
cosigns.push(cosign);
}
@ -363,7 +364,7 @@ impl<D: Db> Cosigning<D> {
let mut cosigns = Faults::get(&self.db, faulted).expect("faulted with no faults");
// Also include all of our recognized-as-honest cosigns in an attempt to induce fault
// identification in those who see the faulty cosigns as honest
for network in serai_client::primitives::NETWORKS {
for network in serai_client::primitives::EXTERNAL_NETWORKS {
if let Some(cosign) = NetworksLatestCosignedBlock::get(&self.db, faulted, network) {
if cosign.cosign.global_session == faulted {
cosigns.push(cosign);
@ -375,8 +376,8 @@ impl<D: Db> Cosigning<D> {
let Some(global_session) = evaluator::currently_evaluated_global_session(&self.db) else {
return vec![];
};
let mut cosigns = Vec::with_capacity(serai_client::primitives::NETWORKS.len());
for network in serai_client::primitives::NETWORKS {
let mut cosigns = Vec::with_capacity(serai_client::primitives::EXTERNAL_NETWORKS.len());
for network in serai_client::primitives::EXTERNAL_NETWORKS {
if let Some(cosign) = NetworksLatestCosignedBlock::get(&self.db, global_session, network) {
cosigns.push(cosign);
}
@ -487,12 +488,12 @@ impl<D: Db> Cosigning<D> {
Ok(())
}
/// Receive intended cosigns to produce for this ValidatorSet.
/// Receive intended cosigns to produce for this ExternalValidatorSet.
///
/// All cosigns intended, up to and including the next notable cosign, are returned.
///
/// This will drain the internal channel and not re-yield these intentions again.
pub fn intended_cosigns(txn: &mut impl DbTxn, set: ValidatorSet) -> Vec<CosignIntent> {
pub fn intended_cosigns(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Vec<CosignIntent> {
let mut res: Vec<CosignIntent> = vec![];
// While we have yet to find a notable cosign...
while !res.last().map(|cosign| cosign.notable).unwrap_or(false) {

View file

@ -14,8 +14,8 @@ use zeroize::Zeroizing;
use schnorrkel::Keypair;
use serai_client::{
primitives::{NetworkId, PublicKey},
validator_sets::primitives::ValidatorSet,
primitives::{ExternalNetworkId, PublicKey},
validator_sets::primitives::ExternalValidatorSet,
Serai,
};
@ -104,7 +104,7 @@ impl serai_coordinator_p2p::Peer<'_> for Peer<'_> {
#[derive(Clone)]
struct Peers {
peers: Arc<RwLock<HashMap<NetworkId, HashSet<PeerId>>>>,
peers: Arc<RwLock<HashMap<ExternalNetworkId, HashSet<PeerId>>>>,
}
// Consider adding identify/kad/autonat/rendevous/(relay + dcutr). While we currently use the Serai
@ -135,7 +135,8 @@ struct Libp2pInner {
signed_cosigns: Mutex<mpsc::UnboundedReceiver<SignedCosign>>,
signed_cosigns_send: mpsc::UnboundedSender<SignedCosign>,
heartbeat_requests: Mutex<mpsc::UnboundedReceiver<(InboundRequestId, ValidatorSet, [u8; 32])>>,
heartbeat_requests:
Mutex<mpsc::UnboundedReceiver<(InboundRequestId, ExternalValidatorSet, [u8; 32])>>,
notable_cosign_requests: Mutex<mpsc::UnboundedReceiver<(InboundRequestId, [u8; 32])>>,
inbound_request_responses: mpsc::UnboundedSender<(InboundRequestId, Response)>,
}
@ -312,7 +313,7 @@ impl serai_cosign::RequestNotableCosigns for Libp2p {
impl serai_coordinator_p2p::P2p for Libp2p {
type Peer<'a> = Peer<'a>;
fn peers(&self, network: NetworkId) -> impl Send + Future<Output = Vec<Self::Peer<'_>>> {
fn peers(&self, network: ExternalNetworkId) -> impl Send + Future<Output = Vec<Self::Peer<'_>>> {
async move {
let Some(peer_ids) = self.0.peers.peers.read().await.get(&network).cloned() else {
return vec![];

View file

@ -6,7 +6,7 @@ use std::{
use borsh::BorshDeserialize;
use serai_client::validator_sets::primitives::ValidatorSet;
use serai_client::validator_sets::primitives::ExternalValidatorSet;
use tokio::sync::{mpsc, oneshot, RwLock};
@ -68,7 +68,7 @@ pub(crate) struct SwarmTask {
outbound_request_responses: HashMap<OutboundRequestId, oneshot::Sender<Response>>,
inbound_request_response_channels: HashMap<InboundRequestId, ResponseChannel<Response>>,
heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ValidatorSet, [u8; 32])>,
heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ExternalValidatorSet, [u8; 32])>,
notable_cosign_requests: mpsc::UnboundedSender<(InboundRequestId, [u8; 32])>,
inbound_request_responses: mpsc::UnboundedReceiver<(InboundRequestId, Response)>,
}
@ -324,7 +324,7 @@ impl SwarmTask {
outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>,
heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ValidatorSet, [u8; 32])>,
heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ExternalValidatorSet, [u8; 32])>,
notable_cosign_requests: mpsc::UnboundedSender<(InboundRequestId, [u8; 32])>,
inbound_request_responses: mpsc::UnboundedReceiver<(InboundRequestId, Response)>,
) {

View file

@ -4,7 +4,9 @@ use std::{
collections::{HashSet, HashMap},
};
use serai_client::{primitives::NetworkId, validator_sets::primitives::Session, SeraiError, Serai};
use serai_client::{
primitives::ExternalNetworkId, validator_sets::primitives::Session, SeraiError, Serai,
};
use serai_task::{Task, ContinuallyRan};
@ -24,11 +26,11 @@ pub(crate) struct Validators {
serai: Arc<Serai>,
// A cache for which session we're populated with the validators of
sessions: HashMap<NetworkId, Session>,
sessions: HashMap<ExternalNetworkId, Session>,
// The validators by network
by_network: HashMap<NetworkId, HashSet<PeerId>>,
by_network: HashMap<ExternalNetworkId, HashSet<PeerId>>,
// The validators and their networks
validators: HashMap<PeerId, HashSet<NetworkId>>,
validators: HashMap<PeerId, HashSet<ExternalNetworkId>>,
// The channel to send the changes down
changes: mpsc::UnboundedSender<Changes>,
@ -49,8 +51,8 @@ impl Validators {
async fn session_changes(
serai: impl Borrow<Serai>,
sessions: impl Borrow<HashMap<NetworkId, Session>>,
) -> Result<Vec<(NetworkId, Session, HashSet<PeerId>)>, SeraiError> {
sessions: impl Borrow<HashMap<ExternalNetworkId, Session>>,
) -> Result<Vec<(ExternalNetworkId, Session, HashSet<PeerId>)>, SeraiError> {
/*
This uses the latest finalized block, not the latest cosigned block, which should be fine as
in the worst case, we'd connect to unexpected validators. They still shouldn't be able to
@ -67,13 +69,10 @@ impl Validators {
// FuturesUnordered can be bad practice as it'll cause timeouts if infrequently polled, but
// we poll it till it yields all futures with the most minimal processing possible
let mut futures = FuturesUnordered::new();
for network in serai_client::primitives::NETWORKS {
if network == NetworkId::Serai {
continue;
}
for network in serai_client::primitives::EXTERNAL_NETWORKS {
let sessions = sessions.borrow();
futures.push(async move {
let session = match temporal_serai.session(network).await {
let session = match temporal_serai.session(network.into()).await {
Ok(Some(session)) => session,
Ok(None) => return Ok(None),
Err(e) => return Err(e),
@ -82,7 +81,7 @@ impl Validators {
if sessions.get(&network) == Some(&session) {
Ok(None)
} else {
match temporal_serai.active_network_validators(network).await {
match temporal_serai.active_network_validators(network.into()).await {
Ok(validators) => Ok(Some((
network,
session,
@ -105,7 +104,7 @@ impl Validators {
fn incorporate_session_changes(
&mut self,
session_changes: Vec<(NetworkId, Session, HashSet<PeerId>)>,
session_changes: Vec<(ExternalNetworkId, Session, HashSet<PeerId>)>,
) {
let mut removed = HashSet::new();
let mut added = HashSet::new();
@ -160,11 +159,11 @@ impl Validators {
Ok(())
}
pub(crate) fn by_network(&self) -> &HashMap<NetworkId, HashSet<PeerId>> {
pub(crate) fn by_network(&self) -> &HashMap<ExternalNetworkId, HashSet<PeerId>> {
&self.by_network
}
pub(crate) fn networks(&self, peer_id: &PeerId) -> Option<&HashSet<NetworkId>> {
pub(crate) fn networks(&self, peer_id: &PeerId) -> Option<&HashSet<ExternalNetworkId>> {
self.validators.get(peer_id)
}
}

View file

@ -1,7 +1,7 @@
use core::future::Future;
use std::time::{Duration, SystemTime};
use serai_client::validator_sets::primitives::{MAX_KEY_SHARES_PER_SET, ValidatorSet};
use serai_client::validator_sets::primitives::{MAX_KEY_SHARES_PER_SET, ExternalValidatorSet};
use futures_lite::FutureExt;
@ -38,7 +38,7 @@ pub const BATCH_SIZE_LIMIT: usize = MIN_BLOCKS_PER_BATCH *
/// If the other validator has more blocks then we do, they're expected to inform us. This forms
/// the sync protocol for our Tributaries.
pub(crate) struct HeartbeatTask<TD: Db, Tx: TransactionTrait, P: P2p> {
pub(crate) set: ValidatorSet,
pub(crate) set: ExternalValidatorSet,
pub(crate) tributary: Tributary<TD, Tx, P>,
pub(crate) reader: TributaryReader<TD, Tx>,
pub(crate) p2p: P,

View file

@ -7,7 +7,7 @@ use std::collections::HashMap;
use borsh::{BorshSerialize, BorshDeserialize};
use serai_client::{primitives::NetworkId, validator_sets::primitives::ValidatorSet};
use serai_client::{primitives::ExternalNetworkId, validator_sets::primitives::ExternalValidatorSet};
use serai_db::Db;
use tributary_sdk::{ReadWrite, TransactionTrait, Tributary, TributaryReader};
@ -25,7 +25,7 @@ use crate::heartbeat::HeartbeatTask;
#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, Debug)]
pub struct Heartbeat {
/// The Tributary this is the heartbeat of.
pub set: ValidatorSet,
pub set: ExternalValidatorSet,
/// The hash of the latest block added to the Tributary.
pub latest_block_hash: [u8; 32],
}
@ -56,7 +56,7 @@ pub trait P2p:
type Peer<'a>: Peer<'a>;
/// Fetch the peers for this network.
fn peers(&self, network: NetworkId) -> impl Send + Future<Output = Vec<Self::Peer<'_>>>;
fn peers(&self, network: ExternalNetworkId) -> impl Send + Future<Output = Vec<Self::Peer<'_>>>;
/// Broadcast a cosign.
fn publish_cosign(&self, cosign: SignedCosign) -> impl Send + Future<Output = ()>;
@ -131,13 +131,13 @@ fn handle_heartbeat<D: Db, T: TransactionTrait>(
pub async fn run<TD: Db, Tx: TransactionTrait, P: P2p>(
db: impl Db,
p2p: P,
mut add_tributary: mpsc::UnboundedReceiver<(ValidatorSet, Tributary<TD, Tx, P>)>,
mut retire_tributary: mpsc::UnboundedReceiver<ValidatorSet>,
mut add_tributary: mpsc::UnboundedReceiver<(ExternalValidatorSet, Tributary<TD, Tx, P>)>,
mut retire_tributary: mpsc::UnboundedReceiver<ExternalValidatorSet>,
send_cosigns: mpsc::UnboundedSender<SignedCosign>,
) {
let mut readers = HashMap::<ValidatorSet, TributaryReader<TD, Tx>>::new();
let mut readers = HashMap::<ExternalValidatorSet, TributaryReader<TD, Tx>>::new();
let mut tributaries = HashMap::<[u8; 32], mpsc::UnboundedSender<Vec<u8>>>::new();
let mut heartbeat_tasks = HashMap::<ValidatorSet, _>::new();
let mut heartbeat_tasks = HashMap::<ExternalValidatorSet, _>::new();
loop {
tokio::select! {

View file

@ -6,8 +6,8 @@ use serai_db::{create_db, db_channel};
use dkg::Participant;
use serai_client::{
primitives::NetworkId,
validator_sets::primitives::{Session, ValidatorSet, KeyPair},
primitives::ExternalNetworkId,
validator_sets::primitives::{Session, ExternalValidatorSet, KeyPair},
};
use serai_cosign::SignedCosign;
@ -43,22 +43,21 @@ pub(crate) fn coordinator_db() -> Db {
db(&format!("{root_path}/coordinator/db"))
}
fn tributary_db_folder(set: ValidatorSet) -> String {
fn tributary_db_folder(set: ExternalValidatorSet) -> String {
let root_path = serai_env::var("DB_PATH").expect("path to DB wasn't specified");
let network = match set.network {
NetworkId::Serai => panic!("creating Tributary for the Serai network"),
NetworkId::Bitcoin => "Bitcoin",
NetworkId::Ethereum => "Ethereum",
NetworkId::Monero => "Monero",
ExternalNetworkId::Bitcoin => "Bitcoin",
ExternalNetworkId::Ethereum => "Ethereum",
ExternalNetworkId::Monero => "Monero",
};
format!("{root_path}/tributary-{network}-{}", set.session.0)
}
pub(crate) fn tributary_db(set: ValidatorSet) -> Db {
pub(crate) fn tributary_db(set: ExternalValidatorSet) -> Db {
db(&format!("{}/db", tributary_db_folder(set)))
}
pub(crate) fn prune_tributary_db(set: ValidatorSet) {
pub(crate) fn prune_tributary_db(set: ExternalValidatorSet) {
log::info!("pruning data directory for tributary {set:?}");
let db = tributary_db_folder(set);
if fs::exists(&db).expect("couldn't check if tributary DB exists") {
@ -73,15 +72,15 @@ create_db! {
// The latest Tributary to have been retired for a network
// Since Tributaries are retired sequentially, this is informative to if any Tributary has been
// retired
RetiredTributary: (network: NetworkId) -> Session,
RetiredTributary: (network: ExternalNetworkId) -> Session,
// The last handled message from a Processor
LastProcessorMessage: (network: NetworkId) -> u64,
LastProcessorMessage: (network: ExternalNetworkId) -> u64,
// Cosigns we produced and tried to intake yet incurred an error while doing so
ErroneousCosigns: () -> Vec<SignedCosign>,
// The keys to confirm and set on the Serai network
KeysToConfirm: (set: ValidatorSet) -> KeyPair,
KeysToConfirm: (set: ExternalValidatorSet) -> KeyPair,
// The key was set on the Serai network
KeySet: (set: ValidatorSet) -> (),
KeySet: (set: ExternalValidatorSet) -> (),
}
}
@ -90,7 +89,7 @@ db_channel! {
// Cosigns we produced
SignedCosigns: () -> SignedCosign,
// Tributaries to clean up upon reboot
TributaryCleanup: () -> ValidatorSet,
TributaryCleanup: () -> ExternalValidatorSet,
}
}
@ -100,50 +99,50 @@ mod _internal_db {
db_channel! {
Coordinator {
// Tributary transactions to publish from the Processor messages
TributaryTransactionsFromProcessorMessages: (set: ValidatorSet) -> Transaction,
TributaryTransactionsFromProcessorMessages: (set: ExternalValidatorSet) -> Transaction,
// Tributary transactions to publish from the DKG confirmation task
TributaryTransactionsFromDkgConfirmation: (set: ValidatorSet) -> Transaction,
TributaryTransactionsFromDkgConfirmation: (set: ExternalValidatorSet) -> Transaction,
// Participants to remove
RemoveParticipant: (set: ValidatorSet) -> Participant,
RemoveParticipant: (set: ExternalValidatorSet) -> Participant,
}
}
}
pub(crate) struct TributaryTransactionsFromProcessorMessages;
impl TributaryTransactionsFromProcessorMessages {
pub(crate) fn send(txn: &mut impl DbTxn, set: ValidatorSet, tx: &Transaction) {
pub(crate) fn send(txn: &mut impl DbTxn, set: ExternalValidatorSet, tx: &Transaction) {
// If this set has yet to be retired, send this transaction
if RetiredTributary::get(txn, set.network).map(|session| session.0) < Some(set.session.0) {
_internal_db::TributaryTransactionsFromProcessorMessages::send(txn, set, tx);
}
}
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ValidatorSet) -> Option<Transaction> {
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Option<Transaction> {
_internal_db::TributaryTransactionsFromProcessorMessages::try_recv(txn, set)
}
}
pub(crate) struct TributaryTransactionsFromDkgConfirmation;
impl TributaryTransactionsFromDkgConfirmation {
pub(crate) fn send(txn: &mut impl DbTxn, set: ValidatorSet, tx: &Transaction) {
pub(crate) fn send(txn: &mut impl DbTxn, set: ExternalValidatorSet, tx: &Transaction) {
// If this set has yet to be retired, send this transaction
if RetiredTributary::get(txn, set.network).map(|session| session.0) < Some(set.session.0) {
_internal_db::TributaryTransactionsFromDkgConfirmation::send(txn, set, tx);
}
}
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ValidatorSet) -> Option<Transaction> {
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Option<Transaction> {
_internal_db::TributaryTransactionsFromDkgConfirmation::try_recv(txn, set)
}
}
pub(crate) struct RemoveParticipant;
impl RemoveParticipant {
pub(crate) fn send(txn: &mut impl DbTxn, set: ValidatorSet, participant: Participant) {
pub(crate) fn send(txn: &mut impl DbTxn, set: ExternalValidatorSet, participant: Participant) {
// If this set has yet to be retired, send this transaction
if RetiredTributary::get(txn, set.network).map(|session| session.0) < Some(set.session.0) {
_internal_db::RemoveParticipant::send(txn, set, &participant);
}
}
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ValidatorSet) -> Option<Participant> {
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Option<Participant> {
_internal_db::RemoveParticipant::try_recv(txn, set)
}
}

View file

@ -17,7 +17,7 @@ use serai_db::{DbTxn, Db as DbTrait};
use serai_client::{
primitives::SeraiAddress,
validator_sets::primitives::{ValidatorSet, musig_context, set_keys_message},
validator_sets::primitives::{ExternalValidatorSet, musig_context, set_keys_message},
};
use serai_task::{DoesNotError, ContinuallyRan};
@ -141,7 +141,7 @@ impl<CD: DbTrait, TD: DbTrait> ConfirmDkgTask<CD, TD> {
Self { db, set, tributary_db, key, signer: None }
}
fn slash(db: &mut CD, set: ValidatorSet, validator: SeraiAddress) {
fn slash(db: &mut CD, set: ExternalValidatorSet, validator: SeraiAddress) {
let mut txn = db.txn();
TributaryTransactionsFromDkgConfirmation::send(
&mut txn,
@ -153,7 +153,7 @@ impl<CD: DbTrait, TD: DbTrait> ConfirmDkgTask<CD, TD> {
fn preprocess(
db: &mut CD,
set: ValidatorSet,
set: ExternalValidatorSet,
attempt: u32,
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
signer: &mut Option<Signer>,
@ -162,7 +162,9 @@ impl<CD: DbTrait, TD: DbTrait> ConfirmDkgTask<CD, TD> {
let (machine, preprocess) = AlgorithmMachine::new(
schnorrkel(),
// We use a 1-of-1 Musig here as we don't know who will actually be in this Musig yet
musig(&musig_context(set), key, &[Ristretto::generator() * key.deref()]).unwrap().into(),
musig(&musig_context(set.into()), key, &[Ristretto::generator() * key.deref()])
.unwrap()
.into(),
)
.preprocess(&mut OsRng);
// We take the preprocess so we can use it in a distinct machine with the actual Musig
@ -256,8 +258,9 @@ impl<CD: DbTrait, TD: DbTrait> ContinuallyRan for ConfirmDkgTask<CD, TD> {
})
.collect::<Vec<_>>();
let keys =
musig(&musig_context(self.set.set), &self.key, &musig_public_keys).unwrap().into();
let keys = musig(&musig_context(self.set.set.into()), &self.key, &musig_public_keys)
.unwrap()
.into();
// Rebuild the machine
let (machine, preprocess_from_cache) =

View file

@ -14,8 +14,8 @@ use borsh::BorshDeserialize;
use tokio::sync::mpsc;
use serai_client::{
primitives::{NetworkId, PublicKey, SeraiAddress, Signature},
validator_sets::primitives::{ValidatorSet, KeyPair},
primitives::{ExternalNetworkId, PublicKey, SeraiAddress, Signature},
validator_sets::primitives::{ExternalValidatorSet, KeyPair},
Serai,
};
use message_queue::{Service, client::MessageQueue};
@ -153,14 +153,13 @@ async fn handle_network(
mut db: impl serai_db::Db,
message_queue: Arc<MessageQueue>,
serai: Arc<Serai>,
network: NetworkId,
network: ExternalNetworkId,
) {
// Spawn the task to publish batches for this network
{
let (publish_batch_task_def, publish_batch_task) = Task::new();
tokio::spawn(
PublishBatchTask::new(db.clone(), serai.clone(), network)
.unwrap()
.continually_run(publish_batch_task_def, vec![]),
);
// Forget its handle so it always runs in the background
@ -197,7 +196,7 @@ async fn handle_network(
match msg {
messages::ProcessorMessage::KeyGen(msg) => match msg {
messages::key_gen::ProcessorMessage::Participation { session, participation } => {
let set = ValidatorSet { network, session };
let set = ExternalValidatorSet { network, session };
TributaryTransactionsFromProcessorMessages::send(
&mut txn,
set,
@ -211,7 +210,7 @@ async fn handle_network(
} => {
KeysToConfirm::set(
&mut txn,
ValidatorSet { network, session },
ExternalValidatorSet { network, session },
&KeyPair(
PublicKey::from_raw(substrate_key),
network_key
@ -221,15 +220,15 @@ async fn handle_network(
);
}
messages::key_gen::ProcessorMessage::Blame { session, participant } => {
RemoveParticipant::send(&mut txn, ValidatorSet { network, session }, participant);
RemoveParticipant::send(&mut txn, ExternalValidatorSet { network, session }, participant);
}
},
messages::ProcessorMessage::Sign(msg) => match msg {
messages::sign::ProcessorMessage::InvalidParticipant { session, participant } => {
RemoveParticipant::send(&mut txn, ValidatorSet { network, session }, participant);
RemoveParticipant::send(&mut txn, ExternalValidatorSet { network, session }, participant);
}
messages::sign::ProcessorMessage::Preprocesses { id, preprocesses } => {
let set = ValidatorSet { network, session: id.session };
let set = ExternalValidatorSet { network, session: id.session };
if id.attempt == 0 {
// Batches are declared by their intent to be signed
if let messages::sign::VariantSignId::Batch(hash) = id.id {
@ -254,7 +253,7 @@ async fn handle_network(
);
}
messages::sign::ProcessorMessage::Shares { id, shares } => {
let set = ValidatorSet { network, session: id.session };
let set = ExternalValidatorSet { network, session: id.session };
TributaryTransactionsFromProcessorMessages::send(
&mut txn,
set,
@ -282,7 +281,7 @@ async fn handle_network(
} => {
SlashReports::set(
&mut txn,
ValidatorSet { network, session },
ExternalValidatorSet { network, session },
slash_report,
Signature(signature),
);
@ -298,7 +297,7 @@ async fn handle_network(
.push(plan.transaction_plan_id);
}
for (session, plans) in by_session {
let set = ValidatorSet { network, session };
let set = ExternalValidatorSet { network, session };
SubstrateBlockPlans::set(&mut txn, set, block, &plans);
TributaryTransactionsFromProcessorMessages::send(
&mut txn,
@ -481,10 +480,7 @@ async fn main() {
);
// Handle each of the networks
for network in serai_client::primitives::NETWORKS {
if network == NetworkId::Serai {
continue;
}
for network in serai_client::primitives::EXTERNAL_NETWORKS {
tokio::spawn(handle_network(db.clone(), message_queue.clone(), serai.clone(), network));
}

View file

@ -9,7 +9,7 @@ use tokio::sync::mpsc;
use serai_db::{DbTxn, Db as DbTrait};
use serai_client::validator_sets::primitives::{Session, ValidatorSet};
use serai_client::validator_sets::primitives::{Session, ExternalValidatorSet};
use message_queue::{Service, Metadata, client::MessageQueue};
use tributary_sdk::Tributary;
@ -27,8 +27,8 @@ pub(crate) struct SubstrateTask<P: P2p> {
pub(crate) message_queue: Arc<MessageQueue>,
pub(crate) p2p: P,
pub(crate) p2p_add_tributary:
mpsc::UnboundedSender<(ValidatorSet, Tributary<Db, Transaction, P>)>,
pub(crate) p2p_retire_tributary: mpsc::UnboundedSender<ValidatorSet>,
mpsc::UnboundedSender<(ExternalValidatorSet, Tributary<Db, Transaction, P>)>,
pub(crate) p2p_retire_tributary: mpsc::UnboundedSender<ExternalValidatorSet>,
}
impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
@ -38,7 +38,7 @@ impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
let mut made_progress = false;
// Handle the Canonical events
for network in serai_client::primitives::NETWORKS {
for network in serai_client::primitives::EXTERNAL_NETWORKS {
loop {
let mut txn = self.db.txn();
let Some(msg) = serai_coordinator_substrate::Canonical::try_recv(&mut txn, network)
@ -48,7 +48,7 @@ impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
match msg {
messages::substrate::CoordinatorMessage::SetKeys { session, .. } => {
KeySet::set(&mut txn, ValidatorSet { network, session }, &());
KeySet::set(&mut txn, ExternalValidatorSet { network, session }, &());
}
messages::substrate::CoordinatorMessage::SlashesReported { session } => {
let prior_retired = crate::db::RetiredTributary::get(&txn, network);
@ -58,7 +58,7 @@ impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
crate::db::RetiredTributary::set(&mut txn, network, &session);
self
.p2p_retire_tributary
.send(ValidatorSet { network, session })
.send(ExternalValidatorSet { network, session })
.expect("p2p retire_tributary channel dropped?");
}
messages::substrate::CoordinatorMessage::Block { .. } => {}
@ -108,7 +108,10 @@ impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
*/
crate::db::TributaryCleanup::send(
&mut txn,
&ValidatorSet { network: new_set.set.network, session: Session(historic_session) },
&ExternalValidatorSet {
network: new_set.set.network,
session: Session(historic_session),
},
);
}

View file

@ -11,7 +11,7 @@ use tokio::sync::mpsc;
use serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
use scale::Encode;
use serai_client::validator_sets::primitives::ValidatorSet;
use serai_client::validator_sets::primitives::ExternalValidatorSet;
use tributary_sdk::{TransactionKind, TransactionError, ProvidedError, TransactionTrait, Tributary};
@ -33,13 +33,13 @@ use crate::{
create_db! {
Coordinator {
PublishOnRecognition: (set: ValidatorSet, topic: Topic) -> Transaction,
PublishOnRecognition: (set: ExternalValidatorSet, topic: Topic) -> Transaction,
}
}
db_channel! {
Coordinator {
PendingCosigns: (set: ValidatorSet) -> CosignIntent,
PendingCosigns: (set: ExternalValidatorSet) -> CosignIntent,
}
}
@ -48,7 +48,7 @@ db_channel! {
/// This is not a well-designed function. This is specific to the context in which its called,
/// within this file. It should only be considered an internal helper for this domain alone.
async fn provide_transaction<TD: DbTrait, P: P2p>(
set: ValidatorSet,
set: ExternalValidatorSet,
tributary: &Tributary<TD, Transaction, P>,
tx: Transaction,
) {
@ -211,7 +211,7 @@ async fn add_signed_unsigned_transaction<TD: DbTrait, P: P2p>(
}
async fn add_with_recognition_check<TD: DbTrait, P: P2p>(
set: ValidatorSet,
set: ExternalValidatorSet,
tributary_db: &mut TD,
tributary: &Tributary<TD, Transaction, P>,
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
@ -350,7 +350,7 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactio
/// Takes the messages from ScanTributaryTask and publishes them to the message-queue.
pub(crate) struct TributaryProcessorMessagesTask<TD: DbTrait> {
tributary_db: TD,
set: ValidatorSet,
set: ExternalValidatorSet,
message_queue: Arc<MessageQueue>,
}
impl<TD: DbTrait> ContinuallyRan for TributaryProcessorMessagesTask<TD> {
@ -430,7 +430,7 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for SignSlashReportTask<CD
/// Run the scan task whenever the Tributary adds a new block.
async fn scan_on_new_block<CD: DbTrait, TD: DbTrait, P: P2p>(
db: CD,
set: ValidatorSet,
set: ExternalValidatorSet,
tributary: Tributary<TD, Transaction, P>,
scan_tributary_task: TaskHandle,
tasks_to_keep_alive: Vec<TaskHandle>,
@ -469,7 +469,7 @@ pub(crate) async fn spawn_tributary<P: P2p>(
db: Db,
message_queue: Arc<MessageQueue>,
p2p: P,
p2p_add_tributary: &mpsc::UnboundedSender<(ValidatorSet, Tributary<Db, Transaction, P>)>,
p2p_add_tributary: &mpsc::UnboundedSender<(ExternalValidatorSet, Tributary<Db, Transaction, P>)>,
set: NewSetInformation,
serai_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
) {

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use futures::stream::{StreamExt, FuturesOrdered};
use serai_client::Serai;
use serai_client::{validator_sets::primitives::ExternalValidatorSet, Serai};
use messages::substrate::{InInstructionResult, ExecutedBatch, CoordinatorMessage};
@ -152,6 +152,7 @@ impl<D: Db> ContinuallyRan for CanonicalEventStream<D> {
else {
panic!("SetRetired event wasn't a SetRetired event: {set_retired:?}");
};
let Ok(set) = ExternalValidatorSet::try_from(*set) else { continue };
crate::Canonical::send(
&mut txn,
set.network,
@ -159,7 +160,7 @@ impl<D: Db> ContinuallyRan for CanonicalEventStream<D> {
);
}
for network in serai_client::primitives::NETWORKS {
for network in serai_client::primitives::EXTERNAL_NETWORKS {
let mut batch = None;
for this_batch in &block.batch_events {
let serai_client::in_instructions::InInstructionsEvent::Batch {
@ -201,7 +202,7 @@ impl<D: Db> ContinuallyRan for CanonicalEventStream<D> {
let serai_client::coins::CoinsEvent::BurnWithInstruction { from: _, instruction } =
&burn
else {
panic!("Burn event wasn't a Burn.in event: {burn:?}");
panic!("BurnWithInstruction event wasn't a BurnWithInstruction event: {burn:?}");
};
if instruction.balance.coin.network() == network {
burns.push(instruction.clone());

View file

@ -4,8 +4,8 @@ use std::sync::Arc;
use futures::stream::{StreamExt, FuturesOrdered};
use serai_client::{
primitives::{NetworkId, SeraiAddress, EmbeddedEllipticCurve},
validator_sets::primitives::MAX_KEY_SHARES_PER_SET,
primitives::{SeraiAddress, EmbeddedEllipticCurve},
validator_sets::primitives::{MAX_KEY_SHARES_PER_SET, ExternalValidatorSet},
Serai,
};
@ -130,16 +130,13 @@ impl<D: Db> ContinuallyRan for EphemeralEventStream<D> {
let serai_client::validator_sets::ValidatorSetsEvent::NewSet { set } = &new_set else {
panic!("NewSet event wasn't a NewSet event: {new_set:?}");
};
// We only coordinate over external networks
if set.network == NetworkId::Serai {
continue;
}
let Ok(set) = ExternalValidatorSet::try_from(*set) else { continue };
let serai = self.serai.as_of(block.block_hash);
let serai = serai.validator_sets();
let Some(validators) =
serai.participants(set.network).await.map_err(|e| format!("{e:?}"))?
serai.participants(set.network.into()).await.map_err(|e| format!("{e:?}"))?
else {
Err(format!(
"block #{block_number} declared a new set but didn't have the participants"
@ -222,11 +219,11 @@ impl<D: Db> ContinuallyRan for EphemeralEventStream<D> {
}
let mut new_set = NewSetInformation {
set: *set,
set,
serai_block: block.block_hash,
declaration_time: block.time,
// TODO: Why do we have this as an explicit field here?
// Shouldn't this be inlined into the Processor's key gen code, where it's used?
// TODO: This should be inlined into the Processor's key gen code
// It's legacy from when we removed participants from the key gen
threshold: ((total_weight * 2) / 3) + 1,
validators,
evrf_public_keys,
@ -246,7 +243,8 @@ impl<D: Db> ContinuallyRan for EphemeralEventStream<D> {
else {
panic!("AcceptedHandover event wasn't a AcceptedHandover event: {accepted_handover:?}");
};
crate::SignSlashReport::send(&mut txn, *set);
let Ok(set) = ExternalValidatorSet::try_from(*set) else { continue };
crate::SignSlashReport::send(&mut txn, set);
}
txn.commit();

View file

@ -10,8 +10,8 @@ use borsh::{BorshSerialize, BorshDeserialize};
use dkg::Participant;
use serai_client::{
primitives::{NetworkId, SeraiAddress, Signature},
validator_sets::primitives::{Session, ValidatorSet, KeyPair, SlashReport},
primitives::{ExternalNetworkId, SeraiAddress, Signature},
validator_sets::primitives::{Session, ExternalValidatorSet, KeyPair, SlashReport},
in_instructions::primitives::SignedBatch,
Transaction,
};
@ -35,7 +35,7 @@ pub use publish_slash_report::PublishSlashReportTask;
#[borsh(init = init_participant_indexes)]
pub struct NewSetInformation {
/// The set.
pub set: ValidatorSet,
pub set: ExternalValidatorSet,
/// The Serai block which declared it.
pub serai_block: [u8; 32],
/// The time of the block which declared it, in seconds.
@ -82,24 +82,24 @@ mod _public_db {
db_channel!(
CoordinatorSubstrate {
// Canonical messages to send to the processor
Canonical: (network: NetworkId) -> messages::substrate::CoordinatorMessage,
Canonical: (network: ExternalNetworkId) -> messages::substrate::CoordinatorMessage,
// Relevant new set, from an ephemeral event stream
NewSet: () -> NewSetInformation,
// Potentially relevant sign slash report, from an ephemeral event stream
SignSlashReport: (set: ValidatorSet) -> (),
SignSlashReport: (set: ExternalValidatorSet) -> (),
// Signed batches to publish onto the Serai network
SignedBatches: (network: NetworkId) -> SignedBatch,
SignedBatches: (network: ExternalNetworkId) -> SignedBatch,
}
);
create_db!(
CoordinatorSubstrate {
// Keys to set on the Serai network
Keys: (network: NetworkId) -> (Session, Vec<u8>),
Keys: (network: ExternalNetworkId) -> (Session, Vec<u8>),
// Slash reports to publish onto the Serai network
SlashReports: (network: NetworkId) -> (Session, Vec<u8>),
SlashReports: (network: ExternalNetworkId) -> (Session, Vec<u8>),
}
);
}
@ -109,7 +109,7 @@ pub struct Canonical;
impl Canonical {
pub(crate) fn send(
txn: &mut impl DbTxn,
network: NetworkId,
network: ExternalNetworkId,
msg: &messages::substrate::CoordinatorMessage,
) {
_public_db::Canonical::send(txn, network, msg);
@ -117,7 +117,7 @@ impl Canonical {
/// Try to receive a canonical event, returning `None` if there is none to receive.
pub fn try_recv(
txn: &mut impl DbTxn,
network: NetworkId,
network: ExternalNetworkId,
) -> Option<messages::substrate::CoordinatorMessage> {
_public_db::Canonical::try_recv(txn, network)
}
@ -141,12 +141,12 @@ impl NewSet {
/// notifications for all relevant validator sets will be included.
pub struct SignSlashReport;
impl SignSlashReport {
pub(crate) fn send(txn: &mut impl DbTxn, set: ValidatorSet) {
pub(crate) fn send(txn: &mut impl DbTxn, set: ExternalValidatorSet) {
_public_db::SignSlashReport::send(txn, set, &());
}
/// Try to receive a notification to sign a slash report, returning `None` if there is none to
/// receive.
pub fn try_recv(txn: &mut impl DbTxn, set: ValidatorSet) -> Option<()> {
pub fn try_recv(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Option<()> {
_public_db::SignSlashReport::try_recv(txn, set)
}
}
@ -160,7 +160,7 @@ impl Keys {
/// reported at once.
pub fn set(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
key_pair: KeyPair,
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
signature: Signature,
@ -180,7 +180,10 @@ impl Keys {
);
_public_db::Keys::set(txn, set.network, &(set.session, tx.encode()));
}
pub(crate) fn take(txn: &mut impl DbTxn, network: NetworkId) -> Option<(Session, Transaction)> {
pub(crate) fn take(
txn: &mut impl DbTxn,
network: ExternalNetworkId,
) -> Option<(Session, Transaction)> {
let (session, tx) = _public_db::Keys::take(txn, network)?;
Some((session, <_>::decode(&mut tx.as_slice()).unwrap()))
}
@ -193,7 +196,7 @@ impl SignedBatches {
pub fn send(txn: &mut impl DbTxn, batch: &SignedBatch) {
_public_db::SignedBatches::send(txn, batch.batch.network, batch);
}
pub(crate) fn try_recv(txn: &mut impl DbTxn, network: NetworkId) -> Option<SignedBatch> {
pub(crate) fn try_recv(txn: &mut impl DbTxn, network: ExternalNetworkId) -> Option<SignedBatch> {
_public_db::SignedBatches::try_recv(txn, network)
}
}
@ -207,7 +210,7 @@ impl SlashReports {
/// slashes reported at once.
pub fn set(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
slash_report: SlashReport,
signature: Signature,
) {
@ -225,7 +228,10 @@ impl SlashReports {
);
_public_db::SlashReports::set(txn, set.network, &(set.session, tx.encode()));
}
pub(crate) fn take(txn: &mut impl DbTxn, network: NetworkId) -> Option<(Session, Transaction)> {
pub(crate) fn take(
txn: &mut impl DbTxn,
network: ExternalNetworkId,
) -> Option<(Session, Transaction)> {
let (session, tx) = _public_db::SlashReports::take(txn, network)?;
Some((session, <_>::decode(&mut tx.as_slice()).unwrap()))
}

View file

@ -2,7 +2,7 @@ use core::future::Future;
use std::sync::Arc;
#[rustfmt::skip]
use serai_client::{primitives::NetworkId, in_instructions::primitives::SignedBatch, SeraiError, Serai};
use serai_client::{primitives::ExternalNetworkId, in_instructions::primitives::SignedBatch, SeraiError, Serai};
use serai_db::{Get, DbTxn, Db, create_db};
use serai_task::ContinuallyRan;
@ -11,8 +11,8 @@ use crate::SignedBatches;
create_db!(
CoordinatorSubstrate {
LastPublishedBatch: (network: NetworkId) -> u32,
BatchesToPublish: (network: NetworkId, batch: u32) -> SignedBatch,
LastPublishedBatch: (network: ExternalNetworkId) -> u32,
BatchesToPublish: (network: ExternalNetworkId, batch: u32) -> SignedBatch,
}
);
@ -20,19 +20,13 @@ create_db!(
pub struct PublishBatchTask<D: Db> {
db: D,
serai: Arc<Serai>,
network: NetworkId,
network: ExternalNetworkId,
}
impl<D: Db> PublishBatchTask<D> {
/// Create a task to publish `SignedBatch`s onto Serai.
///
/// Returns None if `network == NetworkId::Serai`.
// TODO: ExternalNetworkId
pub fn new(db: D, serai: Arc<Serai>, network: NetworkId) -> Option<Self> {
if network == NetworkId::Serai {
None?
};
Some(Self { db, serai, network })
pub fn new(db: D, serai: Arc<Serai>, network: ExternalNetworkId) -> Self {
Self { db, serai, network }
}
}

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use serai_db::{DbTxn, Db};
use serai_client::{primitives::NetworkId, validator_sets::primitives::Session, Serai};
use serai_client::{primitives::ExternalNetworkId, validator_sets::primitives::Session, Serai};
use serai_task::ContinuallyRan;
@ -24,7 +24,7 @@ impl<D: Db> PublishSlashReportTask<D> {
impl<D: Db> PublishSlashReportTask<D> {
// Returns if a slash report was successfully published
async fn publish(&mut self, network: NetworkId) -> Result<bool, String> {
async fn publish(&mut self, network: ExternalNetworkId) -> Result<bool, String> {
let mut txn = self.db.txn();
let Some((session, slash_report)) = SlashReports::take(&mut txn, network) else {
// No slash report to publish
@ -36,7 +36,7 @@ impl<D: Db> PublishSlashReportTask<D> {
let serai = self.serai.as_of_latest_finalized_block().await.map_err(|e| format!("{e:?}"))?;
let serai = serai.validator_sets();
let session_after_slash_report = Session(session.0 + 1);
let current_session = serai.session(network).await.map_err(|e| format!("{e:?}"))?;
let current_session = serai.session(network.into()).await.map_err(|e| format!("{e:?}"))?;
let current_session = current_session.map(|session| session.0);
// Only attempt to publish the slash report for session #n while session #n+1 is still
// active
@ -84,11 +84,7 @@ impl<D: Db> ContinuallyRan for PublishSlashReportTask<D> {
async move {
let mut made_progress = false;
let mut error = None;
for network in serai_client::primitives::NETWORKS {
if network == NetworkId::Serai {
continue;
};
for network in serai_client::primitives::EXTERNAL_NETWORKS {
let network_res = self.publish(network).await;
// We made progress if any network successfully published their slash report
made_progress |= network_res == Ok(true);

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use serai_db::{DbTxn, Db};
use serai_client::{primitives::NetworkId, validator_sets::primitives::ValidatorSet, Serai};
use serai_client::{validator_sets::primitives::ExternalValidatorSet, Serai};
use serai_task::ContinuallyRan;
@ -28,11 +28,7 @@ impl<D: Db> ContinuallyRan for SetKeysTask<D> {
fn run_iteration(&mut self) -> impl Send + Future<Output = Result<bool, Self::Error>> {
async move {
let mut made_progress = false;
for network in serai_client::primitives::NETWORKS {
if network == NetworkId::Serai {
continue;
};
for network in serai_client::primitives::EXTERNAL_NETWORKS {
let mut txn = self.db.txn();
let Some((session, keys)) = Keys::take(&mut txn, network) else {
// No keys to set
@ -44,7 +40,7 @@ impl<D: Db> ContinuallyRan for SetKeysTask<D> {
let serai =
self.serai.as_of_latest_finalized_block().await.map_err(|e| format!("{e:?}"))?;
let serai = serai.validator_sets();
let current_session = serai.session(network).await.map_err(|e| format!("{e:?}"))?;
let current_session = serai.session(network.into()).await.map_err(|e| format!("{e:?}"))?;
let current_session = current_session.map(|session| session.0);
// Only attempt to set these keys if this isn't a retired session
if Some(session.0) < current_session {
@ -62,7 +58,7 @@ impl<D: Db> ContinuallyRan for SetKeysTask<D> {
// If this session already has had its keys set, move on
if serai
.keys(ValidatorSet { network, session })
.keys(ExternalValidatorSet { network, session })
.await
.map_err(|e| format!("{e:?}"))?
.is_some()

View file

@ -3,7 +3,7 @@ use std::collections::HashMap;
use scale::Encode;
use borsh::{BorshSerialize, BorshDeserialize};
use serai_client::{primitives::SeraiAddress, validator_sets::primitives::ValidatorSet};
use serai_client::{primitives::SeraiAddress, validator_sets::primitives::ExternalValidatorSet};
use messages::sign::{VariantSignId, SignId};
@ -97,7 +97,7 @@ impl Topic {
/// The SignId for this topic
///
/// Returns None if Topic isn't Topic::Sign
pub(crate) fn sign_id(self, set: ValidatorSet) -> Option<messages::sign::SignId> {
pub(crate) fn sign_id(self, set: ExternalValidatorSet) -> Option<messages::sign::SignId> {
#[allow(clippy::match_same_arms)]
match self {
Topic::RemoveParticipant { .. } => None,
@ -115,7 +115,7 @@ impl Topic {
/// Returns None if Topic isn't Topic::DkgConfirmation.
pub(crate) fn dkg_confirmation_sign_id(
self,
set: ValidatorSet,
set: ExternalValidatorSet,
) -> Option<messages::sign::SignId> {
#[allow(clippy::match_same_arms)]
match self {
@ -227,41 +227,48 @@ pub(crate) enum DataSet<D: Borshy> {
create_db!(
CoordinatorTributary {
// The last handled tributary block's (number, hash)
LastHandledTributaryBlock: (set: ValidatorSet) -> (u64, [u8; 32]),
LastHandledTributaryBlock: (set: ExternalValidatorSet) -> (u64, [u8; 32]),
// The slash points a validator has accrued, with u32::MAX representing a fatal slash.
SlashPoints: (set: ValidatorSet, validator: SeraiAddress) -> u32,
SlashPoints: (set: ExternalValidatorSet, validator: SeraiAddress) -> u32,
// The cosign intent for a Substrate block
CosignIntents: (set: ValidatorSet, substrate_block_hash: [u8; 32]) -> CosignIntent,
CosignIntents: (set: ExternalValidatorSet, substrate_block_hash: [u8; 32]) -> CosignIntent,
// The latest Substrate block to cosign.
LatestSubstrateBlockToCosign: (set: ValidatorSet) -> [u8; 32],
LatestSubstrateBlockToCosign: (set: ExternalValidatorSet) -> [u8; 32],
// The hash of the block we're actively cosigning.
ActivelyCosigning: (set: ValidatorSet) -> [u8; 32],
ActivelyCosigning: (set: ExternalValidatorSet) -> [u8; 32],
// If this block has already been cosigned.
Cosigned: (set: ValidatorSet, substrate_block_hash: [u8; 32]) -> (),
Cosigned: (set: ExternalValidatorSet, substrate_block_hash: [u8; 32]) -> (),
// The plans to recognize upon a `Transaction::SubstrateBlock` being included on-chain.
SubstrateBlockPlans: (set: ValidatorSet, substrate_block_hash: [u8; 32]) -> Vec<[u8; 32]>,
SubstrateBlockPlans: (
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32]
) -> Vec<[u8; 32]>,
// The weight accumulated for a topic.
AccumulatedWeight: (set: ValidatorSet, topic: Topic) -> u16,
AccumulatedWeight: (set: ExternalValidatorSet, topic: Topic) -> u16,
// The entries accumulated for a topic, by validator.
Accumulated: <D: Borshy>(set: ValidatorSet, topic: Topic, validator: SeraiAddress) -> D,
Accumulated: <D: Borshy>(
set: ExternalValidatorSet,
topic: Topic,
validator: SeraiAddress
) -> D,
// Topics to be recognized as of a certain block number due to the reattempt protocol.
Reattempt: (set: ValidatorSet, block_number: u64) -> Vec<Topic>,
Reattempt: (set: ExternalValidatorSet, block_number: u64) -> Vec<Topic>,
}
);
db_channel!(
CoordinatorTributary {
// Messages to send to the processor
ProcessorMessages: (set: ValidatorSet) -> messages::CoordinatorMessage,
ProcessorMessages: (set: ExternalValidatorSet) -> messages::CoordinatorMessage,
// Messages for the DKG confirmation
DkgConfirmationMessages: (set: ValidatorSet) -> messages::sign::CoordinatorMessage,
DkgConfirmationMessages: (set: ExternalValidatorSet) -> messages::sign::CoordinatorMessage,
// Topics which have been explicitly recognized
RecognizedTopics: (set: ValidatorSet) -> Topic,
RecognizedTopics: (set: ExternalValidatorSet) -> Topic,
}
);
@ -269,13 +276,13 @@ pub(crate) struct TributaryDb;
impl TributaryDb {
pub(crate) fn last_handled_tributary_block(
getter: &impl Get,
set: ValidatorSet,
set: ExternalValidatorSet,
) -> Option<(u64, [u8; 32])> {
LastHandledTributaryBlock::get(getter, set)
}
pub(crate) fn set_last_handled_tributary_block(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
block_number: u64,
block_hash: [u8; 32],
) {
@ -284,23 +291,26 @@ impl TributaryDb {
pub(crate) fn latest_substrate_block_to_cosign(
getter: &impl Get,
set: ValidatorSet,
set: ExternalValidatorSet,
) -> Option<[u8; 32]> {
LatestSubstrateBlockToCosign::get(getter, set)
}
pub(crate) fn set_latest_substrate_block_to_cosign(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32],
) {
LatestSubstrateBlockToCosign::set(txn, set, &substrate_block_hash);
}
pub(crate) fn actively_cosigning(txn: &mut impl DbTxn, set: ValidatorSet) -> Option<[u8; 32]> {
pub(crate) fn actively_cosigning(
txn: &mut impl DbTxn,
set: ExternalValidatorSet,
) -> Option<[u8; 32]> {
ActivelyCosigning::get(txn, set)
}
pub(crate) fn start_cosigning(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32],
substrate_block_number: u64,
) {
@ -320,33 +330,33 @@ impl TributaryDb {
},
);
}
pub(crate) fn finish_cosigning(txn: &mut impl DbTxn, set: ValidatorSet) {
pub(crate) fn finish_cosigning(txn: &mut impl DbTxn, set: ExternalValidatorSet) {
assert!(ActivelyCosigning::take(txn, set).is_some(), "finished cosigning but not cosigning");
}
pub(crate) fn mark_cosigned(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32],
) {
Cosigned::set(txn, set, substrate_block_hash, &());
}
pub(crate) fn cosigned(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32],
) -> bool {
Cosigned::get(txn, set, substrate_block_hash).is_some()
}
pub(crate) fn recognize_topic(txn: &mut impl DbTxn, set: ValidatorSet, topic: Topic) {
pub(crate) fn recognize_topic(txn: &mut impl DbTxn, set: ExternalValidatorSet, topic: Topic) {
AccumulatedWeight::set(txn, set, topic, &0);
RecognizedTopics::send(txn, set, &topic);
}
pub(crate) fn recognized(getter: &impl Get, set: ValidatorSet, topic: Topic) -> bool {
pub(crate) fn recognized(getter: &impl Get, set: ExternalValidatorSet, topic: Topic) -> bool {
AccumulatedWeight::get(getter, set, topic).is_some()
}
pub(crate) fn start_of_block(txn: &mut impl DbTxn, set: ValidatorSet, block_number: u64) {
pub(crate) fn start_of_block(txn: &mut impl DbTxn, set: ExternalValidatorSet, block_number: u64) {
for topic in Reattempt::take(txn, set, block_number).unwrap_or(vec![]) {
/*
TODO: Slash all people who preprocessed but didn't share, and add a delay to their
@ -376,7 +386,7 @@ impl TributaryDb {
pub(crate) fn fatal_slash(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
validator: SeraiAddress,
reason: &str,
) {
@ -386,7 +396,7 @@ impl TributaryDb {
pub(crate) fn is_fatally_slashed(
getter: &impl Get,
set: ValidatorSet,
set: ExternalValidatorSet,
validator: SeraiAddress,
) -> bool {
SlashPoints::get(getter, set, validator).unwrap_or(0) == u32::MAX
@ -395,7 +405,7 @@ impl TributaryDb {
#[allow(clippy::too_many_arguments)]
pub(crate) fn accumulate<D: Borshy>(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
validators: &[SeraiAddress],
total_weight: u16,
block_number: u64,
@ -511,7 +521,7 @@ impl TributaryDb {
pub(crate) fn send_message(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
message: impl Into<messages::CoordinatorMessage>,
) {
ProcessorMessages::send(txn, set, &message.into());

View file

@ -10,7 +10,7 @@ use dkg::Participant;
use serai_client::{
primitives::SeraiAddress,
validator_sets::primitives::{ValidatorSet, Slash},
validator_sets::primitives::{ExternalValidatorSet, Slash},
};
use serai_db::*;
@ -41,7 +41,10 @@ pub use db::Topic;
pub struct ProcessorMessages;
impl ProcessorMessages {
/// Try to receive a message to send to a Processor.
pub fn try_recv(txn: &mut impl DbTxn, set: ValidatorSet) -> Option<messages::CoordinatorMessage> {
pub fn try_recv(
txn: &mut impl DbTxn,
set: ExternalValidatorSet,
) -> Option<messages::CoordinatorMessage> {
db::ProcessorMessages::try_recv(txn, set)
}
}
@ -58,7 +61,7 @@ impl DkgConfirmationMessages {
/// across validator sets, with no guarantees of uniqueness across contexts.
pub fn try_recv(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
) -> Option<messages::sign::CoordinatorMessage> {
db::DkgConfirmationMessages::try_recv(txn, set)
}
@ -70,12 +73,12 @@ impl CosignIntents {
/// Provide a CosignIntent for this Tributary.
///
/// This must be done before the associated `Transaction::Cosign` is provided.
pub fn provide(txn: &mut impl DbTxn, set: ValidatorSet, intent: &CosignIntent) {
pub fn provide(txn: &mut impl DbTxn, set: ExternalValidatorSet, intent: &CosignIntent) {
db::CosignIntents::set(txn, set, intent.block_hash, intent);
}
fn take(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32],
) -> Option<CosignIntent> {
db::CosignIntents::take(txn, set, substrate_block_hash)
@ -88,13 +91,13 @@ impl RecognizedTopics {
/// If this topic has been recognized by this Tributary.
///
/// This will either be by explicit recognition or participation.
pub fn recognized(getter: &impl Get, set: ValidatorSet, topic: Topic) -> bool {
pub fn recognized(getter: &impl Get, set: ExternalValidatorSet, topic: Topic) -> bool {
TributaryDb::recognized(getter, set, topic)
}
/// The next topic requiring recognition which has been recognized by this Tributary.
pub fn try_recv_topic_requiring_recognition(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
) -> Option<Topic> {
db::RecognizedTopics::try_recv(txn, set)
}
@ -109,7 +112,7 @@ impl SubstrateBlockPlans {
/// This must be done before the associated `Transaction::Cosign` is provided.
pub fn set(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32],
plans: &Vec<[u8; 32]>,
) {
@ -117,7 +120,7 @@ impl SubstrateBlockPlans {
}
fn take(
txn: &mut impl DbTxn,
set: ValidatorSet,
set: ExternalValidatorSet,
substrate_block_hash: [u8; 32],
) -> Option<Vec<[u8; 32]>> {
db::SubstrateBlockPlans::take(txn, set, substrate_block_hash)

View file

@ -1,24 +0,0 @@
[package]
name = "tiny-bip39"
version = "1.0.2"
description = "tiny-bip39 which patches to the latest update"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/tiny-bip39"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
rust-version = "1.70"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-machete]
ignored = ["tiny-bip39"]
[lib]
name = "bip39"
path = "src/lib.rs"
[dependencies]
tiny-bip39 = "2"

View file

@ -1 +0,0 @@
pub use bip39::*;

View file

@ -90,7 +90,7 @@ use bitcoin_serai::bitcoin::{
};
use serai_client::{
primitives::{MAX_DATA_LEN, Coin, NetworkId, Amount, Balance},
primitives::{MAX_DATA_LEN, ExternalNetworkId, ExternalCoin, Amount, Balance},
networks::bitcoin::Address,
};
*/

View file

@ -14,7 +14,7 @@ use borsh::{BorshSerialize, BorshDeserialize};
use serai_db::Get;
use serai_client::{
primitives::{Coin, Amount, Balance, ExternalAddress},
primitives::{ExternalCoin, Amount, ExternalBalance, ExternalAddress},
networks::bitcoin::Address,
};
@ -127,8 +127,8 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
self.presumed_origin.clone()
}
fn balance(&self) -> Balance {
Balance { coin: Coin::Bitcoin, amount: Amount(self.output.value()) }
fn balance(&self) -> ExternalBalance {
ExternalBalance { coin: ExternalCoin::Bitcoin, amount: Amount(self.output.value()) }
}
fn data(&self) -> &[u8] {

View file

@ -2,7 +2,7 @@ use core::future::Future;
use bitcoin_serai::rpc::{RpcError, Rpc as BRpc};
use serai_client::primitives::{NetworkId, Coin, Amount};
use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount};
use serai_db::Db;
use scanner::ScannerFeed;
@ -21,7 +21,7 @@ pub(crate) struct Rpc<D: Db> {
}
impl<D: Db> ScannerFeed for Rpc<D> {
const NETWORK: NetworkId = NetworkId::Bitcoin;
const NETWORK: ExternalNetworkId = ExternalNetworkId::Bitcoin;
// 6 confirmations is widely accepted as secure and shouldn't occur
const CONFIRMATIONS: u64 = 6;
// The window length should be roughly an hour
@ -118,8 +118,8 @@ impl<D: Db> ScannerFeed for Rpc<D> {
}
}
fn dust(coin: Coin) -> Amount {
assert_eq!(coin, Coin::Bitcoin);
fn dust(coin: ExternalCoin) -> Amount {
assert_eq!(coin, ExternalCoin::Bitcoin);
/*
A Taproot input is:
@ -158,11 +158,11 @@ impl<D: Db> ScannerFeed for Rpc<D> {
fn cost_to_aggregate(
&self,
coin: Coin,
coin: ExternalCoin,
_reference_block: &Self::Block,
) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>> {
async move {
assert_eq!(coin, Coin::Bitcoin);
assert_eq!(coin, ExternalCoin::Bitcoin);
// TODO
Ok(Amount(0))
}

View file

@ -8,7 +8,7 @@ use bitcoin_serai::{
};
use serai_client::{
primitives::{Coin, Amount},
primitives::{ExternalCoin, Amount},
networks::bitcoin::Address,
};
@ -59,7 +59,7 @@ fn signable_transaction<D: Db>(
.map(|payment| {
(ScriptBuf::from(payment.address().clone()), {
let balance = payment.balance();
assert_eq!(balance.coin, Coin::Bitcoin);
assert_eq!(balance.coin, ExternalCoin::Bitcoin);
balance.amount.0
})
})

View file

@ -8,7 +8,7 @@ use scale::{Encode, Decode};
use borsh::{BorshSerialize, BorshDeserialize};
use serai_client::{
primitives::{NetworkId, Coin, Amount, Balance},
primitives::{ExternalNetworkId, ExternalCoin, Amount, ExternalBalance},
networks::ethereum::Address,
};
@ -17,20 +17,20 @@ use ethereum_router::{Coin as EthereumCoin, InInstruction as EthereumInInstructi
use crate::{DAI, ETHER_DUST};
fn coin_to_serai_coin(coin: &EthereumCoin) -> Option<Coin> {
fn coin_to_serai_coin(coin: &EthereumCoin) -> Option<ExternalCoin> {
match coin {
EthereumCoin::Ether => Some(Coin::Ether),
EthereumCoin::Ether => Some(ExternalCoin::Ether),
EthereumCoin::Erc20(token) => {
if *token == DAI {
return Some(Coin::Dai);
return Some(ExternalCoin::Dai);
}
None
}
}
}
fn amount_to_serai_amount(coin: Coin, amount: U256) -> Amount {
assert_eq!(coin.network(), NetworkId::Ethereum);
fn amount_to_serai_amount(coin: ExternalCoin, amount: U256) -> Amount {
assert_eq!(coin.network(), ExternalNetworkId::Ethereum);
assert_eq!(coin.decimals(), 8);
// Remove 10 decimals so we go from 18 decimals to 8 decimals
let divisor = U256::from(10_000_000_000u64);
@ -119,7 +119,7 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
}
}
fn balance(&self) -> Balance {
fn balance(&self) -> ExternalBalance {
match self {
Output::Output { key: _, instruction } => {
let coin = coin_to_serai_coin(&instruction.coin).unwrap_or_else(|| {
@ -128,9 +128,11 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
"this never should have been yielded"
)
});
Balance { coin, amount: amount_to_serai_amount(coin, instruction.amount) }
ExternalBalance { coin, amount: amount_to_serai_amount(coin, instruction.amount) }
}
Output::Eventuality { .. } => {
ExternalBalance { coin: ExternalCoin::Ether, amount: ETHER_DUST }
}
Output::Eventuality { .. } => Balance { coin: Coin::Ether, amount: ETHER_DUST },
}
}
fn data(&self) -> &[u8] {

View file

@ -7,7 +7,7 @@ use alloy_transport::{RpcError, TransportErrorKind};
use alloy_simple_request_transport::SimpleRequest;
use alloy_provider::{Provider, RootProvider};
use serai_client::primitives::{NetworkId, Coin, Amount};
use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount};
use tokio::task::JoinSet;
@ -30,7 +30,7 @@ pub(crate) struct Rpc<D: Db> {
}
impl<D: Db> ScannerFeed for Rpc<D> {
const NETWORK: NetworkId = NetworkId::Ethereum;
const NETWORK: ExternalNetworkId = ExternalNetworkId::Ethereum;
// We only need one confirmation as Ethereum properly finalizes
const CONFIRMATIONS: u64 = 1;
@ -209,22 +209,22 @@ impl<D: Db> ScannerFeed for Rpc<D> {
}
}
fn dust(coin: Coin) -> Amount {
assert_eq!(coin.network(), NetworkId::Ethereum);
fn dust(coin: ExternalCoin) -> Amount {
assert_eq!(coin.network(), ExternalNetworkId::Ethereum);
match coin {
Coin::Ether => ETHER_DUST,
Coin::Dai => DAI_DUST,
ExternalCoin::Ether => ETHER_DUST,
ExternalCoin::Dai => DAI_DUST,
_ => unreachable!(),
}
}
fn cost_to_aggregate(
&self,
coin: Coin,
coin: ExternalCoin,
_reference_block: &Self::Block,
) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>> {
async move {
assert_eq!(coin.network(), NetworkId::Ethereum);
assert_eq!(coin.network(), ExternalNetworkId::Ethereum);
// There is no cost to aggregate as we receive to an account
Ok(Amount(0))
}

View file

@ -3,7 +3,7 @@ use std::collections::HashMap;
use alloy_core::primitives::U256;
use serai_client::{
primitives::{NetworkId, Coin, Balance},
primitives::{ExternalNetworkId, ExternalCoin, ExternalBalance},
networks::ethereum::Address,
};
@ -17,17 +17,17 @@ use ethereum_router::Coin as EthereumCoin;
use crate::{DAI, transaction::Action, rpc::Rpc};
fn coin_to_ethereum_coin(coin: Coin) -> EthereumCoin {
assert_eq!(coin.network(), NetworkId::Ethereum);
fn coin_to_ethereum_coin(coin: ExternalCoin) -> EthereumCoin {
assert_eq!(coin.network(), ExternalNetworkId::Ethereum);
match coin {
Coin::Ether => EthereumCoin::Ether,
Coin::Dai => EthereumCoin::Erc20(DAI),
ExternalCoin::Ether => EthereumCoin::Ether,
ExternalCoin::Dai => EthereumCoin::Erc20(DAI),
_ => unreachable!(),
}
}
fn balance_to_ethereum_amount(balance: Balance) -> U256 {
assert_eq!(balance.coin.network(), NetworkId::Ethereum);
fn balance_to_ethereum_amount(balance: ExternalBalance) -> U256 {
assert_eq!(balance.coin.network(), ExternalNetworkId::Ethereum);
assert_eq!(balance.coin.decimals(), 8);
// Restore 10 decimals so we go from 8 decimals to 18 decimals
// TODO: Document the expectation all integrated coins have 18 decimals
@ -73,17 +73,17 @@ impl<D: Db> smart_contract_scheduler::SmartContract<Rpc<D>> for SmartContract {
}
let mut res = vec![];
for coin in [Coin::Ether, Coin::Dai] {
for coin in [ExternalCoin::Ether, ExternalCoin::Dai] {
let Some(outs) = outs.remove(&coin) else { continue };
assert!(!outs.is_empty());
let fee_per_gas = match coin {
// 10 gwei
Coin::Ether => {
ExternalCoin::Ether => {
U256::try_from(10u64).unwrap() * alloy_core::primitives::utils::Unit::GWEI.wei()
}
// 0.0003 DAI
Coin::Dai => {
ExternalCoin::Dai => {
U256::try_from(30u64).unwrap() * alloy_core::primitives::utils::Unit::TWEI.wei()
}
_ => unreachable!(),

View file

@ -8,7 +8,7 @@ use scale::{Encode, Decode};
use borsh::{BorshSerialize, BorshDeserialize};
use serai_client::{
primitives::{Coin, Amount, Balance},
primitives::{ExternalCoin, Amount, ExternalBalance},
networks::monero::Address,
};
@ -76,8 +76,8 @@ impl ReceivedOutput<<Ed25519 as Ciphersuite>::G, Address> for Output {
None
}
fn balance(&self) -> Balance {
Balance { coin: Coin::Monero, amount: Amount(self.0.commitment().amount) }
fn balance(&self) -> ExternalBalance {
ExternalBalance { coin: ExternalCoin::Monero, amount: Amount(self.0.commitment().amount) }
}
fn data(&self) -> &[u8] {

View file

@ -3,7 +3,7 @@ use core::future::Future;
use monero_wallet::rpc::{RpcError, Rpc as RpcTrait};
use monero_simple_request_rpc::SimpleRequestRpc;
use serai_client::primitives::{NetworkId, Coin, Amount};
use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount};
use scanner::ScannerFeed;
use signers::TransactionPublisher;
@ -19,7 +19,7 @@ pub(crate) struct Rpc {
}
impl ScannerFeed for Rpc {
const NETWORK: NetworkId = NetworkId::Monero;
const NETWORK: ExternalNetworkId = ExternalNetworkId::Monero;
// Outputs aren't spendable until 10 blocks later due to the 10-block lock
// Since we assumed scanned outputs are spendable, that sets a minimum confirmation depth of 10
// A 10-block reorganization hasn't been observed in years and shouldn't occur
@ -107,8 +107,8 @@ impl ScannerFeed for Rpc {
}
}
fn dust(coin: Coin) -> Amount {
assert_eq!(coin, Coin::Monero);
fn dust(coin: ExternalCoin) -> Amount {
assert_eq!(coin, ExternalCoin::Monero);
// 0.01 XMR
Amount(10_000_000_000)
@ -116,11 +116,11 @@ impl ScannerFeed for Rpc {
fn cost_to_aggregate(
&self,
coin: Coin,
coin: ExternalCoin,
_reference_block: &Self::Block,
) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>> {
async move {
assert_eq!(coin, Coin::Bitcoin);
assert_eq!(coin, ExternalCoin::Bitcoin);
// TODO
Ok(Amount(0))
}

View file

@ -9,7 +9,7 @@ use ciphersuite::{Ciphersuite, Ed25519};
use monero_wallet::rpc::{FeeRate, RpcError};
use serai_client::{
primitives::{Coin, Amount},
primitives::{ExternalCoin, Amount},
networks::monero::Address,
};
@ -106,7 +106,7 @@ async fn signable_transaction(
.map(|payment| {
(MoneroAddress::from(*payment.address()), {
let balance = payment.balance();
assert_eq!(balance.coin, Coin::Monero);
assert_eq!(balance.coin, ExternalCoin::Monero);
balance.amount.0
})
})

View file

@ -5,7 +5,7 @@ use group::GroupEncoding;
use borsh::{BorshSerialize, BorshDeserialize};
use serai_primitives::{ExternalAddress, Balance};
use serai_primitives::{ExternalAddress, ExternalBalance};
use crate::Id;
@ -133,7 +133,7 @@ pub trait ReceivedOutput<K: GroupEncoding, A: Address>:
fn presumed_origin(&self) -> Option<A>;
/// The balance associated with this output.
fn balance(&self) -> Balance;
fn balance(&self) -> ExternalBalance;
/// The arbitrary data (presumably an InInstruction) associated with this output.
fn data(&self) -> &[u8];

View file

@ -3,7 +3,7 @@ use std::io;
use scale::{Encode, Decode, IoReader};
use borsh::{BorshSerialize, BorshDeserialize};
use serai_primitives::Balance;
use serai_primitives::ExternalBalance;
use serai_coins_primitives::OutInstructionWithBalance;
use crate::Address;
@ -12,7 +12,7 @@ use crate::Address;
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct Payment<A: Address> {
address: A,
balance: Balance,
balance: ExternalBalance,
}
impl<A: Address> TryFrom<OutInstructionWithBalance> for Payment<A> {
@ -27,7 +27,7 @@ impl<A: Address> TryFrom<OutInstructionWithBalance> for Payment<A> {
impl<A: Address> Payment<A> {
/// Create a new Payment.
pub fn new(address: A, balance: Balance) -> Self {
pub fn new(address: A, balance: ExternalBalance) -> Self {
Payment { address, balance }
}
@ -36,7 +36,7 @@ impl<A: Address> Payment<A> {
&self.address
}
/// The balance to transfer.
pub fn balance(&self) -> Balance {
pub fn balance(&self) -> ExternalBalance {
self.balance
}
@ -44,7 +44,7 @@ impl<A: Address> Payment<A> {
pub fn read(reader: &mut impl io::Read) -> io::Result<Self> {
let address = A::deserialize_reader(reader)?;
let reader = &mut IoReader(reader);
let balance = Balance::decode(reader).map_err(io::Error::other)?;
let balance = ExternalBalance::decode(reader).map_err(io::Error::other)?;
Ok(Self { address, balance })
}
/// Write the Payment.

View file

@ -7,7 +7,7 @@ use scale::{Encode, Decode, IoReader};
use borsh::{BorshSerialize, BorshDeserialize};
use serai_db::{Get, DbTxn, create_db};
use serai_primitives::Balance;
use serai_primitives::ExternalBalance;
use serai_validator_sets_primitives::Session;
use primitives::EncodableG;
@ -39,7 +39,7 @@ create_db!(
pub(crate) struct ReturnInformation<S: ScannerFeed> {
pub(crate) address: AddressFor<S>,
pub(crate) balance: Balance,
pub(crate) balance: ExternalBalance,
}
pub(crate) struct BatchDb<S: ScannerFeed>(PhantomData<S>);
@ -116,7 +116,7 @@ impl<S: ScannerFeed> BatchDb<S> {
res.push((opt[0] == 1).then(|| {
let address = AddressFor::<S>::deserialize_reader(&mut buf).unwrap();
let balance = Balance::decode(&mut IoReader(&mut buf)).unwrap();
let balance = ExternalBalance::decode(&mut IoReader(&mut buf)).unwrap();
ReturnInformation { address, balance }
}));
}

View file

@ -10,7 +10,7 @@ use group::GroupEncoding;
use borsh::{BorshSerialize, BorshDeserialize};
use serai_db::{Get, DbTxn, Db};
use serai_primitives::{NetworkId, Coin, Amount};
use serai_primitives::{ExternalNetworkId, ExternalCoin, Amount};
use serai_coins_primitives::OutInstructionWithBalance;
use messages::substrate::ExecutedBatch;
@ -64,7 +64,7 @@ impl<B: Block> BlockExt for B {
/// This defines the primitive types used, along with various getters necessary for indexing.
pub trait ScannerFeed: 'static + Send + Sync + Clone {
/// The ID of the network being scanned for.
const NETWORK: NetworkId;
const NETWORK: ExternalNetworkId;
/// The amount of confirmations a block must have to be considered finalized.
///
@ -175,14 +175,14 @@ pub trait ScannerFeed: 'static + Send + Sync + Clone {
///
/// This MUST be constant. Serai MUST NOT create internal outputs worth less than this. This
/// SHOULD be a value worth handling at a human level.
fn dust(coin: Coin) -> Amount;
fn dust(coin: ExternalCoin) -> Amount;
/// The cost to aggregate an input as of the specified block.
///
/// This is defined as the transaction fee for a 2-input, 1-output transaction.
fn cost_to_aggregate(
&self,
coin: Coin,
coin: ExternalCoin,
reference_block: &Self::Block,
) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>>;
}

View file

@ -1,6 +1,6 @@
use borsh::{BorshSerialize, BorshDeserialize};
use serai_primitives::{Coin, Amount, Balance};
use serai_primitives::{ExternalCoin, Amount, ExternalBalance};
use primitives::{Address, Payment};
use scanner::ScannerFeed;
@ -52,7 +52,7 @@ impl<A: Address> TreeTransaction<A> {
/// payments should be made.
pub fn payments<S: ScannerFeed>(
&self,
coin: Coin,
coin: ExternalCoin,
branch_address: &A,
input_value: u64,
) -> Option<Vec<Payment<A>>> {
@ -115,7 +115,10 @@ impl<A: Address> TreeTransaction<A> {
.filter_map(|(payment, amount)| {
amount.map(|amount| {
// The existing payment, with the new amount
Payment::new(payment.address().clone(), Balance { coin, amount: Amount(amount) })
Payment::new(
payment.address().clone(),
ExternalBalance { coin, amount: Amount(amount) },
)
})
})
.collect()
@ -126,7 +129,7 @@ impl<A: Address> TreeTransaction<A> {
.filter_map(|amount| {
amount.map(|amount| {
// A branch output with the new amount
Payment::new(branch_address.clone(), Balance { coin, amount: Amount(amount) })
Payment::new(branch_address.clone(), ExternalBalance { coin, amount: Amount(amount) })
})
})
.collect()

View file

@ -2,7 +2,7 @@ use core::marker::PhantomData;
use group::GroupEncoding;
use serai_primitives::{Coin, Amount, Balance};
use serai_primitives::{ExternalCoin, Amount, ExternalBalance};
use borsh::BorshDeserialize;
use serai_db::{Get, DbTxn, create_db, db_channel};
@ -13,31 +13,31 @@ use scanner::{ScannerFeed, KeyFor, AddressFor, OutputFor};
create_db! {
UtxoScheduler {
OperatingCosts: (coin: Coin) -> Amount,
SerializedOutputs: (key: &[u8], coin: Coin) -> Vec<u8>,
SerializedQueuedPayments: (key: &[u8], coin: Coin) -> Vec<u8>,
OperatingCosts: (coin: ExternalCoin) -> Amount,
SerializedOutputs: (key: &[u8], coin: ExternalCoin) -> Vec<u8>,
SerializedQueuedPayments: (key: &[u8], coin: ExternalCoin) -> Vec<u8>,
}
}
db_channel! {
UtxoScheduler {
PendingBranch: (key: &[u8], balance: Balance) -> Vec<u8>,
PendingBranch: (key: &[u8], balance: ExternalBalance) -> Vec<u8>,
}
}
pub(crate) struct Db<S: ScannerFeed>(PhantomData<S>);
impl<S: ScannerFeed> Db<S> {
pub(crate) fn operating_costs(getter: &impl Get, coin: Coin) -> Amount {
pub(crate) fn operating_costs(getter: &impl Get, coin: ExternalCoin) -> Amount {
OperatingCosts::get(getter, coin).unwrap_or(Amount(0))
}
pub(crate) fn set_operating_costs(txn: &mut impl DbTxn, coin: Coin, amount: Amount) {
pub(crate) fn set_operating_costs(txn: &mut impl DbTxn, coin: ExternalCoin, amount: Amount) {
OperatingCosts::set(txn, coin, &amount)
}
pub(crate) fn outputs(
getter: &impl Get,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Option<Vec<OutputFor<S>>> {
let buf = SerializedOutputs::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice();
@ -51,7 +51,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_outputs(
txn: &mut impl DbTxn,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
outputs: &[OutputFor<S>],
) {
let mut buf = Vec::with_capacity(outputs.len() * 128);
@ -60,14 +60,14 @@ impl<S: ScannerFeed> Db<S> {
}
SerializedOutputs::set(txn, key.to_bytes().as_ref(), coin, &buf);
}
pub(crate) fn del_outputs(txn: &mut impl DbTxn, key: KeyFor<S>, coin: Coin) {
pub(crate) fn del_outputs(txn: &mut impl DbTxn, key: KeyFor<S>, coin: ExternalCoin) {
SerializedOutputs::del(txn, key.to_bytes().as_ref(), coin);
}
pub(crate) fn queued_payments(
getter: &impl Get,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Option<Vec<Payment<AddressFor<S>>>> {
let buf = SerializedQueuedPayments::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice();
@ -81,7 +81,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_queued_payments(
txn: &mut impl DbTxn,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
queued: &[Payment<AddressFor<S>>],
) {
let mut buf = Vec::with_capacity(queued.len() * 128);
@ -90,14 +90,14 @@ impl<S: ScannerFeed> Db<S> {
}
SerializedQueuedPayments::set(txn, key.to_bytes().as_ref(), coin, &buf);
}
pub(crate) fn del_queued_payments(txn: &mut impl DbTxn, key: KeyFor<S>, coin: Coin) {
pub(crate) fn del_queued_payments(txn: &mut impl DbTxn, key: KeyFor<S>, coin: ExternalCoin) {
SerializedQueuedPayments::del(txn, key.to_bytes().as_ref(), coin);
}
pub(crate) fn queue_pending_branch(
txn: &mut impl DbTxn,
key: KeyFor<S>,
balance: Balance,
balance: ExternalBalance,
child: &TreeTransaction<AddressFor<S>>,
) {
PendingBranch::send(txn, key.to_bytes().as_ref(), balance, &borsh::to_vec(child).unwrap())
@ -105,7 +105,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn take_pending_branch(
txn: &mut impl DbTxn,
key: KeyFor<S>,
balance: Balance,
balance: ExternalBalance,
) -> Option<TreeTransaction<AddressFor<S>>> {
PendingBranch::try_recv(txn, key.to_bytes().as_ref(), balance)
.map(|bytes| TreeTransaction::<AddressFor<S>>::deserialize(&mut bytes.as_slice()).unwrap())

View file

@ -7,7 +7,7 @@ use std::collections::HashMap;
use group::GroupEncoding;
use serai_primitives::{Coin, Amount, Balance};
use serai_primitives::{ExternalCoin, Amount, ExternalBalance};
use serai_db::DbTxn;
@ -42,7 +42,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
block: &BlockFor<S>,
key_for_change: KeyFor<S>,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Result<Vec<EventualityFor<S>>, <Self as SchedulerTrait<S>>::EphemeralError> {
let mut eventualities = vec![];
@ -79,7 +79,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
txn: &mut impl DbTxn,
operating_costs: &mut u64,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
value_of_outputs: u64,
) -> Vec<Payment<AddressFor<S>>> {
// Fetch all payments for this key
@ -133,7 +133,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
fn queue_branches(
txn: &mut impl DbTxn,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
effected_payments: Vec<Amount>,
tx: TreeTransaction<AddressFor<S>>,
) {
@ -149,7 +149,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
children thanks to our sort.
*/
for (amount, child) in effected_payments.into_iter().zip(children) {
Db::<S>::queue_pending_branch(txn, key, Balance { coin, amount }, &child);
Db::<S>::queue_pending_branch(txn, key, ExternalBalance { coin, amount }, &child);
}
}
}
@ -216,8 +216,6 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
let branch_address = P::branch_address(key);
'coin: for coin in S::NETWORK.coins() {
let coin = *coin;
// Perform any input aggregation we should
eventualities
.append(&mut self.aggregate_inputs(txn, block, key_for_change, key, coin).await?);
@ -308,7 +306,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
block: &BlockFor<S>,
from: KeyFor<S>,
to: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Result<(), <Self as SchedulerTrait<S>>::EphemeralError> {
let from_bytes = from.to_bytes().as_ref().to_vec();
// Ensure our inputs are aggregated
@ -349,10 +347,10 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
fn activate_key(txn: &mut impl DbTxn, key: KeyFor<S>) {
for coin in S::NETWORK.coins() {
assert!(Db::<S>::outputs(txn, key, *coin).is_none());
Db::<S>::set_outputs(txn, key, *coin, &[]);
assert!(Db::<S>::queued_payments(txn, key, *coin).is_none());
Db::<S>::set_queued_payments(txn, key, *coin, &[]);
assert!(Db::<S>::outputs(txn, key, coin).is_none());
Db::<S>::set_outputs(txn, key, coin, &[]);
assert!(Db::<S>::queued_payments(txn, key, coin).is_none());
Db::<S>::set_queued_payments(txn, key, coin, &[]);
}
}
@ -368,18 +366,18 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
for coin in S::NETWORK.coins() {
// Move the payments to the new key
{
let still_queued = Db::<S>::queued_payments(txn, retiring_key, *coin).unwrap();
let mut new_queued = Db::<S>::queued_payments(txn, new_key, *coin).unwrap();
let still_queued = Db::<S>::queued_payments(txn, retiring_key, coin).unwrap();
let mut new_queued = Db::<S>::queued_payments(txn, new_key, coin).unwrap();
let mut queued = still_queued;
queued.append(&mut new_queued);
Db::<S>::set_queued_payments(txn, retiring_key, *coin, &[]);
Db::<S>::set_queued_payments(txn, new_key, *coin, &queued);
Db::<S>::set_queued_payments(txn, retiring_key, coin, &[]);
Db::<S>::set_queued_payments(txn, new_key, coin, &queued);
}
// Move the outputs to the new key
self.flush_outputs(txn, &mut eventualities, block, retiring_key, new_key, *coin).await?;
self.flush_outputs(txn, &mut eventualities, block, retiring_key, new_key, coin).await?;
}
Ok(eventualities)
}
@ -387,10 +385,10 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
fn retire_key(txn: &mut impl DbTxn, key: KeyFor<S>) {
for coin in S::NETWORK.coins() {
assert!(Db::<S>::outputs(txn, key, *coin).unwrap().is_empty());
Db::<S>::del_outputs(txn, key, *coin);
assert!(Db::<S>::queued_payments(txn, key, *coin).unwrap().is_empty());
Db::<S>::del_queued_payments(txn, key, *coin);
assert!(Db::<S>::outputs(txn, key, coin).unwrap().is_empty());
Db::<S>::del_outputs(txn, key, coin);
assert!(Db::<S>::queued_payments(txn, key, coin).unwrap().is_empty());
Db::<S>::del_queued_payments(txn, key, coin);
}
}
@ -463,7 +461,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
block,
active_keys[0].0,
active_keys[1].0,
*coin,
coin,
)
.await?;
}
@ -552,10 +550,10 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
// Queue the payments for this key
for coin in S::NETWORK.coins() {
let mut queued_payments = Db::<S>::queued_payments(txn, fulfillment_key, *coin).unwrap();
let mut queued_payments = Db::<S>::queued_payments(txn, fulfillment_key, coin).unwrap();
queued_payments
.extend(payments.iter().filter(|payment| payment.balance().coin == *coin).cloned());
Db::<S>::set_queued_payments(txn, fulfillment_key, *coin, &queued_payments);
.extend(payments.iter().filter(|payment| payment.balance().coin == coin).cloned());
Db::<S>::set_queued_payments(txn, fulfillment_key, coin, &queued_payments);
}
// Handle the queued payments

View file

@ -2,7 +2,7 @@ use core::marker::PhantomData;
use group::GroupEncoding;
use serai_primitives::{Coin, Amount};
use serai_primitives::{ExternalCoin, Amount};
use serai_db::{Get, DbTxn, create_db};
@ -11,28 +11,28 @@ use scanner::{ScannerFeed, KeyFor, AddressFor, OutputFor};
create_db! {
TransactionChainingScheduler {
OperatingCosts: (coin: Coin) -> Amount,
SerializedOutputs: (key: &[u8], coin: Coin) -> Vec<u8>,
OperatingCosts: (coin: ExternalCoin) -> Amount,
SerializedOutputs: (key: &[u8], coin: ExternalCoin) -> Vec<u8>,
AlreadyAccumulatedOutput: (id: &[u8]) -> (),
// We should be immediately able to schedule the fulfillment of payments, yet this may not be
// possible if we're in the middle of a multisig rotation (as our output set will be split)
SerializedQueuedPayments: (key: &[u8], coin: Coin) -> Vec<u8>,
SerializedQueuedPayments: (key: &[u8], coin: ExternalCoin) -> Vec<u8>,
}
}
pub(crate) struct Db<S: ScannerFeed>(PhantomData<S>);
impl<S: ScannerFeed> Db<S> {
pub(crate) fn operating_costs(getter: &impl Get, coin: Coin) -> Amount {
pub(crate) fn operating_costs(getter: &impl Get, coin: ExternalCoin) -> Amount {
OperatingCosts::get(getter, coin).unwrap_or(Amount(0))
}
pub(crate) fn set_operating_costs(txn: &mut impl DbTxn, coin: Coin, amount: Amount) {
pub(crate) fn set_operating_costs(txn: &mut impl DbTxn, coin: ExternalCoin, amount: Amount) {
OperatingCosts::set(txn, coin, &amount)
}
pub(crate) fn outputs(
getter: &impl Get,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Option<Vec<OutputFor<S>>> {
let buf = SerializedOutputs::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice();
@ -46,7 +46,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_outputs(
txn: &mut impl DbTxn,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
outputs: &[OutputFor<S>],
) {
let mut buf = Vec::with_capacity(outputs.len() * 128);
@ -55,7 +55,7 @@ impl<S: ScannerFeed> Db<S> {
}
SerializedOutputs::set(txn, key.to_bytes().as_ref(), coin, &buf);
}
pub(crate) fn del_outputs(txn: &mut impl DbTxn, key: KeyFor<S>, coin: Coin) {
pub(crate) fn del_outputs(txn: &mut impl DbTxn, key: KeyFor<S>, coin: ExternalCoin) {
SerializedOutputs::del(txn, key.to_bytes().as_ref(), coin);
}
@ -75,7 +75,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn queued_payments(
getter: &impl Get,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Option<Vec<Payment<AddressFor<S>>>> {
let buf = SerializedQueuedPayments::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice();
@ -89,7 +89,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_queued_payments(
txn: &mut impl DbTxn,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
queued: &[Payment<AddressFor<S>>],
) {
let mut buf = Vec::with_capacity(queued.len() * 128);
@ -98,7 +98,7 @@ impl<S: ScannerFeed> Db<S> {
}
SerializedQueuedPayments::set(txn, key.to_bytes().as_ref(), coin, &buf);
}
pub(crate) fn del_queued_payments(txn: &mut impl DbTxn, key: KeyFor<S>, coin: Coin) {
pub(crate) fn del_queued_payments(txn: &mut impl DbTxn, key: KeyFor<S>, coin: ExternalCoin) {
SerializedQueuedPayments::del(txn, key.to_bytes().as_ref(), coin);
}
}

View file

@ -7,7 +7,7 @@ use std::collections::HashMap;
use group::GroupEncoding;
use serai_primitives::{Coin, Amount};
use serai_primitives::{ExternalCoin, Amount};
use serai_db::DbTxn;
@ -72,7 +72,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
block: &BlockFor<S>,
key_for_change: KeyFor<S>,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Result<Vec<EventualityFor<S>>, <Self as SchedulerTrait<S>>::EphemeralError> {
let mut eventualities = vec![];
@ -112,7 +112,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
txn: &mut impl DbTxn,
operating_costs: &mut u64,
key: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
value_of_outputs: u64,
) -> Vec<Payment<AddressFor<S>>> {
// Fetch all payments for this key
@ -184,8 +184,6 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
let branch_address = P::branch_address(key);
'coin: for coin in S::NETWORK.coins() {
let coin = *coin;
// Perform any input aggregation we should
eventualities
.append(&mut self.aggregate_inputs(txn, block, key_for_change, key, coin).await?);
@ -360,7 +358,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
block: &BlockFor<S>,
from: KeyFor<S>,
to: KeyFor<S>,
coin: Coin,
coin: ExternalCoin,
) -> Result<(), <Self as SchedulerTrait<S>>::EphemeralError> {
let from_bytes = from.to_bytes().as_ref().to_vec();
// Ensure our inputs are aggregated
@ -404,10 +402,10 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
fn activate_key(txn: &mut impl DbTxn, key: KeyFor<S>) {
for coin in S::NETWORK.coins() {
assert!(Db::<S>::outputs(txn, key, *coin).is_none());
Db::<S>::set_outputs(txn, key, *coin, &[]);
assert!(Db::<S>::queued_payments(txn, key, *coin).is_none());
Db::<S>::set_queued_payments(txn, key, *coin, &[]);
assert!(Db::<S>::outputs(txn, key, coin).is_none());
Db::<S>::set_outputs(txn, key, coin, &[]);
assert!(Db::<S>::queued_payments(txn, key, coin).is_none());
Db::<S>::set_queued_payments(txn, key, coin, &[]);
}
}
@ -423,18 +421,18 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
for coin in S::NETWORK.coins() {
// Move the payments to the new key
{
let still_queued = Db::<S>::queued_payments(txn, retiring_key, *coin).unwrap();
let mut new_queued = Db::<S>::queued_payments(txn, new_key, *coin).unwrap();
let still_queued = Db::<S>::queued_payments(txn, retiring_key, coin).unwrap();
let mut new_queued = Db::<S>::queued_payments(txn, new_key, coin).unwrap();
let mut queued = still_queued;
queued.append(&mut new_queued);
Db::<S>::set_queued_payments(txn, retiring_key, *coin, &[]);
Db::<S>::set_queued_payments(txn, new_key, *coin, &queued);
Db::<S>::set_queued_payments(txn, retiring_key, coin, &[]);
Db::<S>::set_queued_payments(txn, new_key, coin, &queued);
}
// Move the outputs to the new key
self.flush_outputs(txn, &mut eventualities, block, retiring_key, new_key, *coin).await?;
self.flush_outputs(txn, &mut eventualities, block, retiring_key, new_key, coin).await?;
}
Ok(eventualities)
}
@ -442,10 +440,10 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
fn retire_key(txn: &mut impl DbTxn, key: KeyFor<S>) {
for coin in S::NETWORK.coins() {
assert!(Db::<S>::outputs(txn, key, *coin).unwrap().is_empty());
Db::<S>::del_outputs(txn, key, *coin);
assert!(Db::<S>::queued_payments(txn, key, *coin).unwrap().is_empty());
Db::<S>::del_queued_payments(txn, key, *coin);
assert!(Db::<S>::outputs(txn, key, coin).unwrap().is_empty());
Db::<S>::del_outputs(txn, key, coin);
assert!(Db::<S>::queued_payments(txn, key, coin).unwrap().is_empty());
Db::<S>::del_queued_payments(txn, key, coin);
}
}
@ -481,7 +479,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
block,
active_keys[0].0,
active_keys[1].0,
*coin,
coin,
)
.await?;
}
@ -570,10 +568,10 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
// Queue the payments for this key
for coin in S::NETWORK.coins() {
let mut queued_payments = Db::<S>::queued_payments(txn, fulfillment_key, *coin).unwrap();
let mut queued_payments = Db::<S>::queued_payments(txn, fulfillment_key, coin).unwrap();
queued_payments
.extend(payments.iter().filter(|payment| payment.balance().coin == *coin).cloned());
Db::<S>::set_queued_payments(txn, fulfillment_key, *coin, &queued_payments);
.extend(payments.iter().filter(|payment| payment.balance().coin == coin).cloned());
Db::<S>::set_queued_payments(txn, fulfillment_key, coin, &queued_payments);
}
// Handle the queued payments

View file

@ -1,10 +1,7 @@
pub use serai_abi::in_instructions::primitives;
use primitives::SignedBatch;
use crate::{
primitives::{BlockHash, ExternalNetworkId},
Transaction, SeraiError, Serai, TemporalSerai,
};
use crate::{primitives::ExternalNetworkId, Transaction, SeraiError, Serai, TemporalSerai};
pub type InInstructionsEvent = serai_abi::in_instructions::Event;
@ -12,6 +9,7 @@ const PALLET: &str = "InInstructions";
#[derive(Clone, Copy)]
pub struct SeraiInInstructions<'a>(pub(crate) &'a TemporalSerai<'a>);
impl SeraiInInstructions<'_> {
pub async fn last_batch_for_network(
&self,
network: ExternalNetworkId,

View file

@ -16,7 +16,7 @@ pub use abi::{primitives, Transaction};
use abi::*;
pub use primitives::{SeraiAddress, Signature, Amount};
use primitives::{Header, NetworkId};
use primitives::{Header, ExternalNetworkId};
pub mod coins;
pub use coins::SeraiCoins;
@ -313,7 +313,7 @@ impl Serai {
/// Return the P2P Multiaddrs for the validators of the specified network.
pub async fn p2p_validators(
&self,
network: NetworkId,
network: ExternalNetworkId,
) -> Result<Vec<multiaddr::Multiaddr>, SeraiError> {
self.call("p2p_validators", network).await
}

View file

@ -5,10 +5,10 @@ use sp_runtime::BoundedVec;
use serai_abi::{primitives::Amount, validator_sets::primitives::ExternalValidatorSet};
pub use serai_abi::validator_sets::primitives;
use primitives::{MAX_KEY_LEN, Session, ValidatorSet, KeyPair, SlashReport};
use primitives::{MAX_KEY_LEN, Session, KeyPair, SlashReport};
use crate::{
primitives::{NetworkId, ExternalNetworkId, EmbeddedEllipticCurve, SeraiAddress},
primitives::{NetworkId, ExternalNetworkId, EmbeddedEllipticCurve},
Transaction, Serai, TemporalSerai, SeraiError,
};
@ -203,7 +203,7 @@ impl SeraiValidatorSets<'_> {
}
pub fn set_keys(
network: NetworkId,
network: ExternalNetworkId,
key_pair: KeyPair,
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
signature: Signature,
@ -237,7 +237,7 @@ impl SeraiValidatorSets<'_> {
}
pub fn report_slashes(
network: NetworkId,
network: ExternalNetworkId,
slashes: SlashReport,
signature: Signature,
) -> Transaction {

View file

@ -8,7 +8,7 @@ use blake2::{
use scale::Encode;
use serai_client::{
primitives::{BlockHash, NetworkId, ExternalCoin, Amount, ExternalBalance, SeraiAddress},
primitives::{BlockHash, ExternalCoin, Amount, ExternalBalance, SeraiAddress},
coins::CoinsEvent,
validator_sets::primitives::Session,
in_instructions::{

View file

@ -11,7 +11,7 @@ use sp_core::Pair;
use serai_client::{
primitives::{
BlockHash, ExternalNetworkId, ExternalCoin, Amount, ExternalBalance, SeraiAddress, ExternalAddress,
BlockHash, ExternalCoin, Amount, ExternalBalance, SeraiAddress, ExternalAddress,
insecure_pair_from_name,
},
coins::{

View file

@ -11,10 +11,11 @@ use sp_core::{sr25519::Signature, Pair as PairTrait};
use serai_abi::{
primitives::{
BlockHash, ExternalNetworkId, ExternalCoin, Amount, ExternalBalance, SeraiAddress, insecure_pair_from_name,
EXTERNAL_COINS, BlockHash, ExternalNetworkId, NetworkId, ExternalCoin, Amount, ExternalBalance,
SeraiAddress, insecure_pair_from_name,
},
validator_sets::primitives::{musig_context, Session, ValidatorSet},
genesis_liquidity::primitives::{oraclize_values_message, Values},
validator_sets::primitives::{Session, ValidatorSet, musig_context},
genesis_liquidity::primitives::{Values, oraclize_values_message},
in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch},
};

View file

@ -9,7 +9,7 @@ use scale::Encode;
use sp_core::Pair;
use serai_client::{
primitives::{BlockHash, NetworkId, ExternalBalance, SeraiAddress, insecure_pair_from_name},
primitives::{BlockHash, ExternalBalance, SeraiAddress, insecure_pair_from_name},
validator_sets::primitives::{ExternalValidatorSet, KeyPair},
in_instructions::{
primitives::{Batch, SignedBatch, batch_message, InInstruction, InInstructionWithBalance},

View file

@ -16,12 +16,12 @@ use frost::dkg::musig::musig;
use schnorrkel::Schnorrkel;
use serai_client::{
primitives::EmbeddedEllipticCurve,
primitives::{EmbeddedEllipticCurve, Amount},
validator_sets::{
primitives::{MAX_KEY_LEN, ExternalValidatorSet, KeyPair, musig_context, set_keys_message},
ValidatorSetsEvent,
},
Amount, Serai, SeraiValidatorSets,
SeraiValidatorSets, Serai,
};
use crate::common::tx::publish_tx;

View file

@ -6,7 +6,7 @@ use serai_abi::in_instructions::primitives::DexCall;
use serai_client::{
primitives::{
BlockHash, NetworkId, Coin, Amount, Balance, SeraiAddress, ExternalAddress,
BlockHash, ExternalCoin, Coin, Amount, ExternalBalance, Balance, SeraiAddress, ExternalAddress,
insecure_pair_from_name,
},
in_instructions::primitives::{

View file

@ -44,7 +44,7 @@ async fn dht() {
assert!(!Serai::new(serai_rpc.clone())
.await
.unwrap()
.p2p_validators(ExternalNetworkId::Bitcoin.into())
.p2p_validators(ExternalNetworkId::Bitcoin)
.await
.unwrap()
.is_empty());

View file

@ -5,8 +5,8 @@ use serai_client::TemporalSerai;
use serai_abi::{
primitives::{
NETWORKS, COINS, TARGET_BLOCK_TIME, FAST_EPOCH_DURATION, FAST_EPOCH_INITIAL_PERIOD, BlockHash,
Coin,
EXTERNAL_NETWORKS, NETWORKS, TARGET_BLOCK_TIME, FAST_EPOCH_DURATION, FAST_EPOCH_INITIAL_PERIOD,
BlockHash, ExternalNetworkId, NetworkId, ExternalCoin, Amount, ExternalBalance,
},
validator_sets::primitives::Session,
emissions::primitives::{INITIAL_REWARD_PER_BLOCK, SECURE_BY},
@ -38,17 +38,16 @@ async fn send_batches(serai: &Serai, ids: &mut HashMap<ExternalNetworkId, u32>)
let mut block = BlockHash([0; 32]);
OsRng.fill_bytes(&mut block.0);
provide_batch(
serai,
Batch {
network,
id: ids[&network],
external_network_block_hash: block,
instructions: vec![],
},
)
.await;
}
provide_batch(
serai,
Batch {
network,
id: ids[&network],
external_network_block_hash: block,
instructions: vec![],
},
)
.await;
}
}

View file

@ -7,11 +7,11 @@ use sp_core::{
use serai_client::{
primitives::{
FAST_EPOCH_DURATION, TARGET_BLOCK_TIME, NETWORKS, BlockHash, NetworkId, EmbeddedEllipticCurve,
insecure_pair_from_name,
FAST_EPOCH_DURATION, TARGET_BLOCK_TIME, NETWORKS, BlockHash, ExternalNetworkId, NetworkId,
EmbeddedEllipticCurve, Amount, insecure_pair_from_name,
},
validator_sets::{
primitives::{Session, ValidatorSet, ExternalValidatorSet, KeyPair},
primitives::{Session, ExternalValidatorSet, ValidatorSet, KeyPair},
ValidatorSetsEvent,
},
in_instructions::{
@ -313,8 +313,12 @@ async fn validator_set_rotation() {
// provide a batch to complete the handover and retire the previous set
let mut block_hash = BlockHash([0; 32]);
OsRng.fill_bytes(&mut block_hash.0);
let batch =
Batch { network: network.try_into().unwrap(), id: 0, external_network_block_hash: block_hash, instructions: vec![] };
let batch = Batch {
network: network.try_into().unwrap(),
id: 0,
external_network_block_hash: block_hash,
instructions: vec![],
};
publish_tx(
&serai,
&SeraiInInstructions::execute_batch(SignedBatch {

View file

@ -58,7 +58,7 @@ fn burn_with_instruction() {
// we shouldn't be able to burn more than what we have
let mut instruction = OutInstructionWithBalance {
instruction: OutInstruction { address: ExternalAddress::new(vec![]).unwrap(), data: None },
instruction: OutInstruction { address: ExternalAddress::new(vec![]).unwrap() },
balance: ExternalBalance {
coin: coin.try_into().unwrap(),
amount: Amount(balance.amount.0 + 1),

View file

@ -67,7 +67,7 @@ pub mod pallet {
in_instruction_results: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
},
Halt {
network: NetworkId,
network: ExternalNetworkId,
},
}
@ -103,7 +103,7 @@ pub mod pallet {
fn execute(instruction: &InInstructionWithBalance) -> Result<(), DispatchError> {
match &instruction.instruction {
InInstruction::Transfer(address) => {
Coins::<T>::mint(address.into(), instruction.balance.into())?;
Coins::<T>::mint((*address).into(), instruction.balance.into())?;
}
InInstruction::Dex(call) => {
// This will only be initiated by external chain transactions. That is why we only need
@ -222,11 +222,11 @@ pub mod pallet {
}
InInstruction::GenesisLiquidity(address) => {
Coins::<T>::mint(GENESIS_LIQUIDITY_ACCOUNT.into(), instruction.balance.into())?;
GenesisLiq::<T>::add_coin_liquidity(address.into(), instruction.balance)?;
GenesisLiq::<T>::add_coin_liquidity((*address).into(), instruction.balance)?;
}
InInstruction::SwapToStakedSRI(address, network) => {
Coins::<T>::mint(POL_ACCOUNT.into(), instruction.balance.into())?;
Emissions::<T>::swap_to_staked_sri(address.into(), network, instruction.balance)?;
Emissions::<T>::swap_to_staked_sri((*address).into(), *network, instruction.balance)?;
}
}
Ok(())
@ -319,7 +319,10 @@ pub mod pallet {
// key is publishing `Batch`s. This should only happen once the current key has verified all
// `Batch`s published by the prior key, meaning they are accepting the hand-over.
if prior.is_some() && (!valid_by_prior) {
ValidatorSets::<T>::retire_set(ValidatorSet { network: network.into(), session: prior_session });
ValidatorSets::<T>::retire_set(ValidatorSet {
network: network.into(),
session: prior_session,
});
}
// check that this validator set isn't publishing a batch more than once per block

View file

@ -20,7 +20,7 @@ use sp_std::vec::Vec;
use sp_runtime::RuntimeDebug;
#[rustfmt::skip]
use serai_primitives::{BlockHash, NetworkId, Balance, SeraiAddress, ExternalAddress, system_address};
use serai_primitives::{BlockHash, ExternalNetworkId, NetworkId, ExternalBalance, Balance, SeraiAddress, ExternalAddress, system_address};
mod shorthand;
pub use shorthand::*;

View file

@ -88,7 +88,10 @@ fn devnet_genesis(
networks: key_shares.clone(),
participants: validators.clone(),
},
emissions: EmissionsConfig { networks: key_shares, participants: validators.clone() },
emissions: EmissionsConfig {
networks: key_shares,
participants: validators.iter().map(|(validator, _)| *validator).collect(),
},
signals: SignalsConfig::default(),
babe: BabeConfig {
authorities: validators.iter().map(|validator| (validator.0.into(), 1)).collect(),

View file

@ -26,9 +26,7 @@ pub enum EmbeddedEllipticCurve {
}
/// The type used to identify external networks.
#[derive(
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, PartialOrd, Ord, MaxEncodedLen, TypeInfo,
)]
#[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 ExternalNetworkId {
@ -162,6 +160,17 @@ impl ExternalNetworkId {
}
impl NetworkId {
/// The embedded elliptic curve actively used for this network.
///
/// This is guaranteed to return `[]`, `[Embedwards25519]`, or
/// `[Embedwards25519, *network specific curve*]`.
pub fn embedded_elliptic_curves(&self) -> &'static [EmbeddedEllipticCurve] {
match self {
Self::Serai => &[],
Self::External(network) => network.embedded_elliptic_curves(),
}
}
pub fn coins(&self) -> Vec<Coin> {
match self {
Self::Serai => vec![Coin::Serai],

View file

@ -1154,8 +1154,8 @@ pub mod pallet {
// session on this assumption
assert_eq!(Pallet::<T>::latest_decided_session(network.into()), Some(current_session));
let participants =
Participants::<T>::get(network).expect("session existed without participants");
let participants = Participants::<T>::get(NetworkId::from(network))
.expect("session existed without participants");
// Check the bitvec is of the proper length
if participants.len() != signature_participants.len() {
@ -1189,7 +1189,7 @@ pub mod pallet {
// Verify the signature with the MuSig key of the signers
// We theoretically don't need set_keys_message to bind to removed_participants, as the
// key we're signing with effectively already does so, yet there's no reason not to
if !musig_key(set, &signers).verify(&set_keys_message(&set, key_pair), signature) {
if !musig_key(set.into(), &signers).verify(&set_keys_message(&set, key_pair), signature) {
Err(InvalidTransaction::BadProof)?;
}
@ -1207,8 +1207,10 @@ pub mod pallet {
};
// There must have been a previous session is PendingSlashReport is populated
let set =
ExternalValidatorSet { network, session: Session(Self::session(network).unwrap().0 - 1) };
let set = ExternalValidatorSet {
network,
session: Session(Self::session(NetworkId::from(network)).unwrap().0 - 1),
};
if !key.verify(&slashes.report_slashes_message(), signature) {
Err(InvalidTransaction::BadProof)?;
}

View file

@ -140,7 +140,7 @@ pub fn musig_key(set: ValidatorSet, set_keys: &[Public]) -> Public {
}
/// The message for the `set_keys` signature.
pub fn set_keys_message(set: &ValidatorSet, key_pair: &KeyPair) -> Vec<u8> {
pub fn set_keys_message(set: &ExternalValidatorSet, key_pair: &KeyPair) -> Vec<u8> {
(b"ValidatorSets-set_keys", set, key_pair).encode()
}