Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 9 additions & 1 deletion crates/storage/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3582,6 +3582,14 @@ impl Store {
.expect("block_data_buffer lock poisoned");
}

#[cfg(any(test, feature = "testing"))]
pub fn buffer_block_with_receipts_for_test(&self, block: &Block, receipts: Vec<Receipt>) {
mutate_block_buffer(&self.block_data_buffer, |b| {
b.insert(block.clone(), receipts, vec![])
})
.expect("block_data_buffer lock poisoned");
}

/// Mark a state root as in-flight (build pending) without doing a build.
/// For testing only — simulates the window where the persist worker has not
/// yet installed the layer, so reads at this root must block in
Expand Down Expand Up @@ -3794,7 +3802,7 @@ fn flush_block_data(
tx.put(
RECEIPTS_V2,
&receipt_key(&hash, index as u64),
&receipt.encode_to_vec(),
&receipt.encode_storage(),
)?;
}
max_number = max_number.max(b.number);
Expand Down
46 changes: 46 additions & 0 deletions test/tests/storage/deferred_persistence_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,52 @@ async fn batch_path_advances_flushed_upto() {
);
}

#[tokio::test]
async fn frame_receipt_survives_deferred_flush_and_eviction() {
use ethrex_common::types::{Receipt, TxType};

let store = Store::new("", EngineType::InMemory).expect("store");
let header = BlockHeader {
number: 7,
..Default::default()
};
let block = Block::new(header, BlockBody::default());
let hash = block.hash();

let receipt = Receipt {
tx_type: TxType::Frame,
succeeded: true,
cumulative_gas_used: 21_000,
logs: vec![],
payer: None,
frame_receipts: Some(vec![]),
};

store.buffer_block_with_receipts_for_test(&block, vec![receipt.clone()]);

let buffered = store
.get_receipts_for_block(&hash)
.await
.expect("receipt must be readable from the buffer before flush");
assert_eq!(
buffered,
vec![receipt.clone()],
"buffered receipt must match what was inserted"
);

store.flush_block_data_for_test().expect("flush");

let after_flush = store
.get_receipts_for_block(&hash)
.await
.expect("receipt must decode from disk after flush without MalformedBoolean");
assert_eq!(
after_flush,
vec![receipt],
"frame receipt must round-trip through the deferred flush unchanged"
);
}

// ── configurable backpressure cap ─────────────────────────────────────────────

/// The `StoreConfig` default must keep the production-tuned capacity of 2.
Expand Down
Loading