Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions src/chainspec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,9 +804,9 @@ impl From<Genesis> for BerachainChainSpec {
mod tests {
use super::*;
use alloy_genesis::Genesis;
use alloy_primitives::address;
use alloy_primitives::{address, b256};
use jsonrpsee_core::__reexports::serde_json::json;
use reth_chainspec::ForkHash;
use reth_chainspec::{EthChainSpec, ForkHash};

#[test]
fn test_builtin_genesis_deposit_contract() {
Expand Down Expand Up @@ -1926,6 +1926,34 @@ mod tests {
assert!(chain_spec.is_prague1_active_at_timestamp(1754496000));
}

#[test]
fn test_bepolia_genesis_hash_regression() {
let bepolia_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/bepolia-genesis.json");
let bepolia_json = std::fs::read_to_string(bepolia_path).unwrap();
let genesis: Genesis = serde_json::from_str(&bepolia_json).unwrap();
let chain_spec = BerachainChainSpec::from(genesis);

assert_eq!(
chain_spec.genesis_hash(),
b256!("0x0207661de38f0e54ba91c8286096e72486784c79dc6a9681fc486b38335c042f")
);
}

#[test]
fn test_mainnet_genesis_hash_regression() {
let mainnet_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/mainnet-genesis.json");
let mainnet_json = std::fs::read_to_string(mainnet_path).unwrap();
let genesis: Genesis = serde_json::from_str(&mainnet_json).unwrap();
let chain_spec = BerachainChainSpec::from(genesis);

assert_eq!(
chain_spec.genesis_hash(),
b256!("0xd57819422128da1c44339fc7956662378c17e2213e669b427ac91cd11dfcfb38")
);
}

#[test]
fn test_chain_uses_id_not_named() {
let mut genesis = Genesis::default();
Expand Down
77 changes: 77 additions & 0 deletions src/primitives/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,4 +947,81 @@ mod tests {
"Header with prev_proposer_pubkey should be larger when compressed"
);
}

mod regression {
use super::*;
use crate::test_utils::regression_fixtures::{
holesky_berachain_header, holesky_berachain_header_with_proposer_pubkey,
};
use alloy_primitives::{b256, hex};

// Sourced from Reth v1.11.4:
// crates/primitives/src/header.rs test_compact_header_holesky()
// Block #1947953 on Holesky testnet.
const HOLESKY_COMPACT: &[u8] = &hex!(
"81a121788605e0c46689f66b3deed82598e43d5002b71a929023b665228728f0c6e62a951dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347c6e2459991bfe27cca6d86722f35da23a1e4cb97edad188ca5647d62f4cca417c11a1afbadebce30d23260767f6f587e9b3b99934daf25dc08a841aa22aa0d3cb3e1f159d4dcaf6a6063d4d36bfac11d3fdb63ee1a1500328e8ade2592bbea1e04f9a9fd8c0142d3175d6e8420984ee159abd0edd0f7f22d6d915be5a3b9c0fee353f14de5ac5c8ac1850b76ce9be70b69dfe37d36410880400480e1090a001c408880800019808000125124002100400048442220020000408040423088300004d0000050803000862485a02020011600a5010404143021800881e8e08c402940404002105004820c440051640000809c000011080002300208510808150101000038002500400040000230000000110442800000800204420100008110080200088c1610c0b80000c6008900000340400200200210010111020000200041a2010804801100030a0284a8463820120a0601480244521002a10201100400801101006002001000008000000ce011011041086418609002000128800008180141002003004c00800040940c00c1180ca0028900401db93101c9c38044094966982980574db0ff0a2243b434ba2a35da8f2f72df08bca44f8733f4908d10dcaebc89f101080306000000aa1d9606b7932f2280a19b3498b9ae9eebc6a83f1afde8e45944f79d353db4c1726574682f76312e302e302f6c696e7578"
);

// Self-generated snapshot: hash_slow() output for holesky_berachain_header().
// Uses canonical RLP+keccak semantics for this fixed fixture.
// Regenerate via: cargo test print_regression_values -- --ignored --nocapture
const HOLESKY_HASH: B256 =
b256!("0x2537b92b5139455368c19ec33a92e1ff0cf6b96e6fd8488bed4ed409d401ac9a");

// Self-generated snapshot: compress_to_buf() output of the same Holesky header
// with synthetic Berachain-specific fields (prev_proposer_pubkey, requests_hash).
// No external reference exists for these fields; this pins bera-reth's own format.
// Regenerate via: cargo test print_regression_values -- --ignored --nocapture
const WITH_PROPOSER_COMPACT: &[u8] = &hex!(
"81a121f88605e0c46689f66b3deed82598e43d5002b71a929023b665228728f0c6e62a951dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347c6e2459991bfe27cca6d86722f35da23a1e4cb97edad188ca5647d62f4cca417c11a1afbadebce30d23260767f6f587e9b3b99934daf25dc08a841aa22aa0d3cb3e1f159d4dcaf6a6063d4d36bfac11d3fdb63ee1a1500328e8ade2592bbea1e04f9a9fd8c0142d3175d6e8420984ee159abd0edd0f7f22d6d915be5a3b9c0fee353f14de5ac5c8ac1850b76ce9be70b69dfe37d36410880400480e1090a001c408880800019808000125124002100400048442220020000408040423088300004d0000050803000862485a02020011600a5010404143021800881e8e08c402940404002105004820c440051640000809c000011080002300208510808150101000038002500400040000230000000110442800000800204420100008110080200088c1610c0b80000c6008900000340400200200210010111020000200041a2010804801100030a0284a8463820120a0601480244521002a10201100400801101006002001000008000000ce011011041086418609002000128800008180141002003004c00800040940c00c1180ca0028900401db93101c9c38044094966982980574db0ff0a2243b434ba2a35da8f2f72df08bca44f8733f4908d10dcaebc89f101080306000000aa1d9606b7932f2280a19b3498b9ae9eebc6a83f1afde8e45944f79d353db4c15203111111111111111111111111111111111111111111111111111111111111111130424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242726574682f76312e302e302f6c696e7578"
);

// Self-generated snapshot: hash_slow() output of the header with Berachain ext fields.
// Regenerate via: cargo test print_regression_values -- --ignored --nocapture
const WITH_PROPOSER_HASH: B256 =
b256!("0xf822917a3ec331a4acc12c48325b1ecfd1f7771bb55dec41d648c365ee6855cb");

#[test]
fn compact_bitflag_layout() {
assert_eq!(CompactBerachainHeader::bitflag_encoded_bytes(), 4);
assert_eq!(BerachainHeaderExt::bitflag_encoded_bytes(), 1);
}

#[test]
fn holesky_compact_matches_reth_v1_11_4() {
let header = holesky_berachain_header();
let mut buf = Vec::new();
header.compress_to_buf(&mut buf);
assert_eq!(buf.as_slice(), HOLESKY_COMPACT);

let decompressed = BerachainHeader::decompress(HOLESKY_COMPACT).unwrap();
assert_eq!(decompressed, header);

let mut reencoded = Vec::new();
decompressed.compress_to_buf(&mut reencoded);
assert_eq!(reencoded.as_slice(), HOLESKY_COMPACT);
}

#[test]
fn holesky_hash_regression() {
assert_eq!(holesky_berachain_header().hash_slow(), HOLESKY_HASH);
}

#[test]
fn prev_proposer_pubkey_compact_regression() {
let header = holesky_berachain_header_with_proposer_pubkey();
let mut buf = Vec::new();
header.compress_to_buf(&mut buf);
assert_eq!(buf.as_slice(), WITH_PROPOSER_COMPACT);
assert_eq!(BerachainHeader::decompress(WITH_PROPOSER_COMPACT).unwrap(), header);
}

#[test]
fn prev_proposer_pubkey_hash_regression() {
assert_eq!(
holesky_berachain_header_with_proposer_pubkey().hash_slow(),
WITH_PROPOSER_HASH
);
}
}
}
3 changes: 3 additions & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(test)]
pub mod regression_fixtures;

use crate::chainspec::BerachainChainSpec;
use reth_cli::chainspec::parse_genesis;
use std::sync::Arc;
Expand Down
126 changes: 126 additions & 0 deletions src/test_utils/regression_fixtures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use crate::primitives::header::{BerachainHeader, BlsPublicKey};
use alloy_consensus::EMPTY_OMMER_ROOT_HASH;
use alloy_primitives::{Address, B64, Bytes, U256, address, b256, bloom, bytes};

pub fn holesky_berachain_header() -> BerachainHeader {
BerachainHeader {
parent_hash: b256!("0x8605e0c46689f66b3deed82598e43d5002b71a929023b665228728f0c6e62a95"),
ommers_hash: EMPTY_OMMER_ROOT_HASH,
beneficiary: address!("0xc6e2459991bfe27cca6d86722f35da23a1e4cb97"),
state_root: b256!("0xedad188ca5647d62f4cca417c11a1afbadebce30d23260767f6f587e9b3b9993"),
transactions_root: b256!(
"0x4daf25dc08a841aa22aa0d3cb3e1f159d4dcaf6a6063d4d36bfac11d3fdb63ee"
),
receipts_root: b256!("0x1a1500328e8ade2592bbea1e04f9a9fd8c0142d3175d6e8420984ee159abd0ed"),
withdrawals_root: Some(b256!(
"0xd0f7f22d6d915be5a3b9c0fee353f14de5ac5c8ac1850b76ce9be70b69dfe37d"
)),
logs_bloom: bloom!(
"36410880400480e1090a001c408880800019808000125124002100400048442220020000408040423088300004d0000050803000862485a02020011600a5010404143021800881e8e08c402940404002105004820c440051640000809c000011080002300208510808150101000038002500400040000230000000110442800000800204420100008110080200088c1610c0b80000c6008900000340400200200210010111020000200041a2010804801100030a0284a8463820120a0601480244521002a10201100400801101006002001000008000000ce011011041086418609002000128800008180141002003004c00800040940c00c1180ca002890040"
),
difficulty: U256::ZERO,
number: 0x1db931,
gas_limit: 0x1c9c380,
gas_used: 0x440949,
timestamp: 0x66982980,
mix_hash: b256!("0x574db0ff0a2243b434ba2a35da8f2f72df08bca44f8733f4908d10dcaebc89f1"),
nonce: B64::ZERO,
base_fee_per_gas: Some(0x8),
blob_gas_used: Some(0x60000),
excess_blob_gas: Some(0x0),
parent_beacon_block_root: Some(b256!(
"0xaa1d9606b7932f2280a19b3498b9ae9eebc6a83f1afde8e45944f79d353db4c1"
)),
requests_hash: None,
prev_proposer_pubkey: None,
extra_data: bytes!("726574682f76312e302e302f6c696e7578"),
}
}

pub fn holesky_berachain_header_with_proposer_pubkey() -> BerachainHeader {
BerachainHeader {
prev_proposer_pubkey: Some(BlsPublicKey::from([0x42; 48])),
requests_hash: Some(b256!(
"0x1111111111111111111111111111111111111111111111111111111111111111"
)),
..holesky_berachain_header()
}
}

pub fn minimal_pol_tx() -> crate::transaction::PoLTx {
use alloy_primitives::ChainId;
crate::transaction::PoLTx {
chain_id: ChainId::from(80084u64),
from: Address::ZERO,
to: Address::from([1u8; 20]),
nonce: 42,
gas_limit: 21000,
gas_price: 1000000000u128,
input: Bytes::from("test data"),
}
}

#[cfg(test)]
mod print_regression {
use super::*;
use crate::{
chainspec::BerachainChainSpec,
test_utils::bepolia_chainspec,
transaction::{BerachainTxEnvelope, BerachainTxType, pol::create_pol_transaction},
};
use alloy_primitives::{Sealable, Sealed, U256};
use reth_chainspec::EthChainSpec;
use reth_cli::chainspec::parse_genesis;
use reth_codecs::Compact;
use reth_db_api::table::Compress;

#[test]
#[ignore = "manual regression values generator"]
fn print_regression_values() {
let holesky = holesky_berachain_header();
let mut buf = Vec::new();
holesky.compress_to_buf(&mut buf);
eprintln!("holesky_hash={:#x}", holesky.hash_slow());
eprintln!("holesky_compact={}", alloy_primitives::hex::encode(&buf));

let with_pubkey = holesky_berachain_header_with_proposer_pubkey();
let mut buf = Vec::new();
with_pubkey.compress_to_buf(&mut buf);
eprintln!("with_pubkey_hash={:#x}", with_pubkey.hash_slow());
eprintln!("with_pubkey_compact={}", alloy_primitives::hex::encode(&buf));

let pol = minimal_pol_tx();
eprintln!("minimal_pol_hash={:#x}", pol.hash_slow());
let mut buf = Vec::new();
pol.to_compact(&mut buf);
eprintln!("minimal_pol_compact={}", alloy_primitives::hex::encode(&buf));

let envelope = BerachainTxEnvelope::Berachain(Sealed::new(pol.clone()));
let mut buf = Vec::new();
envelope.compress_to_buf(&mut buf);
eprintln!("minimal_pol_envelope_compact={}", alloy_primitives::hex::encode(&buf));

let tx_type = BerachainTxType::Berachain;
let mut buf = Vec::new();
let id = tx_type.to_compact(&mut buf);
eprintln!("berachain_tx_type_id={id}");
eprintln!("berachain_tx_type_compact={}", alloy_primitives::hex::encode(&buf));

let chain_spec = bepolia_chainspec();
let pubkey = BlsPublicKey::from([1u8; 48]);
let pol_prod =
match create_pol_transaction(chain_spec, pubkey, U256::from(10), 1000).unwrap() {
BerachainTxEnvelope::Berachain(sealed) => sealed,
_ => panic!("expected pol"),
};
eprintln!("production_pol_hash={:#x}", pol_prod.hash());

let bepolia_json = include_str!("../../tests/fixtures/bepolia-genesis.json");
let bepolia = BerachainChainSpec::from(parse_genesis(bepolia_json).unwrap());
eprintln!("bepolia_genesis_hash={:#x}", bepolia.genesis_hash());

let mainnet_json = include_str!("../../tests/fixtures/mainnet-genesis.json");
let mainnet = BerachainChainSpec::from(parse_genesis(mainnet_json).unwrap());
eprintln!("mainnet_genesis_hash={:#x}", mainnet.genesis_hash());
}
}
52 changes: 52 additions & 0 deletions src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1226,4 +1226,56 @@ mod pol_tx_rlp_tests {
let result = PoLTx::rlp_decode(&mut malformed_rlp.as_slice());
assert!(matches!(result, Err(alloy_rlp::Error::InputTooShort)));
}

mod regression {
use super::*;
use crate::test_utils::regression_fixtures::minimal_pol_tx;
use alloy_primitives::{b256, hex};
use reth_codecs::Compact;
use reth_db_api::table::Compress;

// Self-generated snapshot: hash_slow() output of regression_fixtures::minimal_pol_tx().
// Regenerate via: cargo test print_regression_values -- --ignored --nocapture
const MINIMAL_POL_HASH: alloy_primitives::B256 =
b256!("0x0a7a43d18a263b300d6fea2dfaa45e05798bbd0b11ce2b20f3a7e269f873e59f");

// Self-generated snapshot: to_compact() output of regression_fixtures::minimal_pol_tx().
// Regenerate via: cargo test print_regression_values -- --ignored --nocapture
const MINIMAL_POL_COMPACT: &[u8] = &hex!(
"1342000138d4000000000000000000000000000000000000000001010101010101010101010101010101010101012a52083b9aca00746573742064617461"
);

// Self-generated snapshot: compress_to_buf() output of
// BerachainTxEnvelope::Berachain(Sealed::new(regression_fixtures::minimal_pol_tx())).
// Regenerate via: cargo test print_regression_values -- --ignored --nocapture
const MINIMAL_POL_ENVELOPE_COMPACT: &[u8] = &hex!(
"06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e1342000138d4000000000000000000000000000000000000000001010101010101010101010101010101010101012a52083b9aca00746573742064617461"
);

#[test]
fn minimal_pol_tx_hash_regression() {
let pol_tx = minimal_pol_tx();
assert_eq!(pol_tx.hash_slow(), MINIMAL_POL_HASH);
}

#[test]
fn minimal_pol_tx_compact_regression() {
let pol_tx = minimal_pol_tx();
let mut buf = Vec::new();
pol_tx.to_compact(&mut buf);
assert_eq!(buf.as_slice(), MINIMAL_POL_COMPACT);
}

#[test]
fn minimal_pol_envelope_compact_regression() {
let envelope = BerachainTxEnvelope::Berachain(Sealed::new(minimal_pol_tx()));
let mut buf = Vec::new();
envelope.compress_to_buf(&mut buf);
assert_eq!(buf.as_slice(), MINIMAL_POL_ENVELOPE_COMPACT);
assert_eq!(
BerachainTxEnvelope::decompress(MINIMAL_POL_ENVELOPE_COMPACT).unwrap(),
envelope
);
}
}
}
47 changes: 46 additions & 1 deletion src/transaction/pol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub fn validate_pol_transaction(
mod tests {
use super::*;
use alloy_eips::eip7002::SYSTEM_ADDRESS;
use alloy_primitives::{U256, address};
use alloy_primitives::{U256, address, b256};

use crate::test_utils::bepolia_chainspec;

Expand Down Expand Up @@ -234,4 +234,49 @@ mod tests {
"Identical PoL transactions should have identical hashes"
);
}

#[test]
fn test_pol_transaction_hash_regression() {
let chain_spec = bepolia_chainspec();
let pubkey = mock_bls_pubkey();
let pol_tx = match create_pol_transaction(chain_spec, pubkey, U256::from(10), 1000).unwrap()
{
BerachainTxEnvelope::Berachain(sealed_tx) => sealed_tx,
_ => panic!("Expected PoL transaction"),
};

assert_eq!(
*pol_tx.hash(),
b256!("0x35b5cc4612e0e4ec54e339c189158098ef764de6229c7db0707d95c0850b5eb7")
);
}

#[test]
fn test_pol_transaction_compact_regression() {
use alloy_primitives::hex;
use reth_db::table::Decompress;
use reth_db_api::table::Compress;

// Self-generated snapshot: compress_to_buf output for a production-like PoL tx
// using bepolia chain spec, block 10, base_fee 1000, pubkey [1u8; 48].
// Same inputs as test_pol_transaction_hash_regression.
// Regenerate via: cargo test print_regression_values -- --ignored --nocapture
const PRODUCTION_POL_COMPACT: &[u8] = &hex!(
"0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028b52ffd23e4c3b413baed010094027e1324000138c5fffed2f19a79b026fb636a7c300bf5947df1139407610901c9c38003e860644a300106fc00023884e6f1eb031ef566f3de5587f9"
);

let chain_spec = bepolia_chainspec();
let pubkey = mock_bls_pubkey();
let sealed_pol =
match create_pol_transaction(chain_spec, pubkey, U256::from(10), 1000).unwrap() {
BerachainTxEnvelope::Berachain(sealed) => sealed,
_ => panic!("Expected PoL transaction"),
};
let envelope = BerachainTxEnvelope::Berachain(sealed_pol);
let mut buf = Vec::new();
envelope.compress_to_buf(&mut buf);
assert_eq!(buf.as_slice(), PRODUCTION_POL_COMPACT);

assert_eq!(BerachainTxEnvelope::decompress(PRODUCTION_POL_COMPACT).unwrap(), envelope);
}
}
14 changes: 14 additions & 0 deletions src/transaction/txtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,18 @@ mod tests {
assert_eq!(decoded, expected_berachain_type);
}
}

#[test]
fn test_berachain_tx_type_compact_regression() {
let tx_type = BerachainTxType::Berachain;
let mut buf = Vec::new();
let identifier = tx_type.to_compact(&mut buf);

assert_eq!(identifier, 3usize);
assert_eq!(buf.as_slice(), &[0x7eu8]);

let (decoded, remaining) = BerachainTxType::from_compact(&buf, identifier);
assert_eq!(decoded, BerachainTxType::Berachain);
assert!(remaining.is_empty());
}
}