Skip to content

tests(ethexe/processor): test that injected vs events tasks are processed in correct order#5248

Closed
playX18 wants to merge 3 commits intomasterfrom
ap-add-test-order
Closed

tests(ethexe/processor): test that injected vs events tasks are processed in correct order#5248
playX18 wants to merge 3 commits intomasterfrom
ap-add-test-order

Conversation

@playX18
Copy link
Copy Markdown
Member

@playX18 playX18 commented Mar 25, 2026

No description provided.

@playX18 playX18 self-assigned this Mar 25, 2026
@playX18 playX18 added A0-pleasereview PR is ready to be reviewed by the team D8-ethexe ethexe-related PR labels Mar 25, 2026
@semanticdiff-com
Copy link
Copy Markdown

semanticdiff-com bot commented Mar 25, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  ethexe/processor/src/tests.rs  0% smaller

@playX18 playX18 changed the base branch from gsobol/ethexe/tasks-second-step to master March 25, 2026 12:23
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 introduces a critical new test to the ethexe/processor module. The test ensures the correct processing order of injected transactions versus canonical block events, confirming that all injected tasks are fully executed before any block-event processing begins. This enhancement improves the reliability and predictability of transaction handling within the system.

Highlights

  • New Test for Transaction Ordering: A new test case, injected_and_block_events_execute_in_correct_order, was added to ethexe/processor/src/tests.rs. This test specifically verifies that injected transactions are processed entirely before any canonical (block-event) transactions, even if canonical events are queued earlier.
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.

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 reorders the processing steps within the ethexe/processor module, specifically ensuring that injected transactions and block events are handled before scheduled tasks. A new test was introduced to verify the execution order of injected transactions and block events. However, the new test has a verification gap as it directly calls process_queues instead of the higher-level process_programs function, which orchestrates the reordering logic. This means the test does not fully cover the behavior change introduced in lib.rs, which is a violation of the repository's style guide regarding verification expectations for behavior changes.

Comment on lines +1145 to +1283
async fn injected_and_block_events_execute_in_correct_order() {
const INJECTED_COUNT: usize = 10;
const CANONICAL_COUNT: usize = 10;

init_logger();

let (promise_out_tx, mut promise_receiver) = mpsc::unbounded_channel();
let (mut processor, chain, [code_id]) = setup_test_env_and_load_codes([demo_ping::WASM_BINARY]);
let block1 = chain.blocks[1].to_simple();

let canonical_user = ActorId::from(10);
let injected_user = ActorId::from(20);
let actor_id = ActorId::from(0x10000);

// -- Step 1: create and initialise the program --
let mut handler = setup_handler(processor.db.clone(), block1);

handler
.handle_router_event(RouterRequestEvent::ProgramCreated(ProgramCreatedEvent {
actor_id,
code_id,
}))
.expect("failed to create new program");

handler
.handle_mirror_event(
actor_id,
MirrorRequestEvent::ExecutableBalanceTopUpRequested(
ExecutableBalanceTopUpRequestedEvent {
value: 500_000_000_000_000,
},
),
)
.expect("failed to top up balance");

handler
.handle_mirror_event(
actor_id,
MirrorRequestEvent::MessageQueueingRequested(MessageQueueingRequestedEvent {
id: H256::random().0.into(),
source: canonical_user,
payload: b"INIT".to_vec(),
value: 0,
call_reply: false,
}),
)
.expect("failed to send init message");

handler.transitions = processor
.process_queues(handler.transitions, block1, DEFAULT_BLOCK_GAS_LIMIT, None)
.await
.unwrap();

// -- Step 2: queue block events (canonical) BEFORE injected --
// Even though canonical events are queued first, injected messages
// must still be processed before canonical ones.
for _ in 0..CANONICAL_COUNT {
handler
.handle_mirror_event(
actor_id,
MirrorRequestEvent::MessageQueueingRequested(MessageQueueingRequestedEvent {
id: H256::random().0.into(),
source: canonical_user,
payload: b"PING".to_vec(),
value: 0,
call_reply: false,
}),
)
.expect("failed to queue canonical message");
}

let mut tx_hashes = vec![];
for _ in 0..INJECTED_COUNT {
let tx = injected(actor_id, b"PING", 0);
tx_hashes.push(tx.to_hash());
handler
.handle_injected_transaction(injected_user, tx)
.expect("failed to queue injected transaction");
}

// -- Step 3: process all queues --
let transitions = processor
.process_queues(
handler.transitions,
block1,
DEFAULT_BLOCK_GAS_LIMIT,
Some(promise_out_tx),
)
.await
.unwrap();

// -- Step 4: verify promises for every injected transaction --
for tx_hash in &tx_hashes {
let promise = promise_receiver
.recv()
.await
.expect("expected promise for injected transaction");

assert_eq!(&promise.tx_hash, tx_hash);
assert_eq!(
promise.reply.code,
ReplyCode::Success(SuccessReplyReason::Manual),
);
assert_eq!(promise.reply.payload, b"PONG");
}

// -- Step 5: verify ordering in outgoing messages --
// Skip the very first message which is the INIT reply.
// All injected replies (destination == injected_user) must appear
// before any canonical reply (destination == canonical_user).
let messages: Vec<_> = transitions.current_messages().into_iter().skip(1).collect();

let mut injected_count = 0;
let mut canonical_count = 0;
let mut seen_canonical = false;

for (_, message) in &messages {
if message.destination == injected_user {
injected_count += 1;
assert!(
!seen_canonical,
"Injected reply appeared after a canonical reply — \
injected messages must be fully processed first"
);
} else if message.destination == canonical_user {
canonical_count += 1;
seen_canonical = true;
}
}

assert_eq!(
injected_count, INJECTED_COUNT,
"Expected {INJECTED_COUNT} injected replies"
);
assert_eq!(
canonical_count, CANONICAL_COUNT,
"Expected {CANONICAL_COUNT} canonical replies"
);
}
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.

high

This test is intended to verify the correct processing order of injected transactions and block events. However, it calls processor.process_queues directly, bypassing the main processor.process_programs function where the ordering logic between handle_injected_and_events, process_tasks, and process_queues is defined.

The recent change in ethexe/processor/src/lib.rs reordered process_tasks and handle_injected_and_events within process_programs. This test does not cover that change, creating a verification gap, which is against the repository's style guide (see rule on Verification Expectations).

To properly test the end-to-end processing order, this test should be refactored to call processor.process_programs. This would involve:

  1. Collecting the BlockRequestEvents and signed InjectedTransactions instead of calling handler.handle_mirror_event and handler.handle_injected_transaction.
  2. Constructing an ExecutableData struct with these events and transactions.
  3. Calling processor.process_programs with this ExecutableData.
  4. Asserting on the resulting FinalizedBlockTransitions.

This would ensure that the test validates the overall processing logic, including the recent reordering, and not just the behavior of process_queues in isolation.

References
  1. The style guide requires that behavior changes are accompanied by tests. The logic change in lib.rs is a behavior change that is not covered by the new test, creating a verification gap. (link)

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

Labels

A0-pleasereview PR is ready to be reviewed by the team D8-ethexe ethexe-related PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants