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
62 changed files with 452 additions and 508 deletions

60
Cargo.lock generated
View File

@@ -5630,19 +5630,6 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "monero-serai" name = "monero-serai"
version = "0.1.4-alpha" version = "0.1.4-alpha"
@@ -5717,21 +5704,6 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "multiaddr" name = "multiaddr"
version = "0.18.1" version = "0.18.1"
@@ -6478,17 +6450,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156" 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]] [[package]]
name = "pasta_curves" name = "pasta_curves"
version = "0.5.1" version = "0.5.1"
@@ -6533,9 +6494,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [ dependencies = [
"digest 0.10.7", "digest 0.10.7",
"hmac",
"password-hash",
"sha2",
] ]
[[package]] [[package]]
@@ -6658,20 +6616,6 @@ dependencies = [
"universal-hash", "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]] [[package]]
name = "polyval" name = "polyval"
version = "0.6.2" version = "0.6.2"
@@ -9006,6 +8950,7 @@ dependencies = [
"serai-coins-primitives", "serai-coins-primitives",
"serai-primitives", "serai-primitives",
"sp-core", "sp-core",
"sp-io",
"sp-runtime", "sp-runtime",
"sp-std", "sp-std",
] ]
@@ -9445,7 +9390,7 @@ dependencies = [
"generalized-bulletproofs-circuit-abstraction", "generalized-bulletproofs-circuit-abstraction",
"generalized-bulletproofs-ec-gadgets", "generalized-bulletproofs-ec-gadgets",
"minimal-ed448", "minimal-ed448",
"monero-wallet-util", "monero-wallet",
"multiexp", "multiexp",
"schnorr-signatures", "schnorr-signatures",
"secq256k1", "secq256k1",
@@ -9531,6 +9476,7 @@ dependencies = [
"sp-core", "sp-core",
"sp-io", "sp-io",
"sp-runtime", "sp-runtime",
"sp-std",
"zeroize", "zeroize",
] ]

View File

@@ -191,9 +191,6 @@ parking_lot = { path = "patches/parking_lot" }
zstd = { path = "patches/zstd" } zstd = { path = "patches/zstd" }
# Needed for WAL compression # Needed for WAL compression
rocksdb = { path = "patches/rocksdb" } 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 now has an std-based solution with an equivalent API
is-terminal = { path = "patches/is-terminal" } is-terminal = { path = "patches/is-terminal" }

View File

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

View File

