Skip to content

Commit

Permalink
Create a ProtocolInitializer repository and migration to remove the…
Browse files Browse the repository at this point in the history
… `ProtocolInitializerStore` that use the `StoreAdpater`
  • Loading branch information
sfauvel committed Nov 18, 2024
1 parent 6f5f2df commit e7f2282
Show file tree
Hide file tree
Showing 16 changed files with 617 additions and 292 deletions.
24 changes: 24 additions & 0 deletions mithril-signer/src/database/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,30 @@ insert into stake_pool (epoch, stake_pool_id, stake, created_at)
from stake, json_each(stake.value) as stake_dis
order by epoch asc;
drop table stake;
"#,
),
// Migration 5
// Add the `protocol_initializer` table and migration data from the previous
// `protocol_initializer` JSON format.
SqlMigration::new(
5,
r#"
create table new_protocol_initializer (
epoch integer not null,
protocol json not null,
created_at text not null,
primary key (epoch)
);
create table if not exists protocol_initializer (key_hash text primary key, key json not null, value json not null);
insert into new_protocol_initializer (epoch, protocol, created_at)
select
protocol_initializer.key as epoch,
protocol_initializer.value,
strftime('%Y-%m-%dT%H:%M:%fZ', current_timestamp)
from protocol_initializer
order by epoch asc;
drop table protocol_initializer;
alter table new_protocol_initializer rename to protocol_initializer;
"#,
),
]
Expand Down
2 changes: 2 additions & 0 deletions mithril-signer/src/database/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Signer related database queries
mod protocol_initializer;
mod signed_beacon;
mod stake_pool;

pub use protocol_initializer::*;
pub use signed_beacon::*;
pub use stake_pool::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use sqlite::Value;

use mithril_common::entities::Epoch;
use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};

use crate::database::record::ProtocolInitializerRecord;

/// Query to delete old [ProtocolInitializer] from the sqlite database
pub struct DeleteProtocolInitializerQuery {
condition: WhereCondition,
}

impl Query for DeleteProtocolInitializerQuery {
type Entity = ProtocolInitializerRecord;

fn filters(&self) -> WhereCondition {
self.condition.clone()
}

fn get_definition(&self, condition: &str) -> String {
// it is important to alias the fields with the same name as the table
// since the table cannot be aliased in a RETURNING statement in SQLite.
let projection = Self::Entity::get_projection().expand(SourceAlias::new(&[(
"{:protocol_initializer:}",
"protocol_initializer",
)]));

format!("delete from protocol_initializer where {condition} returning {projection}")
}
}

