Implement SeraiAddress <-> Participant mapping and add RemoveParticipant transactions

This commit is contained in:
Luke Parker
2025-01-15 12:51:35 -05:00
parent bea4f92b7a
commit 167826aa88
9 changed files with 125 additions and 79 deletions

View File

@@ -3,6 +3,8 @@ use std::{path::Path, fs};
pub(crate) use serai_db::{Get, DbTxn, Db as DbTrait};
use serai_db::{create_db, db_channel};
use dkg::Participant;
use serai_client::{
primitives::NetworkId,
validator_sets::primitives::{Session, ValidatorSet},
@@ -95,6 +97,8 @@ mod _internal_db {
Coordinator {
// Tributary transactions to publish
TributaryTransactions: (set: ValidatorSet) -> Transaction,
// Participants to remove
RemoveParticipant: (set: ValidatorSet) -> Participant,
}
}
}
@@ -111,3 +115,16 @@ impl TributaryTransactions {
_internal_db::TributaryTransactions::try_recv(txn, set)
}
}
pub(crate) struct RemoveParticipant;
impl RemoveParticipant {
pub(crate) fn send(txn: &mut impl DbTxn, set: ValidatorSet, participant: Participant) {
// If this set has yet to be retired, send this transaction
if RetiredTributary::get(txn, set.network).map(|session| session.0) < Some(set.session.0) {
_internal_db::RemoveParticipant::send(txn, set, &participant);
}
}
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ValidatorSet) -> Option<Participant> {
_internal_db::RemoveParticipant::try_recv(txn, set)
}
}

View File

