Skip to content

feat(ethexe/rpc): add TxReceipt for injected transactions#5382

Open
ecol-master wants to merge 12 commits into
masterfrom
kd/feat/no-promise-error
Open

feat(ethexe/rpc): add TxReceipt for injected transactions#5382
ecol-master wants to merge 12 commits into
masterfrom
kd/feat/no-promise-error

Conversation

@ecol-master
Copy link
Copy Markdown
Member

@ecol-master ecol-master commented Apr 28, 2026

@gear-tech/dev

Closes #5438

@semanticdiff-com
Copy link
Copy Markdown

semanticdiff-com Bot commented Apr 28, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  ethexe/db/src/database.rs  52% smaller
  ethexe/service/src/tests/mod.rs  49% smaller
  ethexe/network/src/lib.rs  45% smaller
  ethexe/consensus/src/validator/producer.rs  45% smaller
  ethexe/rpc/src/lib.rs  39% smaller
  ethexe/rpc/src/apis/injected/promise_manager.rs  37% smaller
  ethexe/rpc/src/apis/injected/mod.rs  34% smaller
  ethexe/consensus/src/tx_validation.rs  33% smaller
  ethexe/consensus/src/announces.rs  28% smaller
  ethexe/sdk/src/mirror.rs  24% smaller
  ethexe/rpc/src/apis/injected/server.rs  19% smaller
  ethexe/rpc/src/apis/injected/spawner.rs  12% smaller
  ethexe/common/src/injected.rs  10% smaller
  ethexe/common/src/db.rs  8% smaller
  ethexe/consensus/src/validator/tx_pool.rs  6% smaller
  Cargo.lock Unsupported file format
  ethexe/cli/src/commands/tx.rs Unsupported file format
  ethexe/consensus/src/lib.rs Unsupported file format
  ethexe/network/src/gossipsub.rs  0% smaller
  ethexe/network/src/validator/topic.rs  0% smaller
  ethexe/rpc/src/apis/injected/trait.rs  0% smaller
  ethexe/rpc/src/tests.rs  0% smaller
  ethexe/service/src/lib.rs Unsupported file format
  ethexe/service/src/tests/utils/events.rs  0% smaller
  protocol/gsigner/src/schemes/secp256k1/signature.rs  0% smaller

@ecol-master ecol-master added type: feat New functionality or user-visible improvement size: M Medium task (1–2 days) scope: vara.eth Vara Ethereum application layer (L2) labels May 5, 2026
@ecol-master ecol-master changed the title feat(ethexe-rpc): Return error to user when no promise error feat(ethexe-rpc): TxReceipt for injected transaction May 6, 2026
@ecol-master ecol-master force-pushed the kd/feat/no-promise-error branch from 611e511 to 1c6d9ec Compare May 8, 2026 11:31
ecol-master and others added 2 commits May 12, 2026 14:40
Implemented:
- generic Receipt<P> enum
- types for receipts handling in RPC and other modules
- receipt handling receipt across all ethexe services

Removed:
- SignedCompactPromise - replaced with SignedCompactTxReceipt
@ecol-master
Copy link
Copy Markdown
Member Author

@claude review

@claude
Copy link
Copy Markdown

claude Bot commented May 12, 2026

Claude finished @ecol-master's task in 2m 48s —— View job


Code Review

  • Gathering PR context
  • Reading changed files
  • Analyzing code quality and correctness
  • Writing review

Overview

This PR replaces SignedCompactPromise / SignedPromise with a new Receipt<P> enum that unifies two outcomes — a successful Promise and a TransactionError — under one type. The producer now emits signed receipts for both successful and rejected transactions, clients subscribe to SignedTxReceipt, and the network gossipsub topic is renamed accordingly. The design is sound and the test coverage is adequate. A few issues worth addressing below.


severity: highwaiting_for_compute entries for HashesMismatch are never cleaned up

File: ethexe/rpc/src/apis/injected/promise_manager.rs lines 157–162

When on_computed_promise calls try_fill_with and gets HashesMismatch, the unfilled receipt is re-inserted back into waiting_for_compute. But the subscriber's on_finish callback only removes from subscribers, not from waiting_for_compute. After the subscriber times out, the stale UnfilledPromiseReceipt stays in the map indefinitely with no eviction path — a memory leak under sustained mismatch conditions (byzantine producer, hash collision).

Same in on_tx_receipt lines 130–135: on mismatch with a promise already in DB, the receipt is parked in waiting_for_compute but there's nothing that would re-attempt it, so it also lingers.

Fix this →


severity: high — Network protocol break: gossipsub topic rename is silent

File: ethexe/network/src/gossipsub.rs line 128

The gossipsub topic is renamed from "promises" to "tx_receipts" (keyed per router address). Nodes running old code subscribe to "promises", nodes running new code subscribe to "tx_receipts". During a mixed rollout they will silently stop exchanging receipts — no error, just lost messages. If this is an intentional protocol version bump it should be documented; if nodes are expected to upgrade atomically, no change needed, but it's worth a comment.


severity: medium — RPC method name still getTransactionPromise after rename

File: ethexe/rpc/src/apis/injected/trait.rs lines 52–56

