Skip to content

Commit f3b05c7

Browse files
committed
WIP remove the header store
1 parent 2114cdc commit f3b05c7

12 files changed

Lines changed: 36 additions & 863 deletions

File tree

src/builder.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@ use super::{client::Client, config::NodeConfig, node::Node};
99
#[cfg(feature = "rusqlite")]
1010
use crate::db::error::SqlInitializationError;
1111
#[cfg(feature = "rusqlite")]
12-
use crate::db::sqlite::{headers::SqliteHeaderDb, peers::SqlitePeerDb};
12+
use crate::db::sqlite::peers::SqlitePeerDb;
1313
use crate::network::dns::{DnsResolver, DNS_RESOLVER_PORT};
1414
use crate::network::ConnectionType;
15-
use crate::{
16-
chain::checkpoints::HeaderCheckpoint,
17-
db::traits::{HeaderStore, PeerStore},
18-
};
15+
use crate::{chain::checkpoints::HeaderCheckpoint, db::traits::PeerStore};
1916
use crate::{LogLevel, PeerStoreSizeConfig, TrustedPeer};
2017

2118
#[cfg(feature = "rusqlite")]
2219
/// The default node returned from the [`NodeBuilder`].
23-
pub type NodeDefault = Node<SqliteHeaderDb, SqlitePeerDb>;
20+
pub type NodeDefault = Node<SqlitePeerDb>;
2421

2522
const MIN_PEERS: u8 = 1;
2623
const MAX_PEERS: u8 = 15;
@@ -219,26 +216,18 @@ impl NodeBuilder {
219216
#[cfg(feature = "rusqlite")]
220217
pub fn build(&mut self) -> Result<(NodeDefault, Client), SqlInitializationError> {
221218
let peer_store = SqlitePeerDb::new(self.network, self.config.data_path.clone())?;
222-
let header_store = SqliteHeaderDb::new(self.network, self.config.data_path.clone())?;
223219
Ok(Node::new(
224220
self.network,
225221
core::mem::take(&mut self.config),
226222
peer_store,
227-
header_store,
228223
))
229224
}
230225

231226
/// Consume the node builder by using custom database implementations, receiving a [`Node`] and [`Client`].
232-
pub fn build_with_databases<H: HeaderStore + 'static, P: PeerStore + 'static>(
227+
pub fn build_with_databases<P: PeerStore + 'static>(
233228
&mut self,
234229
peer_store: P,
235-
header_store: H,
236-
) -> (Node<H, P>, Client) {
237-
Node::new(
238-
self.network,
239-
core::mem::take(&mut self.config),
240-
peer_store,
241-
header_store,
242-
)
230+
) -> (Node<P>, Client) {
231+
Node::new(self.network, core::mem::take(&mut self.config), peer_store)
243232
}
244233
}

src/chain/chain.rs

Lines changed: 4 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
extern crate alloc;
22
use std::{
33
collections::{BTreeMap, HashSet},
4-
ops::Range,
54
sync::Arc,
65
};
76

@@ -18,37 +17,33 @@ use super::{
1817
error::{CFHeaderSyncError, CFilterSyncError, HeaderSyncError},
1918
graph::{AcceptHeaderChanges, BlockTree, HeaderRejection},
2019
CFHeaderChanges, Filter, FilterCheck, FilterHeaderRequest, FilterRequest, FilterRequestState,
21-
HeaderChainChanges, HeightExt, HeightMonitor, PeerId,
20+
HeaderChainChanges, HeightMonitor, PeerId,
2221
};
2322
#[cfg(feature = "filter-control")]
2423
use crate::IndexedFilter;
2524
use crate::{
2625
chain::header_batch::HeadersBatch,
27-
db::{traits::HeaderStore, BlockHeaderChanges},
2826
dialog::Dialog,
29-
error::HeaderPersistenceError,
3027
messages::{Event, Warning},
3128
Info, Progress,
3229
};
3330

