Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aggregator single signatures buffer #1934

Merged
merged 43 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e02968d
Scaffold integration test for signing with buffered signatures
Alenar Sep 2, 2024
b038620
Uncouple signatures registration from certifier in integration tests
Alenar Sep 2, 2024
33bd027
Promote aggregator `certifier` module to directory
Alenar Sep 2, 2024
047e26b
Rearrange `certifier` module
Alenar Sep 2, 2024
10af4a0
Scaffold `BufferedCertifierService` decorator
Alenar Sep 2, 2024
c6b0d45
Define a store for buffered signatures with an in-memory impl
Alenar Sep 3, 2024
4c203a5
Make buffer certifier buffer signature if no open message is available
Alenar Sep 3, 2024
fa55f44
Make buffered certifier add buffered signatures when opening a new me…
Alenar Sep 3, 2024
40dcab7
Add a dedicated error when registering invalid single signatures in c…
Alenar Sep 4, 2024
ec0053d
Move `InMemoryBufferedSingleSignatureStore` to store module
Alenar Sep 4, 2024
9ad80bd
Don't fail but log when transferring buffered signatures to new message
Alenar Sep 4, 2024
eeef280
Scaffold a sqlite BufferedSingleSignatureStore
Alenar Sep 10, 2024
0821617
Remove epoch from `BufferedSingleSignatureRecord`
Alenar Sep 10, 2024
795d3eb
Add unique constraint on `buffered_single_signature:signature` column
Alenar Sep 10, 2024
d7e4c0d
Fix crypto_helper:setup_protocol_initializer crash if party id is les…
Alenar Sep 10, 2024
5a7f9ea
Fix buffered_single_signature table constraints
Alenar Sep 10, 2024
407e481
Implement `buffer_signature` on sqlite store
Alenar Sep 10, 2024
b37bcfe
Implement `remove_buffered_signatures` on sqlite store
Alenar Sep 10, 2024
f07dafd
Remove unique(signature) constraint on buffered sig table
Alenar Sep 11, 2024
c3d1b0f
Skip invalid signatures when registering buffered data
Alenar Sep 11, 2024
20981a1
Remove RwLock wrapping from aggregator multi-signer
Alenar Sep 11, 2024
9aac986
Add `AsMessage` trait to allow multiple type to be sign or verified
Alenar Sep 11, 2024
44ad88b
Make aggregator multi signer able to verify signature issued for the …
Alenar Sep 11, 2024
028cf29
Check signature against message before buffering
Alenar Sep 12, 2024
c7f0878
Check signature against message using next stake distribution
Alenar Sep 12, 2024
a903d92
Add a status to certifier signature registration
Alenar Sep 12, 2024
d9185fe
Use sqlite store in buffered certifier tests
Alenar Sep 13, 2024
34a7219
Use sqlite buffer store everywhere and remove in memory version
Alenar Sep 13, 2024
76ffeae
Add `authentication_status` to SingleSignatures entity
Alenar Sep 17, 2024
a9ba1ff
Buffer signature if they're authenticated
Alenar Sep 17, 2024
c859a5a
Remove `multi_signer` dependency from buffered certifier service
Alenar Sep 17, 2024
c19f497
Skip (de)serialization of single signature `authentication_status`
Alenar Sep 17, 2024
5d81f67
Make buffer integration test send authenticated signatures
Alenar Sep 17, 2024
ebdea24
Add `SingleSignatureAuthenticator` in aggregator
Alenar Sep 17, 2024
f51ac9a
Wire `SingleSignatureAuthenticator` in aggregator dependencies
Alenar Sep 17, 2024
2d6e9eb
Make aggregator `register_signatures` route check signature authenticity
Alenar Sep 17, 2024
4c32c7b
Aggregator `/register-signatures` return 404 when signature with sign…
Alenar Sep 17, 2024
eeb23cf
Remove `signed_message` from `SingleSignatures` entity
Alenar Sep 17, 2024
d06bb6e
refactor: rename `AsMessage` to `ToMessage`
Alenar Sep 18, 2024
ad4d1db
refactor+style: Implement changes asked in PR reviews
Alenar Sep 18, 2024
90f7c20
style: naming & comments adjustements from pr reviews
Alenar Sep 19, 2024
f62785c
chore: bump crates & openapi versions
Alenar Sep 19, 2024
5b578c7
docs: update CHANGELOG
Alenar Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions mithril-aggregator/src/database/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,23 @@ pragma foreign_keys=true;
26,
r#"
create unique index signed_entity_unique_index on signed_entity(signed_entity_type_id, beacon);
"#,
),
// Migration 27
SqlMigration::new(
27,
r#"
create table buffered_single_signature (
signed_entity_type_id integer not null,
party_id text not null,
lottery_indexes json not null,
signature text not null,
created_at text not null,
primary key (signed_entity_type_id, party_id)
);

create index buffered_single_signature_signed_entity_type_id on buffered_single_signature(signed_entity_type_id);
create index buffered_single_signature_party_id_index on buffered_single_signature(party_id);
"#,
),
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use sqlite::Value;

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