#[method(name = "getTransactionPromise")]
async fn get_transaction_receipt(

The JSON-RPC wire name is unchanged while the Rust function was renamed. This silently preserves backward compatibility for existing callers, but the mismatch will confuse anyone reading the code. Either rename the wire method to "getTransactionReceipt" (breaking change for callers) or add a comment explaining that the wire name is intentionally preserved for compatibility.


severity: mediumunsafe pointer cast to read #[repr(u8)] discriminant

File: ethexe/common/src/injected.rs lines 354–357

pub fn variant_index(&self) -> u8 {
    unsafe { (self as *const TransactionErrorReason).cast::<u8>().read() }
}

Since the enum is #[repr(u8)] with explicit discriminants, this can be written safely as *self as u8. The pointer-cast approach is sound here (the repr guarantees the layout) but it triggers unsafe, bypasses Miri analysis, and is surprising to readers. *self as u8 is the idiomatic safe equivalent.


severity: medium — Commented-out dead code in ConsensusEvent

File: ethexe/consensus/src/lib.rs around line 290

// #[from]
// PublishTransactionResult(SignedTransactionResult),

Dead commented-out code in a public enum. Remove before merging or replace with a proper TODO if the variant is planned.


severity: low — DB key gap skips 20, not 13/16

File: ethexe/db/src/database.rs line 85

TxReceipt is assigned discriminant 21, skipping 20 (the old CompactPromise). This avoids colliding with old stored data, which is correct. However, existing nodes that stored data under key 20 will silently lose access to it — there is no migration. Worth a comment if in-place upgrades are expected.


severity: low — Typo in doc comment

File: ethexe/common/src/injected.rs line 265

"It is uses as lightweight transfer type"

Should be "It is used as a lightweight transfer type".


severity: low — Debug format used for user-facing error message

File: ethexe/cli/src/commands/tx.rs line 1138, ethexe/sdk/src/mirror.rs line 274

return Err(anyhow!("injected transaction failed: {err:?}"));

TransactionError has reason: TransactionErrorReason which derives Display. Using {err:?} gives the Rust debug representation rather than the human-readable reason string. Consider "injected transaction failed: {}", err.reason or implement Display on TransactionError.


chatgpt-codex-connector[bot]

This comment was marked as outdated.

@gear-tech gear-tech deleted a comment from chatgpt-codex-connector Bot May 12, 2026
@ecol-master
Copy link
Copy Markdown
Member Author

@claude review-delta

@claude
Copy link
Copy Markdown

claude Bot commented May 12, 2026

Claude finished @ecol-master's task in 1m 1s —— View job


Review Delta

Reviewing commit 1c046af ("fix claude review") against the previous review.


What Was Fixed ✅

  • Typo ("It is uses""It is used") — fixed
  • Debug format in error messages — both tx.rs and mirror.rs now use {err} with a proper Display impl on TransactionError
  • RPC wire name"getTransactionPromise""getTransactionReceipt" — fixed, breaking change acknowledged
  • Commented-out dead code in ConsensusEvent — removed
  • DB key gapTxReceipt moved from 2120 (eliminates unused slot; safe since 20 was never written under the old code)

What Was Not Fixed

severity: highwaiting_for_compute memory leak not addressed

promise_manager.rs lines 157–162: HashesMismatch entries are still re-inserted into waiting_for_compute with no eviction path when the subscriber times out. cancel_registration only removes from subscribers. The stale entries accumulate indefinitely under sustained mismatch conditions.

severity: high — Gossipsub topic rename still silently breaks mixed-version rollouts

network/src/gossipsub.rs line 128: no change. If this is intentional (atomic upgrade required), a comment would prevent future confusion.

severity: mediumunsafe block not removed

File: ethexe/common/src/injected.rs lines 354–357

The fix changed .cast::<u8>() to as *const u8 — these are semantically identical, both still unsafe raw pointer reads. The suggested safe form *self as u8 was not used:

// Before (still unsafe, just different cast syntax):
unsafe { (self as *const TransactionErrorReason as *const u8).read() }

// Should be:
*self as u8

Since TransactionErrorReason is #[repr(u8)] with explicit discriminants, casting via as u8 is safe, idiomatic, and removes the unsafe block entirely. Fix this →


@ecol-master ecol-master marked this pull request as ready for review May 12, 2026 13:05
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the injected transaction lifecycle in ethexe by replacing the "Promise" mechanism with a more comprehensive "Receipt" system. This change introduces a Receipt enum that can represent either a successful execution promise or a specific TransactionError, allowing validators to propagate execution failures to RPC subscribers and across the network. The implementation involves significant updates across the database, consensus, network, and RPC layers to support SignedTxReceipt and its compact version. Feedback was provided regarding the new unsafe constructor in the gsigner crate, suggesting the use of #[doc(hidden)] to discourage general use of this performance-oriented internal function.

Comment thread protocol/gsigner/src/schemes/secp256k1/signature.rs
@gear-tech gear-tech deleted a comment from gemini-code-assist Bot May 12, 2026
@breathx breathx removed the size: M Medium task (1–2 days) label May 13, 2026
@breathx
Copy link
Copy Markdown
Member

breathx commented May 13, 2026

Removing size and priority labels — per CONTRIBUTING.md §7.3, these are for issues only and MUST NOT be used on PRs.

@breathx breathx changed the title feat(ethexe-rpc): TxReceipt for injected transaction feat(ethexe/rpc): add TxReceipt for injected transactions May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: vara.eth Vara Ethereum application layer (L2) type: feat New functionality or user-visible improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve promise error reporting with typed failure reasons

2 participants