Skip to content

Commit 9104258

Browse files
authored
Merge pull request #1685 from input-output-hk/djo/1645/prune_ctx_in_signer
Prune cardano transactions in signer after block range roots computation
2 parents 2fe74c2 + e258352 commit 9104258

File tree

18 files changed

+596
-213
lines changed

18 files changed

+596
-213
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ As a minor extension, we have adopted a slightly different versioning convention
1111

1212
- Support computation of the Cardano Transactions signature and proving with the pre-computed Block Range Merkle Roots retrieved from the database.
1313

14+
- Prune Cardano Transactions from the signer database after the Block Range Merkle Roots have been computed.
15+
1416
- Update website and explorer user interface to use the new mithril logo.
1517

1618
- Crates versions:

Cargo.lock

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/mithril-persistence/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-persistence"
3-
version = "0.1.11"
3+
version = "0.1.12"
44
description = "Common types, interfaces, and utilities to persist data for Mithril nodes."
55
authors = { workspace = true }
66
edition = { workspace = true }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
use anyhow::Context;
2+
use sqlite::Value;
3+
4+
use mithril_common::entities::BlockNumber;
5+
use mithril_common::StdResult;
6+
7+
use crate::database::record::CardanoTransactionRecord;
8+
use crate::sqlite::{
9+
EntityCursor, Provider, SourceAlias, SqLiteEntity, SqliteConnection, WhereCondition,
10+
};
11+
12+
/// Query to delete old [CardanoTransactionRecord] from the sqlite database
13+
pub struct DeleteCardanoTransactionProvider<'conn> {
14+
connection: &'conn SqliteConnection,
15+
}
16+
17+
impl<'conn> Provider<'conn> for DeleteCardanoTransactionProvider<'conn> {
18+
type Entity = CardanoTransactionRecord;
19+
20+
fn get_connection(&'conn self) -> &'conn SqliteConnection {
21+
self.connection
22+
}
23+
24+
fn get_definition(&self, condition: &str) -> String {
25+
// it is important to alias the fields with the same name as the table
26+
// since the table cannot be aliased in a RETURNING statement in SQLite.
27+
let projection = Self::Entity::get_projection()
28+
.expand(SourceAlias::new(&[("{:cardano_tx:}", "cardano_tx")]));
29+
30+
format!("delete from cardano_tx where {condition} returning {projection}")
31+
}
32+
}
33+
34+
impl<'conn> DeleteCardanoTransactionProvider<'conn> {
35+
/// Create a new instance
36+
pub fn new(connection: &'conn SqliteConnection) -> Self {
37+
Self { connection }
38+
}
39+
40+
fn get_prune_condition(
41+
&self,
42+
block_number_threshold: BlockNumber,
43+
) -> StdResult<WhereCondition> {
44+
let threshold = Value::Integer(block_number_threshold.try_into().with_context(|| {
45+
format!("Failed to convert threshold `{block_number_threshold}` to i64")
46+
})?);
47+
48+
Ok(WhereCondition::new("block_number < ?*", vec![threshold]))
49+
}
50+
51+
/// Prune the cardano transaction data below the given threshold.
52+
pub fn prune(
53+
&self,
54+
block_number_threshold: BlockNumber,
55+
) -> StdResult<EntityCursor<CardanoTransactionRecord>> {
56+
let filters = self.get_prune_condition(block_number_threshold)?;
57+
58+
self.find(filters)
59+
}
60+
}
61+
62+
#[cfg(test)]
63+
mod tests {
64+
use crate::database::provider::{
65+
GetCardanoTransactionProvider, InsertCardanoTransactionProvider,
66+
};
67+
use crate::database::test_helper::cardano_tx_db_connection;
68+
use crate::sqlite::GetAllProvider;
69+
70+
use super::*;
71+
72+
fn insert_transactions(connection: &SqliteConnection, records: Vec<CardanoTransactionRecord>) {
73+
let provider = InsertCardanoTransactionProvider::new(connection);
74+
let condition = provider.get_insert_many_condition(records).unwrap();
75+
let mut cursor = provider.find(condition).unwrap();
76+
cursor.next().unwrap();
77+
}
78+
79+
fn test_transaction_set() -> Vec<CardanoTransactionRecord> {
80+
vec![
81+
CardanoTransactionRecord::new("tx-hash-0", 10, 50, "block-hash-10", 1),
82+
CardanoTransactionRecord::new("tx-hash-1", 10, 51, "block-hash-10", 1),
83+
CardanoTransactionRecord::new("tx-hash-2", 11, 52, "block-hash-11", 1),
84+
CardanoTransactionRecord::new("tx-hash-3", 11, 53, "block-hash-11", 1),
85+
CardanoTransactionRecord::new("tx-hash-4", 12, 54, "block-hash-12", 1),
86+
CardanoTransactionRecord::new("tx-hash-5", 12, 55, "block-hash-12", 1),
87+
]
88+
}
89+
90+
#[test]
91+
fn test_prune_work_even_without_transactions_in_db() {
92+
let connection = cardano_tx_db_connection().unwrap();
93+
94+
let prune_provider = DeleteCardanoTransactionProvider::new(&connection);
95+
let cursor = prune_provider
96+
.prune(100)
97+
.expect("pruning shouldn't crash without transactions stored");
98+
assert_eq!(0, cursor.count());
99+
}
100+
101+
#[test]
102+
fn test_prune_all_data_if_given_block_number_is_larger_than_stored_number_of_block() {
103+
let connection = cardano_tx_db_connection().unwrap();
104+
insert_transactions(&connection, test_transaction_set());
105+
106+
let prune_provider = DeleteCardanoTransactionProvider::new(&connection);
107+
let cursor = prune_provider.prune(100_000).unwrap();
108+
assert_eq!(test_transaction_set().len(), cursor.count());
109+
110+
let get_provider = GetCardanoTransactionProvider::new(&connection);
111+
let cursor = get_provider.get_all().unwrap();
112+
assert_eq!(0, cursor.count());
113+
}
114+
115+
#[test]
116+
fn test_prune_keep_all_tx_of_last_block_if_given_number_of_block_is_zero() {
117+
let connection = cardano_tx_db_connection().unwrap();
118+
insert_transactions(&connection, test_transaction_set());
119+
120+
let prune_provider = DeleteCardanoTransactionProvider::new(&connection);
121+
let cursor = prune_provider.prune(0).unwrap();
122+
assert_eq!(0, cursor.count());
123+
124+
let get_provider = GetCardanoTransactionProvider::new(&connection);
125+
let cursor = get_provider.get_all().unwrap();
126+
assert_eq!(test_transaction_set().len(), cursor.count());
127+
}
128+
129+
#[test]
130+
fn test_prune_data_of_below_given_blocks() {
131+
let connection = cardano_tx_db_connection().unwrap();
132+
insert_transactions(&connection, test_transaction_set());
133+
134+
let prune_provider = DeleteCardanoTransactionProvider::new(&connection);
135+
let cursor = prune_provider.prune(12).unwrap();
136+
assert_eq!(4, cursor.count());
137+
138+
let get_provider = GetCardanoTransactionProvider::new(&connection);
139+
let cursor = get_provider.get_all().unwrap();
140+
assert_eq!(2, cursor.count());
141+
}
142+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
mod delete_cardano_transaction;
12
mod get_cardano_transaction;
23
mod insert_cardano_transaction;
34

5+
pub use delete_cardano_transaction::*;
46
pub use get_cardano_transaction::*;
57
pub use insert_cardano_transaction::*;

0 commit comments

Comments
 (0)