Skip to content

Commit

Permalink
Start receipts reader
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby committed Nov 18, 2023
1 parent 0e43357 commit 0a17a98
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 10 deletions.
14 changes: 14 additions & 0 deletions crates/db-utils/src/leveldb/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use leveldb::database::key::Key;
pub const HEADER_PREFIX: u8 = b"h"[0];
pub const HEADER_HASH_SUFFIX: u8 = b"n"[0];
pub const BLOCK_BODY_PREFIX: u8 = b"b"[0];
pub const BLOCK_RECEIPTS_PREFIX: u8 = b"r"[0];

/// Wrapper around a [Vec<u8>] to implement the [Key] trait.
pub struct DBKey(Vec<u8>);
Expand Down Expand Up @@ -50,6 +51,19 @@ impl DBKey {
key.extend_from_slice(&hash);
Self(key)
}

/// Get a key for the `block receipts by number + hash` table in the Geth leveldb.
///
/// Format: `block_receipts_prefix + number + hash -> block receipts`
pub fn receipts_by_hash(hash: [u8; 32], number: u64) -> Self {
const KEY_SIZE: usize = 1 + 8 + 32;

let mut key = Vec::with_capacity(KEY_SIZE);
key.push(BLOCK_RECEIPTS_PREFIX);
key.extend_from_slice(&number.to_be_bytes());
key.extend_from_slice(&hash);
Self(key)
}
}

impl From<Vec<u8>> for DBKey {
Expand Down
68 changes: 58 additions & 10 deletions crates/db-utils/src/leveldb/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloy_rlp::Decodable;
use anyhow::{anyhow, Result};
use leveldb::{database::Database, kv::KV, options::ReadOptions};
use reth_primitives::{Header, SealedBlock, SealedHeader, TransactionSigned};
use reth_primitives::{Header, ReceiptWithBloom, SealedBlock, SealedHeader, TransactionSigned};

mod key;
pub use self::key::DBKey;
Expand All @@ -21,24 +21,37 @@ impl GethDBReader {
Self { db: database }
}

/// Retrieve a header hash by its number from a Geth LevelDB.
///
/// ### Takes
/// - `number`: The block number of the header hash to retrieve
///
/// ### Returns
/// - Success: A [u8; 32] containing the header hash
/// - Failure: An [anyhow::Error] if the header hash could not be found
pub fn hash_by_number(&self, number: u64) -> Result<[u8; 32]> {
let key = DBKey::hash_by_number(number);
let hash = self
.db
.get(ReadOptions::new(), key)?
.ok_or(anyhow!("Header hash not found"))?
.try_into()
.map_err(|_| anyhow!("Header hash received from DB is not 32 bytes in size"))?;

Ok(hash)
}

/// Retrieve a [SealedHeader] by its block number from a Geth LevelDB
///
/// ### Takes
/// - `db`: A reference to a [Database] instance
/// - `number`: The block number of the [SealedHeader] to retrieve
///
/// ### Returns
/// - Success: A [SealedHeader] instance
/// - Failure: An [anyhow::Error] if the header could not be found
pub fn header_by_number(&self, number: u64) -> Result<SealedHeader> {
// Fetch the header hash
let header_hash_key = DBKey::hash_by_number(number);
let header_hash: [u8; 32] = self
.db
.get(ReadOptions::new(), header_hash_key)?
.ok_or(anyhow::anyhow!("Header hash not found"))?
.try_into()
.map_err(|_| anyhow!("Header hash received from DB is not 32 bytes in size"))?;
let header_hash = self.hash_by_number(number)?;

// Fetch the header RLP
let header_key = DBKey::header_lookup(header_hash, number);
Expand All @@ -58,7 +71,6 @@ impl GethDBReader {
/// Retrieve a [SealedBlock] by its block number from a Geth LevelDB.
///
/// ### Takes
/// - `db`: A reference to a [Database] instance
/// - `number`: The block number of the [SealedBlock] to Retrieve
///
/// ### Returns
Expand All @@ -84,6 +96,29 @@ impl GethDBReader {
withdrawals: None,
})
}

/// Reads the receipts for a [SealedBlock] by its number from a Geth LevelDB.
///
/// ### Takes
/// - `db`: A reference to a [Database] instance
///
/// ### Returns
/// - Success: A [Vec] of [ReceiptWithBloom] instances
/// - Failure: An [anyhow::Error] if the receipts could not be found
pub fn receipts_by_number(&self, number: u64) -> Result<Vec<ReceiptWithBloom>> {
let header_hash = self.hash_by_number(number)?;

let receipts_key = DBKey::receipts_by_hash(header_hash, number);
let receipts_rlp = self
.db
.get(ReadOptions::new(), receipts_key)?
.ok_or(anyhow::anyhow!("Receipts RLP not found"))?;

let receipts = <Vec<ReceiptWithBloom>>::decode(&mut receipts_rlp.as_slice())?;
dbg!(&receipts);

Ok(receipts)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -120,4 +155,17 @@ mod db_test {

dbg!(reader.block_by_number(TEST_BLOCK_NO).unwrap());
}

#[test]
#[ignore]
fn sanity_read_receipts() {
let mut db_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
db_path.push("testdata/geth/chaindata");

let options = Options::new();
let database: Database<DBKey> = Database::open(db_path.as_path(), options).unwrap();
let reader = GethDBReader::new(database);

dbg!(reader.receipts_by_number(TEST_BLOCK_NO).unwrap());
}
}

0 comments on commit 0a17a98

Please sign in to comment.