Skip to content

Commit 1a70de9

Browse files
phlip9shesek
authored andcommitted
bitcoind: support v28.0 new default blk*.dat xor'ing
See: <bitcoin/bitcoin#28052>
1 parent dca8c59 commit 1a70de9

2 files changed

Lines changed: 37 additions & 4 deletions

File tree

src/daemon.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use std::cell::OnceCell;
22
use std::collections::{HashMap, HashSet};
3-
use std::env;
3+
use std::convert::TryFrom;
44
use std::io::{BufRead, BufReader, Lines, Write};
55
use std::net::{SocketAddr, TcpStream};
66
use std::path::PathBuf;
77
use std::str::FromStr;
88
use std::sync::{Arc, Mutex};
99
use std::time::Duration;
10+
use std::{env, fs, io};
1011

1112
use base64::prelude::{Engine, BASE64_STANDARD};
1213
use error_chain::ChainedError;
@@ -393,6 +394,26 @@ impl Daemon {
393394
Ok(paths)
394395
}
395396

397+
/// bitcoind v28.0+ defaults to xor-ing all blk*.dat files with this key,
398+
/// stored in the blocks dir.
399+
/// See: <https://github.com/bitcoin/bitcoin/pull/28052>
400+
pub fn read_blk_file_xor_key(&self) -> Result<Option<[u8; 8]>> {
401+
// From: <https://github.com/bitcoin/bitcoin/blob/v28.0/src/node/blockstorage.cpp#L1160>
402+
let path = self.blocks_dir.join("xor.dat");
403+
let bytes = match fs::read(path) {
404+
Ok(bytes) => bytes,
405+
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None),
406+
Err(err) => return Err(err).chain_err(|| "failed to read daemon xor.dat file"),
407+
};
408+
let xor_key: [u8; 8] = <[u8; 8]>::try_from(bytes.as_slice()).chain_err(|| {
409+
format!(
410+
"xor.dat unexpected length: actual: {}, expected: 8",
411+
bytes.len()
412+
)
413+
})?;
414+
Ok(Some(xor_key))
415+
}
416+
396417
pub fn magic(&self) -> u32 {
397418
self.network.magic()
398419
}

src/new_index/fetch.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,15 @@ fn blkfiles_fetcher(
111111
) -> Result<Fetcher<Vec<BlockEntry>>> {
112112
let magic = daemon.magic();
113113
let blk_files = daemon.list_blk_files()?;
114+
let xor_key = daemon.read_blk_file_xor_key()?;
114115

115116
let chan = SyncChannel::new(1);
116117
let sender = chan.sender();
117118

118119
let mut entry_map: HashMap<BlockHash, HeaderEntry> =
119120
new_headers.into_iter().map(|h| (*h.hash(), h)).collect();
120121

121-
let parser = blkfiles_parser(blkfiles_reader(blk_files), magic);
122+
let parser = blkfiles_parser(blkfiles_reader(blk_files, xor_key), magic);
122123
Ok(Fetcher::from(
123124
chan.into_receiver(),
124125
spawn_thread("blkfiles_fetcher", move || {
@@ -151,7 +152,7 @@ fn blkfiles_fetcher(
151152
))
152153
}
153154

154-
fn blkfiles_reader(blk_files: Vec<PathBuf>) -> Fetcher<Vec<u8>> {
155+
fn blkfiles_reader(blk_files: Vec<PathBuf>, xor_key: Option<[u8; 8]>) -> Fetcher<Vec<u8>> {
155156
let chan = SyncChannel::new(1);
156157
let sender = chan.sender();
157158

@@ -160,8 +161,11 @@ fn blkfiles_reader(blk_files: Vec<PathBuf>) -> Fetcher<Vec<u8>> {
160161
spawn_thread("blkfiles_reader", move || {
161162
for path in blk_files {
162163
trace!("reading {:?}", path);
163-
let blob = fs::read(&path)
164+
let mut blob = fs::read(&path)
164165
.unwrap_or_else(|e| panic!("failed to read {:?}: {:?}", path, e));
166+
if let Some(xor_key) = xor_key {
167+
blkfile_apply_xor_key(xor_key, &mut blob);
168+
}
165169
sender
166170
.send(blob)
167171
.unwrap_or_else(|_| panic!("failed to send {:?} contents", path));
@@ -170,6 +174,14 @@ fn blkfiles_reader(blk_files: Vec<PathBuf>) -> Fetcher<Vec<u8>> {
170174
)
171175
}
172176

177+
/// By default, bitcoind v28.0+ applies an 8-byte "xor key" over each "blk*.dat"
178+
/// file. We have xor again to undo this transformation.
179+
fn blkfile_apply_xor_key(xor_key: [u8; 8], blob: &mut [u8]) {
180+
for (i, blob_i) in blob.iter_mut().enumerate() {
181+
*blob_i ^= xor_key[i & 0x7];
182+
}
183+
}
184+
173185
fn blkfiles_parser(blobs: Fetcher<Vec<u8>>, magic: u32) -> Fetcher<Vec<SizedBlock>> {
174186
let chan = SyncChannel::new(1);
175187
let sender = chan.sender();

0 commit comments

Comments
 (0)