Skip to content

Commit b280774

Browse files
committed
fix: remove rolled-back transactions edge cases
Does not trigger an error when no block exists above the slot number, also find the closest block above the slot number if rolled back block does not have transaction.
1 parent 8d4ac38 commit b280774

File tree

3 files changed

+128
-21
lines changed

3 files changed

+128
-21
lines changed

internal/mithril-persistence/src/database/repository/cardano_transaction_repository.rs

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,13 @@ impl CardanoTransactionRepository {
215215
Ok(())
216216
}
217217

218-
/// Get the block number for a given slot number
219-
pub async fn get_block_number_by_slot_number(
218+
/// Get the closest block number above a given slot number
219+
pub async fn get_closest_block_number_above_slot_number(
220220
&self,
221221
slot_number: SlotNumber,
222222
) -> StdResult<Option<BlockNumber>> {
223-
let query = GetCardanoTransactionQuery::by_slot_number(slot_number);
223+
let query =
224+
GetCardanoTransactionQuery::with_highest_block_number_below_slot_number(slot_number);
224225
let record = self.connection_pool.connection()?.fetch_first(query)?;
225226

226227
Ok(record.map(|r| r.block_number))
@@ -277,7 +278,7 @@ impl CardanoTransactionRepository {
277278
///
278279
/// * Remove transactions with block number strictly greater than the given block number
279280
/// * Remove block range roots that have lower bound range strictly above the given block number
280-
pub async fn remove_rolled_back_transactions_and_block_range(
281+
pub async fn remove_rolled_back_transactions_and_block_range_by_block_number(
281282
&self,
282283
block_number: BlockNumber,
283284
) -> StdResult<()> {
@@ -293,6 +294,25 @@ impl CardanoTransactionRepository {
293294

294295
Ok(())
295296
}
297+
298+
/// Remove transactions and block range roots that are in a rolled-back fork
299+
///
300+
/// * Remove transactions with closest block number strictly greater than the given slot number if exists
301+
/// * Remove block range roots that have lower bound range strictly above the aforementioned block number
302+
pub async fn remove_rolled_back_transactions_and_block_range_by_slot_number(
303+
&self,
304+
slot_number: SlotNumber,
305+
) -> StdResult<()> {
306+
if let Some(block_number) = self
307+
.get_closest_block_number_above_slot_number(slot_number)
308+
.await?
309+
{
310+
self.remove_rolled_back_transactions_and_block_range_by_block_number(block_number)
311+
.await?;
312+
}
313+
314+
Ok(())
315+
}
296316
}
297317

298318
#[async_trait]
@@ -910,7 +930,7 @@ mod tests {
910930
}
911931

912932
#[tokio::test]
913-
async fn repository_get_block_number_by_slot_number() {
933+
async fn repository_get_closest_block_number_by_slot_number() {
914934
let connection = cardano_tx_db_connection().unwrap();
915935
let repository = CardanoTransactionRepository::new(Arc::new(
916936
SqliteConnectionPool::build_from_connection(connection),
@@ -927,7 +947,7 @@ mod tests {
927947
.unwrap();
928948

929949
let transaction_block_number_retrieved = repository
930-
.get_block_number_by_slot_number(SlotNumber(500))
950+
.get_closest_block_number_above_slot_number(SlotNumber(500))
931951
.await
932952
.unwrap();
933953

@@ -1215,10 +1235,109 @@ mod tests {
12151235
.unwrap();
12161236

12171237
repository
1218-
.remove_rolled_back_transactions_and_block_range(BlockRange::LENGTH * 3)
1238+
.remove_rolled_back_transactions_and_block_range_by_block_number(BlockRange::LENGTH * 3)
12191239
.await
12201240
.unwrap();
12211241
assert_eq!(2, repository.get_all_transactions().await.unwrap().len());
12221242
assert_eq!(2, repository.get_all_block_range_root().unwrap().len());
12231243
}
1244+
1245+
#[tokio::test]
1246+
async fn remove_rolled_back_transactions_and_block_range_by_slot_number() {
1247+
fn transaction_record(
1248+
block_number: BlockNumber,
1249+
slot_number: SlotNumber,
1250+
) -> CardanoTransactionRecord {
1251+
CardanoTransactionRecord::new(
1252+
format!("tx-hash-{}", slot_number),
1253+
block_number,
1254+
slot_number,
1255+
format!("block-hash-{}", block_number),
1256+
)
1257+
}
1258+
1259+
let repository = CardanoTransactionRepository::new(Arc::new(
1260+
SqliteConnectionPool::build(1, cardano_tx_db_connection).unwrap(),
1261+
));
1262+
1263+
repository
1264+
.create_transactions(vec![
1265+
transaction_record(BlockNumber(10), SlotNumber(50)),
1266+
transaction_record(BlockNumber(11), SlotNumber(51)),
1267+
transaction_record(BlockNumber(13), SlotNumber(52)),
1268+
transaction_record(BlockNumber(101), SlotNumber(100)),
1269+
transaction_record(BlockNumber(202), SlotNumber(200)),
1270+
])
1271+
.await
1272+
.unwrap();
1273+
1274+
{
1275+
repository
1276+
.remove_rolled_back_transactions_and_block_range_by_slot_number(SlotNumber(110))
1277+
.await
1278+
.expect("Failed to remove rolled back transactions");
1279+
1280+
let transactions = repository
1281+
.get_all()
1282+
.await
1283+
.unwrap()
1284+
.into_iter()
1285+
.map(|v| v.into())
1286+
.collect::<Vec<_>>();
1287+
assert_eq!(
1288+
vec![
1289+
transaction_record(BlockNumber(10), SlotNumber(50)),
1290+
transaction_record(BlockNumber(11), SlotNumber(51)),
1291+
transaction_record(BlockNumber(13), SlotNumber(52)),
1292+
transaction_record(BlockNumber(101), SlotNumber(100)),
1293+
],
1294+
transactions
1295+
);
1296+
}
1297+
1298+
{
1299+
repository
1300+
.remove_rolled_back_transactions_and_block_range_by_slot_number(SlotNumber(53))
1301+
.await
1302+
.expect("Failed to remove rolled back transactions");
1303+
1304+
let transactions = repository
1305+
.get_all()
1306+
.await
1307+
.unwrap()
1308+
.into_iter()
1309+
.map(|v| v.into())
1310+
.collect::<Vec<_>>();
1311+
assert_eq!(
1312+
vec![
1313+
transaction_record(BlockNumber(10), SlotNumber(50)),
1314+
transaction_record(BlockNumber(11), SlotNumber(51)),
1315+
transaction_record(BlockNumber(13), SlotNumber(52)),
1316+
],
1317+
transactions
1318+
);
1319+
}
1320+
1321+
{
1322+
repository
1323+
.remove_rolled_back_transactions_and_block_range_by_slot_number(SlotNumber(51))
1324+
.await
1325+
.expect("Failed to remove rolled back transactions");
1326+
1327+
let transactions = repository
1328+
.get_all()
1329+
.await
1330+
.unwrap()
1331+
.into_iter()
1332+
.map(|v| v.into())
1333+
.collect::<Vec<_>>();
1334+
assert_eq!(
1335+
vec![
1336+
transaction_record(BlockNumber(10), SlotNumber(50)),
1337+
transaction_record(BlockNumber(11), SlotNumber(51)),
1338+
],
1339+
transactions
1340+
);
1341+
}
1342+
}
12241343
}

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,7 @@ impl TransactionStore for CardanoTransactionRepository {
5151
&self,
5252
slot_number: SlotNumber,
5353
) -> StdResult<()> {
54-
let block_number = self
55-
.get_block_number_by_slot_number(slot_number)
56-
.await?
57-
.ok_or_else(|| {
58-
anyhow::anyhow!("No block number found for slot number {}", slot_number)
59-
})?;
60-
self.remove_rolled_back_transactions_and_block_range(block_number)
54+
self.remove_rolled_back_transactions_and_block_range_by_slot_number(slot_number)
6155
.await
6256
}
6357
}

mithril-signer/src/database/repository/cardano_transaction_repository.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,7 @@ impl TransactionStore for CardanoTransactionRepository {
5151
&self,
5252
slot_number: SlotNumber,
5353
) -> StdResult<()> {
54-
let block_number = self
55-
.get_block_number_by_slot_number(slot_number)
56-
.await?
57-
.ok_or_else(|| {
58-
anyhow::anyhow!("No block number found for slot number {}", slot_number)
59-
})?;
60-
self.remove_rolled_back_transactions_and_block_range(block_number)
54+
self.remove_rolled_back_transactions_and_block_range_by_slot_number(slot_number)
6155
.await
6256
}
6357
}

0 commit comments

Comments
 (0)