Skip to content

Commit ca1debc

Browse files
authored
Merge pull request #1028 from input-output-hk/djo/1015/bug/signer_vkey_discrepancy
Try to Signer verification key discrepancy (see #1015)
2 parents 81aba91 + 50dcc10 commit ca1debc

File tree

15 files changed

+410
-336
lines changed

15 files changed

+410
-336
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-aggregator/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-aggregator"
3-
version = "0.3.45"
3+
version = "0.3.46"
44
description = "A Mithril Aggregator server"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-aggregator/src/database/provider/signer_registration.rs

Lines changed: 78 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
use async_trait::async_trait;
22
use chrono::{DateTime, Utc};
33
use sqlite::{Connection, Value};
4-
use std::{
5-
collections::{BTreeMap, HashMap},
6-
sync::Arc,
7-
};
4+
use std::{collections::HashMap, sync::Arc};
85
use tokio::sync::Mutex;
96

107
use mithril_common::{
118
crypto_helper::KESPeriod,
129
entities::{
1310
Epoch, HexEncodedOpCert, HexEncodedVerificationKey, HexEncodedVerificationKeySignature,
14-
PartyId, SignerWithStake, Stake,
11+
PartyId, Signer, SignerWithStake, Stake,
1512
},
1613
sqlite::{
1714
EntityCursor, HydrationError, Projection, Provider, SourceAlias, SqLiteEntity,
1815
WhereCondition,
1916
},
20-
store::adapter::{AdapterError, StoreAdapter},
17+
store::{adapter::AdapterError, StoreError},
2118
StdError,
2219
};
2320

21+
use crate::VerificationKeyStorer;
22+
2423
/// SignerRegistration record is the representation of a stored signer_registration.
2524
#[derive(Debug, PartialEq, Clone)]
2625
pub struct SignerRegistrationRecord {
@@ -64,9 +63,21 @@ impl SignerRegistrationRecord {
6463
}
6564
}
6665

66+
impl From<SignerRegistrationRecord> for Signer {
67+
fn from(other: SignerRegistrationRecord) -> Self {
68+
Self {
69+
party_id: other.signer_id,
70+
verification_key: other.verification_key,
71+
verification_key_signature: other.verification_key_signature,
72+
operational_certificate: other.operational_certificate,
73+
kes_period: other.kes_period,
74+
}
75+
}
76+
}
77+
6778
impl From<SignerRegistrationRecord> for SignerWithStake {
68-
fn from(other: SignerRegistrationRecord) -> SignerWithStake {
69-
SignerWithStake {
79+
fn from(other: SignerRegistrationRecord) -> Self {
80+
Self {
7081
party_id: other.signer_id,
7182
verification_key: other.verification_key,
7283
verification_key_signature: other.verification_key_signature,
@@ -381,144 +392,82 @@ impl<'conn> DeleteSignerRegistrationRecordProvider<'conn> {
381392
}
382393

383394
/// Service to deal with signer_registration (read & write).
384-
pub struct SignerRegistrationStoreAdapter {
395+
pub struct SignerRegistrationStore {
385396
connection: Arc<Mutex<Connection>>,
386397
}
387398

388-
impl SignerRegistrationStoreAdapter {
389-
/// Create a new SignerRegistrationStoreAdapter service
399+
impl SignerRegistrationStore {
400+
/// Create a new [SignerRegistrationStore] service
390401
pub fn new(connection: Arc<Mutex<Connection>>) -> Self {
391402
Self { connection }
392403
}
393404
}
394405

395406
#[async_trait]
396-
impl StoreAdapter for SignerRegistrationStoreAdapter {
397-
type Key = Epoch;
398-
type Record = HashMap<PartyId, SignerWithStake>;
399-
400-
async fn store_record(
401-
&mut self,
402-
key: &Self::Key,
403-
record: &Self::Record,
404-
) -> Result<(), AdapterError> {
407+
impl VerificationKeyStorer for SignerRegistrationStore {
408+
async fn save_verification_key(
409+
&self,
410+
epoch: Epoch,
411+
signer: SignerWithStake,
412+
) -> Result<Option<SignerWithStake>, StoreError> {
405413
let connection = &*self.connection.lock().await;
406414
let provider = InsertOrReplaceSignerRegistrationRecordProvider::new(connection);
407-
connection
408-
.execute("begin transaction")
409-
.map_err(|e| AdapterError::QueryError(e.into()))?;
410-
411-
for signer_with_stake in record.values() {
412-
let _signer_registration_record = provider
413-
.persist(SignerRegistrationRecord::from_signer_with_stake(
414-
signer_with_stake.to_owned(),
415-
*key,
416-
))
417-
.map_err(|e| AdapterError::GeneralError(format!("{e}")))?;
418-
}
419-
420-
connection
421-
.execute("commit transaction")
422-
.map_err(|e| AdapterError::QueryError(e.into()))?;
423-
424-
Ok(())
425-
}
426-
427-
async fn get_record(&self, key: &Self::Key) -> Result<Option<Self::Record>, AdapterError> {
428-
let connection = &*self.connection.lock().await;
429-
let provider = SignerRegistrationRecordProvider::new(connection);
430-
let cursor = provider
431-
.get_by_epoch(key)
415+
let existing_record = SignerRegistrationRecordProvider::new(connection)
416+
.get_by_signer_id_and_epoch(signer.party_id.clone(), &epoch)
417+
.map_err(|e| AdapterError::QueryError(e))?
418+
.next();
419+
420+
let _updated_record = provider
421+
.persist(SignerRegistrationRecord::from_signer_with_stake(
422+
signer, epoch,
423+
))
432424
.map_err(|e| AdapterError::GeneralError(format!("{e}")))?;
433-
let mut signer_with_stakes = HashMap::new();
434-
for signer_registration_record in cursor {
435-
signer_with_stakes.insert(
436-
signer_registration_record.signer_id.to_string(),
437-
signer_registration_record.into(),
438-
);
439-
}
440-
if signer_with_stakes.is_empty() {
441-
Ok(None)
442-
} else {
443-
Ok(Some(signer_with_stakes))
444-
}
445-
}
446425

447-
async fn record_exists(&self, key: &Self::Key) -> Result<bool, AdapterError> {
448-
Ok(self.get_record(key).await?.is_some())
426+
match existing_record {
427+
None => Ok(None),
428+
Some(previous_record) => Ok(Some(previous_record.into())),
429+
}
449430
}
450431

451-
async fn get_last_n_records(
432+
async fn get_verification_keys(
452433
&self,
453-
how_many: usize,
454-
) -> Result<Vec<(Self::Key, Self::Record)>, AdapterError> {
434+
epoch: Epoch,
435+
) -> Result<Option<HashMap<PartyId, Signer>>, StoreError> {
455436
let connection = &*self.connection.lock().await;
456437
let provider = SignerRegistrationRecordProvider::new(connection);
457438
let cursor = provider
458-
.get_all()
459-
.map_err(|e| AdapterError::GeneralError(format!("{e}")))?
460-
.collect::<Vec<_>>()
461-
.into_iter()
462-
.rev();
463-
let signer_with_stake_by_epoch: BTreeMap<Self::Key, Self::Record> = cursor.fold(
464-
BTreeMap::<Self::Key, Self::Record>::new(),
465-
|mut acc, signer_registration_record| {
466-
let epoch = signer_registration_record.epoch_setting_id;
467-
let mut signer_with_stakes: Self::Record =
468-
if let Some(signer_with_stakes) = acc.get_mut(&epoch) {
469-
signer_with_stakes.to_owned()
470-
} else {
471-
HashMap::new()
472-
};
473-
signer_with_stakes.insert(
474-
signer_registration_record.signer_id.to_string(),
475-
signer_registration_record.into(),
476-
);
477-
acc.insert(epoch, signer_with_stakes);
478-
acc
479-
},
480-
);
481-
Ok(signer_with_stake_by_epoch
482-
.into_iter()
483-
.rev()
484-
.take(how_many)
485-
.collect())
486-
}
487-
488-
async fn remove(&mut self, key: &Self::Key) -> Result<Option<Self::Record>, AdapterError> {
489-
let connection = &*self.connection.lock().await;
490-
let provider = DeleteSignerRegistrationRecordProvider::new(connection);
491-
let cursor = provider
492-
.delete(*key)
439+
.get_by_epoch(&epoch)
493440
.map_err(|e| AdapterError::GeneralError(format!("{e}")))?;
494-
let mut signer_with_stakes = HashMap::new();
495-
for signer_registration_record in cursor {
496-
signer_with_stakes.insert(
497-
signer_registration_record.signer_id.to_string(),
498-
signer_registration_record.into(),
499-
);
500-
}
501441

502-
if signer_with_stakes.is_empty() {
503-
Ok(None)
504-
} else {
505-
Ok(Some(signer_with_stakes))
442+
let signer_with_stakes: HashMap<PartyId, Signer> =
443+
HashMap::from_iter(cursor.map(|record| (record.signer_id.to_owned(), record.into())));
444+
445+
match signer_with_stakes.is_empty() {
446+
true => Ok(None),
447+
false => Ok(Some(signer_with_stakes)),
506448
}
507449
}
508450

509-
async fn get_iter(&self) -> Result<Box<dyn Iterator<Item = Self::Record> + '_>, AdapterError> {
510-
let records = self.get_last_n_records(usize::MAX).await?;
511-
Ok(Box::new(records.into_iter().map(|(_k, v)| v)))
451+
async fn prune_verification_keys(&self, max_epoch_to_prune: Epoch) -> Result<(), StoreError> {
452+
let connection = &*self.connection.lock().await;
453+
let _deleted_records = DeleteSignerRegistrationRecordProvider::new(connection)
454+
// we want to prune including the given epoch (+1)
455+
.prune(max_epoch_to_prune + 1)
456+
.map_err(|e| AdapterError::QueryError(e))?
457+
.collect::<Vec<_>>();
458+
459+
Ok(())
512460
}
513461
}
514462

515463
#[cfg(test)]
516464
mod tests {
517-
use std::collections::{BTreeMap, HashMap};
465+
use std::collections::HashMap;
518466

519467
use mithril_common::test_utils::MithrilFixtureBuilder;
520468

521469
use crate::database::provider::{apply_all_migrations_to_db, disable_foreign_key_support};
470+
use crate::store::test_verification_key_storer;
522471

523472
use super::*;
524473

@@ -849,63 +798,24 @@ mod tests {
849798
}
850799
}
851800

852-
#[tokio::test]
853-
async fn test_store_adapter() {
854-
let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
855-
let signer_with_stakes = fixture.signers_with_stake();
856-
let signer_with_stakes_by_epoch: Vec<(Epoch, HashMap<PartyId, SignerWithStake>)> = (0..5)
857-
.map(|e| {
858-
(
859-
Epoch(e),
860-
signer_with_stakes
861-
.clone()
862-
.into_iter()
863-
.map(|s| (s.party_id.to_owned(), s))
864-
.collect(),
865-
)
866-
})
867-
.collect();
868-
801+
pub fn init_signer_registration_store(
802+
initial_data: Vec<(Epoch, HashMap<PartyId, SignerWithStake>)>,
803+
) -> Arc<dyn VerificationKeyStorer> {
869804
let connection = Connection::open(":memory:").unwrap();
870-
setup_signer_registration_db(&connection, Vec::new()).unwrap();
871-
872-
let mut signer_registration_store_adapter =
873-
SignerRegistrationStoreAdapter::new(Arc::new(Mutex::new(connection)));
805+
let initial_data: Vec<(Epoch, Vec<SignerWithStake>)> = initial_data
806+
.into_iter()
807+
.map(|(e, signers)| (e, signers.into_values().collect::<Vec<_>>()))
808+
.collect();
874809

875-
for (epoch, signer_with_stakes) in &signer_with_stakes_by_epoch {
876-
assert!(signer_registration_store_adapter
877-
.store_record(epoch, signer_with_stakes)
878-
.await
879-
.is_ok());
880-
}
810+
setup_signer_registration_db(&connection, initial_data).unwrap();
881811

882-
for (epoch, signer_with_stakes) in &signer_with_stakes_by_epoch {
883-
assert!(signer_registration_store_adapter
884-
.record_exists(epoch)
885-
.await
886-
.unwrap());
887-
assert_eq!(
888-
Some(signer_with_stakes.to_owned()),
889-
signer_registration_store_adapter
890-
.get_record(epoch)
891-
.await
892-
.unwrap()
893-
);
894-
}
895-
assert_eq!(
896-
signer_with_stakes_by_epoch
897-
.clone()
898-
.into_iter()
899-
.map(|(k, v)| (k, BTreeMap::from_iter(v.into_iter())))
900-
.collect::<Vec<(Epoch, BTreeMap<PartyId, SignerWithStake>)>>(),
901-
signer_registration_store_adapter
902-
.get_last_n_records(signer_with_stakes_by_epoch.len())
903-
.await
904-
.unwrap()
905-
.into_iter()
906-
.rev()
907-
.map(|(k, v)| (k, BTreeMap::from_iter(v.into_iter())))
908-
.collect::<Vec<(Epoch, BTreeMap<PartyId, SignerWithStake>)>>()
909-
)
812+
Arc::new(SignerRegistrationStore::new(Arc::new(Mutex::new(
813+
connection,
814+
))))
910815
}
816+
817+
test_verification_key_storer!(
818+
test_signer_registration_store =>
819+
crate::database::provider::signer_registration::tests::init_signer_registration_store
820+
);
911821
}

mithril-aggregator/src/dependency.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ use crate::{
2525
signer_registerer::SignerRecorder,
2626
ticker_service::TickerService,
2727
CertificatePendingStore, CertificateStore, ProtocolParametersStore, ProtocolParametersStorer,
28-
SignerRegisterer, SignerRegistrationRoundOpener, Snapshotter, VerificationKeyStore,
29-
VerificationKeyStorer,
28+
SignerRegisterer, SignerRegistrationRoundOpener, Snapshotter, VerificationKeyStorer,
3029
};
3130
use crate::{event_store::TransmitterService, multi_signer::MultiSigner};
3231
use crate::{
@@ -63,7 +62,7 @@ pub struct DependencyManager {
6362
pub certificate_store: Arc<CertificateStore>,
6463

6564
/// Verification key store.
66-
pub verification_key_store: Arc<VerificationKeyStore>,
65+
pub verification_key_store: Arc<dyn VerificationKeyStorer>,
6766

6867
/// Protocol parameter store.
6968
pub protocol_parameters_store: Arc<ProtocolParametersStore>,
@@ -249,7 +248,7 @@ impl DependencyManager {
249248
/// Fill the stores of a [DependencyManager] in a way to simulate an aggregator genesis state.
250249
///
251250
/// For the current and the next epoch:
252-
/// * Fill the [VerificationKeyStore] with the given signers keys.
251+
/// * Fill the [VerificationKeyStorer] with the given signers keys.
253252
/// * Fill the [StakeStore] with the given signers stakes.
254253
/// * Fill the [ProtocolParametersStore] with the given parameters.
255254
pub async fn prepare_for_genesis(

0 commit comments

Comments
 (0)