Skip to content

Commit 1490e53

Browse files
committed
tests: add testnet3 parsing tests
Also, introduce and document a small Python script that facilitates cleaning up the LevelDB so the amount of binary data can be minimized.
1 parent cd65c3d commit 1490e53

File tree

10 files changed

+74
-21
lines changed

10 files changed

+74
-21
lines changed

tests/bitcoin.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,8 @@
1-
fn storage() -> bitcoin_blockparser::parser::chain::ChainStorage {
2-
let options = bitcoin_blockparser::ParserOptions {
3-
callback: Box::new(bitcoin_blockparser::callbacks::simplestats::SimpleStats::default()),
4-
coin: "bitcoin".parse().unwrap(),
5-
verify: true,
6-
blockchain_dir: std::path::PathBuf::from("tests/testdata/bitcoin"),
7-
range: bitcoin_blockparser::BlockHeightRange::new(0, Some(200)).unwrap(),
8-
};
9-
let storage = bitcoin_blockparser::parser::chain::ChainStorage::new(&options).unwrap();
10-
11-
// Discard transient diff on LevelDB files
12-
std::process::Command::new("git")
13-
.args(["checkout", "tests/testdata/bitcoin"])
14-
.output()
15-
.unwrap();
16-
storage
17-
}
1+
mod common;
182

193
static STORAGE: once_cell::sync::Lazy<
204
std::sync::Mutex<bitcoin_blockparser::parser::chain::ChainStorage>,
21-
> = once_cell::sync::Lazy::new(|| std::sync::Mutex::new(storage()));
5+
> = once_cell::sync::Lazy::new(|| std::sync::Mutex::new(common::storage("bitcoin", 170)));
226

237
#[test]
248
fn test_bitcoin_genesis() {

tests/common/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
pub fn storage(datadir: &str, max_height: u64) -> bitcoin_blockparser::parser::chain::ChainStorage {
2+
let options = bitcoin_blockparser::ParserOptions {
3+
callback: Box::new(bitcoin_blockparser::callbacks::simplestats::SimpleStats::default()),
4+
coin: datadir.parse().unwrap(),
5+
verify: true,
6+
blockchain_dir: std::path::PathBuf::from(format!("tests/testdata/{datadir}")),
7+
range: bitcoin_blockparser::BlockHeightRange::new(0, Some(max_height)).unwrap(),
8+
};
9+
let storage = bitcoin_blockparser::parser::chain::ChainStorage::new(&options).unwrap();
10+
11+
// Discard transient diff on LevelDB files
12+
std::process::Command::new("git")
13+
.args(["checkout", format!("tests/testdata/{datadir}").as_str()])
14+
.output()
15+
.unwrap();
16+
storage
17+
}

tests/testdata/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ Contains Bitcoin block data as dumped by Bitcoin Core after syncing up to a smal
66
This data can be generated roughly as follows:
77
1. Start bitcoind on the desired network
88
1. Sync a small number of initial blocks, then kill the daemon
9-
1. Prune LevelDB
10-
1. Remove non-block entries (the key doesn't begin with `b'b'`)
11-
1. [Copy entries over](https://github.com/wbolster/plyvel/issues/153#issuecomment-1669387180) into a new database, this results in a dramatic serialization size decrease
9+
1. Copy the `blocks` content over to the `testdata` directory
10+
1. Prune LevelDB:
11+
1. Set the correct API endpoint, max block height and path to the local DB in `clean_leveldb.py`
12+
1. Run `python clean_leveldb.py` which will create a pruned DB, removing all superfluous data
1213
1. Prune trailing zero bytes from `.dat` file
1314
1. `sed '$ s/\x00*$//' blk00000.dat > blk00000.dat.stripped`
1415

tests/testdata/clean_leveldb.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from pathlib import Path
2+
import requests
3+
import plyvel
4+
5+
LEVEL_DB_PATH = "./testnet3/index"
6+
MAX_BLOCK_HEIGHT = 120
7+
API_ENDPOINT = "https://blockstream.info/testnet/api/"
8+
9+
def get_blockhash(height: int) -> str:
10+
return requests.get(f"{API_ENDPOINT}block-height/{height}").text.strip()
11+
12+
def make_prefix_copy(db: plyvel.DB) -> None:
13+
path = Path("./pruned-db")
14+
path.mkdir()
15+
db2 = plyvel.DB(str(path), create_if_missing=True, error_if_exists=True)
16+
for height in range(MAX_BLOCK_HEIGHT + 1):
17+
block_hash = get_blockhash(height)
18+
key = b'b' + bytes.fromhex(block_hash)[::-1]
19+
db2.put(key, db.get(key))
20+
if height % 10 == 0:
21+
print(f"processed height {height} of {MAX_BLOCK_HEIGHT}")
22+
db2.close()
23+
24+
if __name__ == "__main__":
25+
db = plyvel.DB(LEVEL_DB_PATH)
26+
make_prefix_copy(db)
27+
db.close()

tests/testdata/testnet3/blk00000.dat

23.7 KB
Binary file not shown.
17.3 KB
Binary file not shown.

tests/testdata/testnet3/index/CURRENT

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MANIFEST-000002

tests/testdata/testnet3/index/LOCK

Whitespace-only changes.
50 Bytes
Binary file not shown.

tests/testnet3.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
mod common;
2+
3+
static STORAGE: once_cell::sync::Lazy<
4+
std::sync::Mutex<bitcoin_blockparser::parser::chain::ChainStorage>,
5+
> = once_cell::sync::Lazy::new(|| std::sync::Mutex::new(common::storage("testnet3", 120)));
6+
7+
#[test]
8+
fn test_blockdata_parsing() {
9+
assert_eq!(
10+
STORAGE
11+
.lock()
12+
.unwrap()
13+
.get_block(0)
14+
.unwrap()
15+
.block_hash()
16+
.to_string(),
17+
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
18+
);
19+
for height in 0..=120 {
20+
let block = STORAGE.lock().unwrap().get_block(height).unwrap();
21+
assert_eq!(block.txdata.len(), 1);
22+
}
23+
}

0 commit comments

Comments
 (0)