@@ -14,7 +14,7 @@ use borsh::BorshDeserialize;
use tokio::sync::mpsc;
use serai_client::{
primitives::{NetworkId, PublicKey, Signature},
primitives::{NetworkId, SeraiAddress, Signature},
validator_sets::primitives::ValidatorSet,
Serai,
};
@@ -209,28 +209,12 @@ async fn handle_network(
network_key,
} => todo!("TODO Transaction::DkgConfirmationPreprocess"),
messages::key_gen::ProcessorMessage::Blame { session, participant } => {
let set = ValidatorSet { network, session };
TributaryTransactions::send(
&mut txn,
set,
&Transaction::RemoveParticipant {
participant: todo!("TODO"),
signed: Signed::default(),
},
);
RemoveParticipant::send(&mut txn, ValidatorSet { network, session }, participant);
}
},
messages::ProcessorMessage::Sign(msg) => match msg {
messages::sign::ProcessorMessage::InvalidParticipant { session, participant } => {
let set = ValidatorSet { network, session };
TributaryTransactions::send(
&mut txn,
set,
&Transaction::RemoveParticipant {
participant: todo!("TODO"),
signed: Signed::default(),
},
);
RemoveParticipant::send(&mut txn, ValidatorSet { network, session }, participant);
}
messages::sign::ProcessorMessage::Preprocesses { id, preprocesses } => {
let set = ValidatorSet { network, session: id.session };
@@ -371,6 +355,8 @@ async fn main() {
while !Cosigning::<Db>::intended_cosigns(&mut txn, to_cleanup).is_empty() {}
// Drain the transactions to publish for this set
while TributaryTransactions::try_recv(&mut txn, to_cleanup).is_some() {}
// Drain the participants to remove for this set
while RemoveParticipant::try_recv(&mut txn, to_cleanup).is_some() {}
// Remove the SignSlashReport notification
SignSlashReport::try_recv(&mut txn, to_cleanup);
}
@@ -434,7 +420,7 @@ async fn main() {
EphemeralEventStream::new(
db.clone(),
serai.clone(),
PublicKey::from_raw((<Ristretto as Ciphersuite>::generator() * serai_key.deref()).to_bytes()),
SeraiAddress((<Ristretto as Ciphersuite>::generator() * serai_key.deref()).to_bytes()),
)
.continually_run(substrate_ephemeral_task_def, vec![substrate_task]),
);

View File

@@ -26,7 +26,7 @@ use serai_coordinator_tributary::{
};
use serai_coordinator_p2p::P2p;
use crate::{Db, TributaryTransactions};
use crate::{Db, TributaryTransactions, RemoveParticipant};
create_db! {
Coordinator {
@@ -158,8 +158,14 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan
#[must_use]
async fn add_signed_unsigned_transaction<TD: DbTrait, P: P2p>(
tributary: &Tributary<TD, Transaction, P>,
tx: &Transaction,
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
mut tx: Transaction,
) -> bool {
// If this is a signed transaction, sign it
if matches!(tx.kind(), TransactionKind::Signed(_, _)) {
tx.sign(&mut OsRng, tributary.genesis(), key);
}
let res = tributary.add_transaction(tx.clone()).await;
match &res {
// Fresh publication, already published
@@ -191,7 +197,7 @@ pub(crate) struct AddTributaryTransactionsTask<CD: DbTrait, TD: DbTrait, P: P2p>
db: CD,
tributary_db: TD,
tributary: Tributary<TD, Transaction, P>,
set: ValidatorSet,
set: NewSetInformation,
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
}
impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactionsTask<CD, TD, P> {
@@ -204,23 +210,20 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactio
// Provide/add all transactions sent our way
loop {
let mut txn = self.db.txn();
let Some(mut tx) = TributaryTransactions::try_recv(&mut txn, self.set) else { break };
let Some(tx) = TributaryTransactions::try_recv(&mut txn, self.set.set) else { break };
let kind = tx.kind();
match kind {
TransactionKind::Provided(_) => provide_transaction(self.set, &self.tributary, tx).await,
TransactionKind::Provided(_) => {
provide_transaction(self.set.set, &self.tributary, tx).await
}
TransactionKind::Unsigned | TransactionKind::Signed(_, _) => {
// If this is a signed transaction, sign it
if matches!(kind, TransactionKind::Signed(_, _)) {
tx.sign(&mut OsRng, self.tributary.genesis(), &self.key);
}
// If this is a transaction with signing data, check the topic is recognized before
// publishing
let topic = tx.topic();
let still_requires_recognition = if let Some(topic) = topic {
(topic.requires_recognition() &&
(!RecognizedTopics::recognized(&self.tributary_db, self.set, topic)))
(!RecognizedTopics::recognized(&self.tributary_db, self.set.set, topic)))
.then_some(topic)
} else {
None
@@ -229,11 +232,11 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactio
// Queue the transaction until the topic is recognized
// We use the Tributary DB for this so it's cleaned up when the Tributary DB is
let mut txn = self.tributary_db.txn();
PublishOnRecognition::set(&mut txn, self.set, topic, &tx);
PublishOnRecognition::set(&mut txn, self.set.set, topic, &tx);
txn.commit();
} else {
// Actually add the transaction
if !add_signed_unsigned_transaction(&self.tributary, &tx).await {
if !add_signed_unsigned_transaction(&self.tributary, &self.key, tx).await {
break;
}
}
@@ -248,12 +251,12 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactio
loop {
let mut txn = self.tributary_db.txn();
let Some(topic) =
RecognizedTopics::try_recv_topic_requiring_recognition(&mut txn, self.set)
RecognizedTopics::try_recv_topic_requiring_recognition(&mut txn, self.set.set)
else {
break;
};
if let Some(tx) = PublishOnRecognition::take(&mut txn, self.set, topic) {
if !add_signed_unsigned_transaction(&self.tributary, &tx).await {
if let Some(tx) = PublishOnRecognition::take(&mut txn, self.set.set, topic) {
if !add_signed_unsigned_transaction(&self.tributary, &self.key, tx).await {
break;
}
}
@@ -262,6 +265,21 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactio
txn.commit();
}
// Publish any participant removals
loop {
let mut txn = self.db.txn();
let Some(participant) = RemoveParticipant::try_recv(&mut txn, self.set.set) else { break };
let tx = Transaction::RemoveParticipant {
participant: self.set.participant_indexes_reverse_lookup[&participant],
signed: Default::default(),
};
if !add_signed_unsigned_transaction(&self.tributary, &self.key, tx).await {
break;
}
made_progress = true;
txn.commit();
}
Ok(made_progress)
}
}
@@ -487,7 +505,7 @@ pub(crate) async fn spawn_tributary<P: P2p>(
db: db.clone(),
tributary_db,
tributary: tributary.clone(),
set: set.set,
set: set.clone(),
key: serai_key,
})
.continually_run(add_tributary_transactions_task_def, vec![]),