From 1919ba3bbb3e2baa1f8f1d949bedcf4deeac80d8 Mon Sep 17 00:00:00 2001 From: Alexgao001 Date: Thu, 19 Sep 2024 11:04:14 +0800 Subject: [PATCH 01/11] fix: an empty static file should be kept unless its blocks are unwound --- crates/storage/provider/src/providers/static_file/writer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/storage/provider/src/providers/static_file/writer.rs b/crates/storage/provider/src/providers/static_file/writer.rs index b5e2a07cccfe..ea74f822c27f 100644 --- a/crates/storage/provider/src/providers/static_file/writer.rs +++ b/crates/storage/provider/src/providers/static_file/writer.rs @@ -387,7 +387,7 @@ impl StaticFileProviderRW { } }; - if remaining_rows >= len { + if remaining_rows > len { // If there's more rows to delete than this static file contains, then just // delete the whole file and go to the next static file let block_start = self.writer.user_header().expected_block_start(); From e5c9c349e562a5833b6ee9c137b25b97bb03bd57 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:46:49 +0100 Subject: [PATCH 02/11] revert --- crates/storage/provider/src/providers/static_file/writer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/storage/provider/src/providers/static_file/writer.rs b/crates/storage/provider/src/providers/static_file/writer.rs index ea74f822c27f..b5e2a07cccfe 100644 --- a/crates/storage/provider/src/providers/static_file/writer.rs +++ b/crates/storage/provider/src/providers/static_file/writer.rs @@ -387,7 +387,7 @@ impl StaticFileProviderRW { } }; - if remaining_rows > len { + if remaining_rows >= len { // If there's more rows to delete than this static file contains, then just // delete the whole file and go to the next static file let block_start = self.writer.user_header().expected_block_start(); From 2a25038f2e1a316c3a7fc900f655e672c567e30a Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:53:42 +0100 Subject: [PATCH 03/11] ensure file is deleted if last_block is on a prev file --- crates/storage/provider/src/providers/static_file/writer.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/storage/provider/src/providers/static_file/writer.rs b/crates/storage/provider/src/providers/static_file/writer.rs index b5e2a07cccfe..6faf063e1912 100644 --- a/crates/storage/provider/src/providers/static_file/writer.rs +++ b/crates/storage/provider/src/providers/static_file/writer.rs @@ -392,7 +392,10 @@ impl StaticFileProviderRW { // delete the whole file and go to the next static file let block_start = self.writer.user_header().expected_block_start(); - if block_start != 0 { + if block_start != 0 || last_block.is_some_and(|b| b < block_start) { + // If it's a tx-based segment and `block_start` has no transactions, we need to + // ensure that `last_block` is lower than this file's block start, before + // deleting the current file. self.delete_current_and_open_previous()?; } else { // Update `SegmentHeader` From 6b4123c9dc683966f1fd919aac2823ac09bb3e09 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:10:21 +0100 Subject: [PATCH 04/11] fix condition --- .../storage/provider/src/providers/static_file/writer.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/storage/provider/src/providers/static_file/writer.rs b/crates/storage/provider/src/providers/static_file/writer.rs index 6faf063e1912..32b0b9800916 100644 --- a/crates/storage/provider/src/providers/static_file/writer.rs +++ b/crates/storage/provider/src/providers/static_file/writer.rs @@ -377,8 +377,9 @@ impl StaticFileProviderRW { /// Commits to the configuration file at the end. fn truncate(&mut self, num_rows: u64, last_block: Option) -> ProviderResult<()> { let mut remaining_rows = num_rows; + let segment = self.writer.user_header().segment(); while remaining_rows > 0 { - let len = match self.writer.user_header().segment() { + let len = match segment { StaticFileSegment::Headers => { self.writer.user_header().block_len().unwrap_or_default() } @@ -392,7 +393,9 @@ impl StaticFileProviderRW { // delete the whole file and go to the next static file let block_start = self.writer.user_header().expected_block_start(); - if block_start != 0 || last_block.is_some_and(|b| b < block_start) { + if block_start != 0 && + (segment.is_headers() || last_block.is_some_and(|b| b < block_start)) + { // If it's a tx-based segment and `block_start` has no transactions, we need to // ensure that `last_block` is lower than this file's block start, before // deleting the current file. From 56e9b536fcd5ba1d935a9a41fb733970d92717ff Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:09:56 +0100 Subject: [PATCH 05/11] fix update_index when unwound block range no longer has txes/receipts --- crates/static-file/types/src/segment.rs | 10 ++++++++-- .../src/providers/static_file/manager.rs | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/crates/static-file/types/src/segment.rs b/crates/static-file/types/src/segment.rs index cb742b3f3184..94f09b64a51a 100644 --- a/crates/static-file/types/src/segment.rs +++ b/crates/static-file/types/src/segment.rs @@ -122,6 +122,12 @@ impl StaticFileSegment { pub const fn is_receipts(&self) -> bool { matches!(self, Self::Receipts) } + + /// Returns `true` if the segment is `StaticFileSegment::Receipts` or + /// `StaticFileSegment::Transactions`. + pub const fn is_tx_based(&self) -> bool { + matches!(self, Self::Receipts | Self::Transactions) + } } /// A segment header that contains information common to all segments. Used for storage. @@ -239,7 +245,7 @@ impl SegmentHeader { match self.segment { StaticFileSegment::Headers => { if let Some(range) = &mut self.block_range { - if num > range.end { + if num > range.end - range.start { self.block_range = None; } else { range.end = range.end.saturating_sub(num); @@ -248,7 +254,7 @@ impl SegmentHeader { } StaticFileSegment::Transactions | StaticFileSegment::Receipts => { if let Some(range) = &mut self.tx_range { - if num > range.end { + if num > range.end - range.start { self.tx_range = None; } else { range.end = range.end.saturating_sub(num); diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 36cb3629b11f..7aa8852b062c 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -533,15 +533,16 @@ impl StaticFileProvider { }) .or_insert_with(|| BTreeMap::from([(tx_end, current_block_range)])); } - } else if tx_index.get(&segment).map(|index| index.len()) == Some(1) { - // Only happens if we unwind all the txs/receipts from the first static file. - // Should only happen in test scenarios. - if jar.user_header().expected_block_start() == 0 && - matches!( - segment, - StaticFileSegment::Receipts | StaticFileSegment::Transactions - ) - { + } else if segment.is_tx_based() { + // The unwound file has no more transactions/receipts. However, the tip is part + // of this files' block range. We only retain entries with + // block ranges before the current one. + tx_index.entry(segment).and_modify(|index| { + index.retain(|_, block_range| block_range.start() < fixed_range.start()); + }); + + // If the segment index is empty, just remove it. + if tx_index.get(&segment).is_some_and(|index| index.is_empty()) { tx_index.remove(&segment); } } From 12f474d0894816e5d3b31e402c0ccc04e6c61634 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:10:33 +0100 Subject: [PATCH 06/11] add more assertions on truncation --- .../provider/src/providers/static_file/mod.rs | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/crates/storage/provider/src/providers/static_file/mod.rs b/crates/storage/provider/src/providers/static_file/mod.rs index 8152dd0ed9ca..57cb719ce98f 100644 --- a/crates/storage/provider/src/providers/static_file/mod.rs +++ b/crates/storage/provider/src/providers/static_file/mod.rs @@ -67,6 +67,7 @@ mod tests { static_file::{find_fixed_range, SegmentRangeInclusive, DEFAULT_BLOCKS_PER_STATIC_FILE}, BlockHash, Header, Receipt, TransactionSignedNoHash, }; + use reth_storage_api::{ReceiptProvider, TransactionsProvider}; use reth_testing_utils::generators::{self, random_header_range}; use std::{fmt::Debug, fs, ops::Range, path::Path}; @@ -204,6 +205,14 @@ mod tests { "block mismatch", )?; + if let Some(id) = expected_tip { + assert_eyre( + sf_rw.header_by_number(id)?.map(|h| h.number), + expected_tip, + "header mismatch", + )?; + } + // Validate the number of files remaining in the directory assert_eyre( fs::read_dir(static_dir)?.count(), @@ -304,17 +313,22 @@ mod tests { mut tx_count: u64, next_tx_num: &mut u64, ) { + let mut receipt = Receipt::default(); + let mut tx = TransactionSignedNoHash::default(); + for block in block_range.clone() { writer.increment_block(block).unwrap(); // Append transaction/receipt if there's still a transaction count to append if tx_count > 0 { if segment.is_receipts() { - writer.append_receipt(*next_tx_num, &Receipt::default()).unwrap(); + // Used as ID for validation + receipt.cumulative_gas_used = *next_tx_num; + writer.append_receipt(*next_tx_num, &receipt).unwrap(); } else { - writer - .append_transaction(*next_tx_num, &TransactionSignedNoHash::default()) - .unwrap(); + // Used as ID for validation + tx.transaction.set_nonce(*next_tx_num); + writer.append_transaction(*next_tx_num, &tx).unwrap(); } *next_tx_num += 1; tx_count -= 1; @@ -379,7 +393,6 @@ mod tests { } #[test] - #[ignore] fn test_tx_based_truncation() { let segments = [StaticFileSegment::Transactions, StaticFileSegment::Receipts]; let blocks_per_file = 10; // Number of blocks per file @@ -393,7 +406,7 @@ mod tests { segment: StaticFileSegment, prune_count: u64, last_block: u64, - expected_tx_tip: u64, + expected_tx_tip: Option, expected_file_count: i32, ) -> eyre::Result<()> { let mut writer = sf_rw.latest_writer(segment)?; @@ -412,11 +425,25 @@ mod tests { Some(last_block), "block mismatch", )?; - assert_eyre( - sf_rw.get_highest_static_file_tx(segment), - Some(expected_tx_tip), - "tx mismatch", - )?; + assert_eyre(sf_rw.get_highest_static_file_tx(segment), expected_tx_tip, "tx mismatch")?; + + // Verify that transactions and receipts are returned correctly. Uses + // cumulative_gas_used & nonce as ids. + if let Some(id) = expected_tx_tip { + if segment.is_receipts() { + assert_eyre( + expected_tx_tip, + sf_rw.receipt(id)?.map(|r| r.cumulative_gas_used), + "tx mismatch", + )?; + } else { + assert_eyre( + expected_tx_tip, + sf_rw.transaction_by_id(id)?.map(|t| t.nonce()), + "tx mismatch", + )?; + } + } // Ensure the file count has reduced as expected assert_eyre( @@ -448,15 +475,15 @@ mod tests { // It ensures that the file is not deleted even though there are no rows, since the // `last_block` which is passed to the prune method is the first // block of the range. - (1, blocks_per_file * 2, highest_tx - 1, initial_file_count), + (1, blocks_per_file * 2, Some(highest_tx - 1), initial_file_count), // Case 1: 10..=19 has no txs. There are no txes in the whole block range, but want // to unwind to block 9. Ensures that the 20..=29 and 10..=19 files // are deleted. - (0, blocks_per_file - 1, highest_tx - 1, files_per_range + 1), // includes lockfile + (0, blocks_per_file - 1, Some(highest_tx - 1), files_per_range + 1), /* includes lockfile */ // Case 2: Prune most txs up to block 1. - (7, 1, 1, files_per_range + 1), + (8, 1, Some(0), files_per_range + 1), // Case 3: Prune remaining tx and ensure that file is not deleted. - (1, 0, 0, files_per_range + 1), + (1, 0, None, files_per_range + 1), ]; // Loop through test cases From 9d841944db2aad79eefd5d8c79839c0370e6e6a6 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:40:31 +0100 Subject: [PATCH 07/11] add tx index expectations --- .../src/providers/static_file/manager.rs | 6 ++ .../provider/src/providers/static_file/mod.rs | 57 ++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 7aa8852b062c..930eec1feea3 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -1142,6 +1142,12 @@ impl StaticFileProvider { pub fn path(&self) -> &Path { &self.path } + + #[cfg(any(test, feature = "test-utils"))] + /// Returns `static_files` transaction index + pub fn tx_index(&self) -> &RwLock { + &self.static_files_tx_index + } } /// Helper trait to manage different [`StaticFileProviderRW`] of an `Arc, expected_file_count: i32, + expected_tx_index: Vec<(TxNumber, SegmentRangeInclusive)>, ) -> eyre::Result<()> { let mut writer = sf_rw.latest_writer(segment)?; @@ -451,6 +462,15 @@ mod tests { expected_file_count as usize, "file count mismatch", )?; + + // Ensure that the inner tx index (max_tx -> block range) is as expected + let tx_index = sf_rw.tx_index().read(); + assert_eyre( + tx_index.get(&segment).map(|index| index.iter().map(|(k, v)| (*k, *v)).collect()), + (!expected_tx_index.is_empty()).then_some(expected_tx_index), + "tx index mismatch", + )?; + Ok(()) } @@ -469,26 +489,46 @@ mod tests { let highest_tx = sf_rw.get_highest_static_file_tx(segment).unwrap(); // Test cases - // [prune_count, last_block, expected_tx_tip, expected_file_count) + // [prune_count, last_block, expected_tx_tip, expected_file_count, expected_tx_index) let test_cases = vec![ // Case 0: 20..=29 has only one tx. Prune the only tx of the block range. // It ensures that the file is not deleted even though there are no rows, since the // `last_block` which is passed to the prune method is the first // block of the range. - (1, blocks_per_file * 2, Some(highest_tx - 1), initial_file_count), + ( + 1, + blocks_per_file * 2, + Some(highest_tx - 1), + initial_file_count, + vec![(highest_tx - 1, SegmentRangeInclusive::new(0, 9))], + ), // Case 1: 10..=19 has no txs. There are no txes in the whole block range, but want // to unwind to block 9. Ensures that the 20..=29 and 10..=19 files // are deleted. - (0, blocks_per_file - 1, Some(highest_tx - 1), files_per_range + 1), /* includes lockfile */ + ( + 0, + blocks_per_file - 1, + Some(highest_tx - 1), + files_per_range + 1, + vec![(highest_tx - 1, SegmentRangeInclusive::new(0, 9))], + ), /* includes lockfile */ // Case 2: Prune most txs up to block 1. - (8, 1, Some(0), files_per_range + 1), + ( + highest_tx - 1, + 1, + Some(0), + files_per_range + 1, + vec![(0, SegmentRangeInclusive::new(0, 1))], + ), // Case 3: Prune remaining tx and ensure that file is not deleted. - (1, 0, None, files_per_range + 1), + (1, 0, None, files_per_range + 1, vec![]), ]; // Loop through test cases - for (case, (prune_count, last_block, expected_tx_tip, expected_file_count)) in - test_cases.into_iter().enumerate() + for ( + case, + (prune_count, last_block, expected_tx_tip, expected_file_count, expected_tx_index), + ) in test_cases.into_iter().enumerate() { prune_and_validate( &sf_rw, @@ -498,6 +538,7 @@ mod tests { last_block, expected_tx_tip, expected_file_count, + expected_tx_index, ) .map_err(|err| eyre::eyre!("Test case {case}: {err}")) .unwrap(); From 4fbd8514a418e53ce98cdaa3f26a4d5c06c3349b Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:46:29 +0100 Subject: [PATCH 08/11] adjust docs on truncate --- .../storage/provider/src/providers/static_file/writer.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/storage/provider/src/providers/static_file/writer.rs b/crates/storage/provider/src/providers/static_file/writer.rs index e03163528261..d086c5693ca5 100644 --- a/crates/storage/provider/src/providers/static_file/writer.rs +++ b/crates/storage/provider/src/providers/static_file/writer.rs @@ -397,12 +397,14 @@ impl StaticFileProviderRW { // delete the whole file and go to the next static file let block_start = self.writer.user_header().expected_block_start(); + // We only delete the file if it's NOT the first static file AND: + // * it's a Header segment OR + // * it's a tx-based segment AND `last_block` is lower than the first block of this + // file's block range. Otherwise, having no rows simply means that this block + // range has no transactions, but the file should remain. if block_start != 0 && (segment.is_headers() || last_block.is_some_and(|b| b < block_start)) { - // If it's a tx-based segment and `block_start` has no transactions, we need to - // ensure that `last_block` is lower than this file's block start, before - // deleting the current file. self.delete_current_and_open_previous()?; } else { // Update `SegmentHeader` From 094e761a290a79ef9b6ab4b9988d10b8a1d76368 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 21 Sep 2024 20:05:29 +0100 Subject: [PATCH 09/11] clippy --- .../provider/src/providers/static_file/mod.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/storage/provider/src/providers/static_file/mod.rs b/crates/storage/provider/src/providers/static_file/mod.rs index 40b39437aba3..4d133612ea72 100644 --- a/crates/storage/provider/src/providers/static_file/mod.rs +++ b/crates/storage/provider/src/providers/static_file/mod.rs @@ -393,8 +393,10 @@ mod tests { // Ensure transaction index let tx_index = sf_rw.tx_index().read(); - let expected_tx_index = - vec![(8, SegmentRangeInclusive::new(0, 9)), (9, SegmentRangeInclusive::new(20, 29))]; + let expected_tx_index = vec![ + (8, SegmentRangeInclusive::new(0, 9)), + (9, SegmentRangeInclusive::new(20, 29)), + ]; assert_eq!( tx_index.get(&segment).map(|index| index.iter().map(|(k, v)| (*k, *v)).collect()), (!expected_tx_index.is_empty()).then_some(expected_tx_index), @@ -410,6 +412,7 @@ mod tests { let file_set_count = 3; // Number of sets of files to create let initial_file_count = files_per_range * file_set_count + 1; // Includes lockfile + #[allow(clippy::too_many_arguments)] fn prune_and_validate( sf_rw: &StaticFileProvider, static_dir: impl AsRef, @@ -513,13 +516,7 @@ mod tests { vec![(highest_tx - 1, SegmentRangeInclusive::new(0, 9))], ), /* includes lockfile */ // Case 2: Prune most txs up to block 1. - ( - highest_tx - 1, - 1, - Some(0), - files_per_range + 1, - vec![(0, SegmentRangeInclusive::new(0, 1))], - ), + (highest_tx - 1, 1, Some(0), files_per_range + 1, vec![(0, SegmentRangeInclusive::new(0, 1))]), // Case 3: Prune remaining tx and ensure that file is not deleted. (1, 0, None, files_per_range + 1, vec![]), ]; From 6cdee2e7bbd59235768e2bed63a21bcc240b962c Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 21 Sep 2024 21:54:35 +0100 Subject: [PATCH 10/11] fmt --- .../provider/src/providers/static_file/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/storage/provider/src/providers/static_file/mod.rs b/crates/storage/provider/src/providers/static_file/mod.rs index 4d133612ea72..f6d9f310e26f 100644 --- a/crates/storage/provider/src/providers/static_file/mod.rs +++ b/crates/storage/provider/src/providers/static_file/mod.rs @@ -393,10 +393,8 @@ mod tests { // Ensure transaction index let tx_index = sf_rw.tx_index().read(); - let expected_tx_index = vec![ - (8, SegmentRangeInclusive::new(0, 9)), - (9, SegmentRangeInclusive::new(20, 29)), - ]; + let expected_tx_index = + vec![(8, SegmentRangeInclusive::new(0, 9)), (9, SegmentRangeInclusive::new(20, 29))]; assert_eq!( tx_index.get(&segment).map(|index| index.iter().map(|(k, v)| (*k, *v)).collect()), (!expected_tx_index.is_empty()).then_some(expected_tx_index), @@ -516,7 +514,13 @@ mod tests { vec![(highest_tx - 1, SegmentRangeInclusive::new(0, 9))], ), /* includes lockfile */ // Case 2: Prune most txs up to block 1. - (highest_tx - 1, 1, Some(0), files_per_range + 1, vec![(0, SegmentRangeInclusive::new(0, 1))]), + ( + highest_tx - 1, + 1, + Some(0), + files_per_range + 1, + vec![(0, SegmentRangeInclusive::new(0, 1))], + ), // Case 3: Prune remaining tx and ensure that file is not deleted. (1, 0, None, files_per_range + 1, vec![]), ]; From f581935686ceb6a566b6063bb97c6ff8a7916b44 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 21 Sep 2024 22:00:48 +0100 Subject: [PATCH 11/11] adjust docs --- .../storage/provider/src/providers/static_file/manager.rs | 8 ++++---- crates/storage/provider/src/providers/static_file/mod.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 930eec1feea3..1c045b9be49a 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -534,14 +534,14 @@ impl StaticFileProvider { .or_insert_with(|| BTreeMap::from([(tx_end, current_block_range)])); } } else if segment.is_tx_based() { - // The unwound file has no more transactions/receipts. However, the tip is part - // of this files' block range. We only retain entries with - // block ranges before the current one. + // The unwinded file has no more transactions/receipts. However, the highest + // block is within this files' block range. We only retain + // entries with block ranges before the current one. tx_index.entry(segment).and_modify(|index| { index.retain(|_, block_range| block_range.start() < fixed_range.start()); }); - // If the segment index is empty, just remove it. + // If the index is empty, just remove it. if tx_index.get(&segment).is_some_and(|index| index.is_empty()) { tx_index.remove(&segment); } diff --git a/crates/storage/provider/src/providers/static_file/mod.rs b/crates/storage/provider/src/providers/static_file/mod.rs index f6d9f310e26f..25c5ec7ef6aa 100644 --- a/crates/storage/provider/src/providers/static_file/mod.rs +++ b/crates/storage/provider/src/providers/static_file/mod.rs @@ -510,9 +510,9 @@ mod tests { 0, blocks_per_file - 1, Some(highest_tx - 1), - files_per_range + 1, + files_per_range + 1, // includes lockfile vec![(highest_tx - 1, SegmentRangeInclusive::new(0, 9))], - ), /* includes lockfile */ + ), // Case 2: Prune most txs up to block 1. ( highest_tx - 1,