impl DeleteProtocolInitializerQuery {
/// Create the SQL query to prune data older than the given Epoch.
pub fn below_epoch_threshold(epoch_threshold: Epoch) -> Self {
let condition = WhereCondition::new(
"epoch < ?*",
vec![Value::Integer(epoch_threshold.try_into().unwrap())],
);

Self { condition }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use sqlite::Value;

use mithril_common::entities::Epoch;
use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};

use crate::database::record::ProtocolInitializerRecord;

/// Simple queries to retrieve [ProtocolInitializer] from the sqlite database.
pub struct GetProtocolInitializerQuery {
condition: WhereCondition,
limit: Option<usize>,
}

impl GetProtocolInitializerQuery {
/// Get all signed beacons that match the given signed entity types.
pub fn for_epoch(epoch: Epoch) -> Self {
let epoch_i64: i64 = epoch.try_into().unwrap();
let condition = WhereCondition::new(
"protocol_initializer.epoch = ?",
vec![Value::Integer(epoch_i64)],
);

Self {
condition,
limit: None,
}
}

pub fn last_n(limit: usize) -> Self {
let condition = WhereCondition::default();
Self {
condition,
limit: Some(limit),
}
}
}

impl Query for GetProtocolInitializerQuery {
type Entity = ProtocolInitializerRecord;

fn filters(&self) -> WhereCondition {
self.condition.clone()
}

fn get_definition(&self, condition: &str) -> String {
let aliases = SourceAlias::new(&[("{:protocol_initializer:}", "protocol_initializer")]);
let projection = Self::Entity::get_projection().expand(aliases);
let limit = self
.limit
.map_or("".to_string(), |limit| format!(" limit {}", limit));
format!("select {projection} from protocol_initializer where {condition} order by rowid desc{limit}")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use sqlite::Value;

use mithril_common::StdResult;
use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};

use crate::database::record::ProtocolInitializerRecord;

/// Query to insert or replace [ProtocolInitializerRecord] in the sqlite database
pub struct InsertOrReplaceProtocolInitializerQuery {
condition: WhereCondition,
}

impl InsertOrReplaceProtocolInitializerQuery {
pub fn one(record: ProtocolInitializerRecord) -> StdResult<Self> {
let value = serde_json::to_string(&record.protocol_initializer).unwrap();
let condition = WhereCondition::new(
"(epoch, protocol, created_at) values (?*, ?*, ?*)",
vec![
Value::Integer(record.epoch.try_into()?),
Value::String(value),
Value::String(record.created_at.to_rfc3339()),
],
);

Ok(Self { condition })
}
}

impl Query for InsertOrReplaceProtocolInitializerQuery {
type Entity = ProtocolInitializerRecord;

fn filters(&self) -> WhereCondition {
self.condition.clone()
}

fn get_definition(&self, condition: &str) -> String {
// it is important to alias the fields with the same name as the table
// since the table cannot be aliased in a RETURNING statement in SQLite.
let projection = Self::Entity::get_projection().expand(SourceAlias::new(&[(
"{:protocol_initializer:}",
"protocol_initializer",
)]));

format!("insert or replace into protocol_initializer {condition} returning {projection}")
}
}
7 changes: 7 additions & 0 deletions mithril-signer/src/database/query/protocol_initializer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod delete_protocol_initializer;
mod get_protocol_initializer;
mod insert_protocol_initializer;

pub use delete_protocol_initializer::*;
pub use get_protocol_initializer::*;
pub use insert_protocol_initializer::*;
2 changes: 2 additions & 0 deletions mithril-signer/src/database/record/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Signer related database records
mod protocol_initializer_record;
mod signed_beacon_record;
mod stake_pool;

pub use protocol_initializer_record::*;
pub use signed_beacon_record::*;
pub use stake_pool::*;
60 changes: 60 additions & 0 deletions mithril-signer/src/database/record/protocol_initializer_record.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use chrono::{DateTime, Utc};

use mithril_common::{crypto_helper::ProtocolInitializer, entities::Epoch};
use mithril_persistence::sqlite::{HydrationError, Projection, SqLiteEntity};

/// Protocol initializer.
#[derive(Debug)]
pub struct ProtocolInitializerRecord {
/// Epoch
pub epoch: Epoch,

/// Protocol Initializer
pub protocol_initializer: ProtocolInitializer,

/// DateTime of the record creation.
pub created_at: DateTime<Utc>,
}

impl SqLiteEntity for ProtocolInitializerRecord {
fn hydrate(row: sqlite::Row) -> Result<Self, HydrationError>
where
Self: Sized,
{
let epoch_int = row.read::<i64, _>(0);
let protocol = row.read::<&str, _>(1);
let datetime = &row.read::<&str, _>(2);

let record = Self {
protocol_initializer: serde_json::from_str(protocol).map_err(|e| {
HydrationError::InvalidData(format!(
"Could not cast string ({}) to ProtocolInitializer. Error: '{e}'",
protocol
))
})?,
epoch: Epoch(epoch_int.try_into().map_err(|e| {
HydrationError::InvalidData(format!(
"Could not cast i64 ({epoch_int}) to u64. Error: '{e}'"
))
})?),
created_at: DateTime::parse_from_rfc3339(datetime)
.map_err(|e| {
HydrationError::InvalidData(format!(
"Could not turn string '{datetime}' to rfc3339 Datetime. Error: {e}"
))
})?
.with_timezone(&Utc),
};

Ok(record)
}

fn get_projection() -> Projection {
let mut projection = Projection::default();
projection.add_field("epoch", "{:protocol_initializer:}.epoch", "integer");
projection.add_field("protocol", "{:protocol_initializer:}.protocol", "integer");
projection.add_field("created_at", "{:protocol_initializer:}.created_at", "text");

projection
}
}
2 changes: 2 additions & 0 deletions mithril-signer/src/database/repository/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
//! Signer related database repositories
mod cardano_transaction_repository;
mod protocol_initializer_repository;
mod signed_beacon_repository;
mod stake_pool_store;

pub use protocol_initializer_repository::*;
pub use signed_beacon_repository::*;
pub use stake_pool_store::*;
Loading

0 comments on commit e7f2282

Please sign in to comment.