From 1c29aff27b4cf9a14b3cdc0a0cf0e9685b857a49 Mon Sep 17 00:00:00 2001 From: Philip Kannegaard Hayes Date: Thu, 14 Nov 2024 16:52:04 -0800 Subject: [PATCH 1/2] bitcoind: support v28.0 new default blk*.dat xor'ing See: --- src/daemon.rs | 23 ++++++++++++++++++++++- src/new_index/fetch.rs | 18 +++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/daemon.rs b/src/daemon.rs index 6190f15f..68089079 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,12 +1,13 @@ use std::cell::OnceCell; use std::collections::{HashMap, HashSet}; -use std::env; +use std::convert::TryFrom; use std::io::{BufRead, BufReader, Lines, Write}; use std::net::{SocketAddr, TcpStream}; use std::path::PathBuf; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::Duration; +use std::{env, fs, io}; use base64::prelude::{Engine, BASE64_STANDARD}; use error_chain::ChainedError; @@ -393,6 +394,26 @@ impl Daemon { Ok(paths) } + /// bitcoind v28.0+ defaults to xor-ing all blk*.dat files with this key, + /// stored in the blocks dir. + /// See: + pub fn read_blk_file_xor_key(&self) -> Result> { + // From: + let path = self.blocks_dir.join("xor.dat"); + let bytes = match fs::read(path) { + Ok(bytes) => bytes, + Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), + Err(err) => return Err(err).chain_err(|| "failed to read daemon xor.dat file"), + }; + let xor_key: [u8; 8] = <[u8; 8]>::try_from(bytes.as_slice()).chain_err(|| { + format!( + "xor.dat unexpected length: actual: {}, expected: 8", + bytes.len() + ) + })?; + Ok(Some(xor_key)) + } + pub fn magic(&self) -> u32 { self.network.magic() } diff --git a/src/new_index/fetch.rs b/src/new_index/fetch.rs index d7637ee5..3778a884 100644 --- a/src/new_index/fetch.rs +++ b/src/new_index/fetch.rs @@ -111,6 +111,7 @@ fn blkfiles_fetcher( ) -> Result>> { let magic = daemon.magic(); let blk_files = daemon.list_blk_files()?; + let xor_key = daemon.read_blk_file_xor_key()?; let chan = SyncChannel::new(1); let sender = chan.sender(); @@ -118,7 +119,7 @@ fn blkfiles_fetcher( let mut entry_map: HashMap = new_headers.into_iter().map(|h| (*h.hash(), h)).collect(); - let parser = blkfiles_parser(blkfiles_reader(blk_files), magic); + let parser = blkfiles_parser(blkfiles_reader(blk_files, xor_key), magic); Ok(Fetcher::from( chan.into_receiver(), spawn_thread("blkfiles_fetcher", move || { @@ -151,7 +152,7 @@ fn blkfiles_fetcher( )) } -fn blkfiles_reader(blk_files: Vec) -> Fetcher> { +fn blkfiles_reader(blk_files: Vec, xor_key: Option<[u8; 8]>) -> Fetcher> { let chan = SyncChannel::new(1); let sender = chan.sender(); @@ -160,8 +161,11 @@ fn blkfiles_reader(blk_files: Vec) -> Fetcher> { spawn_thread("blkfiles_reader", move || { for path in blk_files { trace!("reading {:?}", path); - let blob = fs::read(&path) + let mut blob = fs::read(&path) .unwrap_or_else(|e| panic!("failed to read {:?}: {:?}", path, e)); + if let Some(xor_key) = xor_key { + blkfile_apply_xor_key(xor_key, &mut blob); + } sender .send(blob) .unwrap_or_else(|_| panic!("failed to send {:?} contents", path)); @@ -170,6 +174,14 @@ fn blkfiles_reader(blk_files: Vec) -> Fetcher> { ) } +/// By default, bitcoind v28.0+ applies an 8-byte "xor key" over each "blk*.dat" +/// file. We have xor again to undo this transformation. +fn blkfile_apply_xor_key(xor_key: [u8; 8], blob: &mut [u8]) { + for (i, blob_i) in blob.iter_mut().enumerate() { + *blob_i ^= xor_key[i & 0x7]; + } +} + fn blkfiles_parser(blobs: Fetcher>, magic: u32) -> Fetcher> { let chan = SyncChannel::new(1); let sender = chan.sender(); From c7f7595d21678b7fa9e828ef8e02d5dfc5b775f2 Mon Sep 17 00:00:00 2001 From: Philip Kannegaard Hayes Date: Thu, 14 Nov 2024 16:54:15 -0800 Subject: [PATCH 2/2] clippy: "oldcpu" feature doesn't exist anymore. remove deadcode. --- src/lib.rs | 6 ------ src/new_index/db.rs | 3 --- 2 files changed, 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9dbc5815..834758a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,5 @@ #![recursion_limit = "1024"] -// See https://github.com/romanz/electrs/issues/193 & https://github.com/rust-rocksdb/rust-rocksdb/issues/327 -#[cfg(not(feature = "oldcpu"))] -extern crate rocksdb; -#[cfg(feature = "oldcpu")] -extern crate rocksdb_oldcpu as rocksdb; - #[macro_use] extern crate clap; #[macro_use] diff --git a/src/new_index/db.rs b/src/new_index/db.rs index b6617d42..20db12f4 100644 --- a/src/new_index/db.rs +++ b/src/new_index/db.rs @@ -163,10 +163,7 @@ impl DB { rows.sort_unstable_by(|a, b| a.key.cmp(&b.key)); let mut batch = rocksdb::WriteBatch::default(); for row in rows { - #[cfg(not(feature = "oldcpu"))] batch.put(&row.key, &row.value); - #[cfg(feature = "oldcpu")] - batch.put(&row.key, &row.value).unwrap(); } let do_flush = match flush { DBFlush::Enable => true,