Commit b43b807f authored by clabby's avatar clabby

Use live block for testing

parent cf2b67eb
...@@ -3737,6 +3737,7 @@ dependencies = [ ...@@ -3737,6 +3737,7 @@ dependencies = [
name = "rethdb-reader" name = "rethdb-reader"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"alloy-rlp",
"anyhow", "anyhow",
"reth-blockchain-tree", "reth-blockchain-tree",
"reth-db", "reth-db",
......
...@@ -23,3 +23,4 @@ anyhow = "1.0.75" ...@@ -23,3 +23,4 @@ anyhow = "1.0.75"
[dev-dependencies] [dev-dependencies]
reth-revm = { git = "https://github.com/paradigmxyz/reth.git" } reth-revm = { git = "https://github.com/paradigmxyz/reth.git" }
alloy-rlp = "0.3.3"
.PHONY: testdata
tetstdata:
mkdir -p testdata
@echo "Fetching block RLP and receipts for block #18,663,292 from ethereum mainnet"
cast rpc debug_getRawBlock 0x11CC77C | jq -r | xxd -r -p > testdata/block.rlp
cast rpc debug_getRawReceipts 0x11CC77C | jq -r > testdata/receipts.json
@echo "Done. Generating testdata DB & testing integrity..."
cargo test
...@@ -29,10 +29,10 @@ cargo +nightly fmt -- && cargo +nightly clippy --all --all-features -- -D warnin ...@@ -29,10 +29,10 @@ cargo +nightly fmt -- && cargo +nightly clippy --all --all-features -- -D warnin
**Generating `testdata`** **Generating `testdata`**
The testdata DB is automatically generated upon running the tests. The testdata block and `reth` database can be generated by running the `testdata` make directive:
```sh ```sh
cargo test ETH_RPC_URL="<your_L1_RPC_URL>" make testdata
``` ```
**Generating the C header** **Generating the C header**
......
...@@ -211,59 +211,80 @@ fn build_transaction_receipt_with_block_receipts( ...@@ -211,59 +211,80 @@ fn build_transaction_receipt_with_block_receipts(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use alloy_rlp::Decodable;
use reth_db::database::Database; use reth_db::database::Database;
use reth_primitives::{ use reth_primitives::{
address, b256, bloom, Block, Bytes, Log, Receipts, SealedBlockWithSenders, TxType, U8, address, b256, bloom, hex, Address, Block, Bytes, ReceiptWithBloom, Receipts,
SealedBlockWithSenders, U8,
}; };
use reth_provider::{BlockWriter, BundleStateWithReceipts, DatabaseProvider}; use reth_provider::{BlockWriter, BundleStateWithReceipts, DatabaseProvider};
use reth_revm::revm::db::BundleState; use reth_revm::revm::db::BundleState;
use std::{ffi::CString, fs::File, path::Path}; use std::{ffi::CString, fs::File, path::Path};
#[inline]
fn dummy_block_with_receipts() -> Result<(Block, Vec<Receipt>)> {
// To generate testdata (block 18,663,292 on Ethereum Mainnet):
// 1. BLOCK RLP: `cast rpc debug_getRawBlock 0x11CC77C | jq -r | xxd -r -p > testdata/block.rlp`
// 2. RECEIPTS RLP: `cast rpc debug_getRawReceipts 0x11CC77C | jq -r > testdata/receipts.json`
let block_rlp = include_bytes!("../testdata/block.rlp");
let block = Block::decode(&mut block_rlp.as_ref())?;
let receipt_rlp: Vec<Vec<u8>> = serde_json::from_str(include_str!(
"../testdata/receipts.json"
))
.map(|v: Vec<String>| {
v.into_iter()
.map(|s| hex::decode(s))
.collect::<Result<Vec<Vec<u8>>, _>>()
})??;
let receipts = receipt_rlp
.iter()
.map(|r| ReceiptWithBloom::decode(&mut r.as_slice()).map(|r| r.receipt))
.collect::<Result<Vec<Receipt>, _>>()?;
Ok((block, receipts))
}
#[inline] #[inline]
fn open_receipts_testdata_db() { fn open_receipts_testdata_db() {
if File::open("testdata/db").is_ok() { if File::open("testdata/db").is_ok() {
return; return;
} }
// Open a RW handle to the MDBX database
let db = reth_db::init_db(Path::new("testdata/db"), None).unwrap(); let db = reth_db::init_db(Path::new("testdata/db"), None).unwrap();
let pr = DatabaseProvider::new_rw(db.tx_mut().unwrap(), MAINNET.clone()); let pr = DatabaseProvider::new_rw(db.tx_mut().unwrap(), MAINNET.clone());
let block: Block = serde_json::from_str(include_str!("../testdata/dummy_block.json"))
.expect("failed to parse dummy block"); // Grab the dummy block and receipts
let (mut block, receipts) = dummy_block_with_receipts().unwrap();
// Patch: The block's current state root expects the rest of the chain history to be in the DB;
// manually override it. Otherwise, the DatabaseProvider will fail to commit the block.
block.header.state_root = reth_primitives::constants::EMPTY_ROOT_HASH;
// Fetch the block number and tx senders for bundle state creation.
let block_number = block.header.number; let block_number = block.header.number;
let tx_sender = block.body[0] let senders = block
.recover_signer() .body
.expect("failed to recover signer"); .iter()
.map(|tx| tx.recover_signer())
.collect::<Option<Vec<Address>>>()
.unwrap();
// Commit the bundle state to the database
pr.append_blocks_with_bundle_state( pr.append_blocks_with_bundle_state(
vec![SealedBlockWithSenders { vec![SealedBlockWithSenders {
block: block.seal_slow(), block: block.seal_slow(),
senders: vec![tx_sender], senders,
}], }],
BundleStateWithReceipts::new( BundleStateWithReceipts::new(
BundleState::default(), BundleState::default(),
Receipts::from_block_receipt(vec![Receipt { Receipts::from_block_receipt(receipts),
tx_type: TxType::EIP1559,
success: true,
cumulative_gas_used: 0x3aefc,
logs: vec![Log {
address: address!("4ce63f351597214ef0b9a319124eea9e0f9668bb"),
topics: vec![
b256!(
"0cdbd8bd7813095001c5fe7917bd69d834dc01db7c1dfcf52ca135bd20384413"
),
b256!(
"00000000000000000000000000000000000000000000000000000000000000c2"
),
],
data: Bytes::default(),
}],
}]),
block_number, block_number,
), ),
None, None,
) )
.expect("failed to append block and receipt to database"); .expect("failed to append block and receipt to database");
pr.commit() pr.commit()
.expect("failed to commit block and receipt to database"); .expect("failed to commit block and receipt to database");
} }
...@@ -274,7 +295,7 @@ mod test { ...@@ -274,7 +295,7 @@ mod test {
unsafe { unsafe {
let mut block_hash = let mut block_hash =
b256!("bcc3fb97b87bb4b14bacde74255cbfcf52675c0ad5e06fa264c0e5d6c0afd96e"); b256!("6a229123d607c2232a8b0bdd36f90745945d05181018e64e60ff2b93ab6b52e5");
let receipts_res = super::read_receipts_inner( let receipts_res = super::read_receipts_inner(
block_hash.as_mut_ptr(), block_hash.as_mut_ptr(),
32, 32,
...@@ -290,39 +311,46 @@ mod test { ...@@ -290,39 +311,46 @@ mod test {
receipts.remove(0) receipts.remove(0)
}; };
// Check the first receipt in the block for validity
assert_eq!(receipt.transaction_type, U8::from(2)); assert_eq!(receipt.transaction_type, U8::from(2));
assert_eq!(receipt.status_code, Some(U64::from(1))); assert_eq!(receipt.status_code, Some(U64::from(1)));
assert_eq!(receipt.cumulative_gas_used, U256::from(241_404)); assert_eq!(receipt.cumulative_gas_used, U256::from(115_316));
assert_eq!(receipt.logs_bloom, bloom!("00000000000000000000000000000000000000000100008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000010020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000800000000000000000000000000000000000000000000000000000000")); assert_eq!(receipt.logs_bloom, bloom!("00200000000000000000000080001000000000000000000000000000000000000000000000000000000000000000100002000100080000000000000000000000000000000000000000000008000000200000000400000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000400000000000001000000000000000100000000080000004000000000000000000000000000000000000002000000000000000000000000000000000000000006000000000000000000000000000000000000001000000000000000000000200000000000000100000000020000000000000000000000000000000010"));
assert_eq!( assert_eq!(
receipt.logs[0].address, receipt.logs[0].address,
address!("4ce63f351597214ef0b9a319124eea9e0f9668bb") address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
); );
assert_eq!( assert_eq!(
receipt.logs[0].topics[0], receipt.logs[0].topics[0],
b256!("0cdbd8bd7813095001c5fe7917bd69d834dc01db7c1dfcf52ca135bd20384413") b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
); );
assert_eq!( assert_eq!(
receipt.logs[0].topics[1], receipt.logs[0].topics[1],
b256!("00000000000000000000000000000000000000000000000000000000000000c2") b256!("00000000000000000000000000000000003b3cc22af3ae1eac0440bcee416b40")
);
assert_eq!(
receipt.logs[0].data,
Bytes::from_static(
hex!("00000000000000000000000000000000000000000000000008a30cd230000000")
.as_slice()
)
); );
assert_eq!(receipt.logs[0].data, Bytes::default());
assert_eq!( assert_eq!(
receipt.from, receipt.from,
address!("a24efab96523efa6abb2de9b2c16205cfa3c1dc8") address!("41d3ab85aafed2ef9e644cb7d3bbca2fc4d8cac8")
); );
assert_eq!( assert_eq!(
receipt.to, receipt.to,
Some(address!("4ce63f351597214ef0b9a319124eea9e0f9668bb")) Some(address!("00000000003b3cc22af3ae1eac0440bcee416b40"))
); );
assert_eq!( assert_eq!(
receipt.transaction_hash, receipt.transaction_hash,
Some(b256!( Some(b256!(
"12c0074a4a7916fe6f39de8417fe93f1fa77bcadfd5fc31a317fb6c344f66602" "88b2d153a4e893ba91ac235325c44b1aa0c802fcb42657701e1a73e1c675f7ca"
)) ))
); );
assert_eq!(receipt.block_number, Some(U256::from(9_942_861))); assert_eq!(receipt.block_number, Some(U256::from(18_663_292)));
assert_eq!(receipt.block_hash, Some(block_hash)); assert_eq!(receipt.block_hash, Some(block_hash));
assert_eq!(receipt.transaction_index, U64::from(0)); assert_eq!(receipt.transaction_index, U64::from(0));
......
{
"header": {
"parent_hash": "0xa2feb804b2ec06df67df4851a2ef75524820febc1a140ad5db424b80f9c3114d",
"ommers_hash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"beneficiary": "0x0000000000000000000000000000000000000000",
"state_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"transactions_root": "0x78aecefe9a8944f627b6ffef3aad9ab5f5a5031e360bd014a10a50bcf37979c6",
"receipts_root": "0x99bdc617e7e3781b02ce06c06a77acd45988be16be63d58578a4399f3cc10fed",
"withdrawals_root": "0x558291986c64e0ef409d79093c5f4306257fa56179f07efe4483eeaa14299a0c",
"logs_bloom": "0x00b8830810238200002802008031000400a80400054013c04083000a11000082820028c40500100209140a4202018028000a0a344921910c001286001024000010834000ec4004010000002b82108423461b8460020600001404031680200020004010008e4a08500528418800010804100000c809600200008a0098800810c2008220100112250062c044050001404080651013422442da000101400500041002281000031100000300008010104a0800110208800051804ac41a2420000110e0104103102242c0020a2000041042c8040201024004871471018012404065280c30021c202082030800040000020808020104421010c241c80a400408020054",
"difficulty": "0x0",
"number": 9942861,
"gas_limit": 30000000,
"gas_used": 13179518,
"timestamp": 1698454668,
"mix_hash": "0xc7bd100be413127b4e4695b29835cb15592c81e98b704b49838d358d13642c56",
"nonce": 0,
"base_fee_per_gas": 9,
"blob_gas_used": null,
"excess_blob_gas": null,
"parent_beacon_block_root": null,
"extra_data": "0xd883010b04846765746888676f312e32302e32856c696e7578"
},
"body": [
{
"hash": "0x12c0074a4a7916fe6f39de8417fe93f1fa77bcadfd5fc31a317fb6c344f66602",
"signature": {
"r": "0x200a045cf9b74dc7eaa71cbbc257c0d8365a11c3dc3f547267f4d93e3863e358",
"s": "0x1f9f7a37b2fa471c9212009c1f19daf3f03dbfd1787be7e227b56765daf084a",
"odd_y_parity": true
},
"transaction": {
"Eip1559": {
"chain_id": 5,
"nonce": 19275,
"gas_limit": 245823,
"max_fee_per_gas": 1500000018,
"max_priority_fee_per_gas": 1500000000,
"to": {
"Call": "0x4ce63f351597214ef0b9a319124eea9e0f9668bb"
},
"value": "0x0",
"access_list": [],
"input": "0x70ab1eb60000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000003ed1c85eb0477c9ac0308a4c7022c37e606627b328daa4ab363f44981e287d69bb075d81fcbff15450b978f9b84ca9fd9ca96b1e8faf3ea1f2951e496980b466186ae4a9f759f4d75d4fe28fde9d6ebad99f49cb30f791a2bfc85a8a2a36569f00000000000000000000000000000000000000000000000000000000653c5bf50c07ca9327b541241b9a7d856294622c1b03d4991fdf44537d97173709a7c7f4084a7f906d3e5594377cd9d7c36fc66c53716e69c8114b8fa425ad06e53807302eb1efd7eaf8c72107458873cda1b771bb5bf0154caa2ed63d3073e970cf63da0c1d1e58f31dff4dba615c61b3996a01d41e1f45999ea132e254c8e6129e535817235adea1ec0def8111508cc9b658347db64bdf3904c592f5ad4d9258f57b0c167f59373778385fc2f01ee9539befaaf97a8d540ae926242061d2da5fea4a91152ea7d88c390b356fb780a6f93c57efa6aab34d9409dec4dd23bc0ffa8f3f7825dd47e27434b2e4d9d9730db0ae0c2faa556f0e7440724d2c44c527c4d1ad8e29da7229592b10d727c8a7d633c8a0e6240db2452282ecee26ef3d8d9980b463"
}
}
}
],
"ommers": [],
"withdrawals": null
}
\ No newline at end of file
This diff is collapsed.
...@@ -14,25 +14,30 @@ import ( ...@@ -14,25 +14,30 @@ import (
func TestRethDBReceiptsLoad(t *testing.T) { func TestRethDBReceiptsLoad(t *testing.T) {
t.Parallel() t.Parallel()
// Goerli block #9942861, with only the first transaction persisted to the DB // ETH Mainnet block #18,663,292
// //
// https://goerli.etherscan.io/tx/0x12c0074a4a7916fe6f39de8417fe93f1fa77bcadfd5fc31a317fb6c344f66602 // https://etherscan.io/tx/0x88b2d153a4e893ba91ac235325c44b1aa0c802fcb42657701e1a73e1c675f7ca
blockHash := common.HexToHash("0xbcc3fb97b87bb4b14bacde74255cbfcf52675c0ad5e06fa264c0e5d6c0afd96e") //
// NOTE: The block hash differs from the live block due to a state root mismatch. In order to generate
// a testdata database with only this block in it, the state root of the block was modified.
// Old State Root: 0xaf81a692d228d56d35c80d65aeba59636b4671403054f6c57446c0e3e4d951c8
// New State Root (Empty MPT): 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
blockHash := common.HexToHash("0x6a229123d607c2232a8b0bdd36f90745945d05181018e64e60ff2b93ab6b52e5")
res, err := FetchRethReceipts("../rethdb-reader/testdata/db", &blockHash) res, err := FetchRethReceipts("../rethdb-reader/testdata/db", &blockHash)
require.NoError(t, err) require.NoError(t, err)
receipt := (*types.Receipt)(res[0]) receipt := (*types.Receipt)(res[0])
require.Equal(t, receipt.Type, uint8(2)) require.Equal(t, receipt.Type, uint8(2))
require.Equal(t, receipt.Status, uint64(1)) require.Equal(t, receipt.Status, uint64(1))
require.Equal(t, receipt.CumulativeGasUsed, uint64(241_404)) require.Equal(t, receipt.CumulativeGasUsed, uint64(115_316))
require.Equal(t, receipt.Bloom, types.BytesToBloom(common.Hex2Bytes("00000000000000000000000000000000000000000100008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000010020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000800000000000000000000000000000000000000000000000000000000"))) require.Equal(t, receipt.Bloom, types.BytesToBloom(common.Hex2Bytes("00200000000000000000000080001000000000000000000000000000000000000000000000000000000000000000100002000100080000000000000000000000000000000000000000000008000000200000000400000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000400000000000001000000000000000100000000080000004000000000000000000000000000000000000002000000000000000000000000000000000000000006000000000000000000000000000000000000001000000000000000000000200000000000000100000000020000000000000000000000000000000010")))
require.Equal(t, receipt.Logs[0].Address, common.HexToAddress("4ce63f351597214ef0b9a319124eea9e0f9668bb")) require.Equal(t, receipt.Logs[0].Address, common.HexToAddress("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
require.Equal(t, receipt.Logs[0].Topics[0], common.HexToHash("0cdbd8bd7813095001c5fe7917bd69d834dc01db7c1dfcf52ca135bd20384413")) require.Equal(t, receipt.Logs[0].Topics[0], common.HexToHash("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"))
require.Equal(t, receipt.Logs[0].Topics[1], common.HexToHash("00000000000000000000000000000000000000000000000000000000000000c2")) require.Equal(t, receipt.Logs[0].Topics[1], common.HexToHash("00000000000000000000000000000000003b3cc22af3ae1eac0440bcee416b40"))
require.Equal(t, receipt.Logs[0].Data, []byte{}) require.Equal(t, receipt.Logs[0].Data, common.Hex2Bytes("00000000000000000000000000000000000000000000000008a30cd230000000"))
require.Equal(t, receipt.TxHash, common.HexToHash("0x12c0074a4a7916fe6f39de8417fe93f1fa77bcadfd5fc31a317fb6c344f66602")) require.Equal(t, receipt.TxHash, common.HexToHash("0x88b2d153a4e893ba91ac235325c44b1aa0c802fcb42657701e1a73e1c675f7ca"))
require.Equal(t, receipt.BlockHash, common.HexToHash("0xbcc3fb97b87bb4b14bacde74255cbfcf52675c0ad5e06fa264c0e5d6c0afd96e")) require.Equal(t, receipt.BlockHash, blockHash)
require.Equal(t, receipt.BlockNumber, big.NewInt(9942861)) require.Equal(t, receipt.BlockNumber, big.NewInt(18_663_292))
require.Equal(t, receipt.TransactionIndex, uint(0)) require.Equal(t, receipt.TransactionIndex, uint(0))
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment