Skip to content

Commit e2c42cf

Browse files
committed
Fix retrieval of block ranges when computing merkle root
It was missing one block range when retrieving data. With the given block ranges in DB (end is exclusive): [ (15..30), (30..45), (45..60) ] Before the fix it would return when asked block number: - `44`: [ (15..30) ] -> WRONG, should also include (30..45) - `45`: [ (15..30) ] -> WRONG, should also include (30..45) - `46`: [ (15..30), (30..45) ] -> WRONG, should also include (45..60)
1 parent 571ccb9 commit e2c42cf

File tree

5 files changed

+137
-69
lines changed

5 files changed

+137
-69
lines changed

internal/mithril-persistence/src/database/query/block_range_root/delete_block_range_root.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,13 @@ mod tests {
4949
use mithril_common::crypto_helper::MKTreeNode;
5050
use mithril_common::entities::BlockRange;
5151

52-
use crate::database::query::{GetBlockRangeRootQuery, InsertBlockRangeRootQuery};
52+
use crate::database::query::block_range_root::test_helper::insert_block_range_roots;
53+
use crate::database::query::GetBlockRangeRootQuery;
5354
use crate::database::test_helper::cardano_tx_db_connection;
54-
use crate::sqlite::{ConnectionExtensions, SqliteConnection};
55+
use crate::sqlite::ConnectionExtensions;
5556

5657
use super::*;
5758

58-
fn insert_block_range_roots(connection: &SqliteConnection, records: Vec<BlockRangeRootRecord>) {
59-
connection
60-
.fetch_first(InsertBlockRangeRootQuery::insert_many(records).unwrap())
61-
.unwrap();
62-
}
63-
6459
fn block_range_root_dataset() -> Vec<BlockRangeRootRecord> {
6560
[
6661
(

internal/mithril-persistence/src/database/query/block_range_root/get_block_range_root.rs

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use mithril_common::entities::BlockNumber;
21
use sqlite::Value;
32

3+
use mithril_common::entities::BlockNumber;
4+
45
use crate::database::record::BlockRangeRootRecord;
56
use crate::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
67

@@ -16,12 +17,9 @@ impl GetBlockRangeRootQuery {
1617
}
1718
}
1819

19-
pub fn up_to_block_number(up_to_or_equal_end_block_number: BlockNumber) -> Self {
20+
pub fn contains_or_below_block_number(block_number: BlockNumber) -> Self {
2021
Self {
21-
condition: WhereCondition::new(
22-
"end <= ?*",
23-
vec![Value::Integer(up_to_or_equal_end_block_number as i64)],
24-
),
22+
condition: WhereCondition::new("start < ?*", vec![Value::Integer(block_number as i64)]),
2523
}
2624
}
2725
}
@@ -40,3 +38,100 @@ impl Query for GetBlockRangeRootQuery {
4038
format!("select {projection} from block_range_root where {condition} order by start, end")
4139
}
4240
}
41+
42+
#[cfg(test)]
43+
mod tests {
44+
use mithril_common::crypto_helper::MKTreeNode;
45+
use mithril_common::entities::BlockRange;
46+
47+
use crate::database::query::block_range_root::test_helper::insert_block_range_roots;
48+
use crate::database::query::GetBlockRangeRootQuery;
49+
use crate::database::test_helper::cardano_tx_db_connection;
50+
use crate::sqlite::ConnectionExtensions;
51+
52+
use super::*;
53+
54+
fn block_range_root_dataset() -> Vec<BlockRangeRootRecord> {
55+
[
56+
(
57+
BlockRange::from_block_number(15),
58+
MKTreeNode::from_hex("AAAA").unwrap(),
59+
),
60+
(
61+
BlockRange::from_block_number(30),
62+
MKTreeNode::from_hex("BBBB").unwrap(),
63+
),
64+
(
65+
BlockRange::from_block_number(45),
66+
MKTreeNode::from_hex("CCCC").unwrap(),
67+
),
68+
]
69+
.into_iter()
70+
.map(BlockRangeRootRecord::from)
71+
.collect()
72+
}
73+
74+
#[test]
75+
fn test_get_contains_or_below_block_number_with_empty_db() {
76+
let connection = cardano_tx_db_connection().unwrap();
77+
78+
let cursor: Vec<BlockRangeRootRecord> = connection
79+
.fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(100))
80+
.unwrap();
81+
assert_eq!(Vec::<BlockRangeRootRecord>::new(), cursor);
82+
}
83+
84+
#[test]
85+
fn test_get_contains_or_below_block_number_higher_than_the_highest_stored_block_range() {
86+
let connection = cardano_tx_db_connection().unwrap();
87+
let dataset = block_range_root_dataset();
88+
insert_block_range_roots(&connection, dataset.clone());
89+
90+
let cursor: Vec<BlockRangeRootRecord> = connection
91+
.fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(
92+
10_000,
93+
))
94+
.unwrap();
95+
96+
assert_eq!(dataset, cursor);
97+
}
98+
99+
#[test]
100+
fn test_get_contains_or_below_block_number_below_end_of_the_third_block_range() {
101+
let connection = cardano_tx_db_connection().unwrap();
102+
let dataset = block_range_root_dataset();
103+
insert_block_range_roots(&connection, dataset.clone());
104+
105+
let cursor: Vec<BlockRangeRootRecord> = connection
106+
.fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(44))
107+
.unwrap();
108+
109+
assert_eq!(&dataset[0..2], &cursor);
110+
}
111+
112+
#[test]
113+
fn test_get_contains_or_below_block_number_equal_to_end_of_the_third_block_range() {
114+
let connection = cardano_tx_db_connection().unwrap();
115+
let dataset = block_range_root_dataset();
116+
insert_block_range_roots(&connection, dataset.clone());
117+
118+
let cursor: Vec<BlockRangeRootRecord> = connection
119+
.fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(45))
120+
.unwrap();
121+
122+
assert_eq!(&dataset[0..2], &cursor);
123+
}
124+
125+
#[test]
126+
fn test_get_contains_or_below_block_number_after_end_of_the_third_block_range() {
127+
let connection = cardano_tx_db_connection().unwrap();
128+
let dataset = block_range_root_dataset();
129+
insert_block_range_roots(&connection, dataset.clone());
130+
131+
let cursor: Vec<BlockRangeRootRecord> = connection
132+
.fetch_collect(GetBlockRangeRootQuery::contains_or_below_block_number(46))
133+
.unwrap();
134+
135+
assert_eq!(dataset, cursor);
136+
}
137+
}

