mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
Add a cosigning protocol to ensure finalizations are unique (#433)
* Add a function to deterministically decide which Serai blocks should be co-signed Has a 5 minute latency between co-signs, also used as the maximal latency before a co-sign is started. * Get all active tributaries we're in at a specific block * Add and route CosignSubstrateBlock, a new provided TX * Split queued cosigns per network * Rename BatchSignId to SubstrateSignId * Add SubstrateSignableId, a meta-type for either Batch or Block, and modularize around it * Handle the CosignSubstrateBlock provided TX * Revert substrate_signer.rs to develop (and patch to still work) Due to SubstrateSigner moving when the prior multisig closes, yet cosigning occurring with the most recent key, a single SubstrateSigner can be reused. We could manage multiple SubstrateSigners, yet considering the much lower specifications for cosigning, I'd rather treat it distinctly. * Route cosigning through the processor * Add note to rename SubstrateSigner post-PR I don't want to do so now in order to preserve the diff's clarity. * Implement cosign evaluation into the coordinator * Get tests to compile * Bug fixes, mark blocks without cosigners available as cosigned * Correct the ID Batch preprocesses are saved under, add log statements * Create a dedicated function to handle cosigns * Correct the flow around Batch verification/queueing Verifying `Batch`s could stall when a `Batch` was signed before its predecessors/before the block it's contained in was cosigned (the latter being inevitable as we can't sign a block containing a signed batch before signing the batch). Now, Batch verification happens on a distinct async task in order to not block the handling of processor messages. This task is the sole caller of verify in order to ensure last_verified_batch isn't unexpectedly mutated. When the processor message handler needs to access it, or needs to queue a Batch, it associates the DB TXN with a lock preventing the other task from doing so. This lock, as currently implemented, is a poor and inefficient design. It should be modified to the pattern used for cosign management. Additionally, a new primitive of a DB-backed channel may be immensely valuable. Fixes a standing potential deadlock and a deadlock introduced with the cosigning protocol. * Working full-stack tests After the last commit, this only required extending a timeout. * Replace "co-sign" with "cosign" to make finding text easier * Update the coordinator tests to support cosigning * Inline prior_batch calculation to prevent panic on rotation Noticed when doing a final review of the branch.
This commit is contained in:
@@ -36,7 +36,10 @@ create_db!(
|
||||
// Overwriting its commitments would be accordingly poor
|
||||
CommitmentsDb: (key: &KeyGenId) -> HashMap<Participant, Vec<u8>>,
|
||||
GeneratedKeysDb: (set: &ValidatorSet, substrate_key: &[u8; 32], network_key: &[u8]) -> Vec<u8>,
|
||||
KeysDb: (network_key: &[u8]) -> Vec<u8>
|
||||
// These do assume a key is only used once across sets, which holds true so long as a single
|
||||
// participant is honest in their execution of the protocol
|
||||
KeysDb: (network_key: &[u8]) -> Vec<u8>,
|
||||
NetworkKey: (substrate_key: [u8; 32]) -> Vec<u8>
|
||||
}
|
||||
);
|
||||
|
||||
@@ -102,6 +105,7 @@ impl KeysDb {
|
||||
keys.1[0].group_key().to_bytes().as_ref(),
|
||||
);
|
||||
txn.put(KeysDb::key(keys.1[0].group_key().to_bytes().as_ref()), keys_vec);
|
||||
NetworkKey::set(txn, key_pair.0.into(), &key_pair.1.clone().into_inner());
|
||||
keys
|
||||
}
|
||||
|
||||
@@ -115,6 +119,16 @@ impl KeysDb {
|
||||
assert_eq!(&res.1[0].group_key(), network_key);
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn substrate_keys_by_substrate_key<N: Network>(
|
||||
getter: &impl Get,
|
||||
substrate_key: &[u8; 32],
|
||||
) -> Option<Vec<ThresholdKeys<Ristretto>>> {
|
||||
let network_key = NetworkKey::get(getter, *substrate_key)?;
|
||||
let res = GeneratedKeysDb::read_keys::<N>(getter, &Self::key(&network_key))?.1;
|
||||
assert_eq!(&res.0[0].group_key().to_bytes(), substrate_key);
|
||||
Some(res.0)
|
||||
}
|
||||
}
|
||||
|
||||
type SecretShareMachines<N> =
|
||||
@@ -152,6 +166,13 @@ impl<N: Network, D: Db> KeyGen<N, D> {
|
||||
KeysDb::keys::<N>(&self.db, key)
|
||||
}
|
||||
|
||||
pub fn substrate_keys_by_substrate_key(
|
||||
&self,
|
||||
substrate_key: &[u8; 32],
|
||||
) -> Option<Vec<ThresholdKeys<Ristretto>>> {
|
||||
KeysDb::substrate_keys_by_substrate_key::<N>(&self.db, substrate_key)
|
||||
}
|
||||
|
||||
pub async fn handle(
|
||||
&mut self,
|
||||
txn: &mut D::Transaction<'_>,
|
||||
|
||||
Reference in New Issue
Block a user