Conversation
|
Claude finished @ZanCorDX's task in 10m 53s —— View job Review of PR #884 — Order Journal
SummaryThis PR adds order journal tracking by introducing an Bug:
|
| /// Enum matching ClickHouse `Enum8('Tx' = 1, 'Bundle' = 2)`. | ||
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | ||
| #[repr(i8)] | ||
| pub enum OrderJournalOrderType { | ||
| Tx = 0, | ||
| Bundle = 1, | ||
| } | ||
|
|
There was a problem hiding this comment.
Stale doc comments: The comments reference 'Tx' = 1, 'Bundle' = 2 and 'Add' = 1, 'Remove' = 2, but the actual Rust values were changed to 0, 1 in a subsequent commit. Please update the doc comments to match the actual enum values (or fix the enum values if the ClickHouse schema truly expects 1-based values).
The same issue applies to the schema comment on lines 157-159 (order_type Enum8('Tx' = 1, 'Bundle' = 2) and operation_type Enum8('Add' = 1, 'Remove' = 2)).
| order_type, | ||
| order_hash: order_id.fixed_bytes(), | ||
| operation_type, | ||
| sequence_number: command.sequence_number() as u32, |
There was a problem hiding this comment.
JournalSequenceNumber is usize (64-bit on 64-bit platforms) but is cast to u32 here. If the sequence number ever exceeds u32::MAX, this silently wraps. While unlikely within a single slot, consider using u32::try_from().unwrap_or(u32::MAX) or at least documenting the assumption.
| let mut next_journal_sequence_number = 0; | ||
| while let Some(input) = input.orders.blocking_recv() { | ||
| // Failing is not critical. | ||
| let _ = root_hasher_prefetcher_sender.try_send(input.clone()); | ||
| let journal_command = | ||
| SimulatedOrderJournalCommand::new(input, next_journal_sequence_number); | ||
| next_journal_sequence_number += 1; | ||
| order_journal_observer.order_delivered(&slot_data_copy, &journal_command); | ||
| // we don't create new subscribers to the broadcast so here we can be sure that err means end of receivers | ||
| if broadcast_input.send(input).is_err() { | ||
| if broadcast_input.send(journal_command).is_err() { | ||
| trace!("Cancelling simulated orders send job, destination stopped"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Minor performance note: order_delivered (in OrderJournalWriter) clones self.builder_name (a String) and calls OffsetDateTime::now_utc() (syscall) for every order event on this hot path. For thousands of orders per slot this adds up. Consider using Arc<str> for the builder name to avoid per-event allocations.
There was a problem hiding this comment.
Both BuiltBlocksWriter and OrderJournalWriter share the same disk_backup instance (via Clone on line 382). If DiskBackup uses the same underlying storage path, both writers' backup data could interleave and compete for the same disk space quota. Is this intentional, or should each writer have its own backup instance with separate paths?
|
Claude finished @ZanCorDX's task in 6m 34s —— View job Review of PR #884 — Order Journal (updated after sync)
Critical:
|
| Issue | Status |
|---|---|
consume_next_batch ignores channel close |
Still open |
| Stale doc comments on enum values | Still open |
usize to u32 truncation on sequence_number (line 612→525) |
Still present — command.sequence_number() as u32 at line 612 |
Per-event String::clone + syscall on hot path |
Still present — self.builder_name.clone() at line 606 |
Shared DiskBackup between writers |
Still present — disk_backup.clone() at flashbots_config.rs:381 |
New observation: next_journal_sequence_number tracking
The next_journal_sequence_number field added to BuiltBlockTrace and BlockRow tracks the journal watermark at block build time. This is correctly threaded through the ordering builder path (ordering_builder.rs:135-148 → block_building_helper.rs:289). However, the parallel builder path hardcodes 0 at block_building_result_assembler.rs:191 and 269, making the field meaningless for parallel-built blocks. The TODO panic (discussed above) is an acknowledgment of this gap but is the wrong solution.
| panic!( | ||
| "TODO: next_journal_sequence_number not set in BlockBuildingHelperFromProvider::new" | ||
| ); | ||
|
|
There was a problem hiding this comment.
This panic! will crash the builder in production if build_new_block is ever called. The #[allow(unreachable_code)] annotation hides the fact that this code IS reachable — the loop above breaks normally when all groups are exhausted, falling through to set_trace_fill_time and then hitting this panic. This needs to be resolved before merging: either properly propagate next_journal_sequence_number through the parallel builder's OrderIntakeStore, or return an error instead of panicking.
| /// Enum matching ClickHouse `Enum8('Tx' = 1, 'Bundle' = 2)`. | ||
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | ||
| #[repr(i8)] | ||
| pub enum OrderJournalOrderType { | ||
| Tx = 0, | ||
| Bundle = 1, | ||
| } |
There was a problem hiding this comment.
Stale doc comments: Comments reference 'Tx' = 1, 'Bundle' = 2 and 'Add' = 1, 'Remove' = 2, but the actual Rust enum values are 0 and 1. The schema doc block on lines 157-159 has the same mismatch. Either update the comments to match the code, or fix the enum values to match the ClickHouse schema.
| /// Enum matching ClickHouse `Enum8('Tx' = 1, 'Bundle' = 2)`. | |
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | |
| #[repr(i8)] | |
| pub enum OrderJournalOrderType { | |
| Tx = 0, | |
| Bundle = 1, | |
| } | |
| /// Enum matching ClickHouse `Enum8('Tx' = 0, 'Bundle' = 1)`. | |
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | |
| #[repr(i8)] | |
| pub enum OrderJournalOrderType { | |
| Tx = 0, | |
| Bundle = 1, | |
| } | |
| /// Enum matching ClickHouse `Enum8('Add' = 0, 'Remove' = 1)`. |
|
Claude finished @ZanCorDX's task in 11m 19s —— View job Review of PR #884 — Order Journal (re-review after sync)
Critical:
|
| Issue | Status |
|---|---|
build_new_block reachable panic |
Still open — inline |
consume_next_batch ignores channel close |
Still open (not in diff; noted above) |
| Stale doc comments on enum values | Still open — inline |
usize to u32 truncation on sequence_number |
Still present — inline |
Per-event String::clone on hot path |
Still present — self.builder_name.clone() at clickhouse.rs:645 |
Shared DiskBackup between writers |
Not an issue — DiskBackup uses Arc<RwLock<redb::Database>> and is designed to be shared across tables |
Observations
-
Prefetcher refactoring is sound. The switch from
broadcast::Receivertostd::sync::mpsc::Receiverfor the root hash prefetcher eliminatesLaggederrors and simplifies the flow. The fan-out pattern instart_building_job(line 238-254) cleanly distributes to broadcast (builders) + sync mpsc (prefetcher) + observer. -
BackupNotTooBigRelaySubmissionPolicy::should_submitnow correctly sums both tables. The change to use.with_label_values(&[BLOCKS_TABLE_NAME])and.with_label_values(&[ORDER_JOURNAL_TABLE_NAME])properly aggregates disk backup size across both the blocks and journal tables. -
OrderJournalWriterDrop impl correctly removes the slot fromactive_slots, preventing resource leaks. -
No tests for
OrderJournalWriter. The PR checklist notes "Added tests" is unchecked. TheNullOrderJournalObserverexists for test isolation, but there are no unit tests verifying the mapping logic inOrderJournalWriter::order_delivered.
| panic!( | ||
| "TODO: next_journal_sequence_number not set in BlockBuildingHelperFromProvider::new" | ||
| ); |
There was a problem hiding this comment.
Critical: Reachable panic! in production code
This panic! is reachable — the loop above breaks normally when all order groups are exhausted, set_trace_fill_time runs, and then this fires. The #[allow(unreachable_code)] on line 182 suppresses the compiler warning but doesn't make the code actually unreachable.
If the parallel builder is enabled, build_new_block will crash the builder process. This must be resolved before merging. Options:
- Properly propagate
next_journal_sequence_numberthrough the parallel builder'sOrderIntakeStore(it already wrapsOrderConsumerwhich tracks it). - Return an
Err(...)instead of panicking if you want to defer the implementation. - At minimum, use
eyre::bail!("...")so it returns an error instead of crashing.
| /// Enum matching ClickHouse `Enum8('Tx' = 1, 'Bundle' = 2)`. | ||
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | ||
| #[repr(i8)] | ||
| pub enum OrderJournalOrderType { | ||
| Tx = 0, | ||
| Bundle = 1, | ||
| } | ||
|
|
||
| /// Enum matching ClickHouse `Enum8('Add' = 1, 'Remove' = 2)`. | ||
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | ||
| #[repr(i8)] | ||
| pub enum OrderJournalOperationType { | ||
| Add = 0, | ||
| Remove = 1, | ||
| } |
There was a problem hiding this comment.
Stale doc comments: enum values mismatch
The comments say 'Tx' = 1, 'Bundle' = 2 and 'Add' = 1, 'Remove' = 2, but the actual Rust values are 0 and 1. The same mismatch exists in the schema doc block on lines 160-162. Either update the comments to match the code, or fix the enum values to match the ClickHouse schema.
| /// Enum matching ClickHouse `Enum8('Tx' = 1, 'Bundle' = 2)`. | |
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | |
| #[repr(i8)] | |
| pub enum OrderJournalOrderType { | |
| Tx = 0, | |
| Bundle = 1, | |
| } | |
| /// Enum matching ClickHouse `Enum8('Add' = 1, 'Remove' = 2)`. | |
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | |
| #[repr(i8)] | |
| pub enum OrderJournalOperationType { | |
| Add = 0, | |
| Remove = 1, | |
| } | |
| /// Enum matching ClickHouse `Enum8('Tx' = 0, 'Bundle' = 1)`. | |
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | |
| #[repr(i8)] | |
| pub enum OrderJournalOrderType { | |
| Tx = 0, | |
| Bundle = 1, | |
| } | |
| /// Enum matching ClickHouse `Enum8('Add' = 0, 'Remove' = 1)`. | |
| #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)] | |
| #[repr(i8)] | |
| pub enum OrderJournalOperationType { | |
| Add = 0, | |
| Remove = 1, | |
| } |
| /// order_type Enum8('Tx' = 1, 'Bundle' = 2) | ||
| /// order_hash FixedString(32) | ||
| /// operation_type Enum8('Add' = 1, 'Remove' = 2) |
There was a problem hiding this comment.
These schema doc values (= 1, = 2) don't match the actual enum values (= 0, = 1). Needs to be updated for consistency.
| triggering_bid_relay, | ||
| bid_to_beat_seen_time, | ||
| bid_to_beat_seen_relay, | ||
| next_journal_sequence_number: built_block_trace.next_journal_sequence_number as u32, |
There was a problem hiding this comment.
JournalSequenceNumber is usize (64-bit on x86_64), cast to u32 here. If the sequence number ever exceeds u32::MAX, this silently wraps. Consider u32::try_from(...).unwrap_or(u32::MAX) or changing the ClickHouse column to UInt64.
📝 Summary
Adds a new clickhouse table to store all orders seen by the builder.
✅ I have completed the following steps:
make lintmake test