Skip to content

Commit 84497d5

Browse files
fix(rpc): EIP-8141 frame receipt RPC MalformedBoolean decoding
1 parent cee872d commit 84497d5

2 files changed

Lines changed: 55 additions & 1 deletion

File tree

crates/storage/store.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3582,6 +3582,14 @@ impl Store {
35823582
.expect("block_data_buffer lock poisoned");
35833583
}
35843584

3585+
#[cfg(any(test, feature = "testing"))]
3586+
pub fn buffer_block_with_receipts_for_test(&self, block: &Block, receipts: Vec<Receipt>) {
3587+
mutate_block_buffer(&self.block_data_buffer, |b| {
3588+
b.insert(block.clone(), receipts, vec![])
3589+
})
3590+
.expect("block_data_buffer lock poisoned");
3591+
}
3592+
35853593
/// Mark a state root as in-flight (build pending) without doing a build.
35863594
/// For testing only — simulates the window where the persist worker has not
35873595
/// yet installed the layer, so reads at this root must block in
@@ -3794,7 +3802,7 @@ fn flush_block_data(
37943802
tx.put(
37953803
RECEIPTS_V2,
37963804
&receipt_key(&hash, index as u64),
3797-
&receipt.encode_to_vec(),
3805+
&receipt.encode_storage(),
37983806
)?;
37993807
}
38003808
max_number = max_number.max(b.number);

test/tests/storage/deferred_persistence_tests.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,52 @@ async fn batch_path_advances_flushed_upto() {
504504
);
505505
}
506506

507+
#[tokio::test]
508+
async fn frame_receipt_survives_deferred_flush_and_eviction() {
509+
use ethrex_common::types::{Receipt, TxType};
510+
511+
let store = Store::new("", EngineType::InMemory).expect("store");
512+
let header = BlockHeader {
513+
number: 7,
514+
..Default::default()
515+
};
516+
let block = Block::new(header, BlockBody::default());
517+
let hash = block.hash();
518+
519+
let receipt = Receipt {
520+
tx_type: TxType::Frame,
521+
succeeded: true,
522+
cumulative_gas_used: 21_000,
523+
logs: vec![],
524+
payer: None,
525+
frame_receipts: Some(vec![]),
526+
};
527+
528+
store.buffer_block_with_receipts_for_test(&block, vec![receipt.clone()]);
529+
530+
let buffered = store
531+
.get_receipts_for_block(&hash)
532+
.await
533+
.expect("receipt must be readable from the buffer before flush");
534+
assert_eq!(
535+
buffered,
536+
vec![receipt.clone()],
537+
"buffered receipt must match what was inserted"
538+
);
539+
540+
store.flush_block_data_for_test().expect("flush");
541+
542+
let after_flush = store
543+
.get_receipts_for_block(&hash)
544+
.await
545+
.expect("receipt must decode from disk after flush without MalformedBoolean");
546+
assert_eq!(
547+
after_flush,
548+
vec![receipt],
549+
"frame receipt must round-trip through the deferred flush unchanged"
550+
);
551+
}
552+
507553
// ── configurable backpressure cap ─────────────────────────────────────────────
508554

509555
/// The `StoreConfig` default must keep the production-tuned capacity of 2.

0 commit comments

Comments
 (0)