From 3cc7b4949299211261f4d17bf2ba7a72fa7102ca Mon Sep 17 00:00:00 2001
From: Luke Parker <lukeparker5132@gmail.com>
Date: Mon, 9 Sep 2024 03:23:55 -0400
Subject: [PATCH] Strongly type SlashReport, populate cosign/slash report tasks
 with work

---
 processor/messages/src/lib.rs                 |  4 +-
 processor/signers/src/db.rs                   |  5 ++-
 processor/signers/src/lib.rs                  | 41 ++++++++++++++++++-
 .../validator-sets/primitives/src/lib.rs      | 20 ++++++++-
 4 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/processor/messages/src/lib.rs b/processor/messages/src/lib.rs
index 4a191b68..dc7f2939 100644
--- a/processor/messages/src/lib.rs
+++ b/processor/messages/src/lib.rs
@@ -9,7 +9,7 @@ use dkg::Participant;
 use serai_primitives::BlockHash;
 use in_instructions_primitives::{Batch, SignedBatch};
 use coins_primitives::OutInstructionWithBalance;
-use validator_sets_primitives::{Session, KeyPair};
+use validator_sets_primitives::{Session, KeyPair, Slash};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
 pub struct SubstrateContext {
@@ -163,7 +163,7 @@ pub mod coordinator {
   #[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
   pub enum CoordinatorMessage {
     CosignSubstrateBlock { session: Session, block_number: u64, block: [u8; 32] },
-    SignSlashReport { session: Session, report: Vec<([u8; 32], u32)> },
+    SignSlashReport { session: Session, report: Vec<Slash> },
   }
 
   #[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
diff --git a/processor/signers/src/db.rs b/processor/signers/src/db.rs
index ae62c947..66894621 100644
--- a/processor/signers/src/db.rs
+++ b/processor/signers/src/db.rs
@@ -1,4 +1,4 @@
-use serai_validator_sets_primitives::Session;
+use serai_validator_sets_primitives::{Session, Slash};
 
 use serai_db::{Get, DbTxn, create_db, db_channel};
 
@@ -15,6 +15,9 @@ create_db! {
 
 db_channel! {
   SignersGlobal {
+    Cosign: (session: Session) -> (u64, [u8; 32]),
+    SlashReport: (session: Session) -> Vec<Slash>,
+
     CoordinatorToCosignerMessages: (session: Session) -> CoordinatorMessage,
     CosignerToCoordinatorMessages: (session: Session) -> ProcessorMessage,
 
diff --git a/processor/signers/src/lib.rs b/processor/signers/src/lib.rs
index 36e2db2e..de456296 100644
--- a/processor/signers/src/lib.rs
+++ b/processor/signers/src/lib.rs
@@ -10,7 +10,7 @@ use zeroize::Zeroizing;
 use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
 use frost::dkg::{ThresholdCore, ThresholdKeys};
 
-use serai_validator_sets_primitives::Session;
+use serai_validator_sets_primitives::{Session, Slash};
 use serai_in_instructions_primitives::SignedBatch;
 
 use serai_db::{DbTxn, Db};
@@ -139,6 +139,8 @@ impl<ST: SignableTransaction> Signers<ST> {
         while scanner::CompletedEventualities::try_recv(&mut txn, &external_key).is_some() {}
 
         // Drain our DB channels
+        while db::Cosign::try_recv(&mut txn, session).is_some() {}
+        while db::SlashReport::try_recv(&mut txn, session).is_some() {}
         while db::CoordinatorToCosignerMessages::try_recv(&mut txn, session).is_some() {}
         while db::CosignerToCoordinatorMessages::try_recv(&mut txn, session).is_some() {}
         while db::CoordinatorToBatchSignerMessages::try_recv(&mut txn, session).is_some() {}
@@ -276,7 +278,7 @@ impl<ST: SignableTransaction> Signers<ST> {
 
   /// Queue handling a message.
   ///
-  /// This is a cheap call and able to be done inline with a higher-level loop.
+  /// This is a cheap call and able to be done inline from a higher-level loop.
   pub fn queue_message(&mut self, txn: &mut impl DbTxn, message: &CoordinatorMessage) {
     let sign_id = message.sign_id();
     let tasks = self.tasks.get(&sign_id.session);
@@ -307,4 +309,39 @@ impl<ST: SignableTransaction> Signers<ST> {
       }
     }
   }
+
+  /// Cosign a block.
+  ///
+  /// This is a cheap call and able to be done inline from a higher-level loop.
+  pub fn cosign_block(
+    &mut self,
+    mut txn: impl DbTxn,
+    session: Session,
+    block_number: u64,
+    block: [u8; 32],
+  ) {
+    db::Cosign::send(&mut txn, session, &(block_number, block));
+    txn.commit();
+
+    if let Some(tasks) = self.tasks.get(&session) {
+      tasks.cosign.run_now();
+    }
+  }
+
+  /// Sign a slash report.
+  ///
+  /// This is a cheap call and able to be done inline from a higher-level loop.
+  pub fn sign_slash_report(
+    &mut self,
+    mut txn: impl DbTxn,
+    session: Session,
+    slash_report: Vec<Slash>,
+  ) {
+    db::SlashReport::send(&mut txn, session, &slash_report);
+    txn.commit();
+
+    if let Some(tasks) = self.tasks.get(&session) {
+      tasks.slash_report.run_now();
+    }
+  }
 }
diff --git a/substrate/validator-sets/primitives/src/lib.rs b/substrate/validator-sets/primitives/src/lib.rs
index 90d58c37..341d211f 100644
--- a/substrate/validator-sets/primitives/src/lib.rs
+++ b/substrate/validator-sets/primitives/src/lib.rs
@@ -103,7 +103,25 @@ pub fn set_keys_message(set: &ValidatorSet, key_pair: &KeyPair) -> Vec<u8> {
   (b"ValidatorSets-set_keys", set, key_pair).encode()
 }
 
-pub fn report_slashes_message(set: &ValidatorSet, slashes: &[(Public, u32)]) -> Vec<u8> {
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
+#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Slash {
+  #[cfg_attr(
+    feature = "borsh",
+    borsh(
+      serialize_with = "serai_primitives::borsh_serialize_public",
+      deserialize_with = "serai_primitives::borsh_deserialize_public"
+    )
+  )]
+  key: Public,
+  points: u32,
+}
+#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SlashReport(pub BoundedVec<Slash, ConstU32<{ MAX_KEY_SHARES_PER_SET / 3 }>>);
+
+pub fn report_slashes_message(set: &ValidatorSet, slashes: &SlashReport) -> Vec<u8> {
   (b"ValidatorSets-report_slashes", set, slashes).encode()
 }