mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-22 18:54:40 +00:00
Cleanup DB handling a bit in key-gen/attempt-manager
This commit is contained in:
parent
1e8a9ec5bd
commit
2f3bd7a02a
6 changed files with 77 additions and 27 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -8603,9 +8603,11 @@ dependencies = [
|
||||||
name = "serai-processor-frost-attempt-manager"
|
name = "serai-processor-frost-attempt-manager"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"borsh",
|
||||||
"hex",
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
|
"parity-scale-codec",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"serai-db",
|
"serai-db",
|
||||||
"serai-processor-messages",
|
"serai-processor-messages",
|
||||||
|
|
|
@ -25,5 +25,9 @@ serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primi
|
||||||
|
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
||||||
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
serai-db = { path = "../../common/db" }
|
serai-db = { path = "../../common/db" }
|
||||||
|
|
||||||
messages = { package = "serai-processor-messages", path = "../messages" }
|
messages = { package = "serai-processor-messages", path = "../messages" }
|
||||||
|
|
|
@ -9,11 +9,19 @@ use frost::{
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_validator_sets_primitives::Session;
|
||||||
|
|
||||||
|
use serai_db::{Get, DbTxn, Db, create_db};
|
||||||
use messages::sign::{SignId, ProcessorMessage};
|
use messages::sign::{SignId, ProcessorMessage};
|
||||||
|
|
||||||
|
create_db!(
|
||||||
|
FrostAttemptManager {
|
||||||
|
Attempted: (id: [u8; 32]) -> u32,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/// An instance of a signing protocol with re-attempts handled internally.
|
/// An instance of a signing protocol with re-attempts handled internally.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub(crate) struct SigningProtocol<M: Clone + PreprocessMachine> {
|
pub(crate) struct SigningProtocol<D: Db, M: Clone + PreprocessMachine> {
|
||||||
|
db: D,
|
||||||
// The session this signing protocol is being conducted by.
|
// The session this signing protocol is being conducted by.
|
||||||
session: Session,
|
session: Session,
|
||||||
// The `i` of our first, or starting, set of key shares we will be signing with.
|
// The `i` of our first, or starting, set of key shares we will be signing with.
|
||||||
|
@ -34,12 +42,19 @@ pub(crate) struct SigningProtocol<M: Clone + PreprocessMachine> {
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Clone + PreprocessMachine> SigningProtocol<M> {
|
impl<D: Db, M: Clone + PreprocessMachine> SigningProtocol<D, M> {
|
||||||
/// Create a new signing protocol.
|
/// Create a new signing protocol.
|
||||||
pub(crate) fn new(session: Session, start_i: Participant, id: [u8; 32], root: Vec<M>) -> Self {
|
pub(crate) fn new(
|
||||||
|
db: D,
|
||||||
|
session: Session,
|
||||||
|
start_i: Participant,
|
||||||
|
id: [u8; 32],
|
||||||
|
root: Vec<M>,
|
||||||
|
) -> Self {
|
||||||
log::info!("starting signing protocol {}", hex::encode(id));
|
log::info!("starting signing protocol {}", hex::encode(id));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
db,
|
||||||
session,
|
session,
|
||||||
start_i,
|
start_i,
|
||||||
id,
|
id,
|
||||||
|
@ -70,7 +85,15 @@ impl<M: Clone + PreprocessMachine> SigningProtocol<M> {
|
||||||
We also won't send the share we were supposed to, unfortunately, yet caching/reloading the
|
We also won't send the share we were supposed to, unfortunately, yet caching/reloading the
|
||||||
preprocess has enough safety issues it isn't worth the headache.
|
preprocess has enough safety issues it isn't worth the headache.
|
||||||
*/
|
*/
|
||||||
// TODO
|
{
|
||||||
|
let mut txn = self.db.txn();
|
||||||
|
let prior_attempted = Attempted::get(&txn, self.id);
|
||||||
|
if Some(attempt) <= prior_attempted {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
Attempted::set(&mut txn, self.id, &attempt);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
log::debug!("attemting a new instance of signing protocol {}", hex::encode(self.id));
|
log::debug!("attemting a new instance of signing protocol {}", hex::encode(self.id));
|
||||||
|
|
||||||
|
@ -248,4 +271,11 @@ impl<M: Clone + PreprocessMachine> SigningProtocol<M> {
|
||||||
|
|
||||||
Ok(signature)
|
Ok(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cleanup the database entries for a specified signing protocol.
|
||||||
|
pub(crate) fn cleanup(db: &mut D, id: [u8; 32]) {
|
||||||
|
let mut txn = db.txn();
|
||||||
|
Attempted::del(&mut txn, id);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use frost::{Participant, sign::PreprocessMachine};
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_validator_sets_primitives::Session;
|
||||||
|
|
||||||
|
use serai_db::Db;
|
||||||
use messages::sign::{ProcessorMessage, CoordinatorMessage};
|
use messages::sign::{ProcessorMessage, CoordinatorMessage};
|
||||||
|
|
||||||
mod individual;
|
mod individual;
|
||||||
|
@ -22,21 +23,28 @@ pub enum Response<M: PreprocessMachine> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A manager of attempts for a variety of signing protocols.
|
/// A manager of attempts for a variety of signing protocols.
|
||||||
pub struct AttemptManager<M: Clone + PreprocessMachine> {
|
pub struct AttemptManager<D: Db, M: Clone + PreprocessMachine> {
|
||||||
|
db: D,
|
||||||
session: Session,
|
session: Session,
|
||||||
start_i: Participant,
|
start_i: Participant,
|
||||||
active: HashMap<[u8; 32], SigningProtocol<M>>,
|
active: HashMap<[u8; 32], SigningProtocol<D, M>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Clone + PreprocessMachine> AttemptManager<M> {
|
impl<D: Db, M: Clone + PreprocessMachine> AttemptManager<D, M> {
|
||||||
/// Create a new attempt manager.
|
/// Create a new attempt manager.
|
||||||
pub fn new(session: Session, start_i: Participant) -> Self {
|
pub fn new(db: D, session: Session, start_i: Participant) -> Self {
|
||||||
AttemptManager { session, start_i, active: HashMap::new() }
|
AttemptManager { db, session, start_i, active: HashMap::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a signing protocol to attempt.
|
/// Register a signing protocol to attempt.
|
||||||
pub fn register(&mut self, id: [u8; 32], machines: Vec<M>) {
|
///
|
||||||
self.active.insert(id, SigningProtocol::new(self.session, self.start_i, id, machines));
|
/// This ID must be unique across all sessions, attempt managers, protocols, etc.
|
||||||
|
pub fn register(&mut self, id: [u8; 32], machines: Vec<M>) -> Vec<ProcessorMessage> {
|
||||||
|
let mut protocol =
|
||||||
|
SigningProtocol::new(self.db.clone(), self.session, self.start_i, id, machines);
|
||||||
|
let messages = protocol.attempt(0);
|
||||||
|
self.active.insert(id, protocol);
|
||||||
|
messages
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retire a signing protocol.
|
/// Retire a signing protocol.
|
||||||
|
@ -45,10 +53,13 @@ impl<M: Clone + PreprocessMachine> AttemptManager<M> {
|
||||||
/// This does not stop the protocol from being re-registered and further worked on (with
|
/// This does not stop the protocol from being re-registered and further worked on (with
|
||||||
/// undefined behavior) then. The higher-level context must never call `register` again with this
|
/// undefined behavior) then. The higher-level context must never call `register` again with this
|
||||||
/// ID.
|
/// ID.
|
||||||
// TODO: Also have the DB for this SigningProtocol cleaned up here.
|
|
||||||
pub fn retire(&mut self, id: [u8; 32]) {
|
pub fn retire(&mut self, id: [u8; 32]) {
|
||||||
log::info!("retiring signing protocol {}", hex::encode(id));
|
if self.active.remove(&id).is_none() {
|
||||||
self.active.remove(&id);
|
log::info!("retiring protocol {}, which we didn't register/already retired", hex::encode(id));
|
||||||
|
} else {
|
||||||
|
log::info!("retired signing protocol {}", hex::encode(id));
|
||||||
|
}
|
||||||
|
SigningProtocol::<D, M>::cleanup(&mut self.db, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a message for a signing protocol.
|
/// Handle a message for a signing protocol.
|
||||||
|
|
|
@ -36,10 +36,10 @@ pub(crate) struct Participations {
|
||||||
}
|
}
|
||||||
|
|
||||||
create_db!(
|
create_db!(
|
||||||
KeyGenDb {
|
KeyGen {
|
||||||
ParamsDb: (session: &Session) -> RawParams,
|
Params: (session: &Session) -> RawParams,
|
||||||
ParticipationsDb: (session: &Session) -> Participations,
|
Participations: (session: &Session) -> Participations,
|
||||||
KeySharesDb: (session: &Session) -> Vec<u8>,
|
KeyShares: (session: &Session) -> Vec<u8>,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ impl<P: KeyGenParams> KeyGenDb<P> {
|
||||||
pub(crate) fn set_params(txn: &mut impl DbTxn, session: Session, params: Params<P>) {
|
pub(crate) fn set_params(txn: &mut impl DbTxn, session: Session, params: Params<P>) {
|
||||||
assert_eq!(params.substrate_evrf_public_keys.len(), params.network_evrf_public_keys.len());
|
assert_eq!(params.substrate_evrf_public_keys.len(), params.network_evrf_public_keys.len());
|
||||||
|
|
||||||
ParamsDb::set(
|
Params::set(
|
||||||
txn,
|
txn,
|
||||||
&session,
|
&session,
|
||||||
&RawParams {
|
&RawParams {
|
||||||
|
@ -68,7 +68,7 @@ impl<P: KeyGenParams> KeyGenDb<P> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn params(getter: &impl Get, session: Session) -> Option<Params<P>> {
|
pub(crate) fn params(getter: &impl Get, session: Session) -> Option<Params<P>> {
|
||||||
ParamsDb::get(getter, &session).map(|params| Params {
|
Params::get(getter, &session).map(|params| Params {
|
||||||
t: params.t,
|
t: params.t,
|
||||||
n: params
|
n: params
|
||||||
.network_evrf_public_keys
|
.network_evrf_public_keys
|
||||||
|
@ -101,12 +101,13 @@ impl<P: KeyGenParams> KeyGenDb<P> {
|
||||||
session: Session,
|
session: Session,
|
||||||
participations: &Participations,
|
participations: &Participations,
|
||||||
) {
|
) {
|
||||||
ParticipationsDb::set(txn, &session, participations)
|
Participations::set(txn, &session, participations)
|
||||||
}
|
}
|
||||||
pub(crate) fn participations(getter: &impl Get, session: Session) -> Option<Participations> {
|
pub(crate) fn participations(getter: &impl Get, session: Session) -> Option<Participations> {
|
||||||
ParticipationsDb::get(getter, &session)
|
Participations::get(getter, &session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the key shares for a session.
|
||||||
pub(crate) fn set_key_shares(
|
pub(crate) fn set_key_shares(
|
||||||
txn: &mut impl DbTxn,
|
txn: &mut impl DbTxn,
|
||||||
session: Session,
|
session: Session,
|
||||||
|
@ -120,7 +121,7 @@ impl<P: KeyGenParams> KeyGenDb<P> {
|
||||||
keys.extend(substrate_keys.serialize().as_slice());
|
keys.extend(substrate_keys.serialize().as_slice());
|
||||||
keys.extend(network_keys.serialize().as_slice());
|
keys.extend(network_keys.serialize().as_slice());
|
||||||
}
|
}
|
||||||
KeySharesDb::set(txn, &session, &keys);
|
KeyShares::set(txn, &session, &keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
|
@ -128,7 +129,7 @@ impl<P: KeyGenParams> KeyGenDb<P> {
|
||||||
getter: &impl Get,
|
getter: &impl Get,
|
||||||
session: Session,
|
session: Session,
|
||||||
) -> Option<(Vec<ThresholdKeys<Ristretto>>, Vec<ThresholdKeys<P::ExternalNetworkCurve>>)> {
|
) -> Option<(Vec<ThresholdKeys<Ristretto>>, Vec<ThresholdKeys<P::ExternalNetworkCurve>>)> {
|
||||||
let keys = KeySharesDb::get(getter, &session)?;
|
let keys = KeyShares::get(getter, &session)?;
|
||||||
let mut keys: &[u8] = keys.as_ref();
|
let mut keys: &[u8] = keys.as_ref();
|
||||||
|
|
||||||
let mut substrate_keys = vec![];
|
let mut substrate_keys = vec![];
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl<P: KeyGenParams, D: Db> KeyGen<P, D> {
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
CoordinatorMessage::GenerateKey { session, threshold, evrf_public_keys } => {
|
CoordinatorMessage::GenerateKey { session, threshold, evrf_public_keys } => {
|
||||||
log::info!("Generating new key. Session: {session:?}");
|
log::info!("generating new key, session: {session:?}");
|
||||||
|
|
||||||
// Unzip the vector of eVRF keys
|
// Unzip the vector of eVRF keys
|
||||||
let substrate_evrf_public_keys =
|
let substrate_evrf_public_keys =
|
||||||
|
@ -258,7 +258,7 @@ impl<P: KeyGenParams, D: Db> KeyGen<P, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
CoordinatorMessage::Participation { session, participant, participation } => {
|
CoordinatorMessage::Participation { session, participant, participation } => {
|
||||||
log::info!("received participation from {:?} for {:?}", participant, session);
|
log::debug!("received participation from {:?} for {:?}", participant, session);
|
||||||
|
|
||||||
let Params { t: threshold, n, substrate_evrf_public_keys, network_evrf_public_keys } =
|
let Params { t: threshold, n, substrate_evrf_public_keys, network_evrf_public_keys } =
|
||||||
KeyGenDb::<P>::params(txn, session).unwrap();
|
KeyGenDb::<P>::params(txn, session).unwrap();
|
||||||
|
@ -293,7 +293,7 @@ impl<P: KeyGenParams, D: Db> KeyGen<P, D> {
|
||||||
// participations and continue. We solely have to verify them, as to identify malicious
|
// participations and continue. We solely have to verify them, as to identify malicious
|
||||||
// participants and prevent DoSs, before returning
|
// participants and prevent DoSs, before returning
|
||||||
if self.key_shares(session).is_some() {
|
if self.key_shares(session).is_some() {
|
||||||
log::info!("already finished generating a key for {:?}", session);
|
log::debug!("already finished generating a key for {:?}", session);
|
||||||
|
|
||||||
match EvrfDkg::<Ristretto>::verify(
|
match EvrfDkg::<Ristretto>::verify(
|
||||||
&mut OsRng,
|
&mut OsRng,
|
||||||
|
@ -511,6 +511,8 @@ impl<P: KeyGenParams, D: Db> KeyGen<P, D> {
|
||||||
}
|
}
|
||||||
KeyGenDb::<P>::set_key_shares(txn, session, &substrate_keys, &network_keys);
|
KeyGenDb::<P>::set_key_shares(txn, session, &substrate_keys, &network_keys);
|
||||||
|
|
||||||
|
log::info!("generated key, session: {session:?}");
|
||||||
|
|
||||||
// Since no one we verified was invalid, and we had the threshold, yield the new keys
|
// Since no one we verified was invalid, and we had the threshold, yield the new keys
|
||||||
vec![ProcessorMessage::GeneratedKeyPair {
|
vec![ProcessorMessage::GeneratedKeyPair {
|
||||||
session,
|
session,
|
||||||
|
|
Loading…
Reference in a new issue