Move ConfirmKeyPair from key_gen to substrate

Clarifies the emitter and accordingly why its mutations are justified.
This commit is contained in:
Luke Parker 2023-04-17 19:39:36 -04:00
parent 059e79c98a
commit e26b861d25
No known key found for this signature in database
5 changed files with 81 additions and 99 deletions

View file

@ -117,7 +117,7 @@ async fn handle_key_gen<D: Db, Pro: Processor>(
// TODO: Check how the processor handles thi being fired multiple times // TODO: Check how the processor handles thi being fired multiple times
processor processor
.send(CoordinatorMessage::KeyGen( .send(CoordinatorMessage::KeyGen(
processor_messages::key_gen::CoordinatorMessage::ConfirmKeyPair { processor_messages::substrate::CoordinatorMessage::ConfirmKeyPair {
context: SubstrateContext { context: SubstrateContext {
coin_latest_finalized_block: serai coin_latest_finalized_block: serai
.get_latest_block_for_network(block.hash(), set.network) .get_latest_block_for_network(block.hash(), set.network)

View file

@ -33,19 +33,13 @@ pub mod key_gen {
Commitments { id: KeyGenId, commitments: HashMap<Participant, Vec<u8>> }, Commitments { id: KeyGenId, commitments: HashMap<Participant, Vec<u8>> },
// Received shares for the specified key generation protocol. // Received shares for the specified key generation protocol.
Shares { id: KeyGenId, shares: HashMap<Participant, Vec<u8>> }, Shares { id: KeyGenId, shares: HashMap<Participant, Vec<u8>> },
// Confirm a key pair.
ConfirmKeyPair { context: SubstrateContext, id: KeyGenId },
} }
impl CoordinatorMessage { impl CoordinatorMessage {
pub fn required_block(&self) -> Option<BlockHash> { pub fn required_block(&self) -> Option<BlockHash> {
if let CoordinatorMessage::ConfirmKeyPair { context, .. } = self {
Some(context.coin_latest_finalized_block)
} else {
None None
} }
} }
}
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub enum ProcessorMessage { pub enum ProcessorMessage {
@ -152,6 +146,10 @@ pub mod substrate {
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)] #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)]
pub enum CoordinatorMessage { pub enum CoordinatorMessage {
ConfirmKeyPair {
context: SubstrateContext,
id: key_gen::KeyGenId,
},
SubstrateBlock { SubstrateBlock {
context: SubstrateContext, context: SubstrateContext,
key: Vec<u8>, key: Vec<u8>,
@ -162,6 +160,7 @@ pub mod substrate {
impl CoordinatorMessage { impl CoordinatorMessage {
pub fn required_block(&self) -> Option<BlockHash> { pub fn required_block(&self) -> Option<BlockHash> {
let context = match self { let context = match self {
CoordinatorMessage::ConfirmKeyPair { context, .. } => context,
CoordinatorMessage::SubstrateBlock { context, .. } => context, CoordinatorMessage::SubstrateBlock { context, .. } => context,
}; };
Some(context.coin_latest_finalized_block) Some(context.coin_latest_finalized_block)

View file

@ -16,18 +16,15 @@ use frost::{
use log::info; use log::info;
use serai_client::{primitives::BlockHash, validator_sets::primitives::ValidatorSet}; use serai_client::{primitives::BlockHash, validator_sets::primitives::ValidatorSet};
use messages::key_gen::*; use messages::{SubstrateContext, key_gen::*};
use crate::{Get, DbTxn, Db, coins::Coin}; use crate::{Get, DbTxn, Db, coins::Coin};
#[derive(Debug)] #[derive(Debug)]
pub enum KeyGenEvent<C: Ciphersuite> { pub struct KeyConfirmed<C: Ciphersuite> {
KeyConfirmed { pub activation_block: BlockHash,
activation_block: BlockHash, pub substrate_keys: ThresholdKeys<Ristretto>,
substrate_keys: ThresholdKeys<Ristretto>, pub coin_keys: ThresholdKeys<C>,
coin_keys: ThresholdKeys<C>,
},
ProcessorMessage(ProcessorMessage),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -145,7 +142,7 @@ impl<C: Coin, D: Db> KeyGen<C, D> {
self.db.keys(key) self.db.keys(key)
} }
pub async fn handle(&mut self, msg: CoordinatorMessage) -> KeyGenEvent<C::Curve> { pub async fn handle(&mut self, msg: CoordinatorMessage) -> ProcessorMessage {
let context = |id: &KeyGenId| { let context = |id: &KeyGenId| {
// TODO2: Also embed the chain ID/genesis block // TODO2: Also embed the chain ID/genesis block
format!( format!(
@ -192,7 +189,7 @@ impl<C: Coin, D: Db> KeyGen<C, D> {
serialized.extend(commitments.1.serialize()); serialized.extend(commitments.1.serialize());
self.active_commit.insert(id.set, machines); self.active_commit.insert(id.set, machines);
KeyGenEvent::ProcessorMessage(ProcessorMessage::Commitments { id, commitments: serialized }) ProcessorMessage::Commitments { id, commitments: serialized }
} }
CoordinatorMessage::Commitments { id, commitments } => { CoordinatorMessage::Commitments { id, commitments } => {
@ -263,7 +260,7 @@ impl<C: Coin, D: Db> KeyGen<C, D> {
KeyGenDb::<C, D>::save_commitments(&mut txn, &id, &commitments); KeyGenDb::<C, D>::save_commitments(&mut txn, &id, &commitments);
txn.commit(); txn.commit();
KeyGenEvent::ProcessorMessage(ProcessorMessage::Shares { id, shares }) ProcessorMessage::Shares { id, shares }
} }
CoordinatorMessage::Shares { id, shares } => { CoordinatorMessage::Shares { id, shares } => {
@ -346,14 +343,20 @@ impl<C: Coin, D: Db> KeyGen<C, D> {
let mut coin_keys = ThresholdKeys::new(coin_keys); let mut coin_keys = ThresholdKeys::new(coin_keys);
C::tweak_keys(&mut coin_keys); C::tweak_keys(&mut coin_keys);
KeyGenEvent::ProcessorMessage(ProcessorMessage::GeneratedKeyPair { ProcessorMessage::GeneratedKeyPair {
id, id,
substrate_key: substrate_keys.group_key().to_bytes(), substrate_key: substrate_keys.group_key().to_bytes(),
coin_key: coin_keys.group_key().to_bytes().as_ref().to_vec(), coin_key: coin_keys.group_key().to_bytes().as_ref().to_vec(),
}) }
}
}
} }
CoordinatorMessage::ConfirmKeyPair { context, id } => { pub async fn confirm(
&mut self,
context: SubstrateContext,
id: KeyGenId,
) -> KeyConfirmed<C::Curve> {
let mut txn = self.db.0.txn(); let mut txn = self.db.0.txn();
let (substrate_keys, coin_keys) = KeyGenDb::<C, D>::confirm_keys(&mut txn, &id); let (substrate_keys, coin_keys) = KeyGenDb::<C, D>::confirm_keys(&mut txn, &id);
txn.commit(); txn.commit();
@ -365,12 +368,10 @@ impl<C: Coin, D: Db> KeyGen<C, D> {
id id
); );
KeyGenEvent::KeyConfirmed { KeyConfirmed {
activation_block: context.coin_latest_finalized_block, activation_block: context.coin_latest_finalized_block,
substrate_keys, substrate_keys,
coin_keys, coin_keys,
} }
} }
} }
}
}

View file

@ -42,7 +42,7 @@ use coins::Bitcoin;
use coins::Monero; use coins::Monero;
mod key_gen; mod key_gen;
use key_gen::{KeyGenEvent, KeyGen}; use key_gen::{KeyConfirmed, KeyGen};
mod signer; mod signer;
use signer::{SignerEvent, Signer}; use signer::{SignerEvent, Signer};
@ -288,11 +288,24 @@ async fn handle_coordinator_msg<D: Db, C: Coin, Co: Coordinator>(
match msg.msg.clone() { match msg.msg.clone() {
CoordinatorMessage::KeyGen(msg) => { CoordinatorMessage::KeyGen(msg) => {
match tributary_mutable.key_gen.handle(msg).await { // TODO: This may be fired multiple times. What's our plan for that?
// This should only occur when Substrate confirms a key, enabling access of coordinator.send(ProcessorMessage::KeyGen(tributary_mutable.key_gen.handle(msg).await)).await;
// substrate_mutable }
// TODO: Move this under Substrate accordingly
KeyGenEvent::KeyConfirmed { activation_block, substrate_keys, coin_keys } => { CoordinatorMessage::Sign(msg) => {
tributary_mutable.signers.get_mut(msg.key()).unwrap().handle(msg).await;
}
CoordinatorMessage::Coordinator(msg) => {
tributary_mutable.substrate_signers.get_mut(msg.key()).unwrap().handle(msg).await;
}
CoordinatorMessage::Substrate(msg) => {
match msg {
messages::substrate::CoordinatorMessage::ConfirmKeyPair { context, id } => {
// See TributaryMutable's struct definition for why this block is safe
let KeyConfirmed { activation_block, substrate_keys, coin_keys } =
tributary_mutable.key_gen.confirm(context, id).await;
tributary_mutable.substrate_signers.insert( tributary_mutable.substrate_signers.insert(
substrate_keys.group_key().to_bytes().to_vec(), substrate_keys.group_key().to_bytes().to_vec(),
SubstrateSigner::new(raw_db.clone(), substrate_keys), SubstrateSigner::new(raw_db.clone(), substrate_keys),
@ -312,29 +325,13 @@ async fn handle_coordinator_msg<D: Db, C: Coin, Co: Coordinator>(
substrate_mutable substrate_mutable
.schedulers .schedulers
.insert(key.to_bytes().as_ref().to_vec(), Scheduler::<C>::new(key)); .insert(key.to_bytes().as_ref().to_vec(), Scheduler::<C>::new(key));
tributary_mutable.signers.insert( tributary_mutable.signers.insert(
key.to_bytes().as_ref().to_vec(), key.to_bytes().as_ref().to_vec(),
Signer::new(raw_db.clone(), coin.clone(), coin_keys), Signer::new(raw_db.clone(), coin.clone(), coin_keys),
); );
} }
// TODO: This may be fired multiple times. What's our plan for that?
KeyGenEvent::ProcessorMessage(msg) => {
coordinator.send(ProcessorMessage::KeyGen(msg)).await;
}
}
}
CoordinatorMessage::Sign(msg) => {
tributary_mutable.signers.get_mut(msg.key()).unwrap().handle(msg).await;
}
CoordinatorMessage::Coordinator(msg) => {
tributary_mutable.substrate_signers.get_mut(msg.key()).unwrap().handle(msg).await;
}
CoordinatorMessage::Substrate(msg) => {
match msg {
messages::substrate::CoordinatorMessage::SubstrateBlock { messages::substrate::CoordinatorMessage::SubstrateBlock {
context, context,
key: key_vec, key: key_vec,

View file

@ -17,7 +17,7 @@ use serai_client::{
use messages::{SubstrateContext, key_gen::*}; use messages::{SubstrateContext, key_gen::*};
use crate::{ use crate::{
coins::Coin, coins::Coin,
key_gen::{KeyGenEvent, KeyGen}, key_gen::{KeyConfirmed, KeyGen},
}; };
const ID: KeyGenId = const ID: KeyGenId =
@ -38,8 +38,7 @@ pub async fn test_key_gen<C: Coin>() {
let mut all_commitments = HashMap::new(); let mut all_commitments = HashMap::new();
for i in 1 ..= 5 { for i in 1 ..= 5 {
let key_gen = key_gens.get_mut(&i).unwrap(); let key_gen = key_gens.get_mut(&i).unwrap();
if let KeyGenEvent::ProcessorMessage(ProcessorMessage::Commitments { id, commitments }) = if let ProcessorMessage::Commitments { id, commitments } = key_gen
key_gen
.handle(CoordinatorMessage::GenerateKey { .handle(CoordinatorMessage::GenerateKey {
id: ID, id: ID,
params: ThresholdParams::new(3, 5, Participant::new(u16::try_from(i).unwrap()).unwrap()) params: ThresholdParams::new(3, 5, Participant::new(u16::try_from(i).unwrap()).unwrap())
@ -68,7 +67,7 @@ pub async fn test_key_gen<C: Coin>() {
for i in 1 ..= 5 { for i in 1 ..= 5 {
let key_gen = key_gens.get_mut(&i).unwrap(); let key_gen = key_gens.get_mut(&i).unwrap();
let i = Participant::new(u16::try_from(i).unwrap()).unwrap(); let i = Participant::new(u16::try_from(i).unwrap()).unwrap();
if let KeyGenEvent::ProcessorMessage(ProcessorMessage::Shares { id, shares }) = key_gen if let ProcessorMessage::Shares { id, shares } = key_gen
.handle(CoordinatorMessage::Commitments { .handle(CoordinatorMessage::Commitments {
id: ID, id: ID,
commitments: clone_without(&all_commitments, &i), commitments: clone_without(&all_commitments, &i),
@ -90,11 +89,7 @@ pub async fn test_key_gen<C: Coin>() {
for i in 1 ..= 5 { for i in 1 ..= 5 {
let key_gen = key_gens.get_mut(&i).unwrap(); let key_gen = key_gens.get_mut(&i).unwrap();
let i = Participant::new(u16::try_from(i).unwrap()).unwrap(); let i = Participant::new(u16::try_from(i).unwrap()).unwrap();
if let KeyGenEvent::ProcessorMessage(ProcessorMessage::GeneratedKeyPair { if let ProcessorMessage::GeneratedKeyPair { id, substrate_key, coin_key } = key_gen
id,
substrate_key,
coin_key,
}) = key_gen
.handle(CoordinatorMessage::Shares { .handle(CoordinatorMessage::Shares {
id: ID, id: ID,
shares: all_shares shares: all_shares
@ -120,27 +115,17 @@ pub async fn test_key_gen<C: Coin>() {
for i in 1 ..= 5 { for i in 1 ..= 5 {
let key_gen = key_gens.get_mut(&i).unwrap(); let key_gen = key_gens.get_mut(&i).unwrap();
if let KeyGenEvent::KeyConfirmed { activation_block, substrate_keys, coin_keys } = key_gen let KeyConfirmed { activation_block, substrate_keys, coin_keys } = key_gen
.handle(CoordinatorMessage::ConfirmKeyPair { .confirm(SubstrateContext { coin_latest_finalized_block: BlockHash([0x11; 32]) }, ID)
context: SubstrateContext { coin_latest_finalized_block: BlockHash([0x11; 32]) }, .await;
id: ID,
})
.await
{
assert_eq!(activation_block, BlockHash([0x11; 32])); assert_eq!(activation_block, BlockHash([0x11; 32]));
let params = let params =
ThresholdParams::new(3, 5, Participant::new(u16::try_from(i).unwrap()).unwrap()).unwrap(); ThresholdParams::new(3, 5, Participant::new(u16::try_from(i).unwrap()).unwrap()).unwrap();
assert_eq!(substrate_keys.params(), params); assert_eq!(substrate_keys.params(), params);
assert_eq!(coin_keys.params(), params); assert_eq!(coin_keys.params(), params);
assert_eq!( assert_eq!(
&( &(substrate_keys.group_key().to_bytes(), coin_keys.group_key().to_bytes().as_ref().to_vec()),
substrate_keys.group_key().to_bytes(),
coin_keys.group_key().to_bytes().as_ref().to_vec()
),
res.as_ref().unwrap() res.as_ref().unwrap()
); );
} else {
panic!("didn't get key back");
}
} }
} }