use std::collections::HashMap; use zeroize::Zeroize; use serde::{Serialize, Deserialize}; use dkg::{Participant, ThresholdParams}; use serai_primitives::BlockHash; use in_instructions_primitives::SignedBatch; use tokens_primitives::OutInstructionWithBalance; use validator_sets_primitives::{ValidatorSet, KeyPair}; #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)] pub struct SubstrateContext { pub serai_time: u64, pub coin_latest_finalized_block: BlockHash, } pub mod key_gen { use super::*; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, Serialize, Deserialize)] pub struct KeyGenId { pub set: ValidatorSet, pub attempt: u32, } #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum CoordinatorMessage { // Instructs the Processor to begin the key generation process. // TODO: Should this be moved under Substrate? GenerateKey { id: KeyGenId, params: ThresholdParams }, // Received commitments for the specified key generation protocol. Commitments { id: KeyGenId, commitments: HashMap> }, // Received shares for the specified key generation protocol. Shares { id: KeyGenId, shares: HashMap> }, } impl CoordinatorMessage { pub fn required_block(&self) -> Option { None } } #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum ProcessorMessage { // Created commitments for the specified key generation protocol. Commitments { id: KeyGenId, commitments: Vec }, // Created shares for the specified key generation protocol. Shares { id: KeyGenId, shares: HashMap> }, // Resulting keys from the specified key generation protocol. GeneratedKeyPair { id: KeyGenId, substrate_key: [u8; 32], coin_key: Vec }, } } pub mod sign { use super::*; #[derive(Clone, PartialEq, Eq, Hash, Debug, Zeroize, Serialize, Deserialize)] pub struct SignId { pub key: Vec, pub id: [u8; 32], pub attempt: u32, } #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum CoordinatorMessage { // Received preprocesses for the specified signing protocol. Preprocesses { id: SignId, preprocesses: HashMap> }, // Received shares for the specified signing protocol. Shares { id: SignId, shares: HashMap> }, // Re-attempt a signing protocol. Reattempt { id: SignId }, // Completed a signing protocol already. Completed { key: Vec, id: [u8; 32], tx: Vec }, } #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)] pub enum ProcessorMessage { // Created preprocess for the specified signing protocol. Preprocess { id: SignId, preprocess: Vec }, // Signed share for the specified signing protocol. Share { id: SignId, share: Vec }, // Completed a signing protocol already. Completed { key: Vec, id: [u8; 32], tx: Vec }, } impl CoordinatorMessage { pub fn required_block(&self) -> Option { None } pub fn key(&self) -> &[u8] { match self { CoordinatorMessage::Preprocesses { id, .. } => &id.key, CoordinatorMessage::Shares { id, .. } => &id.key, CoordinatorMessage::Reattempt { id } => &id.key, CoordinatorMessage::Completed { key, .. } => key, } } } } pub mod coordinator { use super::{sign::SignId, *}; #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum CoordinatorMessage { // Uses Vec instead of [u8; 64] since serde Deserialize isn't implemented for [u8; 64] BatchPreprocesses { id: SignId, preprocesses: HashMap> }, BatchShares { id: SignId, shares: HashMap }, // Re-attempt a batch signing protocol. BatchReattempt { id: SignId }, } impl CoordinatorMessage { pub fn required_block(&self) -> Option { Some(match self { CoordinatorMessage::BatchPreprocesses { id, .. } => BlockHash(id.id), CoordinatorMessage::BatchShares { id, .. } => BlockHash(id.id), CoordinatorMessage::BatchReattempt { id } => BlockHash(id.id), }) } pub fn key(&self) -> &[u8] { match self { CoordinatorMessage::BatchPreprocesses { id, .. } => &id.key, CoordinatorMessage::BatchShares { id, .. } => &id.key, CoordinatorMessage::BatchReattempt { id } => &id.key, } } } #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)] pub enum ProcessorMessage { SubstrateBlockAck { block: u64, plans: Vec<[u8; 32]> }, BatchPreprocess { id: SignId, preprocess: Vec }, BatchShare { id: SignId, share: [u8; 32] }, } } pub mod substrate { use super::*; #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum CoordinatorMessage { ConfirmKeyPair { context: SubstrateContext, set: ValidatorSet, key_pair: KeyPair, }, SubstrateBlock { context: SubstrateContext, block: u64, key: Vec, burns: Vec, }, } impl CoordinatorMessage { pub fn required_block(&self) -> Option { let context = match self { CoordinatorMessage::ConfirmKeyPair { context, .. } => context, CoordinatorMessage::SubstrateBlock { context, .. } => context, }; Some(context.coin_latest_finalized_block) } } #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)] pub enum ProcessorMessage { Update { key: Vec, batch: SignedBatch }, } } #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum CoordinatorMessage { KeyGen(key_gen::CoordinatorMessage), Sign(sign::CoordinatorMessage), Coordinator(coordinator::CoordinatorMessage), Substrate(substrate::CoordinatorMessage), } impl CoordinatorMessage { pub fn required_block(&self) -> Option { let required = match self { CoordinatorMessage::KeyGen(msg) => msg.required_block(), CoordinatorMessage::Sign(msg) => msg.required_block(), CoordinatorMessage::Coordinator(msg) => msg.required_block(), CoordinatorMessage::Substrate(msg) => msg.required_block(), }; // 0 is used when Serai hasn't acknowledged *any* block for this network, which also means // there's no need to wait for the block in question if required == Some(BlockHash([0; 32])) { return None; } required } } #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum ProcessorMessage { KeyGen(key_gen::ProcessorMessage), Sign(sign::ProcessorMessage), Coordinator(coordinator::ProcessorMessage), Substrate(substrate::ProcessorMessage), }