Skip to content

feat(ethexe): Create PromisesBundle for sending promises in network#5099

Closed
ecol-master wants to merge 1 commit intokuzmindev/feat/rpc-subscribe-all-promisesfrom
kuzmindev/feat/promises-bundle-for-network
Closed

feat(ethexe): Create PromisesBundle for sending promises in network#5099
ecol-master wants to merge 1 commit intokuzmindev/feat/rpc-subscribe-all-promisesfrom
kuzmindev/feat/promises-bundle-for-network

Conversation

@ecol-master
Copy link
Copy Markdown
Member

No description provided.

@semanticdiff-com
Copy link
Copy Markdown

semanticdiff-com Bot commented Jan 21, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  ethexe/rpc/src/apis/injected.rs  64% smaller
  ethexe/rpc/src/lib.rs  7% smaller
  ethexe/common/src/injected.rs  3% smaller
  ethexe/service/src/lib.rs Unsupported file format

@ecol-master ecol-master changed the base branch from master to kuzmindev/feat/rpc-subscribe-all-promises January 21, 2026 09:28
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ecol-master, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the handling and distribution of transaction promises within the ethexe system. It introduces a mechanism to bundle promises for efficient network transmission and provides a new RPC endpoint for clients to broadly monitor all promises. The changes streamline promise management, improve network efficiency, and offer more flexible client-side monitoring capabilities, ultimately making the system more robust and scalable for transaction processing.

Highlights

  • Promises Bundling: Introduced a PromisesBundle structure and a utility function split_promises_into_bundles in ethexe-common to group multiple signed promises into a single network message, optimizing network traffic for large numbers of promises.
  • New RPC Subscription for All Promises: Added a new RPC subscription endpoint injected_subscribePromises which allows clients to subscribe and receive all incoming signed promises, providing a broader view of network activity beyond just promises tied to specific injected transactions.
  • Refactored Promise Management in RPC: The InjectedApi in ethexe-rpc has been refactored to use a new PromiseManager struct. This centralizes the handling of individual promise waiters (for sendTransactionAndWatch) and the broadcasting of all promises (for subscribePromises), improving concurrency and maintainability.
  • Promise Reception Timeout: Implemented a timeout mechanism for injected_sendTransactionAndWatch subscriptions. If a promise is not received within a VALIDITY_WINDOW, the subscription will time out, preventing indefinite waiting for potentially lost transactions.
  • Consensus Layer Integration: Modified the ethexe-consensus validator logic (both producer and subordinate roles) to utilize a new sign_promises function, allowing for batch signing of promises before they are potentially bundled and distributed.
  • Dependency Updates: Updated Cargo.toml and Cargo.lock to include new dependencies such as alloy, derive_more, thiserror, tokio-stream, and tracing-subscriber, supporting the new features and improvements.
  • Enhanced Test Coverage: Added new and updated existing test cases in ethexe-rpc and ethexe-service to thoroughly validate the new subscribePromises functionality, concurrent promise production by multiple validators, and the overall robustness of the promise handling system.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

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 introduces a PromisesBundle structure and a helper function split_promises_into_bundles to divide a list of promises into smaller chunks that fit within the maximum gossip message size. This is a good step towards handling large sets of promises for network distribution.

My review has identified a critical bug in the splitting logic that could lead to data loss, as well as a couple of medium-severity issues related to code clarity and robustness. Please see the detailed comments for suggestions on how to address these points.

Comment on lines +172 to +185
let promise_size = promise.encoded_size();
if size_counter + promise_size > MAX_GOSSIP_MESSAGE_SIZE {
bundles.push(PromisesBundle {
promises: current_bundle_promises.drain(..).collect(),
announce_hash,
seqnum,
is_last: false,
});
seqnum += 1;
size_counter = PromisesBundle::encoding_offset();
} else {
current_bundle_promises.push(promise);
size_counter += promise_size;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

There is a critical bug in the promise splitting logic. When a promise causes the current bundle to exceed MAX_GOSSIP_MESSAGE_SIZE, a new bundle is created from the existing promises, but the current promise that caused the overflow is skipped and not added to any bundle. This will lead to data loss.

The logic should be adjusted to create a new bundle when it's full, and then add the current promise to the new current bundle.

        let promise_size = promise.encoded_size();
        if !current_bundle_promises.is_empty() && size_counter + promise_size > MAX_GOSSIP_MESSAGE_SIZE {
            bundles.push(PromisesBundle {
                promises: std::mem::take(&mut current_bundle_promises),
                announce_hash,
                seqnum,
                is_last: false,
            });
            seqnum += 1;
            size_counter = PromisesBundle::encoding_offset();
        }
        current_bundle_promises.push(promise);
        size_counter += promise_size;

/// Currently set to 1 MB.
pub const MAX_GOSSIP_MESSAGE_SIZE: usize = 1024 * 1024;

/// The bundle of promises which will be distributed in network in a single gossip message. #[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

There's a typo in the documentation for PromisesBundle. The #[cfg_attr(...)] attribute appears to have been accidentally included in the comment.

Suggested change
/// The bundle of promises which will be distributed in network in a single gossip message. #[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))]
/// The bundle of promises which will be distributed in network in a single gossip message.

Comment on lines +147 to +153
/// SCALE encoded size offset of the bundle without the promises.
/// This is needed, because of the size of the encoded data is not constant and depends of the data.
///
/// `100` bytes is approximately three times exceeding the actual size of the bundle without promises.
pub fn encoding_offset() -> usize {
100
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The encoding_offset function uses a hardcoded magic number 100. This is brittle and not precise. It would be more robust to calculate this value dynamically by encoding a default PromisesBundle instance with an empty promises vector. This will give you the exact size of the bundle's metadata.

    /// Returns the SCALE encoded size of the bundle's metadata (all fields except `promises`).
    pub fn encoding_offset() -> usize {
        // An empty `PromisesBundle` will give us the size of all fixed-size fields
        // plus the overhead for an empty `Vec`.
        Self::default().encoded_size()
    }

@ecol-master ecol-master closed this Feb 6, 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