@@ -11,8 +11,8 @@ use scale::{Encode, Decode};
use borsh::{BorshSerialize, BorshDeserialize}; use borsh::{BorshSerialize, BorshDeserialize};
use serai_client::{ use serai_client::{
primitives::{NetworkId, SeraiAddress}, primitives::{ExternalNetworkId, SeraiAddress},
validator_sets::primitives::{Session, ValidatorSet, KeyPair}, validator_sets::primitives::{Session, ExternalValidatorSet, KeyPair},
Public, Block, Serai, TemporalSerai, Public, Block, Serai, TemporalSerai,
}; };
@@ -52,13 +52,13 @@ pub const COSIGN_CONTEXT: &[u8] = b"/serai/coordinator/cosign";
#[derive(Debug, BorshSerialize, BorshDeserialize)] #[derive(Debug, BorshSerialize, BorshDeserialize)]
pub(crate) struct GlobalSession { pub(crate) struct GlobalSession {
pub(crate) start_block_number: u64, pub(crate) start_block_number: u64,
pub(crate) sets: Vec<ValidatorSet>, pub(crate) sets: Vec<ExternalValidatorSet>,
pub(crate) keys: HashMap<NetworkId, SeraiAddress>, pub(crate) keys: HashMap<ExternalNetworkId, SeraiAddress>,
pub(crate) stakes: HashMap<NetworkId, u64>, pub(crate) stakes: HashMap<ExternalNetworkId, u64>,
pub(crate) total_stake: u64, pub(crate) total_stake: u64,
} }
impl GlobalSession { 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()); cosigners.sort_by_key(|a| borsh::to_vec(a).unwrap());
Blake2s256::digest(borsh::to_vec(&cosigners).unwrap()).into() Blake2s256::digest(borsh::to_vec(&cosigners).unwrap()).into()
} }
@@ -101,12 +101,12 @@ pub struct Cosign {
/// The hash of the block to cosign. /// The hash of the block to cosign.
pub block_hash: [u8; 32], pub block_hash: [u8; 32],
/// The actual cosigner. /// The actual cosigner.
pub cosigner: NetworkId, pub cosigner: ExternalNetworkId,
} }
impl CosignIntent { impl CosignIntent {
/// Convert this into a `Cosign`. /// 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; let CosignIntent { global_session, block_number, block_hash, notable: _ } = self;
Cosign { global_session, block_number, block_hash, cosigner } 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 // 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 // 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. // 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. // Cosigns received for blocks not locally recognized as finalized.
Faults: (global_session: [u8; 32]) -> Vec<SignedCosign>, Faults: (global_session: [u8; 32]) -> Vec<SignedCosign>,
// The global session which faulted. // The global session which faulted.
@@ -177,15 +180,10 @@ create_db! {
/// Fetch the keys used for cosigning by a specific network. /// Fetch the keys used for cosigning by a specific network.
async fn keys_for_network( async fn keys_for_network(
serai: &TemporalSerai<'_>, serai: &TemporalSerai<'_>,
network: NetworkId, network: ExternalNetworkId,
) -> Result<Option<(Session, KeyPair)>, String> { ) -> 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) = 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 { else {
// If this network hasn't had a session declared, move on // If this network hasn't had a session declared, move on
return Ok(None); return Ok(None);
@@ -194,7 +192,7 @@ async fn keys_for_network(
// Get the keys for the latest session // Get the keys for the latest session
if let Some(keys) = serai if let Some(keys) = serai
.validator_sets() .validator_sets()
.keys(ValidatorSet { network, session: latest_session }) .keys(ExternalValidatorSet { network, session: latest_session })
.await .await
.map_err(|e| format!("{e:?}"))? .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(prior_session) = latest_session.0.checked_sub(1).map(Session) {
if let Some(keys) = serai if let Some(keys) = serai
.validator_sets() .validator_sets()
.keys(ValidatorSet { network, session: prior_session }) .keys(ExternalValidatorSet { network, session: prior_session })
.await .await
.map_err(|e| format!("{e:?}"))? .map_err(|e| format!("{e:?}"))?
{ {
@@ -216,16 +214,19 @@ async fn keys_for_network(
Ok(None) Ok(None)
} }
/// Fetch the `ValidatorSet`s, and their associated keys, used for cosigning as of this block. /// Fetch the `ExternalValidatorSet`s, and their associated keys, used for cosigning as of this
async fn cosigning_sets(serai: &TemporalSerai<'_>) -> Result<Vec<(ValidatorSet, Public)>, String> { /// block.
let mut sets = Vec::with_capacity(serai_client::primitives::NETWORKS.len()); async fn cosigning_sets(
for network in serai_client::primitives::NETWORKS { 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 { let Some((session, keys)) = keys_for_network(serai, network).await? else {
// If this network doesn't have usable keys, move on // If this network doesn't have usable keys, move on
continue; continue;
}; };
sets.push((ValidatorSet { network, session }, keys.0)); sets.push((ExternalValidatorSet { network, session }, keys.0));
} }
Ok(sets) 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 /// If this global session hasn't produced any notable cosigns, this will return the latest
/// cosigns for this session. /// cosigns for this session.
pub fn notable_cosigns(getter: &impl Get, global_session: [u8; 32]) -> Vec<SignedCosign> { pub fn notable_cosigns(getter: &impl Get, global_session: [u8; 32]) -> Vec<SignedCosign> {
let mut cosigns = Vec::with_capacity(serai_client::primitives::NETWORKS.len()); let mut cosigns = Vec::with_capacity(serai_client::primitives::EXTERNAL_NETWORKS.len());
for network in serai_client::primitives::NETWORKS { for network in serai_client::primitives::EXTERNAL_NETWORKS {
if let Some(cosign) = NetworksLatestCosignedBlock::get(getter, global_session, network) { if let Some(cosign) = NetworksLatestCosignedBlock::get(getter, global_session, network) {
cosigns.push(cosign); 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"); 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 // 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 // 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 let Some(cosign) = NetworksLatestCosignedBlock::get(&self.db, faulted, network) {
if cosign.cosign.global_session == faulted { if cosign.cosign.global_session == faulted {
cosigns.push(cosign); cosigns.push(cosign);
@@ -375,8 +376,8 @@ impl<D: Db> Cosigning<D> {
let Some(global_session) = evaluator::currently_evaluated_global_session(&self.db) else { let Some(global_session) = evaluator::currently_evaluated_global_session(&self.db) else {
return vec![]; return vec![];
}; };
let mut cosigns = Vec::with_capacity(serai_client::primitives::NETWORKS.len()); let mut cosigns = Vec::with_capacity(serai_client::primitives::EXTERNAL_NETWORKS.len());
for network in serai_client::primitives::NETWORKS { for network in serai_client::primitives::EXTERNAL_NETWORKS {
if let Some(cosign) = NetworksLatestCosignedBlock::get(&self.db, global_session, network) { if let Some(cosign) = NetworksLatestCosignedBlock::get(&self.db, global_session, network) {
cosigns.push(cosign); cosigns.push(cosign);
} }
@@ -487,12 +488,12 @@ impl<D: Db> Cosigning<D> {
Ok(()) 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. /// 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. /// 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![]; let mut res: Vec<CosignIntent> = vec![];
// While we have yet to find a notable cosign... // While we have yet to find a notable cosign...
while !res.last().map(|cosign| cosign.notable).unwrap_or(false) { while !res.last().map(|cosign| cosign.notable).unwrap_or(false) {

View File

@@ -14,8 +14,8 @@ use zeroize::Zeroizing;
use schnorrkel::Keypair; use schnorrkel::Keypair;
use serai_client::{ use serai_client::{
primitives::{NetworkId, PublicKey}, primitives::{ExternalNetworkId, PublicKey},
validator_sets::primitives::ValidatorSet, validator_sets::primitives::ExternalValidatorSet,
Serai, Serai,
}; };
@@ -104,7 +104,7 @@ impl serai_coordinator_p2p::Peer<'_> for Peer<'_> {
#[derive(Clone)] #[derive(Clone)]
struct Peers { 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 // 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: Mutex<mpsc::UnboundedReceiver<SignedCosign>>,
signed_cosigns_send: mpsc::UnboundedSender<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])>>, notable_cosign_requests: Mutex<mpsc::UnboundedReceiver<(InboundRequestId, [u8; 32])>>,
inbound_request_responses: mpsc::UnboundedSender<(InboundRequestId, Response)>, inbound_request_responses: mpsc::UnboundedSender<(InboundRequestId, Response)>,
} }
@@ -312,7 +313,7 @@ impl serai_cosign::RequestNotableCosigns for Libp2p {
impl serai_coordinator_p2p::P2p for Libp2p { impl serai_coordinator_p2p::P2p for Libp2p {
type Peer<'a> = Peer<'a>; 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 { async move {
let Some(peer_ids) = self.0.peers.peers.read().await.get(&network).cloned() else { let Some(peer_ids) = self.0.peers.peers.read().await.get(&network).cloned() else {
return vec![]; return vec![];

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
use core::future::Future; use core::future::Future;
use std::time::{Duration, SystemTime}; 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; 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 /// If the other validator has more blocks then we do, they're expected to inform us. This forms
/// the sync protocol for our Tributaries. /// the sync protocol for our Tributaries.
pub(crate) struct HeartbeatTask<TD: Db, Tx: TransactionTrait, P: P2p> { 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) tributary: Tributary<TD, Tx, P>,
pub(crate) reader: TributaryReader<TD, Tx>, pub(crate) reader: TributaryReader<TD, Tx>,
pub(crate) p2p: P, pub(crate) p2p: P,

View File

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

View File

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

View File

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

View File

@@ -14,8 +14,8 @@ use borsh::BorshDeserialize;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use serai_client::{ use serai_client::{
primitives::{NetworkId, PublicKey, SeraiAddress, Signature}, primitives::{ExternalNetworkId, PublicKey, SeraiAddress, Signature},
validator_sets::primitives::{ValidatorSet, KeyPair}, validator_sets::primitives::{ExternalValidatorSet, KeyPair},
Serai, Serai,
}; };
use message_queue::{Service, client::MessageQueue}; use message_queue::{Service, client::MessageQueue};
@@ -153,14 +153,13 @@ async fn handle_network(
mut db: impl serai_db::Db, mut db: impl serai_db::Db,
message_queue: Arc<MessageQueue>, message_queue: Arc<MessageQueue>,
serai: Arc<Serai>, serai: Arc<Serai>,
network: NetworkId, network: ExternalNetworkId,
) { ) {
// Spawn the task to publish batches for this network // Spawn the task to publish batches for this network
{ {
let (publish_batch_task_def, publish_batch_task) = Task::new(); let (publish_batch_task_def, publish_batch_task) = Task::new();
tokio::spawn( tokio::spawn(
PublishBatchTask::new(db.clone(), serai.clone(), network) PublishBatchTask::new(db.clone(), serai.clone(), network)
.unwrap()
.continually_run(publish_batch_task_def, vec![]), .continually_run(publish_batch_task_def, vec![]),
); );
// Forget its handle so it always runs in the background // Forget its handle so it always runs in the background
@@ -197,7 +196,7 @@ async fn handle_network(
match msg { match msg {
messages::ProcessorMessage::KeyGen(msg) => match msg { messages::ProcessorMessage::KeyGen(msg) => match msg {
messages::key_gen::ProcessorMessage::Participation { session, participation } => { messages::key_gen::ProcessorMessage::Participation { session, participation } => {
let set = ValidatorSet { network, session }; let set = ExternalValidatorSet { network, session };
TributaryTransactionsFromProcessorMessages::send( TributaryTransactionsFromProcessorMessages::send(
&mut txn, &mut txn,
set, set,
@@ -211,7 +210,7 @@ async fn handle_network(
} => { } => {
KeysToConfirm::set( KeysToConfirm::set(
&mut txn, &mut txn,
ValidatorSet { network, session }, ExternalValidatorSet { network, session },
&KeyPair( &KeyPair(
PublicKey::from_raw(substrate_key), PublicKey::from_raw(substrate_key),
network_key network_key
@@ -221,15 +220,15 @@ async fn handle_network(
); );
} }
messages::key_gen::ProcessorMessage::Blame { session, participant } => { 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::ProcessorMessage::Sign(msg) => match msg {
messages::sign::ProcessorMessage::InvalidParticipant { session, participant } => { 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 } => { messages::sign::ProcessorMessage::Preprocesses { id, preprocesses } => {
let set = ValidatorSet { network, session: id.session }; let set = ExternalValidatorSet { network, session: id.session };
if id.attempt == 0 { if id.attempt == 0 {
// Batches are declared by their intent to be signed // Batches are declared by their intent to be signed
if let messages::sign::VariantSignId::Batch(hash) = id.id { if let messages::sign::VariantSignId::Batch(hash) = id.id {
@@ -254,7 +253,7 @@ async fn handle_network(
); );
} }
messages::sign::ProcessorMessage::Shares { id, shares } => { messages::sign::ProcessorMessage::Shares { id, shares } => {
let set = ValidatorSet { network, session: id.session }; let set = ExternalValidatorSet { network, session: id.session };
TributaryTransactionsFromProcessorMessages::send( TributaryTransactionsFromProcessorMessages::send(
&mut txn, &mut txn,
set, set,
@@ -282,7 +281,7 @@ async fn handle_network(
} => { } => {
SlashReports::set( SlashReports::set(
&mut txn, &mut txn,
ValidatorSet { network, session }, ExternalValidatorSet { network, session },
slash_report, slash_report,
Signature(signature), Signature(signature),
); );
@@ -298,7 +297,7 @@ async fn handle_network(
.push(plan.transaction_plan_id); .push(plan.transaction_plan_id);
} }
for (session, plans) in by_session { for (session, plans) in by_session {
let set = ValidatorSet { network, session }; let set = ExternalValidatorSet { network, session };
SubstrateBlockPlans::set(&mut txn, set, block, &plans); SubstrateBlockPlans::set(&mut txn, set, block, &plans);
TributaryTransactionsFromProcessorMessages::send( TributaryTransactionsFromProcessorMessages::send(
&mut txn, &mut txn,
@@ -481,10 +480,7 @@ async fn main() {
); );
// Handle each of the networks // Handle each of the networks
for network in serai_client::primitives::NETWORKS { for network in serai_client::primitives::EXTERNAL_NETWORKS {
if network == NetworkId::Serai {
continue;
}
tokio::spawn(handle_network(db.clone(), message_queue.clone(), serai.clone(), network)); 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_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 message_queue::{Service, Metadata, client::MessageQueue};
use tributary_sdk::Tributary; use tributary_sdk::Tributary;
@@ -27,8 +27,8 @@ pub(crate) struct SubstrateTask<P: P2p> {
pub(crate) message_queue: Arc<MessageQueue>, pub(crate) message_queue: Arc<MessageQueue>,
pub(crate) p2p: P, pub(crate) p2p: P,
pub(crate) p2p_add_tributary: pub(crate) p2p_add_tributary:
mpsc::UnboundedSender<(ValidatorSet, Tributary<Db, Transaction, P>)>, mpsc::UnboundedSender<(ExternalValidatorSet, Tributary<Db, Transaction, P>)>,
pub(crate) p2p_retire_tributary: mpsc::UnboundedSender<ValidatorSet>, pub(crate) p2p_retire_tributary: mpsc::UnboundedSender<ExternalValidatorSet>,
} }
impl<P: P2p> ContinuallyRan for SubstrateTask<P> { impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
@@ -38,7 +38,7 @@ impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
let mut made_progress = false; let mut made_progress = false;
// Handle the Canonical events // Handle the Canonical events
for network in serai_client::primitives::NETWORKS { for network in serai_client::primitives::EXTERNAL_NETWORKS {
loop { loop {
let mut txn = self.db.txn(); let mut txn = self.db.txn();
let Some(msg) = serai_coordinator_substrate::Canonical::try_recv(&mut txn, network) 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 { match msg {
messages::substrate::CoordinatorMessage::SetKeys { session, .. } => { messages::substrate::CoordinatorMessage::SetKeys { session, .. } => {
KeySet::set(&mut txn, ValidatorSet { network, session }, &()); KeySet::set(&mut txn, ExternalValidatorSet { network, session }, &());
} }
messages::substrate::CoordinatorMessage::SlashesReported { session } => { messages::substrate::CoordinatorMessage::SlashesReported { session } => {
let prior_retired = crate::db::RetiredTributary::get(&txn, network); 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); crate::db::RetiredTributary::set(&mut txn, network, &session);
self self
.p2p_retire_tributary .p2p_retire_tributary
.send(ValidatorSet { network, session }) .send(ExternalValidatorSet { network, session })
.expect("p2p retire_tributary channel dropped?"); .expect("p2p retire_tributary channel dropped?");
} }
messages::substrate::CoordinatorMessage::Block { .. } => {} messages::substrate::CoordinatorMessage::Block { .. } => {}
@@ -108,7 +108,10 @@ impl<P: P2p> ContinuallyRan for SubstrateTask<P> {
*/ */
crate::db::TributaryCleanup::send( crate::db::TributaryCleanup::send(
&mut txn, &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 serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
use scale::Encode; 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}; use tributary_sdk::{TransactionKind, TransactionError, ProvidedError, TransactionTrait, Tributary};
@@ -33,13 +33,13 @@ use crate::{
create_db! { create_db! {
Coordinator { Coordinator {
PublishOnRecognition: (set: ValidatorSet, topic: Topic) -> Transaction, PublishOnRecognition: (set: ExternalValidatorSet, topic: Topic) -> Transaction,
} }
} }
db_channel! { db_channel! {
Coordinator { 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, /// 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. /// within this file. It should only be considered an internal helper for this domain alone.
async fn provide_transaction<TD: DbTrait, P: P2p>( async fn provide_transaction<TD: DbTrait, P: P2p>(
set: ValidatorSet, set: ExternalValidatorSet,
tributary: &Tributary<TD, Transaction, P>, tributary: &Tributary<TD, Transaction, P>,
tx: Transaction, 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>( async fn add_with_recognition_check<TD: DbTrait, P: P2p>(
set: ValidatorSet, set: ExternalValidatorSet,
tributary_db: &mut TD, tributary_db: &mut TD,
tributary: &Tributary<TD, Transaction, P>, tributary: &Tributary<TD, Transaction, P>,
key: &Zeroizing<<Ristretto as Ciphersuite>::F>, 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. /// Takes the messages from ScanTributaryTask and publishes them to the message-queue.
pub(crate) struct TributaryProcessorMessagesTask<TD: DbTrait> { pub(crate) struct TributaryProcessorMessagesTask<TD: DbTrait> {
tributary_db: TD, tributary_db: TD,
set: ValidatorSet, set: ExternalValidatorSet,
message_queue: Arc<MessageQueue>, message_queue: Arc<MessageQueue>,
} }
impl<TD: DbTrait> ContinuallyRan for TributaryProcessorMessagesTask<TD> { 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. /// Run the scan task whenever the Tributary adds a new block.
async fn scan_on_new_block<CD: DbTrait, TD: DbTrait, P: P2p>( async fn scan_on_new_block<CD: DbTrait, TD: DbTrait, P: P2p>(
db: CD, db: CD,
set: ValidatorSet, set: ExternalValidatorSet,
tributary: Tributary<TD, Transaction, P>, tributary: Tributary<TD, Transaction, P>,
scan_tributary_task: TaskHandle, scan_tributary_task: TaskHandle,
tasks_to_keep_alive: Vec<TaskHandle>, tasks_to_keep_alive: Vec<TaskHandle>,
@@ -469,7 +469,7 @@ pub(crate) async fn spawn_tributary<P: P2p>(
db: Db, db: Db,
message_queue: Arc<MessageQueue>, message_queue: Arc<MessageQueue>,
p2p: P, p2p: P,
p2p_add_tributary: &mpsc::UnboundedSender<(ValidatorSet, Tributary<Db, Transaction, P>)>, p2p_add_tributary: &mpsc::UnboundedSender<(ExternalValidatorSet, Tributary<Db, Transaction, P>)>,
set: NewSetInformation, set: NewSetInformation,
serai_key: Zeroizing<<Ristretto as Ciphersuite>::F>, serai_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
) { ) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ use std::collections::HashMap;
use scale::Encode; use scale::Encode;
use borsh::{BorshSerialize, BorshDeserialize}; 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}; use messages::sign::{VariantSignId, SignId};
@@ -97,7 +97,7 @@ impl Topic {
/// The SignId for this topic /// The SignId for this topic
/// ///
/// Returns None if Topic isn't Topic::Sign /// 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)] #[allow(clippy::match_same_arms)]
match self { match self {
Topic::RemoveParticipant { .. } => None, Topic::RemoveParticipant { .. } => None,
@@ -115,7 +115,7 @@ impl Topic {
/// Returns None if Topic isn't Topic::DkgConfirmation. /// Returns None if Topic isn't Topic::DkgConfirmation.
pub(crate) fn dkg_confirmation_sign_id( pub(crate) fn dkg_confirmation_sign_id(
self, self,
set: ValidatorSet, set: ExternalValidatorSet,
) -> Option<messages::sign::SignId> { ) -> Option<messages::sign::SignId> {
#[allow(clippy::match_same_arms)] #[allow(clippy::match_same_arms)]
match self { match self {
@@ -227,41 +227,48 @@ pub(crate) enum DataSet<D: Borshy> {
create_db!( create_db!(
CoordinatorTributary { CoordinatorTributary {
// The last handled tributary block's (number, hash) // 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. // 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 // 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. // 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. // 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. // 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. // 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. // 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. // 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. // 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!( db_channel!(
CoordinatorTributary { CoordinatorTributary {
// Messages to send to the processor // Messages to send to the processor
ProcessorMessages: (set: ValidatorSet) -> messages::CoordinatorMessage, ProcessorMessages: (set: ExternalValidatorSet) -> messages::CoordinatorMessage,
// Messages for the DKG confirmation // Messages for the DKG confirmation
DkgConfirmationMessages: (set: ValidatorSet) -> messages::sign::CoordinatorMessage, DkgConfirmationMessages: (set: ExternalValidatorSet) -> messages::sign::CoordinatorMessage,
// Topics which have been explicitly recognized // Topics which have been explicitly recognized
RecognizedTopics: (set: ValidatorSet) -> Topic, RecognizedTopics: (set: ExternalValidatorSet) -> Topic,
} }
); );
@@ -269,13 +276,13 @@ pub(crate) struct TributaryDb;
impl TributaryDb { impl TributaryDb {
pub(crate) fn last_handled_tributary_block( pub(crate) fn last_handled_tributary_block(
getter: &impl Get, getter: &impl Get,
set: ValidatorSet, set: ExternalValidatorSet,
) -> Option<(u64, [u8; 32])> { ) -> Option<(u64, [u8; 32])> {
LastHandledTributaryBlock::get(getter, set) LastHandledTributaryBlock::get(getter, set)
} }
pub(crate) fn set_last_handled_tributary_block( pub(crate) fn set_last_handled_tributary_block(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
block_number: u64, block_number: u64,
block_hash: [u8; 32], block_hash: [u8; 32],
) { ) {
@@ -284,23 +291,26 @@ impl TributaryDb {
pub(crate) fn latest_substrate_block_to_cosign( pub(crate) fn latest_substrate_block_to_cosign(
getter: &impl Get, getter: &impl Get,
set: ValidatorSet, set: ExternalValidatorSet,
) -> Option<[u8; 32]> { ) -> Option<[u8; 32]> {
LatestSubstrateBlockToCosign::get(getter, set) LatestSubstrateBlockToCosign::get(getter, set)
} }
pub(crate) fn set_latest_substrate_block_to_cosign( pub(crate) fn set_latest_substrate_block_to_cosign(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
substrate_block_hash: [u8; 32], substrate_block_hash: [u8; 32],
) { ) {
LatestSubstrateBlockToCosign::set(txn, set, &substrate_block_hash); 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) ActivelyCosigning::get(txn, set)
} }
pub(crate) fn start_cosigning( pub(crate) fn start_cosigning(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
substrate_block_hash: [u8; 32], substrate_block_hash: [u8; 32],
substrate_block_number: u64, 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"); assert!(ActivelyCosigning::take(txn, set).is_some(), "finished cosigning but not cosigning");
} }
pub(crate) fn mark_cosigned( pub(crate) fn mark_cosigned(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
substrate_block_hash: [u8; 32], substrate_block_hash: [u8; 32],
) { ) {
Cosigned::set(txn, set, substrate_block_hash, &()); Cosigned::set(txn, set, substrate_block_hash, &());
} }
pub(crate) fn cosigned( pub(crate) fn cosigned(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
substrate_block_hash: [u8; 32], substrate_block_hash: [u8; 32],
) -> bool { ) -> bool {
Cosigned::get(txn, set, substrate_block_hash).is_some() 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); AccumulatedWeight::set(txn, set, topic, &0);
RecognizedTopics::send(txn, set, &topic); 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() 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![]) { 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 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( pub(crate) fn fatal_slash(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
validator: SeraiAddress, validator: SeraiAddress,
reason: &str, reason: &str,
) { ) {
@@ -386,7 +396,7 @@ impl TributaryDb {
pub(crate) fn is_fatally_slashed( pub(crate) fn is_fatally_slashed(
getter: &impl Get, getter: &impl Get,
set: ValidatorSet, set: ExternalValidatorSet,
validator: SeraiAddress, validator: SeraiAddress,
) -> bool { ) -> bool {
SlashPoints::get(getter, set, validator).unwrap_or(0) == u32::MAX SlashPoints::get(getter, set, validator).unwrap_or(0) == u32::MAX
@@ -395,7 +405,7 @@ impl TributaryDb {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn accumulate<D: Borshy>( pub(crate) fn accumulate<D: Borshy>(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
validators: &[SeraiAddress], validators: &[SeraiAddress],
total_weight: u16, total_weight: u16,
block_number: u64, block_number: u64,
@@ -511,7 +521,7 @@ impl TributaryDb {
pub(crate) fn send_message( pub(crate) fn send_message(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
set: ValidatorSet, set: ExternalValidatorSet,
message: impl Into<messages::CoordinatorMessage>, message: impl Into<messages::CoordinatorMessage>,
) { ) {
ProcessorMessages::send(txn, set, &message.into()); ProcessorMessages::send(txn, set, &message.into());

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ use core::future::Future;
use monero_wallet::rpc::{RpcError, Rpc as RpcTrait}; use monero_wallet::rpc::{RpcError, Rpc as RpcTrait};
use monero_simple_request_rpc::SimpleRequestRpc; use monero_simple_request_rpc::SimpleRequestRpc;
use serai_client::primitives::{NetworkId, Coin, Amount}; use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount};
use scanner::ScannerFeed; use scanner::ScannerFeed;
use signers::TransactionPublisher; use signers::TransactionPublisher;
@@ -19,7 +19,7 @@ pub(crate) struct Rpc {
} }
impl ScannerFeed for 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 // 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 // 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 // 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 { fn dust(coin: ExternalCoin) -> Amount {
assert_eq!(coin, Coin::Monero); assert_eq!(coin, ExternalCoin::Monero);
// 0.01 XMR // 0.01 XMR
Amount(10_000_000_000) Amount(10_000_000_000)
@@ -116,11 +116,11 @@ impl ScannerFeed for Rpc {
fn cost_to_aggregate( fn cost_to_aggregate(
&self, &self,
coin: Coin, coin: ExternalCoin,
_reference_block: &Self::Block, _reference_block: &Self::Block,
) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>> { ) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>> {
async move { async move {
assert_eq!(coin, Coin::Bitcoin); assert_eq!(coin, ExternalCoin::Bitcoin);
// TODO // TODO
Ok(Amount(0)) Ok(Amount(0))
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,7 +10,7 @@ use group::GroupEncoding;
use borsh::{BorshSerialize, BorshDeserialize}; use borsh::{BorshSerialize, BorshDeserialize};
use serai_db::{Get, DbTxn, Db}; use serai_db::{Get, DbTxn, Db};
use serai_primitives::{NetworkId, Coin, Amount}; use serai_primitives::{ExternalNetworkId, ExternalCoin, Amount};
use serai_coins_primitives::OutInstructionWithBalance; use serai_coins_primitives::OutInstructionWithBalance;
use messages::substrate::ExecutedBatch; 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. /// This defines the primitive types used, along with various getters necessary for indexing.
pub trait ScannerFeed: 'static + Send + Sync + Clone { pub trait ScannerFeed: 'static + Send + Sync + Clone {
/// The ID of the network being scanned for. /// 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. /// 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 /// 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. /// 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. /// 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. /// This is defined as the transaction fee for a 2-input, 1-output transaction.
fn cost_to_aggregate( fn cost_to_aggregate(
&self, &self,
coin: Coin, coin: ExternalCoin,
reference_block: &Self::Block, reference_block: &Self::Block,
) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>>; ) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>>;
} }

View File

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

View File

@@ -2,7 +2,7 @@ use core::marker::PhantomData;
use group::GroupEncoding; use group::GroupEncoding;
use serai_primitives::{Coin, Amount, Balance}; use serai_primitives::{ExternalCoin, Amount, ExternalBalance};
use borsh::BorshDeserialize; use borsh::BorshDeserialize;
use serai_db::{Get, DbTxn, create_db, db_channel}; use serai_db::{Get, DbTxn, create_db, db_channel};
@@ -13,31 +13,31 @@ use scanner::{ScannerFeed, KeyFor, AddressFor, OutputFor};
create_db! { create_db! {
UtxoScheduler { UtxoScheduler {
OperatingCosts: (coin: Coin) -> Amount, OperatingCosts: (coin: ExternalCoin) -> Amount,
SerializedOutputs: (key: &[u8], coin: Coin) -> Vec<u8>, SerializedOutputs: (key: &[u8], coin: ExternalCoin) -> Vec<u8>,
SerializedQueuedPayments: (key: &[u8], coin: Coin) -> Vec<u8>, SerializedQueuedPayments: (key: &[u8], coin: ExternalCoin) -> Vec<u8>,
} }
} }
db_channel! { db_channel! {
UtxoScheduler { UtxoScheduler {
PendingBranch: (key: &[u8], balance: Balance) -> Vec<u8>, PendingBranch: (key: &[u8], balance: ExternalBalance) -> Vec<u8>,
} }
} }
pub(crate) struct Db<S: ScannerFeed>(PhantomData<S>); pub(crate) struct Db<S: ScannerFeed>(PhantomData<S>);
impl<S: ScannerFeed> Db<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)) 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) OperatingCosts::set(txn, coin, &amount)
} }
pub(crate) fn outputs( pub(crate) fn outputs(
getter: &impl Get, getter: &impl Get,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
) -> Option<Vec<OutputFor<S>>> { ) -> Option<Vec<OutputFor<S>>> {
let buf = SerializedOutputs::get(getter, key.to_bytes().as_ref(), coin)?; let buf = SerializedOutputs::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice(); let mut buf = buf.as_slice();
@@ -51,7 +51,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_outputs( pub(crate) fn set_outputs(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
outputs: &[OutputFor<S>], outputs: &[OutputFor<S>],
) { ) {
let mut buf = Vec::with_capacity(outputs.len() * 128); 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); 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); SerializedOutputs::del(txn, key.to_bytes().as_ref(), coin);
} }
pub(crate) fn queued_payments( pub(crate) fn queued_payments(
getter: &impl Get, getter: &impl Get,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
) -> Option<Vec<Payment<AddressFor<S>>>> { ) -> Option<Vec<Payment<AddressFor<S>>>> {
let buf = SerializedQueuedPayments::get(getter, key.to_bytes().as_ref(), coin)?; let buf = SerializedQueuedPayments::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice(); let mut buf = buf.as_slice();
@@ -81,7 +81,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_queued_payments( pub(crate) fn set_queued_payments(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
queued: &[Payment<AddressFor<S>>], queued: &[Payment<AddressFor<S>>],
) { ) {
let mut buf = Vec::with_capacity(queued.len() * 128); 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); 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); SerializedQueuedPayments::del(txn, key.to_bytes().as_ref(), coin);
} }
pub(crate) fn queue_pending_branch( pub(crate) fn queue_pending_branch(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
key: KeyFor<S>, key: KeyFor<S>,
balance: Balance, balance: ExternalBalance,
child: &TreeTransaction<AddressFor<S>>, child: &TreeTransaction<AddressFor<S>>,
) { ) {
PendingBranch::send(txn, key.to_bytes().as_ref(), balance, &borsh::to_vec(child).unwrap()) 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( pub(crate) fn take_pending_branch(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
key: KeyFor<S>, key: KeyFor<S>,
balance: Balance, balance: ExternalBalance,
) -> Option<TreeTransaction<AddressFor<S>>> { ) -> Option<TreeTransaction<AddressFor<S>>> {
PendingBranch::try_recv(txn, key.to_bytes().as_ref(), balance) PendingBranch::try_recv(txn, key.to_bytes().as_ref(), balance)
.map(|bytes| TreeTransaction::<AddressFor<S>>::deserialize(&mut bytes.as_slice()).unwrap()) .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 group::GroupEncoding;
use serai_primitives::{Coin, Amount, Balance}; use serai_primitives::{ExternalCoin, Amount, ExternalBalance};
use serai_db::DbTxn; use serai_db::DbTxn;
@@ -42,7 +42,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
block: &BlockFor<S>, block: &BlockFor<S>,
key_for_change: KeyFor<S>, key_for_change: KeyFor<S>,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
) -> Result<Vec<EventualityFor<S>>, <Self as SchedulerTrait<S>>::EphemeralError> { ) -> Result<Vec<EventualityFor<S>>, <Self as SchedulerTrait<S>>::EphemeralError> {
let mut eventualities = vec![]; let mut eventualities = vec![];
@@ -79,7 +79,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
operating_costs: &mut u64, operating_costs: &mut u64,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
value_of_outputs: u64, value_of_outputs: u64,
) -> Vec<Payment<AddressFor<S>>> { ) -> Vec<Payment<AddressFor<S>>> {
// Fetch all payments for this key // Fetch all payments for this key
@@ -133,7 +133,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
fn queue_branches( fn queue_branches(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
effected_payments: Vec<Amount>, effected_payments: Vec<Amount>,
tx: TreeTransaction<AddressFor<S>>, tx: TreeTransaction<AddressFor<S>>,
) { ) {
@@ -149,7 +149,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
children thanks to our sort. children thanks to our sort.
*/ */
for (amount, child) in effected_payments.into_iter().zip(children) { 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); let branch_address = P::branch_address(key);
'coin: for coin in S::NETWORK.coins() { 'coin: for coin in S::NETWORK.coins() {
let coin = *coin;
// Perform any input aggregation we should // Perform any input aggregation we should
eventualities eventualities
.append(&mut self.aggregate_inputs(txn, block, key_for_change, key, coin).await?); .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>, block: &BlockFor<S>,
from: KeyFor<S>, from: KeyFor<S>,
to: KeyFor<S>, to: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
) -> Result<(), <Self as SchedulerTrait<S>>::EphemeralError> { ) -> Result<(), <Self as SchedulerTrait<S>>::EphemeralError> {
let from_bytes = from.to_bytes().as_ref().to_vec(); let from_bytes = from.to_bytes().as_ref().to_vec();
// Ensure our inputs are aggregated // 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>) { fn activate_key(txn: &mut impl DbTxn, key: KeyFor<S>) {
for coin in S::NETWORK.coins() { for coin in S::NETWORK.coins() {
assert!(Db::<S>::outputs(txn, key, *coin).is_none()); assert!(Db::<S>::outputs(txn, key, coin).is_none());
Db::<S>::set_outputs(txn, key, *coin, &[]); Db::<S>::set_outputs(txn, key, coin, &[]);
assert!(Db::<S>::queued_payments(txn, key, *coin).is_none()); assert!(Db::<S>::queued_payments(txn, key, coin).is_none());
Db::<S>::set_queued_payments(txn, key, *coin, &[]); 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() { for coin in S::NETWORK.coins() {
// Move the payments to the new key // Move the payments to the new key
{ {
let still_queued = Db::<S>::queued_payments(txn, retiring_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 new_queued = Db::<S>::queued_payments(txn, new_key, coin).unwrap();
let mut queued = still_queued; let mut queued = still_queued;
queued.append(&mut new_queued); queued.append(&mut new_queued);
Db::<S>::set_queued_payments(txn, retiring_key, *coin, &[]); 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, new_key, coin, &queued);
} }
// Move the outputs to the new key // 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) 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>) { fn retire_key(txn: &mut impl DbTxn, key: KeyFor<S>) {
for coin in S::NETWORK.coins() { for coin in S::NETWORK.coins() {
assert!(Db::<S>::outputs(txn, key, *coin).unwrap().is_empty()); assert!(Db::<S>::outputs(txn, key, coin).unwrap().is_empty());
Db::<S>::del_outputs(txn, key, *coin); Db::<S>::del_outputs(txn, key, coin);
assert!(Db::<S>::queued_payments(txn, key, *coin).unwrap().is_empty()); assert!(Db::<S>::queued_payments(txn, key, coin).unwrap().is_empty());
Db::<S>::del_queued_payments(txn, key, *coin); Db::<S>::del_queued_payments(txn, key, coin);
} }
} }
@@ -463,7 +461,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
block, block,
active_keys[0].0, active_keys[0].0,
active_keys[1].0, active_keys[1].0,
*coin, coin,
) )
.await?; .await?;
} }
@@ -552,10 +550,10 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
// Queue the payments for this key // Queue the payments for this key
for coin in S::NETWORK.coins() { 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 queued_payments
.extend(payments.iter().filter(|payment| payment.balance().coin == *coin).cloned()); .extend(payments.iter().filter(|payment| payment.balance().coin == coin).cloned());
Db::<S>::set_queued_payments(txn, fulfillment_key, *coin, &queued_payments); Db::<S>::set_queued_payments(txn, fulfillment_key, coin, &queued_payments);
} }
// Handle the queued payments // Handle the queued payments

View File

@@ -2,7 +2,7 @@ use core::marker::PhantomData;
use group::GroupEncoding; use group::GroupEncoding;
use serai_primitives::{Coin, Amount}; use serai_primitives::{ExternalCoin, Amount};
use serai_db::{Get, DbTxn, create_db}; use serai_db::{Get, DbTxn, create_db};
@@ -11,28 +11,28 @@ use scanner::{ScannerFeed, KeyFor, AddressFor, OutputFor};
create_db! { create_db! {
TransactionChainingScheduler { TransactionChainingScheduler {
OperatingCosts: (coin: Coin) -> Amount, OperatingCosts: (coin: ExternalCoin) -> Amount,
SerializedOutputs: (key: &[u8], coin: Coin) -> Vec<u8>, SerializedOutputs: (key: &[u8], coin: ExternalCoin) -> Vec<u8>,
AlreadyAccumulatedOutput: (id: &[u8]) -> (), AlreadyAccumulatedOutput: (id: &[u8]) -> (),
// We should be immediately able to schedule the fulfillment of payments, yet this may not be // 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) // 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>); pub(crate) struct Db<S: ScannerFeed>(PhantomData<S>);
impl<S: ScannerFeed> Db<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)) 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) OperatingCosts::set(txn, coin, &amount)
} }
pub(crate) fn outputs( pub(crate) fn outputs(
getter: &impl Get, getter: &impl Get,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
) -> Option<Vec<OutputFor<S>>> { ) -> Option<Vec<OutputFor<S>>> {
let buf = SerializedOutputs::get(getter, key.to_bytes().as_ref(), coin)?; let buf = SerializedOutputs::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice(); let mut buf = buf.as_slice();
@@ -46,7 +46,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_outputs( pub(crate) fn set_outputs(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
outputs: &[OutputFor<S>], outputs: &[OutputFor<S>],
) { ) {
let mut buf = Vec::with_capacity(outputs.len() * 128); 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); 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); SerializedOutputs::del(txn, key.to_bytes().as_ref(), coin);
} }
@@ -75,7 +75,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn queued_payments( pub(crate) fn queued_payments(
getter: &impl Get, getter: &impl Get,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
) -> Option<Vec<Payment<AddressFor<S>>>> { ) -> Option<Vec<Payment<AddressFor<S>>>> {
let buf = SerializedQueuedPayments::get(getter, key.to_bytes().as_ref(), coin)?; let buf = SerializedQueuedPayments::get(getter, key.to_bytes().as_ref(), coin)?;
let mut buf = buf.as_slice(); let mut buf = buf.as_slice();
@@ -89,7 +89,7 @@ impl<S: ScannerFeed> Db<S> {
pub(crate) fn set_queued_payments( pub(crate) fn set_queued_payments(
txn: &mut impl DbTxn, txn: &mut impl DbTxn,
key: KeyFor<S>, key: KeyFor<S>,
coin: Coin, coin: ExternalCoin,
queued: &[Payment<AddressFor<S>>], queued: &[Payment<AddressFor<S>>],
) { ) {
let mut buf = Vec::with_capacity(queued.len() * 128); 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); 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); SerializedQueuedPayments::del(txn, key.to_bytes().as_ref(), coin);
} }
} }

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ pub use abi::{primitives, Transaction};
use abi::*; use abi::*;
pub use primitives::{SeraiAddress, Signature, Amount}; pub use primitives::{SeraiAddress, Signature, Amount};
use primitives::{Header, NetworkId}; use primitives::{Header, ExternalNetworkId};
pub mod coins; pub mod coins;
pub use coins::SeraiCoins; pub use coins::SeraiCoins;
@@ -313,7 +313,7 @@ impl Serai {
/// Return the P2P Multiaddrs for the validators of the specified network. /// Return the P2P Multiaddrs for the validators of the specified network.
pub async fn p2p_validators( pub async fn p2p_validators(
&self, &self,
network: NetworkId, network: ExternalNetworkId,
) -> Result<Vec<multiaddr::Multiaddr>, SeraiError> { ) -> Result<Vec<multiaddr::Multiaddr>, SeraiError> {
self.call("p2p_validators", network).await 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}; use serai_abi::{primitives::Amount, validator_sets::primitives::ExternalValidatorSet};
pub use serai_abi::validator_sets::primitives; 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::{ use crate::{
primitives::{NetworkId, ExternalNetworkId, EmbeddedEllipticCurve, SeraiAddress}, primitives::{NetworkId, ExternalNetworkId, EmbeddedEllipticCurve},
Transaction, Serai, TemporalSerai, SeraiError, Transaction, Serai, TemporalSerai, SeraiError,
}; };
@@ -203,7 +203,7 @@ impl SeraiValidatorSets<'_> {
} }
pub fn set_keys( pub fn set_keys(
network: NetworkId, network: ExternalNetworkId,
key_pair: KeyPair, key_pair: KeyPair,
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>, signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
signature: Signature, signature: Signature,
@@ -237,7 +237,7 @@ impl SeraiValidatorSets<'_> {
} }
pub fn report_slashes( pub fn report_slashes(
network: NetworkId, network: ExternalNetworkId,
slashes: SlashReport, slashes: SlashReport,
signature: Signature, signature: Signature,
) -> Transaction { ) -> Transaction {

View File

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

View File

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

View File

@@ -11,10 +11,11 @@ use sp_core::{sr25519::Signature, Pair as PairTrait};
use serai_abi::{ use serai_abi::{
primitives::{ 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}, validator_sets::primitives::{Session, ValidatorSet, musig_context},
genesis_liquidity::primitives::{oraclize_values_message, Values}, genesis_liquidity::primitives::{Values, oraclize_values_message},
in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch}, in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch},
}; };

View File

@@ -9,7 +9,7 @@ use scale::Encode;
use sp_core::Pair; use sp_core::Pair;
use serai_client::{ 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}, validator_sets::primitives::{ExternalValidatorSet, KeyPair},
in_instructions::{ in_instructions::{
primitives::{Batch, SignedBatch, batch_message, InInstruction, InInstructionWithBalance}, primitives::{Batch, SignedBatch, batch_message, InInstruction, InInstructionWithBalance},

View File

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

View File

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

View File

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

View File

@@ -5,8 +5,8 @@ use serai_client::TemporalSerai;
use serai_abi::{ use serai_abi::{
primitives::{ primitives::{
NETWORKS, COINS, TARGET_BLOCK_TIME, FAST_EPOCH_DURATION, FAST_EPOCH_INITIAL_PERIOD, BlockHash, EXTERNAL_NETWORKS, NETWORKS, TARGET_BLOCK_TIME, FAST_EPOCH_DURATION, FAST_EPOCH_INITIAL_PERIOD,
Coin, BlockHash, ExternalNetworkId, NetworkId, ExternalCoin, Amount, ExternalBalance,
}, },
validator_sets::primitives::Session, validator_sets::primitives::Session,
emissions::primitives::{INITIAL_REWARD_PER_BLOCK, SECURE_BY}, emissions::primitives::{INITIAL_REWARD_PER_BLOCK, SECURE_BY},
@@ -50,7 +50,6 @@ async fn send_batches(serai: &Serai, ids: &mut HashMap<ExternalNetworkId, u32>)
.await; .await;
} }
} }
}
async fn test_emissions(serai: Serai) { async fn test_emissions(serai: Serai) {
// set up the genesis // set up the genesis

View File

@@ -7,11 +7,11 @@ use sp_core::{
use serai_client::{ use serai_client::{
primitives::{ primitives::{
FAST_EPOCH_DURATION, TARGET_BLOCK_TIME, NETWORKS, BlockHash, NetworkId, EmbeddedEllipticCurve, FAST_EPOCH_DURATION, TARGET_BLOCK_TIME, NETWORKS, BlockHash, ExternalNetworkId, NetworkId,
insecure_pair_from_name, EmbeddedEllipticCurve, Amount, insecure_pair_from_name,
}, },
validator_sets::{ validator_sets::{
primitives::{Session, ValidatorSet, ExternalValidatorSet, KeyPair}, primitives::{Session, ExternalValidatorSet, ValidatorSet, KeyPair},
ValidatorSetsEvent, ValidatorSetsEvent,
}, },
in_instructions::{ in_instructions::{
@@ -313,8 +313,12 @@ async fn validator_set_rotation() {
// provide a batch to complete the handover and retire the previous set // provide a batch to complete the handover and retire the previous set
let mut block_hash = BlockHash([0; 32]); let mut block_hash = BlockHash([0; 32]);
OsRng.fill_bytes(&mut block_hash.0); OsRng.fill_bytes(&mut block_hash.0);
let batch = let batch = Batch {
Batch { network: network.try_into().unwrap(), id: 0, external_network_block_hash: block_hash, instructions: vec![] }; network: network.try_into().unwrap(),
id: 0,
external_network_block_hash: block_hash,
instructions: vec![],
};
publish_tx( publish_tx(
&serai, &serai,
&SeraiInInstructions::execute_batch(SignedBatch { &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 // we shouldn't be able to burn more than what we have
let mut instruction = OutInstructionWithBalance { let mut instruction = OutInstructionWithBalance {
instruction: OutInstruction { address: ExternalAddress::new(vec![]).unwrap(), data: None }, instruction: OutInstruction { address: ExternalAddress::new(vec![]).unwrap() },
balance: ExternalBalance { balance: ExternalBalance {
coin: coin.try_into().unwrap(), coin: coin.try_into().unwrap(),
amount: Amount(balance.amount.0 + 1), 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>, in_instruction_results: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
}, },
Halt { Halt {
network: NetworkId, network: ExternalNetworkId,
}, },
} }
@@ -103,7 +103,7 @@ pub mod pallet {
fn execute(instruction: &InInstructionWithBalance) -> Result<(), DispatchError> { fn execute(instruction: &InInstructionWithBalance) -> Result<(), DispatchError> {
match &instruction.instruction { match &instruction.instruction {
InInstruction::Transfer(address) => { InInstruction::Transfer(address) => {
Coins::<T>::mint(address.into(), instruction.balance.into())?; Coins::<T>::mint((*address).into(), instruction.balance.into())?;
} }
InInstruction::Dex(call) => { InInstruction::Dex(call) => {
// This will only be initiated by external chain transactions. That is why we only need // 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) => { InInstruction::GenesisLiquidity(address) => {
Coins::<T>::mint(GENESIS_LIQUIDITY_ACCOUNT.into(), instruction.balance.into())?; 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) => { InInstruction::SwapToStakedSRI(address, network) => {
Coins::<T>::mint(POL_ACCOUNT.into(), instruction.balance.into())?; 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(()) Ok(())
@@ -319,7 +319,10 @@ pub mod pallet {
// key is publishing `Batch`s. This should only happen once the current key has verified all // 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. // `Batch`s published by the prior key, meaning they are accepting the hand-over.
if prior.is_some() && (!valid_by_prior) { 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 // 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; use sp_runtime::RuntimeDebug;
#[rustfmt::skip] #[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; mod shorthand;
pub use shorthand::*; pub use shorthand::*;

View File

@@ -88,7 +88,10 @@ fn devnet_genesis(
networks: key_shares.clone(), networks: key_shares.clone(),
participants: validators.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(), signals: SignalsConfig::default(),
babe: BabeConfig { babe: BabeConfig {
authorities: validators.iter().map(|validator| (validator.0.into(), 1)).collect(), 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. /// The type used to identify external networks.
#[derive( #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)]
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, PartialOrd, Ord, MaxEncodedLen, TypeInfo,
)]
#[cfg_attr(feature = "std", derive(Zeroize))] #[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ExternalNetworkId { pub enum ExternalNetworkId {
@@ -162,6 +160,17 @@ impl ExternalNetworkId {
} }
impl NetworkId { 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> { pub fn coins(&self) -> Vec<Coin> {
match self { match self {
Self::Serai => vec![Coin::Serai], Self::Serai => vec![Coin::Serai],

View File

@@ -1154,8 +1154,8 @@ pub mod pallet {
// session on this assumption // session on this assumption
assert_eq!(Pallet::<T>::latest_decided_session(network.into()), Some(current_session)); assert_eq!(Pallet::<T>::latest_decided_session(network.into()), Some(current_session));
let participants = let participants = Participants::<T>::get(NetworkId::from(network))
Participants::<T>::get(network).expect("session existed without participants"); .expect("session existed without participants");
// Check the bitvec is of the proper length // Check the bitvec is of the proper length
if participants.len() != signature_participants.len() { if participants.len() != signature_participants.len() {
@@ -1189,7 +1189,7 @@ pub mod pallet {
// Verify the signature with the MuSig key of the signers // 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 // 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 // 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)?; Err(InvalidTransaction::BadProof)?;
} }
@@ -1207,8 +1207,10 @@ pub mod pallet {
}; };
// There must have been a previous session is PendingSlashReport is populated // There must have been a previous session is PendingSlashReport is populated
let set = let set = ExternalValidatorSet {
ExternalValidatorSet { network, session: Session(Self::session(network).unwrap().0 - 1) }; network,
session: Session(Self::session(NetworkId::from(network)).unwrap().0 - 1),
};
if !key.verify(&slashes.report_slashes_message(), signature) { if !key.verify(&slashes.report_slashes_message(), signature) {
Err(InvalidTransaction::BadProof)?; 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. /// 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() (b"ValidatorSets-set_keys", set, key_pair).encode()
} }