use crate::database::record::BufferedSingleSignatureRecord;

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

impl DeleteBufferedSingleSignatureQuery {
pub fn by_discriminant_and_party_ids(
signed_entity_type_discriminants: SignedEntityTypeDiscriminants,
party_ids: Vec<PartyId>,
) -> Self {
let ids_values = party_ids.into_iter().map(Value::String).collect();

Self {
condition: WhereCondition::new(
"signed_entity_type_id = ?*",
vec![Value::Integer(
signed_entity_type_discriminants.index() as i64
)],
)
.and_where(WhereCondition::where_in("party_id", ids_values)),
}
}
}

impl Query for DeleteBufferedSingleSignatureQuery {
type Entity = BufferedSingleSignatureRecord;

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(&[(
"{:buffered_single_signature:}",
"buffered_single_signature",
)]));

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

#[cfg(test)]
mod tests {
use mithril_common::entities::SignedEntityTypeDiscriminants::{
CardanoTransactions, MithrilStakeDistribution,
};
use mithril_persistence::sqlite::ConnectionExtensions;

use crate::database::query::GetBufferedSingleSignatureQuery;
use crate::database::record::strip_buffered_sigs_date;
use crate::database::test_helper::{insert_buffered_single_signatures, main_db_connection};

use super::*;

#[test]
fn test_delete_buffered_single_signature_records_by_discriminant_and_party_ids() {
let connection = main_db_connection().unwrap();
let records = BufferedSingleSignatureRecord::fakes(&[
("party_1", MithrilStakeDistribution),
("party_2", MithrilStakeDistribution),
("party_3", MithrilStakeDistribution),
("party_1", CardanoTransactions),
("party_2", CardanoTransactions),
]);
insert_buffered_single_signatures(&connection, records.clone()).unwrap();

let cursor = connection
.fetch(
DeleteBufferedSingleSignatureQuery::by_discriminant_and_party_ids(
MithrilStakeDistribution,
vec!["party_1".into(), "party_3".into()],
),
)
.unwrap();
assert_eq!(2, cursor.count());

let remaining_records: Vec<BufferedSingleSignatureRecord> = connection
.fetch_collect(GetBufferedSingleSignatureQuery::all())
.unwrap();
assert_eq!(
strip_buffered_sigs_date(&BufferedSingleSignatureRecord::fakes(&[
("party_2", CardanoTransactions),
("party_1", CardanoTransactions),
("party_2", MithrilStakeDistribution),
])),
strip_buffered_sigs_date(&remaining_records)
);

let cursor = connection
.fetch(
DeleteBufferedSingleSignatureQuery::by_discriminant_and_party_ids(
CardanoTransactions,
vec!["party_1".into(), "party_2".into()],
),
)
.unwrap();
assert_eq!(2, cursor.count());

let remaining_records: Vec<BufferedSingleSignatureRecord> = connection
.fetch_collect(GetBufferedSingleSignatureQuery::all())
.unwrap();
assert_eq!(
strip_buffered_sigs_date(&BufferedSingleSignatureRecord::fakes(&[(
"party_2",
MithrilStakeDistribution
),])),
strip_buffered_sigs_date(&remaining_records)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use sqlite::Value;

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

use crate::database::record::BufferedSingleSignatureRecord;

/// Simple queries to retrieve [BufferedSingleSignatureRecord] from the sqlite database.
pub struct GetBufferedSingleSignatureQuery {
condition: WhereCondition,
}

impl GetBufferedSingleSignatureQuery {
#[cfg(test)]
pub(crate) fn all() -> Self {
Self {
condition: WhereCondition::default(),
}
}

pub fn by_discriminant(
signed_entity_type_discriminants: SignedEntityTypeDiscriminants,
) -> Self {
Self {
condition: WhereCondition::new(
"signed_entity_type_id = ?*",
vec![Value::Integer(
signed_entity_type_discriminants.index() as i64
)],
),
}
}
}

impl Query for GetBufferedSingleSignatureQuery {
type Entity = BufferedSingleSignatureRecord;

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

fn get_definition(&self, condition: &str) -> String {
let aliases = SourceAlias::new(&[("{:buffered_single_signature:}", "b")]);
let projection = Self::Entity::get_projection().expand(aliases);
format!("select {projection} from buffered_single_signature as b where {condition} order by ROWID desc")
}
}

#[cfg(test)]
mod tests {
use mithril_common::entities::SignedEntityTypeDiscriminants::{
CardanoImmutableFilesFull, CardanoTransactions, MithrilStakeDistribution,
};
use mithril_persistence::sqlite::ConnectionExtensions;

use crate::database::test_helper::{insert_buffered_single_signatures, main_db_connection};

use super::*;

#[test]
fn test_get_all() {
let connection = main_db_connection().unwrap();
let records = BufferedSingleSignatureRecord::fakes(&[
("party1", MithrilStakeDistribution),
("party2", CardanoTransactions),
("party3", MithrilStakeDistribution),
]);
insert_buffered_single_signatures(&connection, records.clone()).unwrap();

let stored_records: Vec<BufferedSingleSignatureRecord> = connection
.fetch_collect(GetBufferedSingleSignatureQuery::all())
.unwrap();

assert_eq!(
records.into_iter().rev().collect::<Vec<_>>(),
stored_records
);
}

#[test]
fn test_get_buffered_single_signature_records_by_discriminant() {
let connection = main_db_connection().unwrap();
let msd_records = BufferedSingleSignatureRecord::fakes(&[
("party1", MithrilStakeDistribution),
("party2", MithrilStakeDistribution),
]);
let ctx_records = BufferedSingleSignatureRecord::fakes(&[("party3", CardanoTransactions)]);
insert_buffered_single_signatures(
&connection,
[msd_records.clone(), ctx_records.clone()].concat(),
)
.unwrap();

let stored_msd_records: Vec<BufferedSingleSignatureRecord> = connection
.fetch_collect(GetBufferedSingleSignatureQuery::by_discriminant(
MithrilStakeDistribution,
))
.unwrap();
assert_eq!(
msd_records.into_iter().rev().collect::<Vec<_>>(),
stored_msd_records
);

let stored_ctx_records: Vec<BufferedSingleSignatureRecord> = connection
.fetch_collect(GetBufferedSingleSignatureQuery::by_discriminant(
CardanoTransactions,
))
.unwrap();
assert_eq!(
ctx_records.into_iter().rev().collect::<Vec<_>>(),
stored_ctx_records
);

let cursor = connection
.fetch(GetBufferedSingleSignatureQuery::by_discriminant(
CardanoImmutableFilesFull,
))
.unwrap();
assert_eq!(0, cursor.count());
}
}
Loading
Loading