Skip to content

Commit fd0a2cb

Browse files
committed
refactor(aggregator): do not override existing epoch settings on save
1 parent a3b7d1f commit fd0a2cb

File tree

6 files changed

+170
-125
lines changed

6 files changed

+170
-125
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use sqlite::Value;
2+
3+
use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
4+
5+
use crate::database::record::EpochSettingsRecord;
6+
7+
/// Query to update [EpochSettingsRecord] in the sqlite database
8+
pub struct InsertOrIgnoreEpochSettingsQuery {
9+
condition: WhereCondition,
10+
}
11+
12+
impl InsertOrIgnoreEpochSettingsQuery {
13+
pub fn one(epoch_settings: EpochSettingsRecord) -> Self {
14+
Self {
15+
condition: WhereCondition::new(
16+
"(epoch_setting_id, protocol_parameters, cardano_transactions_signing_config) values (?1, ?2, ?3)",
17+
vec![
18+
Value::Integer(*epoch_settings.epoch_settings_id as i64),
19+
Value::String(
20+
serde_json::to_string(&epoch_settings.protocol_parameters).unwrap(),
21+
),
22+
Value::String(
23+
serde_json::to_string(&epoch_settings.cardano_transactions_signing_config)
24+
.unwrap(),
25+
),
26+
],
27+
),
28+
}
29+
}
30+
}
31+
32+
impl Query for InsertOrIgnoreEpochSettingsQuery {
33+
type Entity = EpochSettingsRecord;
34+
35+
fn filters(&self) -> WhereCondition {
36+
self.condition.clone()
37+
}
38+
39+
fn get_definition(&self, condition: &str) -> String {
40+
// it is important to alias the fields with the same name as the table
41+
// since the table cannot be aliased in a RETURNING statement in SQLite.
42+
let projection = Self::Entity::get_projection()
43+
.expand(SourceAlias::new(&[("{:epoch_setting:}", "epoch_setting")]));
44+
45+
format!("insert or ignore into epoch_setting {condition} returning {projection}")
46+
}
47+
}
48+
49+
#[cfg(test)]
50+
mod tests {
51+
use mithril_common::entities::{BlockNumber, CardanoTransactionsSigningConfig, Epoch};
52+
use mithril_common::test::double::fake_data;
53+
use mithril_persistence::sqlite::ConnectionExtensions;
54+
55+
use crate::database::query::GetEpochSettingsQuery;
56+
use crate::database::test_helper::main_db_connection;
57+
58+
use super::*;
59+
60+
#[test]
61+
fn test_insert_epoch_setting_in_empty_db() {
62+
let connection = main_db_connection().unwrap();
63+
64+
let expected_epoch_settings = EpochSettingsRecord {
65+
epoch_settings_id: Epoch(3),
66+
protocol_parameters: fake_data::protocol_parameters(),
67+
cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
68+
security_parameter: BlockNumber(24),
69+
step: BlockNumber(62),
70+
},
71+
};
72+
let record = connection
73+
.fetch_first(InsertOrIgnoreEpochSettingsQuery::one(
74+
expected_epoch_settings.clone(),
75+
))
76+
.unwrap();
77+
78+
assert_eq!(Some(expected_epoch_settings), record);
79+
}
80+
81+
#[test]
82+
fn test_cant_replace_existing_value() {
83+
let connection = main_db_connection().unwrap();
84+
85+
let expected_epoch_settings = EpochSettingsRecord {
86+
epoch_settings_id: Epoch(3),
87+
protocol_parameters: fake_data::protocol_parameters(),
88+
cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
89+
security_parameter: BlockNumber(24),
90+
step: BlockNumber(62),
91+
},
92+
};
93+
let record = connection
94+
.fetch_first(InsertOrIgnoreEpochSettingsQuery::one(
95+
expected_epoch_settings.clone(),
96+
))
97+
.unwrap();
98+
assert!(record.is_some());
99+
100+
let record = connection
101+
.fetch_first(InsertOrIgnoreEpochSettingsQuery::one(EpochSettingsRecord {
102+
cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
103+
security_parameter: BlockNumber(134),
104+
step: BlockNumber(872),
105+
},
106+
..expected_epoch_settings.clone()
107+
}))
108+
.unwrap();
109+
assert!(record.is_none());
110+
111+
let record_in_db = connection
112+
.fetch_first(GetEpochSettingsQuery::by_epoch(Epoch(3)).unwrap())
113+
.unwrap();
114+
assert_eq!(Some(expected_epoch_settings), record_in_db);
115+
}
116+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod delete_epoch_settings;
22
mod get_epoch_settings;
3-
mod update_epoch_settings;
3+
mod insert_or_ignore_epoch_settings;
44

55
pub use delete_epoch_settings::*;
66
pub use get_epoch_settings::*;
7-
pub use update_epoch_settings::*;
7+
pub use insert_or_ignore_epoch_settings::*;

mithril-aggregator/src/database/query/epoch_settings/update_epoch_settings.rs

Lines changed: 0 additions & 103 deletions
This file was deleted.

mithril-aggregator/src/database/record/epoch_settings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use mithril_persistence::sqlite::{HydrationError, Projection, SqLiteEntity};
44
use crate::entities::AggregatorEpochSettings;
55