34-
const REORG_LOOKBACK: u32 = 7;
3531
const FILTER_BASIC: u8 = 0x00;
3632
const CF_HEADER_BATCH_SIZE: u32 = 1_999;
3733
const FILTER_BATCH_SIZE: u32 = 999;
3834

3935
#[derive(Debug)]
40-
pub(crate) struct Chain<H: HeaderStore> {
36+
pub(crate) struct Chain {
4137
pub(crate) header_chain: BlockTree,
4238
request_state: FilterRequestState,
4339
checkpoints: HeaderCheckpoints,
4440
network: Network,
45-
db: Arc<Mutex<H>>,
4641
heights: Arc<Mutex<HeightMonitor>>,
4742
scripts: HashSet<ScriptBuf>,
4843
dialog: Arc<Dialog>,
4944
}
5045

51-
impl<H: HeaderStore> Chain<H> {
46+
impl Chain {
5247
#[allow(clippy::too_many_arguments)]
5348
pub(crate) fn new(
5449
network: Network,
@@ -57,7 +52,6 @@ impl<H: HeaderStore> Chain<H> {
5752
checkpoints: HeaderCheckpoints,
5853
dialog: Arc<Dialog>,
5954
height_monitor: Arc<Mutex<HeightMonitor>>,
60-
db: H,
6155
quorum_required: u8,
6256
) -> Self {
6357
let header_chain = BlockTree::new(anchor, network);
@@ -66,7 +60,6 @@ impl<H: HeaderStore> Chain<H> {
6660
checkpoints,
6761
request_state: FilterRequestState::new(quorum_required),
6862
network,
69-
db: Arc::new(Mutex::new(db)),
7063
heights: height_monitor,
7164
scripts,
7265
dialog,
@@ -93,76 +86,6 @@ impl<H: HeaderStore> Chain<H> {
9386
}
9487
}
9588

96-
// Load in headers, ideally allowing the difficulty adjustment to be audited and
97-
// reorganizations to be handled gracefully.
98-
pub(crate) async fn load_headers(&mut self) -> Result<(), HeaderPersistenceError<H::Error>> {
99-
let mut db = self.db.lock().await;
100-
// The original height the user requested a scan after
101-
let scan_height = self.header_chain.height();
102-
// The header relevant to compute the next adjustment
103-
let last_adjustment = scan_height.last_epoch_start(self.network);
104-
// Seven blocks ago
105-
let reorg = scan_height.saturating_sub(REORG_LOOKBACK);
106-
// To handle adjustments and reorgs, we would have the minimum of each of these heights
107-
let min_interesting_height = last_adjustment.min(reorg);
108-
let max_interesting_height = last_adjustment.max(reorg);
109-
// Get the maximum of the two interesting heights. In case the minimum is not available
110-
if let Some(header) = db.header_at(max_interesting_height).await.ok().flatten() {
111-
self.header_chain =
112-
BlockTree::from_header(max_interesting_height, header, self.network);
113-
}
114-
// If this succeeds, both reorgs and difficulty adjustments can be handled gracefully.
115-
if let Some(header) = db.header_at(min_interesting_height).await.ok().flatten() {
116-
self.header_chain =
117-
BlockTree::from_header(min_interesting_height, header, self.network);
118-
}
119-
// Now that the block tree is updated to the appropriate start, load in the rest of
120-
// the history from this point onward. This is either: from the user start height,
121-
// from the last difficulty adjustment, or seven blocks ago, depending on what the
122-
// header store was able to provide.
123-
let loaded_headers = db
124-
.load(self.header_chain.height().increment()..)
125-
.await
126-
.map_err(HeaderPersistenceError::Database)?;
127-
for (height, header) in loaded_headers {
128-
let apply_header_changes = self.header_chain.accept_header(header);
129-
match apply_header_changes {
130-
AcceptHeaderChanges::Accepted { connected_at } => {
131-
if height.ne(&connected_at.height) {
132-
self.dialog.send_warning(Warning::CorruptedHeaders);
133-
return Err(HeaderPersistenceError::HeadersDoNotLink);
134-
}
135-
if let Some(checkpoint) = self.checkpoints.next() {
136-
if connected_at.header.block_hash().eq(&checkpoint.hash) {
137-
self.checkpoints.advance()
138-
}
139-
}
140-
}
141-
AcceptHeaderChanges::Rejected(reject_reason) => match reject_reason {
142-
HeaderRejection::UnknownPrevHash(_) => {
143-
return Err(HeaderPersistenceError::CannotLocateHistory);
144-
}
145-
HeaderRejection::InvalidPow { expected, got } => {
146-
crate::log!(
147-
self.dialog,
148-
format!(
149-
"Unexpected invalid proof of work when importing a block header. expected {}, got: {}",
150-
expected.to_consensus(),
151-
got.to_consensus()
152-
)
153-
);
154-
}
155-
},
156-
_ => (),
157-
}
158-
}
159-
// Because the user requested a scan after the `scan_height`, the filters below this point
160-
// may be assumed as checked. Note that in a reorg, filters below this height may still be
161-
// retrieved, as this only considers the canonical chain as checked.
162-
self.header_chain.assume_checked_to(scan_height);
163-
Ok(())
164-
}
165-
16689
// Sync the chain with headers from a peer, adjusting to reorgs if needed
16790
pub(crate) async fn sync_chain(
16891
&mut self,
@@ -176,7 +99,6 @@ impl<H: HeaderStore> Chain<H> {
17699
// We check first if the peer is sending us nonsense
177100
self.sanity_check(&header_batch)?;
178101
let next_checkpoint = self.checkpoints.next().copied();
179-
let mut db = self.db.lock().await;
180102
let mut reorged_hashes = None;
181103
let mut fork_added = None;
182104
for header in header_batch.into_iter() {
@@ -191,7 +113,6 @@ impl<H: HeaderStore> Chain<H> {
191113
connected_at.header.block_hash()
192114
)
193115
);
194-
db.stage(BlockHeaderChanges::Connected(connected_at));
195116
if let Some(checkpoint) = next_checkpoint {
196117
if connected_at.height.eq(&checkpoint.height) {
197118
if connected_at.header.block_hash().eq(&checkpoint.hash) {
@@ -238,10 +159,6 @@ impl<H: HeaderStore> Chain<H> {
238159
.map(|index| index.header.block_hash())
239160
.collect();
240161
reorged_hashes = Some(removed_hashes);
241-
db.stage(BlockHeaderChanges::Reorganized {
242-
accepted: accepted.clone(),
243-
reorganized: disconnected.clone(),
244-
});
245162
let disconnected_event = Event::BlocksDisconnected {
246163
accepted,
247164
disconnected,
@@ -260,12 +177,6 @@ impl<H: HeaderStore> Chain<H> {
260177
},
261178
}
262179
}
263-
if let Err(e) = db.write().await {
264-
self.dialog.send_warning(Warning::FailedPersistence {
265-
warning: format!("Could not save headers to disk: {e}"),
266-
});
267-
}
268-
drop(db);
269180
match reorged_hashes {
270181
Some(reorgs) => {
271182
self.clear_compact_filter_queue();
@@ -530,44 +441,6 @@ impl<H: HeaderStore> Chain<H> {
530441
self.scripts.insert(script);
531442
}
532443

533-
// Fetch a header from the cache or disk.
534-
pub(crate) async fn fetch_header(
535-
&mut self,
536-
height: u32,
537-
) -> Result<Option<Header>, HeaderPersistenceError<H::Error>> {
538-
match self.header_chain.header_at_height(height) {
539-
Some(header) => Ok(Some(header)),
540-
None => {
541-
let mut db = self.db.lock().await;
542-
let header_opt = db.header_at(height).await;
543-
if header_opt.is_err() {
544-
self.dialog
545-
.send_warning(Warning::FailedPersistence {
546-
warning: format!(
547-
"Unexpected error fetching a header from the header store at height {height}"
548-
),
549-
});
550-
}
551-
header_opt.map_err(HeaderPersistenceError::Database)
552-
}
553-
}
554-
}
555-
556-
pub(crate) async fn fetch_header_range(
557-
&self,
558-
range: Range<u32>,
559-
) -> Result<BTreeMap<u32, Header>, HeaderPersistenceError<H::Error>> {
560-
let mut db = self.db.lock().await;
561-
let range_opt = db.load(range).await;
562-
if range_opt.is_err() {
563-
self.dialog.send_warning(Warning::FailedPersistence {
564-
warning: "Unexpected error fetching a range of headers from the header store"
565-
.to_string(),
566-
});
567-
}
568-
range_opt.map_err(HeaderPersistenceError::Database)
569-
}
570-
571444
// Reset the compact filter queue because we received a new block
572445
pub(crate) fn clear_compact_filter_queue(&mut self) {
573446
self.request_state.agreement_state.reset_agreements();
@@ -638,7 +511,7 @@ mod tests {
638511
anchor: HeaderCheckpoint,
639512
height_monitor: Arc<Mutex<HeightMonitor>>,
640513
peers: u8,
641-
) -> Chain<()> {
514+
) -> Chain {
642515
let (log_tx, _) = tokio::sync::mpsc::channel::<String>(1);
643516
let (info_tx, _) = tokio::sync::mpsc::channel::<Info>(1);
644517
let (warn_tx, _) = tokio::sync::mpsc::unbounded_channel::<Warning>();
@@ -658,7 +531,6 @@ mod tests {
658531
event_tx,
659532
)),
660533
height_monitor,
661-
(),
662534
peers,
663535
)
664536
}

src/chain/mod.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,6 @@ trait HeightExt: Clone + Copy + std::hash::Hash + PartialEq + Eq + PartialOrd +
239239
fn from_u64_checked(height: u64) -> Option<Self>;
240240

241241
fn is_adjustment_multiple(&self, params: impl AsRef<Params>) -> bool;
242-
243-
fn last_epoch_start(&self, params: impl AsRef<Params>) -> Self;
244242
}
245243

246244
impl HeightExt for u32 {
@@ -255,12 +253,6 @@ impl HeightExt for u32 {
255253
fn from_u64_checked(height: u64) -> Option<Self> {
256254
height.try_into().ok()
257255
}
258-
259-
fn last_epoch_start(&self, params: impl AsRef<Params>) -> Self {
260-
let diff_adjustment_interval = params.as_ref().difficulty_adjustment_interval() as u32;
261-
let floor = self / diff_adjustment_interval;
262-
floor * diff_adjustment_interval
263-
}
264256
}
265257

266258
// Emulation of `GetBlockSubsidy` in Bitcoin Core: https://github.com/bitcoin/bitcoin/blob/master/src/validation.cpp#L1944
@@ -277,7 +269,6 @@ pub(crate) fn block_subsidy(height: u32) -> Amount {
277269
#[cfg(test)]
278270
mod tests {
279271
use super::*;
280-
use bitcoin::Network;
281272

282273
#[test]
283274
fn test_height_monitor() {
@@ -306,18 +297,6 @@ mod tests {
306297
assert!(height_monitor.max().unwrap().eq(&12));
307298
}
308299

309-
#[test]
310-
fn test_height_ext() {
311-
assert!(2016.is_adjustment_multiple(Network::Bitcoin));
312-
assert!(4032.is_adjustment_multiple(Network::Bitcoin));
313-
let height = 2300;
314-
assert_eq!(height.last_epoch_start(Network::Bitcoin), 2016);
315-
let height = 4033;
316-
assert_eq!(height.last_epoch_start(Network::Bitcoin), 4032);
317-
let height = 4032;
318-
assert_eq!(height.last_epoch_start(Network::Bitcoin), 4032);
319-
}
320-
321300
#[test]
322301
fn test_subsidy_calculation() {
323302
let first_subsidy = block_subsidy(2);

0 commit comments

Comments
 (0)