internal/mithril-persistence/src/database/query/block_range_root/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,20 @@ pub use delete_block_range_root::*;
77
pub use get_block_range_root::*;
88
pub use get_interval_without_block_range::*;
99
pub use insert_block_range::*;
10+
11+
#[cfg(test)]
12+
mod test_helper {
13+
use crate::database::record::BlockRangeRootRecord;
14+
use crate::sqlite::{ConnectionExtensions, SqliteConnection};
15+
16+
use super::*;
17+
18+
pub fn insert_block_range_roots(
19+
connection: &SqliteConnection,
20+
records: Vec<BlockRangeRootRecord>,
21+
) {
22+
connection
23+
.fetch_first(InsertBlockRangeRootQuery::insert_many(records).unwrap())
24+
.unwrap();
25+
}
26+
}

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

Lines changed: 15 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,17 @@ impl CardanoTransactionRepository {
146146
)
147147
}
148148

149-
/// Retrieve all the Block Range Roots in database up to the given end block number included.
149+
/// Retrieve all the Block Range Roots in database up to the block range that contains the given
150+
/// block number.
150151
pub async fn retrieve_block_range_roots_up_to(
151152
&self,
152-
up_to_or_equal_end_block_number: BlockNumber,
153+
block_number: BlockNumber,
153154
) -> StdResult<Box<dyn Iterator<Item = (BlockRange, MKTreeNode)> + '_>> {
154155
let block_range_roots = self
155156
.connection_pool
156157
.connection()?
157-
.fetch(GetBlockRangeRootQuery::up_to_block_number(
158-
up_to_or_equal_end_block_number,
158+
.fetch(GetBlockRangeRootQuery::contains_or_below_block_number(
159+
block_number,
159160
))?
160161
.map(|record| -> (BlockRange, MKTreeNode) { record.into() })
161162
.collect::<Vec<_>>(); // TODO: remove this collect to return the iterator directly
@@ -325,13 +326,9 @@ impl CardanoTransactionRepository {
325326
impl BlockRangeRootRetriever for CardanoTransactionRepository {
326327
async fn retrieve_block_range_roots<'a>(
327328
&'a self,
328-
up_to_or_equal_beacon: BlockNumber,
329+
up_to_beacon: BlockNumber,
329330
) -> StdResult<Box<dyn Iterator<Item = (BlockRange, MKTreeNode)> + 'a>> {
330-
let iterator = self
331-
.retrieve_block_range_roots_up_to(up_to_or_equal_beacon)
332-
.await?;
333-
334-
Ok(Box::new(iterator))
331+
self.retrieve_block_range_roots_up_to(up_to_beacon).await
335332
}
336333
}
337334

@@ -973,50 +970,14 @@ mod tests {
973970
.await
974971
.unwrap();
975972

976-
// Retrieve with a block far higher than the highest block range - should return all
977-
{
978-
let retrieved_block_ranges = repository
979-
.retrieve_block_range_roots_up_to(1000)
980-
.await
981-
.unwrap();
982-
assert_eq!(
983-
block_range_roots,
984-
retrieved_block_ranges.collect::<Vec<_>>()
985-
);
986-
}
987-
// Retrieve with a block bellow than the smallest block range - should return none
988-
{
989-
let retrieved_block_ranges = repository
990-
.retrieve_block_range_roots_up_to(2)
991-
.await
992-
.unwrap();
993-
assert_eq!(
994-
Vec::<(BlockRange, MKTreeNode)>::new(),
995-
retrieved_block_ranges.collect::<Vec<_>>()
996-
);
997-
}
998-
// Right below the end of the second block range - should return first of the three
999-
{
1000-
let retrieved_block_ranges = repository
1001-
.retrieve_block_range_roots_up_to(44)
1002-
.await
1003-
.unwrap();
1004-
assert_eq!(
1005-
vec![block_range_roots[0].clone()],
1006-
retrieved_block_ranges.collect::<Vec<_>>()
1007-
);
1008-
}
1009-
// The given block is matched to the end (included) - should return the two of the three
1010-
{
1011-
let retrieved_block_ranges = repository
1012-
.retrieve_block_range_roots_up_to(45)
1013-
.await
1014-
.unwrap();
1015-
assert_eq!(
1016-
block_range_roots[0..=1].to_vec(),
1017-
retrieved_block_ranges.collect::<Vec<_>>()
1018-
);
1019-
}
973+
let retrieved_block_ranges = repository
974+
.retrieve_block_range_roots_up_to(45)
975+
.await
976+
.unwrap();
977+
assert_eq!(
978+
block_range_roots[0..2].to_vec(),
979+
retrieved_block_ranges.collect::<Vec<_>>()
980+
);
1020981
}
1021982

1022983
#[tokio::test]

mithril-common/src/signable_builder/cardano_transactions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub trait BlockRangeRootRetriever: Send + Sync {
2929
/// Returns a Merkle map of the block ranges roots up to a given beacon
3030
async fn retrieve_block_range_roots<'a>(
3131
&'a self,
32-
up_to_or_equal_beacon: BlockNumber,
32+
up_to_beacon: BlockNumber,
3333
) -> StdResult<Box<dyn Iterator<Item = (BlockRange, MKTreeNode)> + 'a>>;
3434

3535
/// Returns a Merkle map of the block ranges roots up to a given beacon

0 commit comments

Comments
 (0)