66
/// Settings for an epoch, including the protocol parameters.
7-
#[derive(Debug, PartialEq)]
7+
#[derive(Debug, PartialEq, Clone)]
88
pub struct EpochSettingsRecord {
99
/// Epoch settings id, i.e. the epoch number.
1010
pub epoch_settings_id: Epoch,

mithril-aggregator/src/database/repository/epoch_settings_store.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use mithril_common::entities::{Epoch, ProtocolParameters};
88
use mithril_persistence::sqlite::{ConnectionExtensions, SqliteConnection};
99

1010
use crate::database::query::{
11-
DeleteEpochSettingsQuery, GetEpochSettingsQuery, UpdateEpochSettingsQuery,
11+
DeleteEpochSettingsQuery, GetEpochSettingsQuery, InsertOrIgnoreEpochSettingsQuery,
1212
};
13+
use crate::database::record::EpochSettingsRecord;
1314
use crate::entities::AggregatorEpochSettings;
1415
use crate::services::EpochPruningTask;
1516
use crate::{EpochSettingsStorer, ProtocolParametersRetriever};
@@ -50,13 +51,17 @@ impl EpochSettingsStorer for EpochSettingsStore {
5051
epoch: Epoch,
5152
epoch_settings: AggregatorEpochSettings,
5253
) -> StdResult<Option<AggregatorEpochSettings>> {
54+
let record_to_insert = EpochSettingsRecord {
55+
epoch_settings_id: epoch,
56+
cardano_transactions_signing_config: epoch_settings.cardano_transactions_signing_config,
57+
protocol_parameters: epoch_settings.protocol_parameters,
58+
};
5359
let epoch_settings_record = self
5460
.connection
55-
.fetch_first(UpdateEpochSettingsQuery::one(epoch, epoch_settings))
56-
.with_context(|| format!("persist epoch settings failure for epoch {epoch:?}"))?
57-
.unwrap_or_else(|| panic!("No entity returned by the persister, epoch = {epoch:?}"));
61+
.fetch_first(InsertOrIgnoreEpochSettingsQuery::one(record_to_insert))
62+
.with_context(|| format!("persist epoch settings failure for epoch {epoch:?}"))?;
5863

59-
Ok(Some(epoch_settings_record.into()))
64+
Ok(epoch_settings_record.map(Into::into))
6065
}
6166

6267
async fn get_epoch_settings(&self, epoch: Epoch) -> StdResult<Option<AggregatorEpochSettings>> {
@@ -171,4 +176,34 @@ mod tests {
171176
assert_eq!(None, epoch_settings);
172177
}
173178
}
179+
180+
#[tokio::test]
181+
async fn save_epoch_settings_does_not_replace_existing_value_in_database() {
182+
let connection = main_db_connection().unwrap();
183+
184+
let store = EpochSettingsStore::new(Arc::new(connection), None);
185+
let expected_epoch_settings = AggregatorEpochSettings {
186+
protocol_parameters: ProtocolParameters::new(1, 1, 0.5),
187+
..Dummy::dummy()
188+
};
189+
190+
store
191+
.save_epoch_settings(Epoch(2), expected_epoch_settings.clone())
192+
.await
193+
.expect("saving epoch settings should not fails");
194+
195+
store
196+
.save_epoch_settings(
197+
Epoch(2),
198+
AggregatorEpochSettings {
199+
protocol_parameters: ProtocolParameters::new(2, 2, 1.5),
200+
..Dummy::dummy()
201+
},
202+
)
203+
.await
204+
.expect("saving epoch settings should not fails");
205+
206+
let epoch_settings = store.get_epoch_settings(Epoch(2)).await.unwrap().unwrap();
207+
assert_eq!(expected_epoch_settings, epoch_settings);
208+
}
174209
}

mithril-aggregator/src/database/test_helper.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@ use mithril_persistence::sqlite::{
1212
};
1313

1414
use crate::database::query::{
15-
ImportSignerRecordQuery, InsertCertificateRecordQuery,
15+
ImportSignerRecordQuery, InsertCertificateRecordQuery, InsertOrIgnoreEpochSettingsQuery,
1616
InsertOrReplaceBufferedSingleSignatureRecordQuery,
1717
InsertOrReplaceSignerRegistrationRecordQuery, InsertOrReplaceStakePoolQuery,
18-
InsertSignedEntityRecordQuery, UpdateEpochSettingsQuery, UpdateSingleSignatureRecordQuery,
18+
InsertSignedEntityRecordQuery, UpdateSingleSignatureRecordQuery,
1919
};
2020
use crate::database::record::{
21-
BufferedSingleSignatureRecord, CertificateRecord, SignedEntityRecord, SignerRecord,
22-
SignerRegistrationRecord, SingleSignatureRecord,
21+
BufferedSingleSignatureRecord, CertificateRecord, EpochSettingsRecord, SignedEntityRecord,
22+
SignerRecord, SignerRegistrationRecord, SingleSignatureRecord,
2323
};
24-
use crate::entities::AggregatorEpochSettings;
2524

2625
/// In-memory sqlite database without foreign key support with migrations applied
2726
pub fn main_db_connection() -> StdResult<SqliteConnection> {
@@ -206,16 +205,14 @@ pub fn insert_epoch_settings(
206205
let query = {
207206
// leverage the expanded parameter from this query which is unit
208207
// tested on its own above.
209-
let (sql_values, _) = UpdateEpochSettingsQuery::one(
210-
Epoch(1),
211-
AggregatorEpochSettings {
212-
protocol_parameters: ProtocolParameters::new(1, 2, 1.0),
213-
cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
214-
security_parameter: BlockNumber(0),
215-
step: BlockNumber(0),
216-
},
208+
let (sql_values, _) = InsertOrIgnoreEpochSettingsQuery::one(EpochSettingsRecord {
209+
epoch_settings_id: Epoch(1),
210+
protocol_parameters: ProtocolParameters::new(1, 2, 1.0),
211+
cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
212+
security_parameter: BlockNumber(0),
213+
step: BlockNumber(0),
217214
},
218-
)
215+
})
219216
.filters()
220217
.expand();
221218

0 commit comments

Comments
 (0)