Skip to content

Process eth_sendRawTransaction txs correctly#900

Closed
ZanCorDX wants to merge 3 commits intodevelopfrom
dx/private-tx-not-mempool
Closed

Process eth_sendRawTransaction txs correctly#900
ZanCorDX wants to merge 3 commits intodevelopfrom
dx/private-tx-not-mempool

Conversation

@ZanCorDX
Copy link
Collaborator

📝 Summary

We distinguish between mempool txs and txs from eth_sendRawTransaction so MempoolTxsDetector treats them correctly.

✅ I have completed the following steps:

  • Run make lint
  • Run make test
  • Added tests (if applicable)

@ZanCorDX ZanCorDX requested a review from dvush as a code owner March 20, 2026 17:20
@claude
Copy link
Contributor

claude bot commented Mar 20, 2026

Claude finished @ZanCorDX's task in 1m 52s —— View job


Review of PR #900

  • Gather context and read key files
  • Review diff for bugs, security, and quality issues
  • Post review feedback

Overall: Clean, well-scoped change that adds an is_private flag to distinguish mempool txs from eth_sendRawTransaction txs. The core logic in MempoolTxsDetector::add_tx correctly filters private txs out of the mempool set. DB version bump is appropriate. Tests cover the new behavior well.

Issues flagged (see inline comments):

  1. RawTx.is_private missing #[serde(default)] — Deserialization of old data without this field will fail. Adding #[serde(default)] would make this backward-compatible since false is the correct default for legacy data.

  2. Hash/PartialEq on MempoolTx now includes is_private — The same transaction received from both mempool and eth_sendRawTransaction would be treated as two different orders. This could lead to duplicate inclusion attempts during block building if not prevented upstream.

  3. Test gaptest_create_sim_value_tx_non_mempool_coinbase_profit only covers the public case, while the bundle test covers both variants.

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RawTx {
pub tx: Bytes,
pub is_private: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_private is a required field for deserialization. If any existing serialized RawTx data is read (e.g., from sources other than the SQLite store, which got a version bump), deserialization will fail because old data won't have this field.

Consider adding #[serde(default)] to make this backward-compatible — false is the correct default for legacy data.

Suggested change
pub is_private: bool,
#[serde(default)]
pub is_private: bool,

/// Since we get txs from mempool and also from builder's endpoint eth_sendRawTransaction
/// MempoolTx is modeling both (is_private <=> came internally through eth_sendRawTransaction).
/// @Pending rename to something like SingleTx.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MempoolTx derives PartialEq, Eq, and Hash, and now is_private participates in all three. This means the same transaction received from both mempool (is_private: false) and eth_sendRawTransaction (is_private: true) will be considered different orders and could produce different hash values.

If these duplicates can reach the order pool, it could lead to double-inclusion attempts during block building. Is this a scenario that's already prevented upstream, or should Hash/PartialEq exclude is_private (e.g., via manual impls that only compare tx_with_blobs)?

@@ -1367,10 +1374,9 @@ mod test {
fn test_create_sim_value_tx_non_mempool_coinbase_profit() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test only covers the public mempool case (is_private: false). Given that the bundle test above covers both is_private variants, consider adding a private tx variant here too for completeness — verifying that a private standalone tx is also handled correctly by create_sim_value.

@claude
Copy link
Contributor

claude bot commented Mar 20, 2026

Claude finished @ZanCorDX's task in 1m 29s —— View job


  • Read diff and gather context
  • Review changes for bugs, security, and quality
  • Post review feedback

Review of PR #900 (post-sync)

The "backwards compatibility" commit addresses the #[serde(default)] issue from the previous review — that's resolved.

The bundle test was updated to cover both is_private variants — good improvement.

Remaining issues:

  1. Hash/PartialEq on MempoolTx still includes is_private (see inline comment) — Not a correctness bug since the order pool deduplicates via OrderId (tx hash only), but semantically surprising. The same transaction shouldn't be "different" based on arrival path. Consider manual Hash/PartialEq impls that delegate only to tx_with_blobs, or document why the derived behavior is acceptable.

  2. test_create_sim_value_tx_non_mempool_coinbase_profit still only covers public case — The bundle test now covers both variants, but the standalone tx test at crates/rbuilder/src/building/mod.rs:1374 only tests is_private: false. Adding a private variant would verify that a private standalone tx is correctly excluded from the mempool set.

/// Since we get txs from mempool and also from builder's endpoint eth_sendRawTransaction
/// MempoolTx is modeling both (is_private <=> came internally through eth_sendRawTransaction).
/// @Pending rename to something like SingleTx.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The derived PartialEq and Hash include is_private, so two MempoolTx values with the same underlying transaction but different is_private flags will compare as unequal and hash differently. This isn't a correctness issue for the order pool (which deduplicates via OrderId based on tx hash alone), but it's semantically surprising — the same transaction shouldn't be "different" based on how it arrived. Consider a manual Hash/PartialEq impl that delegates only to tx_with_blobs, or at minimum add a comment explaining why the derived behavior is acceptable.

@ZanCorDX ZanCorDX closed this Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant